asda?‰PNG  IHDR ? f ??C1 sRGB ??é gAMA ±? üa pHYs ? ??o¨d GIDATx^íüL”÷e÷Y?a?("Bh?_ò???¢§?q5k?*:t0A-o??¥]VkJ¢M??f?±8\k2íll£1]q?ù???T run/chkservd/mysql000064400000000001151027444130010241 0ustar00+usr/bin/mysql000075500021256370151027711210007235 0ustar00ELF>4@xUE@8 @@@@888kd;kd; hj;hj[hj[@ z pt<pt\pt\TTTDDPtd999FFQtdRtdhj;hj[hj[/lib64/ld-linux-x86-64.so.2GNUGNUL,6NA˕xѹXI0DI% P:t B @@iH PT!H X`9 6bHPAaIRH@$BH@Pm@  ( `@A@/ &AAGDDJA@T`n *AX@PA @0 @ AAD r#EPa$`8A@" d( 0 @@"@0)` @ &@zP XPA#%D a  I@bQ` X 8 P #DQ $@@A  p.A $£$ $ %B $DEDAЈ dH H! @!2&`<"H(`Bd $E,`@ E&$dHT0Q'@`@ @`"@APA $PQ2R@#  ` @@F4@ (Xe PtP@AY@@ 9`1 I!T0 "DD`ڹ@H@@ b$QA  РRY! @@PT dDD @Q;"X@DB@*$BP$Rw 0D  [ 1dH 0` %XRP}@". @@0 T! B @ `l @HA 0 eH 8'JJ$ APQZ!`"003~')@h B"",H"@"L$) V @@ @B$Hb@2 GI$S[&U <@CD0 C@DD)@AP$Ȥ eމ  A  @_@' xD () !_j  P ,S!H Q*B$+@Dظ,p 2 $%0PAV7 `   @d)8P XL I@A@LPcU` L, @ 0@ #xAc FZ€DH$ A #@$$!&`B0 X @:pAAc' 9D A@HE P F#J! qD`(Q0+B@ pN"#B$ >`6@@' @ @B3@ "A JCI "@e @!@ @HdK R$)B  `TH$PFRJp"XF  &` @Ap0a" (1 @@TkT@`A @@C PD@UQD5pD  ; Db 8`e`:@PH ) H`AP@@HH!! D$Da  &#    $&')+,-.03678;?@CFIKLMPTVX[]_acdejmpqstyz|    !"$',.3458:<>?DEGMNOPVY\^cfhkmnqvwz| !$&(+/37<=>@ACFGKMOPRTVXY[\_`behkmpqrswy} "$&'(+-/2689>BGHJLNPRTUVWXYZ^_`cgjnpqstwz{~  !$%'()*+./134679;?ABDEFGHJLORVWYZ\^`adghjlnprstuw{|  !#$%&)+-/0346789:;<=>CEFGJLNQRTVX]abdfhklmpqrstw{~  $%(+/069;@ABEFIJKLOQRSW\^`dghjkprvw{|}     "%')*-/1245679<?BHKNQWXZ\]^`cgjlmpqsw{~5ljۈk[Ex2Y3?RnF:dc]@6\Yҿ$b lvyd5+I)OLAt垭G2Ah3I)k|@9rXvsé:7[kpa˔~5u$ 0sC__MNtx ktSU||CN҆ ?MC"/E}g`G Q-_ Q S `2|fʹN7` 8ۆŖQ{J.?G}e9.*=> 2dw"G)CfCޞCD Tzxkcu7w[;{_FCb [Msg) yp(')#MdS jjV[R֕8c֖Kex?'ҞtK쳨th,9z?vA`HG(<Szwo/_qa6MkzBlHn7ڣqaٍL j;j`,+v`/9sn !TmbW.Z ݹ$\8Mj +#Af2i-NOi2LX%d3/t^r˨[30B!ǠYrFr]H d3plz6T(&E56h&p5lHNfG,\PPp#4P'e}r*dB@񩠷Stb#OɅ77 TEI8 JEma*ߓƚvBEѪڣ2Qe QQ`B#.g݄0Oto]so hI#!}QhwФu;Td%þDnsv08hEcĤM@ePMj8I uװ0٫V>̳RFi"~?[{}\+X\_R ZjA;+śQH Iu4F23 ` uDyQ1 No3 9 F $mN$- 60q"aaeKi&7cMuB,_")xيS*C.HC|J%6*V%F~8iFD٭K,JiP/Lu>=~빣qʿ5(z~IUr`ބtit15+H]Q B"D[ : (jؓ]uMlAHg1hǙ˘Bc,_nOu2Ҡel&8;'c3g2RC!cWǂux W;=ܛd`Swݨl"oz U`k&"wC8vGa,gZMЛ BhoMԂzmL#$ֻZM(51ZGmNUT+mLɎ^KSZQOmlMl&1Mp/n$tCi=O@#]/;Y\a'46s,Fɣ Nlh!?]ПM$ӂ9ƫ囀rj,/Y bFQ5Brlud"u>T!>iW= ޢpxKWE++^ )5HgF\=] Uqt MhP+@,knF! պ9fF1T9KZ5Rf>QgqGr<kKbNΘ҆'#WJLoj?ʑg֍?y+7'&$Ln#Z_' ^| iN6ʦ[ $ݷѕQ_͹wnUfDJerbl; 1"J:*",XN?Q4`Ӯhye1l\ #P3qwAx;%?=1 ,F վŸaB m  {D 5fBf{1`d23 " zcpaP,Xi_ ^*Qm[)^PCItU5N>0o^j>"31|m$pqXn5cAr1} n7햞p3p*[mcLk~_Pj/Tϫc_ {h&j EřP)Nd%}.ZgU'*v<#֣4=%-Y4L %4`zV+pE΃I,~I:̋uK* ZtjE\q7,G@l|{]_x sT 6=fZg 9΋mx[nF,R2@*"LmpóXAC!+:f; 6b#~(wnT9Q8(޽h\9"N/dGSk3)Y5ɔ +@o;m.C@ V 1FV% "pZI 7eƲU!%V <p[=u~2a(?|xm !Mj|S7̏8ʷbA/.F8Esdƾ͟J/?֬$*U"Eu~QocK\. q%Z̝\mO@$ N|2cѷc:;k8"I 4NǩQ*K#{n+I6}⭸?VD7BCMF8@;2oV sB*J#7NL .%n#\K"9'8+o7kW{{?a6~X޴ELnPD>DbZvv;6.^!YD:.u3b턀MG{VysۙBϻ_N`3`#کQEClzm- # Nx)dKU7=j j%nB4Ujtx*Nd2YMiCmREs[8QR.d/gtJ?70&X#uV؇ml>V6ۅiI64: Wa4=uv,maVZ~6ۀ6!@ʺ{JW(XfsF@Ux|e,]'֝V(֗__w*(Dk)"@Բ@{$bxg@ਘ@*k? =^QsvVIϙttc~(NJ},+T1@eD/!8 ׌:rDAeD_A5E/招TgԶAꌏna}#rZʉ%KZ`:c @t ;E8~>Y0 3H9%'ܻ~_w2&;{'T*)oBx"'d:ڦ]ADN `aorho~x$Ї3~nX;9p n,{$?{%b"СVz8#N`0CmXiT$=*sg"yCJdfjK T.x $ z!re[p*b{tv _7a %񩫵c\|a6 qB_MO]?IGrA&p.=ޣisW%3̒л&4w-*CaLղKƓ@ s;R^(FM6OcI*&t.߇tcV*IksPK})! 7(@yK Ӑ41` ~zNʹج}!2L6&$'~O+3ǥ݊5 Mhʝ㞃\eoۼvdQZ) ^H$g^/@q""~|>8ԢFZs{"2t#`5 s CgiiP_ "d)VZ S]4YHhJ:S<b`|ŸMҎԓ /kv )p\nk'e`z\*ȃ2'ӹyNFuĻImje (ގKxndq&,i[(Ĩ:y}P+$[ofrت3ɾ>"Ťpd @iw오QY=}3y(׊Ej'DϠw4NdBڋPyg*-a[stLwa;ՋȞZrԯt|"pܨ1W/9!UA6Ql[xO)mx 9/KM(7qwݑDsX5Pn`lу}Y0Z 4}; }.rakh%~i69r0[j|1|I|Z2eՌ/m"0KsT/ U *ZrG Q$Ln#|'w$L,5 x xZnһry‹&K8`geF7uy ίiSsJ$E~AIS<->;>ɑO~,[(:kqD,7yFޜ| R=裞Liv)*G82cz^m XV9 GՂ5^sOGRȢPq6N|!ɾ1#%bG@Z_>M[܃ٶ|ϥ{ /] t1]D2F~kŐYvr Lyp̈j/SJB? !Vɚ2BR^i& n߉\wYD N¦>H 8QK:Oa$p+8 JZ͊ wI2J}X9[Dѯ , "ZvRJ  p I#I` R A ,; p iT ,i> ".H   p ao1 _  OlmU0  FO a *  m xc $ 2O v A  9 eSG+?$ y & o \  =nwFc   ` {L+ '9 C}696 M L A R]i   K  1-"   60 zU~ R  A3-  =qϊ ]H pxfy`Mx3] & sAC] &b  `^v  @D  p [xe. ` 04X @ veǍ ' @ ;o p [ P : 0x3 P  ? "h@`_k %vt " | " J ` P  P)  az1'b?o@`) `O )87]E7 01 s# K1+O 0N@@] V`adj6er`Z\p} O s3 0 )   e > ` OeZ !'de c ? $]  % r  ! P]Vl @ %/ P @\ p} 0g PM~@` @mYeA]^2 T @ * ` n S  G( ~ {;N\pe(#e ']`Z`$e@CXe o h D4C 0 CH `" `&_e<5 `eGk(e| `  `\pex / p0:]և`Y * z 0  P=  `$] exV&b;]@`c6]HP @ M t $  b@`A`& *A]Y `zZ@+bS_  a ` Aj г yU\p(`O|eQ\pƪ G N r eW 0. g d @Li 0 B`3]  |  No3]  Z_ [  d Й J 0" ) ^6s GT ` 7" }3  nU v p` 0a(z ! j $ڗe.`. ` ܩȽe,# B PY#e;]Ə 4*  6M n ` h7v D ͌ 0 QeT@ [e(e p' behN`- & *Y P> ]^``Rr 0& 5 vƙ ` 3/ ) 2  )fg $_[{e 97Ll `= x"b= V4 0 y3]"PD+  x]>]K 09i r *  \ #`EP#e v5@ a ^ b w 0] .ԙ P-7 / F> eneM 8 w \K, K9` "  d h '(,`an 8 nd  "en> P; 9`` a& @ `` `W/ k4PeD 7ke| !< ;X 6q`el&x]HH\D. ] << 0*  ` A0eo Х S^``l q+R 0 ݡ &S 0v T`eIe֤][``C p ! @^ w?H }(zn`?!H7]S p 3;# QVPemevp  v s  PQ } m`6 . Ose . P -x`eQ 0& %' ( 0  n-[ %` UM Ρe)#cJ @*fa a EM > 9]% P 8 P: GeH vڀ L 6 "q `] `e z Ne8@ j39e ` i``@`QI PSp } `r 4 s+\ rH8 `$ |e>eAi ` j s\^, ~ @,~00eoe0 y0#e{  :0 (a.?[A ӖȨeq!A]{P]x d b p ]v$ P- pe Kf y  `tUpeye! 4X&eq  u _ } O  + O uE B IS pA*K | @ّ PL$ pz P mle9 jNe  9 8' K G8eU< @ @ejf  $ о]  % P 4M@;] V}_; 0H ] 0 , ga$e, & #- pK^H 5V Kj ̒  0 0& 0`e+(`` ^1M v P  c 9 d  %  Pe2T Q v Db q 0 O6 Z ~  Т  2 ; W<  `t&]_Ds\ г jT !:q``1 `գ 0 K g Pd 2^o : pte*eD= @q B| P n3]T 1  *ˬ` em,Xe3 `Qp S +:]Tev* ?  ; QXteL e`[\p 0=J 9L  0:b 8J`> 'V ,$e <@  z` P  B]`z w D pb G kJ @!4|!bt и  0U F87]W\p,eXddXet SS\p @ `eE O[ "C; O'_uWȮe  e @ w7c @iXd`(]v  tH ` R"`4 1Sn ` mM p   8 Y;R n  P 9W H x S E `HGTee  Jh@^ k :+z &f 0خer ? <  U  ! H p~ @A AF% 4B0e&k``6 (qeL{  `'P 4 G>]  R d  ^ #r:]K2P7]0Q  Z `j``0e@" [k 1 i e b p ld P D @ e'% P 4d : ea; Fab , r 9 _c[X7]g 0g #e  @ }c_`T@$b  0Ψ@7]}de$e ) R A PL zleDt`eg #  Vl^(eQ <e? ? L `re5 ite-(eBeZ p-Re( 0  ;k Ohe}d 'bHe @3 i U@b ;Y 0 6` ^'q 0  { 0! H}I ^#* @%@p;]N]  /q> P 5: >   .xe7 ^/ ]8#e@*`M  0rra`;]|3\p? :5  1B  =+V\p@?R\pBr 6 Iw`9i"`% pY f7ew\k\e p ^= P a`  # k {@  ;z 0 fae@ ;C4e&l ^u `> e+!eN`Zq Z/ q=  Z`! p[Z #@u`{ P( C׎ \ +٘ `ت`=`M\pz. p !? @ p = 0  T ~  _ 3v 0! r` `9a (8` 1 'J - <X 9 % "uf Pk \ P ' |WP Pd _ec L _ s# PtZT +(w = $ ]& XA' P R) gw p  ji  ТZDHeL`hd / + p Hr 8% Pv ny} 0D !_de\e "%eτ @z Y]K`Y\p8e5 `;6 U;e&  8 Hh yO `h1X  %_\__ X+ p7]I P>*!)`,`O\pG nP p I 9 VL B #[ K e `:l0e,heP Ep  K !(]`P> 9rDe` 0 . D `}m H ZB _E`yG` 4 ` E A yFA]FVhe_{@e0z]~ L e !W _!!{: i ' p  pF eme N % . ! ` ]6 PO \ $  `& x 0D} &b=  oT\p( ' 0M = `3a &׃P\pR0 % )Z m `: R`n 93eT _ "m w`8x s 7Q`%2 `5gd! @_H { p) pʈeP G q w p:|¡  #`?  : p G %Q`v *cR #e9 040e.W 9w 8 " P:=e , s\#&b(' hT |5P "me8u 2  p- ^eT" L"3`xd/{ :L . P0 (;]% 3h 0 ]u J  0  PQٛ 0 H`#bg m 01 IBg c7} p, w @r]E 0_G]W ~ 3 ' !4 ` ] l 0 iͧb p o P 0 do P &b<e6e0 I ' * ^"@`% `ip д`|  _Д @ ,M G΅ & GW c @ 9"( fd$ S p P p Ez ; &]3e- p Ly  Wǂ ]`d & # >FA]{ ,U^ 5g \7( @Q V\ 0 g]`Ԑ_S p& -n :< 0Q.Benn @ aB AXe;`X> v~ ` ~ P !e$ U%6D @ "> a(  2 "e * Ice' + m  fl @ s %bV]Y p _s@$e t| 0 ) em `7 `$v@e r Y s  %PF v _ e $ `_ #. I;] l r + ]à !D 4& P% 8 ``Q 'h= ! 7A@bd4]`ḫen  ( cȓ p 6Bene"PA`9 $ @ @$ZH\  lJ]  <e* - # ֥ Xe^ ab p   ( -$ -  +ep ? t] B  ZY @5 q6e!G P+ M @ .(  Gy p v`' @ 2`|Yeh@`É P,ޕ p6< 4A]v l ~ 9t 0j e 0 X p ޜ Pbther а QD0eV V ' 0x`r~ @t A~ ?  Da [< ` LUA D /| * E `Oe  )H@erQ`L\poe P / m 5G k 9 7n  p2` a|s" &yu +  ,< F J*3]j: @/ =o  PE F5 p- zEh +`X\p8pe? Ц s D _.Y ] u .e\ ` $f ` P |&  <RH `Z @ a 0    p&J z V]w (   X 0 N i s``t``g `g n * "[\pJ(e&]9 P ?` ? eՊ h]G][ w s# wv 5C ce2U]' ? b   Hv   `p a( : 0 `p8@`>K ؜ 6L@_ 9.a3 \  W2 ,b eR\*n%ec ^a( +`9 ` jg0 J n ml t b? O @4 y5 ` q6(bO]` pC y qx  Gw`p\ e= :Qՠ p R# p 7 z e0, 3 0 KV #1N eUS]b`N\p5`B RA]O I  `6gq `   ==SDeئ 09,e{ @N y  8ekhePX8eD ]8 { ] S  ;]P5`V\p `R\p@J` ] 0 I]s``U  e(#e%aبeB C@` (eKR K z1 w9%g  x h%bLx;]Rza  * s_ C [S6]` &#1xe-` Z\pf  [ %o6]i@e $eIe%b vC <wX`` Fs v  ` @/``: ]cX @#eiI L;Oe|[ nG`:] [k em  - wX )p  q`] p I9`C  @eU`^. V=eiV P X P8  %O     : 9jU p; * _cn[i `9CR`7]@9  9mTM\p ZA] P!X0>]J3]]eɛ _ 3ȟ`9 m @= x @ 6!A]P i sezxe| # p 0``a at]@3]>M`o^eg 04 j a@@ewJЮeW P @` ' , 3 Q2 ҁ 1  0 O' $6 1p@`u P1+8e  ef# @ .0xeieed|` b PZ V   @  Ai)X\pZ 3 v8 4J]w Es \(+ b]  o/ $ H  ;8 } S@_) 4>e pH ms @+    0Y$ r.: ^fu 8 в 5: &V wq _ J }i PV _hSe)s 4`\\iL % F ( w  ` "A} Do PU `8_ 7he  < r'.^!K]φ `= @1 P O klZ UE [ Ce& !B) ` 0 [ xCHe8e(97-m^6O\pg Av`de P%  N~ y ' N=   ( 2 !)` a , P q*1 } bt ` %m1 MO1  6D @a q A p\UC 4  K w {e w R=`Q @ k3 c @  P"d/ ,  pW ,-  /  ^` 6 a C0es `a &~` ~ 8 /&H93; @ A`)`<+ 9yk `-peYS\   "ae] 0 .` {  p7 f \ L 0  7* 8 Aw Pn k zY*@bf`t  Tu`X- bj8e ' p `1 Y_q Л Qf h` Meug D Pe%c  pg&]`)e\, Re p 5j ФIpe;j `4tew $ |  ~6 e|']x `9  9ie ; >3 p J1D G^ Д   7 0`U\p)]x .m`Q\p"  *GQ \A]TF`x : 9 @ ? ^ 3#`0 +B !p `De,SeW ( * Ob` IN`a`DO`1 `8 " , 4 p[ @ ` . Y Y+ G F !ac$e  b>`pdvL 3 R  }/ %] 5 M?9%֓ `"4  r ) ;]x`ec C|Be .  M Se4 :' t PL L3 )I `2 UE\p[:]d D  ` @ _ 9 }^ P  `cO 1 4@`S X9 z7 _{K \ŋ p`30$e  we I 1}j`)d  P; "`3 \ PaY\p} @:."_B o = вu< ][ j `e8 >F!e[j$em `ɩ` \W8`0J 0 : t -< 4 $D `V`&]`Ieu A { #  H &#   * _ 0y i 0 p: n To 8 P  p3 Ee $!  [ >!]ePg P Nho @ :i W=T `& &Sf Zt 09 n1e`.`B  ~ ` / O D a 2[ Jx;]f ^ $(eY_YM]mM i  CN 0 <~`F\:eNte1 g? y 9z CWe)M ` @`E\p*e2`3\pd 1 kj @ mr qQKes ; * nT]WxaP9Ղ@`O B pO_de '[ 7 F` M 5c`aKA] UHem 60 &8 7s3``>  Щ k 1{`F _ a]d W| AeQ )&b= cTt H]F Q I)bs 8 % F* >a/ T3e p w\} $]0GB Q` k 9 P eP @47 %Be $ri pJj@] 0  ,n <?͜ 3 &]( p G@  .  . >A] ` `tF 6 pw = 66  \]m P { "N @} !  % 8pe ` _x7 P\ 5A `F yy @N`W\p1 : B`S\p^L\p EN H X = PLG`C p= ,9 &B P8`6 P( .p'eg amv 7`U `;(`3\ 0 Wv  `d Bn K ̊ o97]1 Qc ?B  C: 0Y;`C h  ] @ Hd O8:9 P uDegl 9o @ 6e= PD`qe:]q:] `8 d 0LJ pe g @ h u / O+_ :`A !libpthread.so.0_ITM_deregisterTMCloneTable_ITM_registerTMCloneTablepthread_rwlock_tryrdlockpthread_cond_timedwaitpthread_mutex_initpthread_cond_destroypthread_mutexattr_settypepread64pthread_rwlock_trywrlocklseek64pthread_cond_signalpthread_mutexattr_destroypthread_setspecificpthread_cond_initpwrite64pthread_key_deletepthread_onceraisepthread_rwlock_rdlockpthread_cond_waitpthread_mutex_lockrecvpthread_mutex_destroypthread_mutexattr_init__errno_locationpthread_mutex_unlockpthread_getspecificsigactionpthread_rwlock_wrlockpthread_key_createpthread_createpthread_mutex_trylockpthread_cond_broadcastlibssl.so.1.1__gmon_start__SSL_get_verify_resultSSL_writeSSL_shutdownSSL_CTX_set_ciphersuitesSSL_CTX_use_certificate_chain_fileSSL_CTX_newSSL_clearSSL_set_fdSSL_CTX_get_cert_storeSSL_readOPENSSL_init_sslSSL_set_quiet_shutdownSSL_set_ex_dataSSL_CTX_use_PrivateKeySSL_CTX_check_private_keySSL_CTX_set_optionsSSL_get_errorSSL_get_peer_certificateTLS_client_methodSSL_connectSSL_CTX_freeSSL_CTX_set_default_verify_pathsSSL_CTX_set_cipher_listSSL_CIPHER_get_nameSSL_get_SSL_CTXSSL_get_ex_dataSSL_CTX_set_verifySSL_newSSL_CTX_load_verify_locationsSSL_get_current_cipherSSL_freelibcrypto.so.1.1EVP_PKEY_newX509_digestOpenSSL_versionERR_get_errorX509_check_ip_ascX509_STORE_set_flagsERR_peek_errorX509_verify_cert_error_stringX509_freeX509_STORE_load_locationsEVP_sha1X509_check_hostERR_reason_error_stringEVP_PKEY_freePEM_read_PrivateKeylibz.so.1compress2libdl.so.2dlclosedlsymdlopendlerrorlibncurses.so.6vidattrlibtinfo.so.6BCUPPCtgetnumtputstgototgetenttgetflagsetuptermtgetstrlibstdc++.so.6__gxx_personality_v0__cxa_guard_release__cxa_guard_acquirelibm.so.6libgcc_s.so.1_Unwind_Resumelibc.so.6fflushstrcpy__printf_chksprintfsetlocalembrtowctowlowerstrncmpstrrchr__longjmp_chkwcrtombgetpwuidunlinkat__fdelt_chkclosedirstrncpysigprocmask__stack_chk_failunlinkputcharselecttowupperstrpbrkpopengetpidiswalnumiswlower__ctype_get_mb_cur_maxstrtokendpwentstrtolisattyldivfdatasyncfgetsgetpwnamcallocstrlen__mbrlen__cxa_atexitsigemptysetgetaddrinfomemsetstrstrrmdirtcsetattrchdirmemcmpgetsockopttcflow__fxstat64_setjmppoll__fprintf_chksigaddsetctimeiswupperstdoutfputcfseeko64getrusagefputsstrtok_rstrnlenmemcpyfreopen64__memmove_chk__vsnprintf_chkmkostemp64strtoulsetsockoptgetpassstrcatstrcasecmpftello64__lxstat64nl_langinfoopendir__xstat64__ctype_b_locgetenvgetservbynamewcwidthsigdelsetioctl__snprintf_chk__memset_chkgetlogingetuidstrncasecmp__realpath_chkpclosegethostnameusleepgetcwdgeteuid__memcpy_chkclock_gettimelocaltimestrchr__vfprintf_chkreaddir64tcgetattr__ctype_toupper_loc__strcpy_chk__ctype_tolower_loc__cxa_finalizefreeaddrinfo__xpg_strerror_rfcntl64__sprintf_chkmemmovepthread_selffopen64accessopenat64strcmp__libc_start_mainsetpwentferrorstpcpysetenvstrcoll_edata__bss_start_Z18find_longest_matchP9hashtablePcjPj_rl_completion_case_foldthr_set_sync_wait_callbackrl_mark_rl_output_character_functionkey_memory_QUEUE_rl_digit_valuemthd_my_read_one_rowkey_memory_pack_frmmy_longlong10_to_str_8bitmy_charset_utf16_czech_uca_cifatal_error_handler_hookemacs_meta_keymap_rl_enable_metamysql_list_dbsmy_defaults_group_suffixmy_charset_ucs2_unicode_nopad_cirl_forward_bytemysql_fetch_fieldrl_redisplay_functionmy_charset_utf16_persian_uca_ci_Z25mysql_real_query_for_lazyPKcmmy_getwd_rl_with_macro_inputrl_yank_pop_rl_print_completions_horizontallyrl_vi_completemy_like_range_simpleread_history_rangemthd_stmt_read_execute_responsekey_WT_RESOURCE_condplugin_listmy_once_strduprl_forward_wordread_history_rl_clear_screenmy_strdupmy_b_safe_writewhere_history_ZN13Binary_string4copyERKS_my_b_flush_io_cacherl_variable_bindrl_backward_wordhistory_offset_Z16find_all_matchesP9hashtablePKcjPjmy_charset_8bit_handler_rl_term_autowrap_rl_search_getcharmy_time_to_wait_for_lockkey_memory_max_allocamy_charset_latin2_czech_csrl_getc_functionget_global_errmsgsmy_charset_utf16_handlerhistory_searchrl_attempted_completion_overmy_stream_openedma_field_extension_deep_dupfind_typecharset_name_binaryma_pvio_blockingmy_wildcmp_mb_binpvio_socket_fast_sendmy_charset_ujis_japanese_nopad_ci_Z22batch_readline_commandP14st_line_bufferPcmy_uca_collation_handler_nopad_utf8mb4_Z9tee_fputsPKcP8_IO_FILEmariadb_stmt_fetch_fieldsmy_mutex_endmysql_list_dbs_cont_rl_push_executing_macromysql_server_initrl_execute_nextma_zlib_decompressmysql_stmt_row_seek_rl_kill_kbd_macropvio_socket_async_readrl_completion_append_character_rl_output_meta_charsmysql_thread_endrl_initialize_funmapuca520_length_w2my_unicase_unicode520pvio_socket_closemy_charset_binmy_rmtreeget_typecharset_name_utf32_Z21completion_hash_cleanP9hashtable_Z22completion_hash_existsP9hashtablePcjmy_charset_utf8mb4_myanmar_uca_cimy_charset_utf8mb3_sinhala_uca_cimy_uca_collation_handler_utf8mb3my_charset_ucs2_thai_520_w2my_prognamerl_on_new_line_rl_move_cursor_relativerl_maybe_replace_linecopy_typelib_mariadb_compressmy_uca_collation_handler_nopad_ucs2my_hash_init2tls_protocol_versionrl_deprep_terminalmy_wildcmp_unicodemy_uca_collation_handler_generic_rl_add_macro_charmariadb_get_infoma_pvio_tls_get_protocol_version_id_Z9stringcmpPK13Binary_stringS1_rl_copy_keymapmy_mallocget_history_eventmy_messagemysql_stmt_store_result_cont_rl_lowercase_pmy_strxfrm_pad_desc_and_reverserio_pluginmy_charset_utf8mb4_esperanto_uca_cirl_char_searchmy_strxfrm_flag_normalizemysql_statmy_charset_ucs2_unicode_520_nopad_cimy_fopenmysql_closerl_noninc_forward_searchkey_BITMAP_mutexma_pvio_set_timeout_rl_keyseq_chain_disposemysql_fetch_lengthsmy_charset_filenamerl_vi_fWordmy_disable_flush_key_blockscharset_name_utf8mb4rl_vi_start_insertingmy_charset_ucs2_handlerrl_display_promptmy_uca_package_no_contractions_utf8mb3_rl_vi_textmod_command_rl_term_backspace_defaultMARIADB_DEFAULT_METHODSmy_charset_utf8mb3_german2_uca_ci_ZN6StringD1Evno_completionmysql_options4funmap_program_specific_entry_startmy_charset_sjis_japanese_nopad_cima_init_dynamic_arraymax_allowed_packetmysql_free_result_contma_hashtbl_updatemy_defaults_filecharset_name_utf16lemy_strxfrm_pad_nweights_unicodemy_charset_utf8mb4_icelandic_uca_ci_rl_callback_data_allocmy_charset_latin1_nopad_binrl_vi_overstrike_Z36convert_to_printable_required_lengthjmy_getopt_skip_unknownmysql_portmy_hash_sort_8bit_binmy_collation_is_known_idmy_getopt_prefix_matching_ZZNK21Client_field_metadata34print_data_type_related_attributesEP13Binary_stringE6formatinit_client_errsstrcontmysql_shutdown_contmy_strnxfrmlen_unicode_full_binmy_fcvtrl_vi_tilde_expandmy_charset_ucs2_unicode_520_cimy_setwd_my_signalsmy_hash_sort_latin1_demy_tellmysql_stmt_execute_contrl_completion_query_itemsmysql_stmt_fetch_cont_ZN6String6appendEPKcm_rl_pop_executing_macronet_write_timeoutstr2intma_pvio_has_datamy_charset_eucjpms_japanese_ci_Z7sortcmpPK13Binary_stringS1_PK15charset_info_stkey_memory_MY_STATkey_memory_IO_CACHErl_username_completion_function_rl_set_screen_sizemy_string_repertoire_rl_nsearch_callbackmysql_affected_rowsrl_menu_completerl_vi_arg_digitcharset_name_latin2my_charset_ucs2_persian_uca_cimy_uca_can_be_contraction_tail_ZN13Binary_string7replaceEjjPKcj_rl_screencharshistory_set_poskey_IO_CACHE_SHARE_cond_writerkey_memory_MY_BITMAP_bitmapMADB_OS_CHARSETkey_memory_SAFE_HASH_ENTRYmy_error_registermysql_set_server_optionmy_interval_timerkey_memory_DYNAMIC_STRINGrl_reset_line_state_ZN6String7set_intExbPK15charset_info_st_Z27mysql_store_result_for_lazyPP12st_mysql_resmysql_pingmysql_stmt_send_long_data_contmy_charset_repertoire_ZN6String12copy_alignedEPKcmmPK15charset_info_st_rl_arg_callback_rl_term_immysql_get_client_versionmy_charset_utf32_croatian_mysql561_uca_cimysql_thread_safemy_charset_cp1250_czech_csrl_dump_variables_rl_find_next_mbcharmysql_stmt_errormysql_client_builtins_ZN6String9set_asciiEPKcm_rl_term_gotomy_wc_to_printable_exmysql_ps_fetch_functionsrl_vi_char_searchrl_vi_delete_tomy_charpos_mbrl_bind_keypsi_rwlock_rdlockmy_unicase_mysql500ma_getsmy_charset_ucs2_spanish2_uca_cimy_charset_utf8mb3_turkish_uca_cirl_variable_valuemy_uca_collation_handler_nopad_multilevel_utf8mb4strmov_overlapprl_insert_mode_rl_term_up_defaultenabled_my_optionmysql_refreshcharset_name_big5rl_library_versionmy_charset_utf8mb4_nopad_binmy_wildcmp_ucarl_end_of_linemysql_real_querymysql_set_character_sethistory_total_bytesmthd_my_send_cmdmy_charset_utf8mb4_danish_uca_cimy_charset_latin1rl_invoking_keyseqsget_collation_numbermy_charset_utf32_hungarian_uca_cimy_thread_global_init_IO_stdin_usedmy_charset_utf16_turkish_uca_cimy_strxfrm_desc_and_reversemy_disable_lockingrl_arrow_keysrl_beg_of_linecleanup_dirnamerl_stop_outputmysql_stmt_next_resultrl_add_funmap_entrymy_wc_mb_binma_pvio_tls_initmy_charset_utf16le_nopad_binmy_hash_freemy_charset_utf8mb4_romanian_uca_cirl_set_keymy_hash_replacemy_hash_nextmy_charset_utf8mb4_lithuanian_uca_cikey_LOCK_timer_ZN13Binary_string9qs_appendEdma_pvio_tls_check_fpkey_THR_LOCK_charsetmysql_stmt_close_startrl_event_hookma_pvio_keepalivema_hashtbl_deletedebug_sync_C_callback_ptr_rl_isearch_callbackmysql_send_querymysql_real_escape_stringrl_get_termcapma_pvio_tls_readma_randominit_Z8tee_putciP8_IO_FILErl_restore_staterl_num_chars_to_readmysql_list_processesmy_charset_utf16_spanish2_uca_cirl_vi_fetch_historymysql_query_startmy_charset_utf32_unicode_520_nopad_cinormalize_dirname_ZN13Binary_string7set_hexEy_rl_pure_alphabeticrl_replace_linemy_tmp_file_created_rl_vi_last_commandrl_initialize_ZN6String27needs_conversion_on_storageEmPK15charset_info_stS2_my_print_default_filesmysql_kill_startmy_instr_mbmysql_get_parametersrl_character_lenmysql_free_resultmy_endmy_thread_dbug_idrl_start_kbd_macromake_typereadline_echoing_prl_save_staterl_set_retained_killsma_tls_write_asyncmysql_use_resultma_feoffind_type_with_warningrl_save_promptstrlengthma_pvio_tls_verify_server_certmy_max_str_mb_simplerl_resize_terminal_rl_dispatching_keymapmy_freopenmysql_next_result_startrl_ruboutmy_disable_async_iomy_charset_tis620_thai_nopad_cimysql_set_character_set_contmy_charset_ucs2_polish_uca_cimysql_num_rowsmy_strcasecmp_mb_binmy_charset_utf8mb3_vietnamese_cimy_charlen_8bitmysql_real_query_startmy_uca_collation_handler_multilevel_ucs2my_vfprintfmysql_kill_contvi_movement_keymapkey_memory_TREEmy_charset_utf8mb4_thai_520_w2bchangemy_uca_package_genericrl_readline_versionmysql_autocommitmysql_autocommit_contma_charset_binmy_uca_v400multi_alloc_rootrl_set_keyboard_input_timeouttilde_expansion_preexpansion_hookmy_charset_eucjpms_japanese_nopad_cikey_IO_CACHE_append_buffer_lockmy_register_filenamemy_uca_collation_handler_multilevel_utf8mb3my_atodrl_vi_redomy_charset_latin1_nopadmysql_reset_connection_startmy_uca_collation_handler_nopad_multilevel_ucs2my_charset_sjis_nopad_binmy_sync_dirmy_message_stderrmy_charset_ucs2_slovak_uca_ci_rl_compare_charsma_SHA1Finalmy_charset_utf8mb4_estonian_uca_cimy_xml_parser_freemysql_row_tellrl_completer_quote_characterskey_memory_lf_slist_rl_term_eipvio_socket_is_blockingrl_dump_functionsrl_add_undorl_dispatchingmy_uca_collation_handler_nopad_utf32my_charset_ucs2_lithuanian_uca_cimy_charset_euckr_korean_nopad_cimy_charset_ucs2_nopad_binma_pvio_register_callbackremove_historykey_memory_charsetsrl_vi_bword_rl_term_pcrl_clear_messagema_SHA1Initallocate_dynamicmy_xml_parser_create_rl_term_DChistory_get_timemy_charset_cp932_japanese_cihistory_set_history_statemysql_reset_connection_continit_io_cache_sharerl_deletemy_charset_utf32_icelandic_uca_cimysql_cset_escape_quotesmysql_fetch_field_directmy_charset_utf8mb3_czech_uca_cimy_context_install_suspend_resume_hookrl_vi_columnmy_charset_utf8mb3_polish_uca_cima_alloc_root_rl_qsort_string_compare_mariadb_read_optionsget_charset_rl_history_saved_pointmysql_client_plugin_initrl_bind_key_if_unboundma_open_ZZNK21Client_field_metadata34print_data_type_related_attributesEP13Binary_stringE4typerl_vi_insertion_modemariadb_convert_stringmy_have_got_alarm_rl_parsing_conditionalized_outmy_readlinkmariadb_get_charset_by_nameis_prefixmy_hash_sort_mb_nopad_binmy_charset_utf8mb3_romanian_uca_cimy_reallocset_malloc_size_cbmariadb_get_infovmy_strnncollsp_nchars_genericmy_utf16_unimy_charset_utf16le_binrl_attempted_completion_functionma_send_connect_attr_rl_argcxtmysql_stmt_initma_pvio_tls_set_connectionma_stmt_execute_generate_simple_request_ZN13Binary_string12copy_or_moveEPKcmdisabled_my_optionma_pvio_tls_writemy_charset_ucs2_unicode_cimy_charset_utf16_general_cirl_bind_keyseq_if_unbounddestroy_prepared_stmt_noopmy_charset_utf32_unicode_nopad_cimy_collation_8bit_nopad_bin_handlermy_unicase_pages_unicode520my_qsortrl_basic_quote_characters_Z14batch_readlineP14st_line_bufferbrl_history_search_forwardmy_charset_utf8mb4_latvian_uca_cirelease_configuration_dirsrl_make_keymapmysql_list_fieldsrl_set_signalsrl_dingma_stmt_execute_generate_bulk_requestma_save_session_track_inforl_unbind_key_in_maprl_filename_quote_characters_Z18batch_readline_endP14st_line_bufferrl_parse_and_bindma_pvio_start_sslvi_insertion_keymapmy_uca_package_utf8mb4my_charset_utf32_polish_uca_cimy_charset_utf8mb3_general_cima_pvio_is_blockingmy_uca_collation_handler_nopad_multilevel_utf8mb3my_uca_package_ucs2rl_kill_linemy_charset_utf8mb3_unicode_520_nopad_cimy_charset_utf32_romanian_uca_cimy_freema_pvio_connectmysql_stmt_fetch_startinit_glob_errsadd_history_timemysql_stmt_row_tell_rl_backspacema_free_roothistory_max_entriescurr_dirmy_uca_collation_handler_utf32_rl_update_finalpvio_socket_shutdownkey_THR_LOCK_heapmy_hash_sort_simple_nopadmy_charset_utf16le_general_cimysql_stmt_field_countpvio_socket_set_timeoutrl_kill_regionma_pvio_fast_sendmax_input_history_rl_control_keypadtilde_additional_suffixesma_pvio_tls_closerl_untranslate_keyseqmy_dirrl_delete_or_show_completionsrl_redisplayadd_compiled_extra_collationma_pop_dynamic_rl_complete_show_unmodified_rl_strindexrl_crlfma_pvio_get_handlemy_charset_utf16_icelandic_uca_cirl_forced_update_displayall_mysys_stages_rl_match_hidden_files_rl_meta_flagrl_on_new_line_with_promptrl_noninc_reverse_search_againmysql_num_fieldsrw_pr_destroymy_numchars_mbmy_charset_utf8mb4_unicode_520_nopad_cimy_charset_utf32_slovenian_uca_cirl_set_keymapmy_snprintf_rl_digit_palloc_history_entrymy_sync_dir_by_filekey_memory_LISTmy_memdupmysql_query_contmy_charset_utf8mb3_spanish_uca_cimy_charset_cp932_bin_ZN13Binary_string13qs_append_hexEPKcjrl_unix_filename_rubouttilde_expansion_failure_hookmy_mutex_initrl_completion_matchesrl_alphabeticmysql_send_query_contset_default_charset_by_namemysql_get_timeout_valuemysql_init_ps_subsystemrl_insert_closepsi_prlock_rdlock_rl_term_dc_ZN6String15append_semi_hexEPKcjPK15charset_info_strl_callback_handler_removemy_charset_utf8mb3_estonian_uca_cirl_terminal_namemy_uca_collation_handler_multilevel_utf32my_is_symlinkrl_visible_statsmy_errormysql_field_seekhome_dir_buffmy_caseup_mbrl_line_buffer_lenrl_backward_bytemthd_stmt_read_all_rows_rl_fix_point_ZN13Binary_string6shrinkEm_rl_read_mbcharmysql_stmt_free_result_startmysql_close_cont_Z8add_wordP9hashtablePcmy_uca_collation_handler_nopad_utf16test_if_hard_pathkey_THR_LOCK_openrl_abortmy_context_initmysql_session_track_get_firstmy_string_metadata_getma_pvio_tls_endrl_invoking_keyseqs_in_mapmy_xml_error_stringmy_charset_utf8mb3_unicode_ci_rl_vis_botlinma_pvio_closerl_ignore_completion_duplicatesmysql_stmt_data_seekrl_pointma_delete_dynamicrl_arg_signma_tls_get_finger_printmy_strnncoll_simplerl_history_search_backwardrl_blink_matching_parenmy_unicase_default_pagesmysql_hex_string_rl_char_search_internalmy_caseinfo_cp932my_uca_collation_handler_multilevel_utf8mb4mthd_my_skip_result_rl_any_typeinmy_charset_utf32_roman_uca_cima_net_write_commandmysql_stmt_preparemy_dirend_rl_move_vertmy_caseup_str_mbrl_function_of_keyseqrl_binding_keymapmysql_change_userrl_upcase_word_rl_dispatchmy_hash_sort_mb_binmy_charset_gbk_bin_rl_overwrite_charmysql_stmt_close_rl_mark_modified_linesma_charset_utf16le_general_cimysql_data_homemysql_get_proto_inforl_bind_key_if_unbound_in_mapmy_charset_utf32_danish_uca_cimy_charset_utf8mb4_general_cigetopt_ll_limit_valuerl_get_keymap_name_from_edit_modekey_memory_lf_dynarraymy_charset_utf16_unicode_cima_dynstr_reallocma_hashtbl_freemysql_thread_idmysql_real_query_contmy_hrtimemy_strnncollsp_padspace_binhistory_write_timestampsmysql_refresh_contmy_charset_gb2312_nopad_binmy_charset_utf8mb4_german2_uca_cirl_completion_quote_characterkey_thread_timer_rl_saved_line_for_historylist_lengthma_pvio_wait_io_or_timeoutrl_byte_orientedkey_memory_charset_loaderstrmake_rootrl_basic_word_break_charactersmy_readmy_charset_utf16_general_nopad_cimysql_next_resultrl_quoted_insertrl_directory_completion_hookrl_noninc_forward_search_againma_dynstr_setrl_tab_insertrl_line_buffermy_8bit_collation_flags_from_data_rl_insert_typeinmysql_stmt_reset_startmy_unicase_defaultrl_completion_entry_functionmy_wc_to_printable_genericlist_consmy_charset_get_contractionsmy_charset_utf8mb4_croatian_uca_ci_rl_term_upmy_charset_utf8mb4_unicode_cimy_charset_utf8mb4_persian_uca_cimy_xml_error_posmysql_session_track_get_nextmy_get_tty_password_rl_iscxtmy_charset_ucs2_croatian_mysql561_uca_cimysql_stat_contmysql_stat_startrl_stuff_char_ZN13Binary_string7set_hexEPKcj_rl_init_terminal_io_ZN13Binary_string15append_longlongExrl_gnu_readline_prndmy_charset_utf32_myanmar_uca_cimy_printv_error_rl_keymapmy_disable_symlinksrl_list_funmap_namesmy_charset_ucs2_romanian_uca_cimy_handle_options_init_variableskey_memory_my_err_headmy_snprintf_8bitpvio_socket_async_writeset_psi_server_rl_doing_an_undomy_pwritemy_thread_global_endmy_uca_package_utf8mb3my_convert_fixkey_file_charsethistory_word_delimiters_rl_possible_meta_prefixesmy_charset_utf8mb3_esperanto_uca_cirl_extend_line_buffermy_charset_utf32_general_nopad_cipsi_cond_timedwaitmy_copy_8bitmysql_select_db_contrl_dump_macrosmy_propagate_simple_rl_screenwidthmysql_stmt_next_result_cont_rl_enable_meta_key_my_sig_rememberquick_max_column_widthmy_load_pathrl_vi_insert_begmysql_stdinrl_copy_forward_wordmysql_real_connectmysql_list_tables_startmy_xml_error_linenoma_dynstr_append_memma_charset_latin1key_file_io_cachemy_defaults_extra_filemy_charset_utf16_nopad_binmy_hash_sort_simplesql_protocol_typelibmy_charset_utf32_vietnamese_cimy_charpos_8bitmy_uca_package_utf16unpack_fieldsma_invalidate_stmtsrl_visible_prompt_lengthma_net_readrl_kill_full_linema_charset_utf8_general_cimy_charset_is_ascii_based_rl_complete_mark_directories_rl_convert_meta_chars_to_asciirl_filename_quoting_functionrl_capitalize_wordkey_TMPDIR_mutex_Z8tee_putsPKcP8_IO_FILErl_get_keymap_namedelete_dynamic_with_callbackma_ll2strget_charset_by_csname_rl_find_completion_wordmy_crypt_ZN13Binary_string9qs_appendEPKdrl_restart_outputreplace_history_entrymy_charset_gbk_chinese_cimy_xml_set_value_handler_rl_to_upperrl_yank_nth_argreprepare_prepared_stmt_noop_Z25my_copy_with_hex_escapingPK15charset_info_stPcmPKcmmy_unicase_mysql500_pagesrl_vi_ruboutrl_endmy_fprintfmy_closemysql_debugdirname_partmy_seekmy_charset_euckr_korean_cimy_charset_big5_binmthd_stmt_flush_unbufferedkey_memory_THD_ALARMsql_protocol_names_librl_end_kbd_macro_ZN13Binary_string7reserveEmmrl_vi_search_againnet_buffer_lengthma_pvio_tls_cipher_rl_vi_done_insertingmy_thread_initmy_fstatmy_charset_utf8mb3_thai_520_w2my_charset_utf8mb3_croatian_uca_ci_rl_nscxtmy_charset_utf8mb3_roman_uca_cimy_uca_collation_handler_nopad_utf8mb3rl_vi_editing_modehas_pathmy_sleep_for_spacema_duplicate_resultset_metadatamysql_stmt_execute_startmy_charset_ucs2_german2_uca_cirl_copy_backward_wordfree_rowsmy_charset_ujis_binrl_free_undo_listrl_readline_namemy_strtoll10mysql_stmt_result_metadatarl_pre_input_hookma_net_endrl_completion_display_matches_hookcharset_name_euckrmysql_store_result_rl_scxt_allocmysql_net_store_lengthmy_like_range_genericmysql_list_fields_contmysql_select_db_startmy_vsnprintfma_init_donemthd_stmt_fetch_to_bind_ZN6String4copyEPKcmPK15charset_info_stS4_Pjmy_8bit_charset_flags_from_data_my_b_writema_tls_end_ZN13Binary_string20qs_append_hex_uint32Ejmy_uca_collation_handler_nopad_multilevel_utf16rl_discard_keymapint10_to_strkey_memory_KEY_CACHEmysql_querymy_lengthsp_8bitpsi_rwlock_tryrdlockcharset_name_tis620rl_numeric_argrl_forward_charmysql_select_db_rl_restore_tty_signalsmy_thread_destroy_internal_mutexreplace_history_datamy_thread_stack_sizemy_charset_utf8mb4_slovenian_uca_cirl_delete_horizontal_spacerl_deprep_term_functionkey_THR_LOCK_mallocmy_casedn_str_8bit_rl_screenheightkey_memory_charset_fileVERterminal_widthrl_complete_with_tilde_expansionmysql_read_query_resultmy_hash_searchSQLSTATE_UNKNOWN_rl_out_streammy_filename_rl_erase_at_end_of_line_rl_savestringpvio_socket_get_handlemysql_stmt_param_countrl_reset_screen_sizeend_slave_io_cacherl_free_line_statemy_uca_collation_handler_utf16mysql_inforl_completereadlineinit_compiled_charsets_ZN6String23append_for_single_quoteEPKcmmysql_stmt_send_long_data_startrl_linefuncrl_forward_search_historyhistory_expansion_char_ZNK13Binary_string6strstrERKS_jmy_fdopenhistory_quotes_inhibit_expansionmariadb_deinitialize_sslhistory_expandmy_collation_8bit_simple_ci_handlerma_multi_commandmy_charset_utf8mb3_unicode_520_cimysql_field_countmy_mb_ctype_mb_rl_replace_textrl_completer_word_break_charactershandle_optionsmy_charset_utf16le_general_nopad_cimysql_shutdowndummy_fallback_client_pluginmy_thr_key_mysys_existsmy_charset_utf8mb4_binmy_charset_big5_chinese_nopad_cirl_callback_read_charmthd_supported_buffer_typemy_file_info_defaultmy_strxfrm_pad_unicoderl_key_sequence_lengthmy_syncrl_unix_word_ruboutmy_charset_tis620_binrl_insert_completions_ZNK6String5printEPS__Z14get_one_optionPK9my_optionPKcS3__Z20completion_hash_initP9hashtablejmy_casedn_ujiskey_file_cnfmy_once_root_blockmysql_get_host_infomy_charset_utf16_latvian_uca_cimy_convertmy_charset_utf8mb3_general_nopad_cimysql_escape_stringunpack_filenamehistory_comment_charmy_charset_ucs2_czech_uca_cimy_charset_latin1_german2_cimy_charset_ucs2_slovenian_uca_ci_rl_copy_undo_listkey_LOCK_alarmkey_THR_LOCK_mutex_rl_possible_control_prefixesrl_push_macro_input_rl_arg_overflowmy_collation_statistics_get_use_countma_init_alloc_root_rl_bind_stty_charsmy_renamerl_variable_dumperpvio_socket_wait_io_or_timeoutma_pvio_is_alivemysql_ssl_setmy_charset_utf16_binmy_strerrormy_numcells_mbmy_charset_utf32_german2_uca_cimy_charset_utf32_handlerrl_downcase_wordmysql_set_local_infile_defaultgetopt_double_limit_value_ZN13Binary_string9qs_appendEPKcmmysql_stmt_attr_setmy_getopt_error_reporter_my_b_readmysql_close_slow_part_contget_default_configuration_dirsmysql_ping_contmy_charset_get_by_namemy_strntoul_8bitmy_strndup_rl_set_the_linemy_charset_gb2312_binma_fcvtrl_unix_line_discardmy_charset_loader_init_mysys_rl_callback_datamy_charset_utf8mb4_handlerma_tls_get_ciphermysql_commitmy_context_spawnrl_editing_modedefault_dbug_option_rl_overwrite_ruboutrl_add_defunrl_do_undouca520_lengthkey_my_thread_var_suspendmy_charset_utf16_unicode_520_cima_tls_readmy_charset_utf32_turkish_uca_cimy_charset_utf8mb3_spanish2_uca_cimysql_next_result_contrl_last_funcstore_paramrl_copy_region_to_killmysql_change_user_start_rl_set_insert_modemy_uca_collation_handler_multilevel_utf16rl_bind_keyseq_in_mapmy_charset_utf8mb4_vietnamese_ciclear_historymy_strcasecmp_mblist_freemysql_dump_debug_infomy_charset_utf32_croatian_uca_cimy_charset_utf8mb3_latvian_uca_cilist_walk_rl_term_crrl_generic_bindkey_THR_LOCK_lockps_fetch_from_1_to_8_bytesmysql_commit_contmysql_character_set_namemy_charset_utf32_sinhala_uca_ci_my_thread_varrl_complete_internalsf_leaking_memoryma_net_initmy_charset_utf8mb4_hungarian_uca_cimysql_get_ssl_cipherrl_tilde_expand_rl_arg_initma_dynstr_appendmy_umask_dirrl_startup_hookmy_hash_first_from_hash_valuesystem_filenamemy_charset_sjis_japanese_cimy_realpathmysql_stmt_fetchrl_instreamstrcendmy_uca_v520_thmy_file_total_openedmy_charset_utf16_unicode_nopad_cimy_use_symdircharset_name_gbk_rl_dispatch_callbackgetopt_ulonglong2doubleproc_info_hook_rl_free_history_entrymy_uca_collation_handler_ucs2rl_directory_rewrite_hook_rl_make_prompt_for_searchmy_charset_ucs2_icelandic_uca_cimysql_store_result_start_ZN13Binary_string4fillEmcmysql_stmt_prepare_contmy_charset_utf8mb3_slovenian_uca_cima_tls_get_passwordrl_callback_handler_installmy_preadrl_backward_kill_linemy_uca_collation_handler_nopad_multilevel_utf32resolve_collationma_default_charset_inforl_insert_commentmthd_my_read_rows_rl_isearch_terminatorsrl_completion_suppress_appendrl_vi_bracktypema_hashtbl_searchmy_charset_ucs2_swedish_uca_cimy_strnxfrmlen_simplemysql_data_seekmy_xml_parsemariadb_compiled_charsetsrl_completion_found_quotemy_init_done_Z20completion_hash_freeP9hashtablepvio_socket_methodsmy_numcells_8bitpsi_prlock_wrlockmy_thread_destroy_common_mutexmy_deletemy_min_str_8bit_simplerl_overwrite_modemy_xml_set_user_datamy_charset_utf16_danish_uca_cirl_vi_searchrl_yank_last_argmy_copy_fix_mbmysql_real_connect_start_rl_in_streammy_charset_utf8mb3_bin_ZGVZNK21Client_field_metadata34print_data_type_related_attributesEP13Binary_stringE6formatmy_charset_utf32_lithuanian_uca_cipvio_socket_writerl_vi_bWordmy_charset_ucs2_turkish_uca_cimysql_stmt_bind_resultma_init_dynamic_stringrl_vi_undomysql_stmt_num_rowsmy_charset_utf8mb4_swedish_uca_ci_rl_start_using_historyreadline_internal_teardownma_scramble_41ma_net_clearmy_charset_utf16_myanmar_uca_cimy_collation_get_tailoringmy_uni_ctypemy_wc_mb_8bitsh_unset_nodelay_modepsi_mutex_lockgetopt_double2ulonglongnet_get_errorhistory_is_stifledrl_read_init_filemysql_fetch_rowmy_wc_to_printable_8bitmy_wildcmp_8bitlist_addmy_no_defaultsmy_charset_cp932_japanese_nopad_ciset_prealloc_rootmysql_client_plugin_deinitrl_already_promptedhistory_length_ZNK13Binary_string6strstrEPKcjjmysql_stmt_store_result_startmysql_send_query_startmy_charset_utf32_czech_uca_cimy_charset_utf8mb4_unicode_520_cimthd_stmt_read_prepare_responsemy_initrl_backward_charmy_charset_utf8mb4_roman_uca_cima_tls_verify_server_certrl_clear_pending_inputmy_hash_iteratemthd_my_read_query_resultmy_strnxfrm_unicode_full_bin_rl_pushed_input_availableMARIADB_APImysql_row_seekma_check_buffer_boundariesmy_charset_ucs2_croatian_uca_cimy_disable_syncrl_named_functionmy_charset_utf32_unicode_ciescape_string_for_mysqlmy_charset_utf32_estonian_uca_cimy_gcvt_rl_allow_pathname_alphabetic_charskey_memory_newstrnmovrl_expand_promptmy_charset_utf32_spanish2_uca_cirl_char_is_quoted_prl_vi_yank_toma_multi_mallocmy_strnncollsp_nchars_generic_8bit_rl_adjust_pointmy_once_alloctilde_expand_wordma_net_real_write_rl_want_redisplayrl_undo_commandreal_open_cached_filema_pvio_writewait_for_free_space_rl_comment_beginmy_fileno_rl_input_queuedmysql_get_optionmysql_fetch_row_startmy_charset_ucs2_latvian_uca_ciget_charset_namerl_macro_dumper_rl_kscxtcharset_name_eucjpmsrl_pending_inputmy_charset_utf8mb3_unicode_nopad_cimysql_errormy_uca_collation_handler_nopad_no_contractions_utf8mb4key_LOCK_uuid_generator_rl_callback_data_disposema_memdup_rootmy_strnxfrm_mb_internalrl_vi_change_charrl_reset_after_signalkey_THR_COND_threadsmysql_killrl_vi_overstrike_deletefree_defaultsmysql_get_server_name_ma_hashtbl_initmy_hash_resetrl_modifyingrl_discard_argumentconvert_dirnamemy_casedn_str_mbmy_init_mysys_psi_keys_rl_insert_charstrxnmovmy_print_variablesmy_caseup_str_8bitreset_root_defaultsmysql_get_charset_by_nrmy_charset_error_reportermy_charset_utf32_slovak_uca_cimy_fcloserl_unbind_function_in_maprl_transpose_charsmy_context_continuerw_pr_rdlockrw_pr_unlocksh_set_lines_and_columnskey_THR_LOCK_myisam_mmapmy_uca_collation_handler_multilevel_no_contractions_utf8mb3my_charset_utf16_esperanto_uca_cimysql_get_client_infoma_tls_closenew_ma_field_extensionmysql_stmt_bind_param_ZNK13Binary_string7strrstrERKS_jrl_get_keymapmy_charset_utf32_unicode_520_ci_rl_current_display_lineemacs_standard_keymapxfreemy_dont_interruptmy_charset_utf8mb4_czech_uca_cima_pvio_initmy_thread_endma_simple_commandmysql_stmt_store_resultrl_display_fixed_ZN6String16needs_conversionEmPK15charset_info_stS2_Pjmysql_rollback_startupdate_malloc_sizemy_charset_ucs2_binmy_file_limitmysql_server_endmy_printf_error_rl_uppercase_pmysql_client_register_pluginsh_single_quoterl_vi_set_markma_hashtbl_elementrl_explicit_arggloberrsrl_translate_keyseqmy_uca_collation_handler_nopad_multilevel_genericmysql_stmt_affected_rowsma_tls_start_rl_char_valuema_dynstr_append_quotedmy_charset_utf16_vietnamese_ci_ZN6StringD2Ev_rl_scxt_disposerl_cleanup_after_signaladd_historymysql_dump_debug_info_contmy_errmsgrl_erase_empty_linemy_charset_utf32_general_cimysql_set_local_infile_handler_rl_term_clreolrl_completion_word_break_hookrl_rubout_or_deleterl_tty_statushistory_subst_char_ZN6String6appendEPKcmPK15charset_info_stmysql_list_dbs_startrl_revert_linerl_insert_textmy_charset_utf16_hungarian_uca_cimy_strntoull10rnd_8bitmysql_fetch_fieldsmy_charset_utf16_roman_uca_cirl_getcma_pvio_cache_readpvio_socket_readmysql_find_charset_namema_readmysql_handle_local_infilemy_charset_utf8mb3_persian_uca_cirl_vi_deletepvio_socket_change_timeoutfn_ext_Z7hashpjwPKcjreadline_top_levelrl_prep_terminalmysql_net_read_packetrl_bind_keyseqmy_charset_tis620_nopad_binrl_noninc_reverse_searchhistory_tokenizemysql_commit_startrl_set_markis_file_markerget_charsets_dirkey_my_thread_var_mutexstr_to_TIMEmy_print_defaults_ZN13Binary_string10real_allocEmcharset_name_cp1250rl_vi_putmysql_stmt_more_results__data_start_mysql_stmt_use_resultmy_charset_cp932_nopad_binxreallocrl_end_undo_groupmy_fseekrl_vi_eof_maybemy_charset_utf8mb4_spanish_uca_cimy_charset_utf8mb3_icelandic_uca_cihistory_arg_extractPSI_servercharset_name_ujismy_open_rl_vi_initialize_linekey_memory_lf_nodexmalloc_rl_term_clrpagmy_charset_utf8mb4_sinhala_uca_cimy_hash_sortmy_charset_utf32_nopad_binmy_caseup_8bit_ZGVZNK21Client_field_metadata34print_data_type_related_attributesEP13Binary_stringE4typemy_charset_utf32_thai_520_w2my_fast_mutexattr_rl_clear_to_eol_ZN13Binary_string4copyEvreinit_io_cachemy_uca_collation_handler_no_contractions_utf8mb3_rl_enable_paren_matchingmy_casedn_mb_rl_abort_internalreadline_internal_charmy_charset_ucs2_danish_uca_ci_rl_get_char_lenma_hash_passwordmy_sync_countmy_charset_utf8mb4_unicode_nopad_ci_rl_arg_getcharma_delete_dynamic_elementtilde_additional_prefixesrl_vi_ewordrl_newline_rl_walphabeticrl_set_keymap_from_edit_moderead_user_namekey_THR_LOCK_netget_charset_numbermy_set_errorrl_vi_checkmy_strxfrm_pad_desc_and_reverse_nopadrl_catch_sigwinchhistory_get_history_statedirname_lengthrl_yankmy_collation_8bit_bin_handlermy_uca_package_utf32my_charset_ucs2_general_cima_int_hash_freemysql_stmt_sqlstatepvio_socket_connectmysql_warning_countzlib_client_pluginrl_maybe_unsave_linerl_vi_domoveclose_cached_fileremove_io_threadadd_compiled_collationrl_executing_keymapmysql_free_result_startrl_kill_wordpsi_rwlock_wrlockmy_charset_gb2312_chinese_nopad_cirl_tty_set_default_bindingsrl_completion_modekey_memory_MY_DIRrl_filename_completion_functionma_tls_initmysql_sqlstatema_hashtbl_insertmy_vsnprintf_exmysql_rollbackmy_uca_package_no_contractions_utf8mb4my_charset_utf8mb3_lithuanian_uca_ci_rl_free_match_listmy_xml_set_enter_handlerrl_unbind_command_in_map_ZN13Binary_string6appendEP11st_io_cachejmy_statrl_vi_next_wordrl_vi_first_printrl_vi_fword_my_b_getinit_slave_io_cache_rl_term_ipma_initma_make_scrambled_passwordmy_charset_utf16_croatian_uca_cirl_prep_term_functionmy_getopt_print_errorsmy_strcasecmp_8bitrl_special_prefixesrl_completion_typemy_charset_utf8mb4_general_nopad_cimy_charset_utf16_spanish_uca_cirl_vi_matchma_net_safe_readmy_charset_big5_chinese_cimy_assert_on_error_rl_clean_up_for_exit_rl_vi_set_last_ZN13Binary_string4copyEPKcmrl_set_paren_blink_timeoutmysql_get_server_inforl_kill_textmariadb_stmt_execute_directmysql_reset_connectionrl_backward_kill_wordmy_charset_utf16_estonian_uca_ciunstifle_historyma_pvio_readmysql_old_password_client_plugin_Z22completion_hash_updateP9hashtablePcjS1_mysql_close_startrl_display_match_list_rl_last_v_posmy_charset_ucs2_spanish_uca_cimy_charset_utf16_sinhala_uca_cikey_IO_CACHE_SHARE_mutexmy_max_str_8bit_simplemy_unicase_mysql500_page00key_COND_timer_rl_complete_show_allma_freeze_sizeseek_io_cachemy_charset_ucs2_roman_uca_cirl_completion_mark_symlink_dirsmysql_stmt_free_result_cont_ZN13Binary_string8set_fcvtEdjrun_plugin_authmy_hash_firstmy_propagate_complex_rl_page_completionsrl_backward_char_searchmy_casedn_8bitrl_exchange_point_and_markmy_uca_collation_handler_multilevel_no_contractions_utf8mb4_rl_isearch_dispatchmy_strntod_8bitmy_charset_utf8mb4_croatian_mysql561_uca_cimy_block_writema_get_dynamicpvio_socket_is_alivemy_charset_ucs2_general_mysql500_ci_rl_input_availablema_tls_set_connectionmy_uca_can_be_contraction_headmysql_stmt_warning_countrl_inhibit_completion_rl_term_ICmy_fill_8bitmariadb_cancelmy_once_extrasoundex_maplist_reverse_rl_keyseq_cxt_disposemysql_optionsvmy_strnxfrm_unicode_full_bin_internalpvio_socket_keepalivemy_ftellmysql_errno_ZN13Binary_string9qs_appendEymy_charset_ucs2_sinhala_uca_ci_rl_unget_charmy_context_yieldmy_scan_8bitrl_read_keycharset_name_sjismy_writeinit_io_cache_exttls_library_versionmthd_stmt_get_result_metadatamysql_stmt_param_metadatarl_maybe_save_linereadline_internal_setuppsi_rwlock_trywrlockcharset_name_gb2312rl_funmap_namesmy_min_str_mb_simplemysql_dump_debug_info_startma_endrl_macro_bind_ZN13Binary_string19copy_printable_hhhhEPK15charset_info_stS2_PKcmmy_charset_utf16_slovenian_uca_cimysql_read_query_result_contmysql_store_result_contrl_forward_rl_to_lower__libc_csu_initmysql_set_server_option_cont_rl_copy_undo_entrymysql_get_timeout_value_msescape_quotes_for_mysqlsh_get_env_valuekey_IO_CACHE_SHARE_condmy_getcputimeintern_filenamema_bmove_uppmy_uca_collation_handler_multilevel_genericmy_long10_to_str_8bitmadb_get_os_character_setrl_filename_completion_desiredmy_global_flagsmysql_unix_portarray_append_string_unique_ZN13Binary_string9qs_appendEimysql_stmt_next_result_startrl_refresh_linemy_hash_update_rl_undo_group_level_rl_set_cursor_ZN6String8strip_spEvmysql_change_user_cont_ZN13Binary_string16append_ulonglongEymy_string_stack_guardmy_charset_utf32_swedish_uca_cima_closemysql_stmt_attr_getmy_connect_asyncmy_charset_utf8mb4_spanish2_uca_cirl_vi_change_caseresolve_charsetmysql_initmysys_test_invalid_symlinkrl_emacs_editing_modemy_charset_utf16_polish_uca_ci_rl_disable_tty_signalsmy_cleanup_optionsmysql_list_processes_startmy_charset_utf8mb4_polish_uca_ci_rl_redisplay_after_sigwinchmysql_get_optionv_rl_term_forward_charmy_charset_eucjpms_binmove_root_rl_erase_entire_linestrxmovmy_hash_deletemy_charset_tis620_thai_cicreate_temp_fileTHR_KEY_mysysmy_strnxfrm_mb_nopadmy_hash_insertmysql_list_fields_startmy_charset_gbk_nopad_binmy_strnncollsp_simple_nopadmy_disable_copystat_in_redel_rl_keyseq_cxt_allocmysql_set_character_set_start_Z19batch_readline_initmP8_IO_FILEmy_strnncollsp_simple_ZN6String19set_or_copy_alignedEPKcmPK15charset_info_stmy_charset_utf8mb3_danish_uca_ci_Z19copy_if_not_allocedP6StringS0_jrl_undo_listmy_charset_ucs2_vietnamese_cirl_backward_rl_suppress_redisplayint2strmysql_get_server_version_ZN6String20append_parenthesizedElimy_hash_search_using_hash_valuemysql_more_resultshistory_truncate_filemy_lengthsp_binarymysql_authentication_dialog_askmy_charset_eucjpms_nopad_binrl_reverse_search_history_rl_rubout_charmy_charset_utf8mb3_croatian_mysql561_uca_cirl_function_dumpercopy_history_entrymy_uca_collation_handler_no_contractions_utf8mb4my_uca_contraction2_weightkey_KEY_CACHE_cache_lockmy_charset_utf16_unicode_520_nopad_ci_dig_vec_uppermy_charset_gb2312_chinese_cimysql_stmt_send_long_datarl_call_last_kbd_macromy_charset_latin1_binmariadb_field_attrrl_possible_completionsfind_set_from_flagsmy_unicase_default_page00my_freadmysql_stmt_reset_cont_rl_output_some_chars_rl_next_macro_keymy_charset_euckr_binmy_thread_end_wait_timemy_charset_utf8mb4_slovak_uca_cimthd_stmt_fetch_rowkey_THR_LOCK_myisamma_strdup_root_rl_fix_last_undo_of_typemy_string_repertoire_8bitmy_well_formed_char_length_8bitset_default_charsethistory_listmysql_shutdown_startrl_vi_prev_wordmariadb_reconnectmy_instr_simplerl_vi_yank_argmy_default_csnamefn_formatma_read_ok_packetrl_vi_append_mode_mariadb_compression_algorithm_strcharset_name_cp932my_charset_utf32_esperanto_uca_cikey_SAFEHASH_mutexmy_charset_sjis_binmy_numchars_8bitmy_charset_utf16_thai_520_w2my_mb_wc_8bit_Z20convert_to_printablePcmPKcmPK15charset_info_stm_mariadb_uncompresspvio_socket_has_datamy_strntol_8bitmy_charset_ucs2_myanmar_uca_ci_rl_enable_keypad_rl_is_mbchar_matchedrl_vi_movement_modemy_strnxfrm_simple_internalmysql_close_slow_part_rl_vi_reset_lastmy_charset_utf8mb3_general_mysql500_cimy_once_freekey_THR_LOCK_threadscharset_name_hashrl_do_lowercase_versionmysql_fetch_row_contcharset_name_utf16_rl_get_screen_sizemy_get_err_msg_rl_bell_preferencemy_charset_utf16_croatian_mysql561_uca_ci_ZN13Binary_string11realloc_rawEmfn_ext2my_strnxfrm_unicode_full_nopad_binemacs_ctlx_keymapsh_get_home_dirrl_vi_substmy_charset_gbk_chinese_nopad_cirl_transpose_wordsma_get_hash_keyvalmysql_load_plugin_vmy_charset_utf32_persian_uca_ci_my_b_encr_writemy_uca_collation_handler_nopad_multilevel_no_contractions_utf8mb3rl_filename_quoting_desired_rl_term_icrl_readline_statema_pvio_tls_connectunpack_dirnamema_tls_initialized_ZN13String_copier16well_formed_copyEPK15charset_info_stPcmS2_PKcmmrl_outstreammy_uni_utf16rl_tty_unset_default_bindingsmy_strtod_rl_arg_dispatchsafe_lexcstrdup_rootrw_pr_wrlockmy_mb_ctype_8bitma_scramble_323history_inhibit_expansion_functionpsi_mutex_trylockend_io_cachemy_uca_collation_handler_nopad_genericmy_charset_utf16_swedish_uca_cirl_vi_change_tomariadb_defaultsmy_strnxfrm_simple_nopadmysys_usage_idfind_typesetPSI_hook_rl_term_backspacekey_memory_my_compress_allocrl_replace_from_historymy_charset_utf32_binmysql_ping_startfree_charsets_mariadb_compress_allocrl_filename_dequoting_functioncompression_algorithmsmy_charset_utf16_german2_uca_cihistory_search_prefixhistory_search_pos_Z11tee_fprintfP8_IO_FILEPKczmy_strtoll10_8bitma_dynstr_freemy_charset_ucs2_estonian_uca_cimysql_ps_subsystem_initializedrl_completion_suppress_quotemysql_stmt_free_resultrl_get_previous_history_rl_internal_char_cleanupma_SHA1Updatemy_charset_utf8mb3_swedish_uca_cimy_context_destroymy_load_defaults_rl_init_line_statemy_progname_shortcurrent_historymy_strntoll_8bitma_alloc_dynamicrl_promptmysql_load_pluginmysql_set_server_option_startmysql_stmt_executema_tls_connect_rl_history_preserve_pointmysql_embeddedrl_get_next_history_mariadb_set_conf_option__libc_csu_finirl_delete_textrw_pr_initmysql_net_field_lengthmy_parse_charset_xmlmysql_list_processes_contrl_prefer_env_winsizema_tls_get_protocol_versionmy_wc_mb_utf8mb4_bmp_onlymysql_client_find_pluginpvio_socket_client_pluginma_strmakemy_charset_utf8mb3_hungarian_uca_cirl_reset_terminal_rl_complete_mark_symlink_dirsmy_open_parent_dir_nosymlinksmy_errorcheck_mutexattrmy_like_range_mbmysql_field_tellmy_charset_utf16_lithuanian_uca_cirl_make_bare_keymapmy_umaskmthd_stmt_get_param_metadatamy_thread_var_mutex_in_usemy_convert_using_funcmy_strntoull_8bitset_mysys_varmy_hash_sort_binmy_symlinkget_defaults_optionsma_zlib_compresspvio_callbackmysql_refresh_startmy_charset_utf8mb3_nopad_binmy_wildcmp_binmy_charset_utf8mb4_turkish_uca_ci_rl_reset_argumentmy_charset_utf32_latvian_uca_cimy_uca_collation_handler_utf8mb4mysql_list_tablesrl_bind_key_in_mapmysql_rollback_contullstr_rl_last_command_was_killmysql_get_socketinit_dynamic_array2mysql_get_charset_by_namema_pvio_tls_get_protocol_versionmysql_thread_initmysql_stmt_skip_paramsetmariadb_get_charset_by_nr_rl_strip_promptcharset_name_ucs2stage_waiting_for_table_level_lock_rl_init_eightbitmysql_find_charset_nrmy_charset_utf16_romanian_uca_cikey_memory_my_file_infomy_getopt_get_addrrl_vi_eWordkey_COND_alarm_rl_set_mark_at_posmysql_endmy_print_helpma_net_flushrl_vi_back_to_indentgetopt_ull_limit_valuemy_charset_ucs2_hungarian_uca_cimy_collation_get_by_namerl_copy_textthai_contractionsmariadb_client_errorsmysql_eof_ZNK6String21print_with_conversionEPS_PK15charset_info_stmy_atof_ZN6String35append_for_single_quote_using_mb_wcEPKcmPK15charset_info_strltty_set_default_bindingsmysql_optionsmy_charset_ucs2_esperanto_uca_ci_rl_horizontal_scroll_modewrite_historymysql_get_character_set_infomysql_stmt_errnomysql_stmt_close_contmy_default_record_cache_sizemysql_stmt_insert_idrl_vi_goto_markhistory_no_expand_charsmy_charset_euckr_nopad_binmy_thread_global_reinitmy_charset_ujis_japanese_cicharset_name_utf8mb3_rl_free_saved_history_linemy_charset_big5_nopad_binrl_universal_argumenthistory_basemy_collation_8bit_simple_nopad_ci_handlerrl_vi_end_wordmy_wildcmp_mball_charsetsma_gcvtnet_read_timeoutmy_error_unregisterrl_ignore_some_completions_functionmysql_read_query_result_startrl_insertpsi_cond_waitrl_executing_macrorl_vi_replacelist_deleterl_show_charrl_restore_promptmy_charset_ujis_nopad_binmy_b_appendmy_defaults_mark_filesmy_charset_utf8mb3_handlerrl_re_read_init_filestrfillmy_xml_set_leave_handlerma_hashtbl_nextmysql_close_slow_part_start_rl_terminal_can_insert_rl_eof_char_rl_dispatch_subseqrl_vi_append_eolmariadb_connectionpvio_socket_get_timeoutrl_unbind_keyrl_bind_keyseq_if_unbound_in_mapmy_min_str_8bit_simple_nopadmysql_real_connect_contmy_charset_ucs2_general_nopad_cimysql_stmt_resetmysql_list_tables_contmysql_insert_idma_stmt_execute_generate_requestmthd_my_real_connectkey_memory_defaultsma_tls_read_asyncstmt_set_errormy_error_unregister_allpvio_socket_blockingmy_hash_elementautoset_my_optionrl_end_of_historyrl_catch_signalsmy_once_memduphandle_sigintcharset_name_latin1rl_beginning_of_history_my_b_encr_readrl_get_keymap_by_namemy_strnxfrm_mbthai_contractions_w2my_min_str_mb_simple_nopadmysql_stmt_fetch_columnmy_unicase_turkish_rl_callback_funcmy_uca_collation_handler_nopad_multilevel_no_contractions_utf8mb4my_uca_collation_handler_nopad_no_contractions_utf8mb3mysql_native_password_client_pluginmy_charset_utf8mb3_myanmar_uca_cirl_donerl_clear_signals_rl_read_mbstringmy_charset_utf16_slovak_uca_cirl_digit_argumentappend_historymysql_stmt_prepare_startrl_begin_undo_groupnet_add_multi_commandmysql_autocommit_start_ZN6String8set_realEdjPK15charset_info_stma_tls_writempvio_infohistory_search_delimiter_charserrbuffhistory_getTHR_thread_countma_insert_dynamicrl_set_promptmy_file_openedmy_strnxfrm_simplemy_fwritemy_strnxfrmlen_unicodemy_charset_utf8mb3_slovak_uca_cima_net_writemy_uca_v520my_thread_namemy_time_initmysql_cset_escape_slashesmy_charset_utf32_spanish_uca_ci_rl_last_c_posstrend_rl_find_prev_mbcharmy_caseup_ujisrl_messagema_set_dynamic_dig_vec_lowerkey_memory_MY_TMPDIR_full_listGCC_3.0CXXABI_1.3GLIBC_2.2.5OPENSSL_1_1_0OPENSSL_1_1_1GLIBC_2.3.2GLIBC_2.28GLIBC_2.15GLIBC_2.17GLIBC_2.7GLIBC_2.14GLIBC_2.4GLIBC_2.11GLIBC_2.3GLIBC_2.3.4                         P&y m ӯk u ui  m {0mm0ui ri  ʭii խ ߭ii ii ui ti  hj[5pj[3xj[`5j[j[j[˙j[ϙj[әj[יj[ۙj[ߙj[j[j[j[j[j[k[k[k[k[ k[ (k[0k[@k[|Hk[|`k[|hk[k[|k[ɷk[|k[ѷk[|k[ڷk[|k[l[|l[ l[|(l[@l[|Hl[`l[|hl[l[|l[ l[|l[l[|l[l[|l[$m[|m[+ m[|(m[@m[|Hm[4`m[|hm[<m[|m[Fm[|m[Pm[|m[Xm[|n[| n[|(n[`@n[|Hn[k`n[|n[Xn[tn[|n[]n[= n[p= n[n[n[|n[o[ o[(o[|8o[`o[ho[po[|o[ɸo[To[Ӹo[|o[Zo[0o[p[|p[8p[G@p[Hp[|Xp[p[p[p[|p[|p[Mp[+p[|p[Gq[5q[< q[|0q[0@q[`? Hq[@A Xq[`q[Mhq[|xq[q[B q[ C q[q[^q[|q[pq[wq[~q[|r[0r[G8r[@r[|Pr[M`r[P> hr[P@ xr[gr[r[|r[mr[r[r[|r[#r[> r[> s[ws[ǹs[|(s[عPs[޹Xs[`s[|ps[s[~s[s[|s[s[0? s[> s[ֵs[ s[|t[(t[0t[&8t[|Ht[:pt[7xt[Dt[|t[t[? t[ < t[Wt[\t[|t[lt[P? t[@? u[pu[tu[| u[bHu[Pu[Xu[|hu[|u[u[u[|u[u[u[Ǻu[|u[ۺ v[(v[0v[|@v[hv[pv[xv[|v[v[v[v[|v[v[-w[4w[|w[F@w[MHw[TPw[|`w[fw[mw[mw[|w[Gw[w[tw[|w[:x[ x[(x[|8x[`x[hx[px[|x[x[ > x[= x[x[x[|x[λx[`> x[@ x[Gx[ػy[|y[8y[0@y[Hy[|Xy[y[y[y[|y[y[0y[y[|y[z[z[ z[|0z[|Xz[`z[(hz[|xz[z[Gz[;z[|z[z[z[Oz[|{[0{[G8{[c@{[|P{[x{[M{[v{[|{[f{[0{[{[|{[|[޹|[|[|(|[P|[X|[`|[|p|[|[|[|[||[|[޹|[ɼ|[|}[(}[0}[ܼ8}[|H}[X}[@ `}[< p}[x}[}[|}[}[@ }[< }[0}[}[|}[~[0~[~[| ~[H~[0P~[X~[|h~[~[~[*~[|~[~[~[5~[|~[ [([G0[|@[ۺh[Tp[Zx[|[k[? [A [T[q[|[k[? [A [{[Z[|[([? 0[A @[MH[P[|`[f[[[|[[? [? Ѐ[؀[[|[[? [? [{ [q([|8[H[? P[A `[Mh[p[|[G[޹[ǽ[|ȁ[[-[ҽ[|[F8[p@[ݽH[|X[b[[[|[Ȃ[wЂ[؂[|[ع[[ [|0[X[`[h[|x[ [[[|[|[T[#[|[Z0[g8[-@[|P[mx[7[7[|[[? [ < [GȄ[JЄ[|[[ֵ[U[|([P[X[``[|p[[[k[|[[[u[|[([0[8[|H[|p[x[[|[[7[Ȇ[|؆[[? [ < [X[[| []0[= 8[p= H[GP[X[|h[Mx[P> [P@ [[[|[#[> ȇ[> ؇[~[[|[[0? [> [([ƾ0[|@[P[B X[ C h[wp[Ͼx[|[[W[ھ[|Ј[l[P? [@? [5[[|[0([`? 0[@A @[0H[P[|`[[[[|[[ > [= Љ[޹؉[[|[[ [([|8[%H[`> P[@ `[Th[.p[|[k[? [A [T[?[|Ȋ[k؊[? [A [T[R[|[k [? ([A 8[T@[cH[|X[kh[? p[A [T[u[|[k[? [A ȋ[TЋ[؋[|[k[? [A [T[ [|0[k@[? H[A X[T`[h[|x[k[? [A [T[[|[kЌ[? ،[A [T[̿[|[k[? [A 0[T8[ݿ@[|P[k`[? h[A x[T[[|[k[? [A [Tȍ[Ѝ[|[k[? [A [T[[|([k8[? @[A P[TX[`[|p[k[? [A [T[1[|[kȎ[? Ў[A [T[@[|[k[? [A ([T0[Q8[|H[kX[? `[A p[Tx[d[|[k[? [A [T[uȏ[|؏[k[? [A [T[[| [k0[? 8[A H[TP[X[|h[kx[? [A [T[[|[k[? Ȑ[A ؐ[W[[|[l[P? [@? [W([0[|@[lP[P? X[@? h[Wp[x[|[l[P? [@? [W[[|Б[ [P? [@? [W[[|[ ([P? 0[@? @[WH['P[|`[ p[P? x[@? [W[6[|[ [P? [@? В[Wؒ[G[|[ [P? [@? [W [W([|8[ H[P? P[@? `[Wh[gp[|[ [P? [@? [W[w[|ȓ[ ؓ[P? [@? [W[[|[  [P? ([@? 8[W@[H[|X[ h[P? p[@? [W[[|[ [P? [@? Ȕ[WД[ؔ[|[ [P? [@? [W[ [|0[ @[P? H[@? X[W`[h[|x[ [P? [@? [W[[|[ Е[P? ؕ[@? [W[[|[ [P? [@? 0[W8[ @[|P[ `[P? h[@? x[W[[|[ [P? [@? [WȖ[)Ж[|[ [P? [@? [W[:[|([ 8[P? @[@? P[WX[N`[|p[ [P? [@? [W[a[|[ ȗ[P? З[@? [[z[|[[? [? ([0[8[|H[X[? `[? p[x[[|[[? [? [[Ș[|ؘ[[? [? [[[| [0[? 8[? H[P[X[|h[x[? [? [[[|[[? ș[? ؙ[[[|[[? [? [([0[|@[P[? X[? h[p[x[|[[? [? [[)[|К[[? [? [[8[|[([? 0[? @[H[HP[|`[p[? x[? [[\[|[[? [? Л[؛[[|[[? [? [ [l([|8[H[? P[? `[h[{p[|[[? [? [[[|Ȝ[؜[? [? [[[|[ [? ([? 8[@[H[|X[h[? p[? [[[|[[? [? ȝ[Н[؝[|[[? [? [[ [|0[@[? H[? X[`[h[|x[[? [? [7[D[|[О[? ؞[ < [7[[|[[? [ < 0[78[-@[|P[`[? h[ < x[7[@[|[[? [ < [7ȟ[TП[|[[? [ < [7[i[|([8[? @[ < P[7X[{`[|p[[? [ < [7[[|[Ƞ[? Р[ < [7[[|[[? [ < ([70[8[|H[X[? `[ < p[7x[[|[[? [ < [7[ȡ[|ء[[? [ < [7[[| [0[? 8[ < H[7P[X[|h[x[? [ < [7[[|[[? Ȣ[ < آ[7[[|[[? [ < [7(['0[|@[P[? X[ < h[7p[8x[|[[? [ < [7[K[|У[[? [ < [7[`[|[([? 0[ < @[7H[uP[|`[p[? x[ < [7[[|[[? [ < Ф[7ؤ[[|[[? [ < [7 [([|8[H[? P[ < `[7h[p[|[[? [ < [7[[|ȥ[إ[? [ < [[[|[ [@ ([< 8[@[ H[|X[h[@ p[< [[ [|[[@ [< Ȧ[Ц[3ئ[|[[@ [< [[G [|0[@[@ H[< X[`[\h[|x[[@ [< [[n[|[Ч[@ ا[< [[[|[[@ [< 0[8[@[|P[`[@ h[< x[[[|[[@ [< [Ȩ[Ш[|[[@ [< [[[|([8[@ @[< P[X[`[|p[[@ [< [[[|[ȩ[@ Щ[< [[[|[[@ [< ([0[8[|H[X[@ `[< p[x[+[|[[@ [< [[>Ȫ[|ت[[@ [< [[S[| [0[@ 8[< H[P[hX[|h[x[@ [< [[{[|[[@ ȫ[< ث[[[|[[@ [< [([0[|@[P[@ X[< h[p[x[|[[@ [< [`[[|Ь[v[ B [B [`[[|[v([ B 0[B @[`H[P[|`[vp[ B x[B [7[[|[[@ [< Э[ح[![|[[@ [< [ [4([|8[H[@ P[< `[h[Mp[|[[@ [< [[c[|Ȯ[خ[@ [< [[y[|[ [@ ([< 8[@[H[|X[h[@ p[< [[[|[[@ [< ȯ[Я[د[|[[@ [< [[ [|0[@[@ H[< X[`[h[|x[[@ [< [[[|[а[@ ذ[< [[[|[[@ [< 0[8[)@[|P[`[@ h[< x[[?[|[[@ [< [ȱ[Uб[|[[@ [< [[k[|([8[@ @[< P[X[`[|p[[@ [< [[[|[Ȳ[@ в[< [[[|[[@ [< ([0[8[|H[X[@ `[< p[x[[|[[@ [< [[ȳ[|س[[@ [< [[[| [0[@ 8[< H[P[!X[|h[x[@ [< [[7[|[[@ ȴ[< ش[[M[|[[@ [< [([c0[|@[P[@ X[< h[p[yx[|[[@ [< [[[|е[[@ [< [[[|[([@ 0[< @[H[P[|`[p[@ x[< [[[|[[@ [< ж[ض[[|[[@ [< [ [([|8[H[@ P[< `[h[p[|[[@ [< [[)[|ȷ[ط[@ [< [[?[|[ [@ ([< 8[@[ZH[|X[h[@ p[< [[p[|[[@ [< ȸ[и[ظ[|[[@ [< [[ [|0[@[@ H[< X[`[h[|x[[@ [< [[[|[й[@ ع[< [[[|[[@ [< 0[8[@[|P[`[@ h[< x[[ [|[[@ [< [Ⱥ[ к[|[[@ [< [7[[|([8[? @[ < P[7X[6`[|p[[? [ < [7[I[|[Ȼ[? л[ < [[][|[[@ [< ([0[q8[|H[X[@ `[< p[x[[|[[@ [< [W[)ȼ[|ؼ[ [P? [@? [W[[| [ 0[P? 8[@? H[WP[X[|h[ x[P? [@? [T[[|[k[? Ƚ[A ؽ[T[[|[k[? [A [T([0[|@[kP[? X[A h[p[x[|[[? [? [[[|о[[? [? [[[|[([? 0[? @[XH[#P[|`[]p[= x[p= [[9[|[п[ؿ[P[|[[ [g([|8[ɸ`[Th[|p[|[Z[0[[|[[G[[|[8[@[H[|X[|[M[[|[G[5[[|[0[`? [@A [[ [|0[@[B H[ C X[`[h[|x[p[w[6[|[[G[K[|[M[P> [P@ 0[g8[a@[|P[mx[[x[|[#[> [> [w[[|[ع[޹[[|([P[~X[`[|p[[0? [> [ֵ[[|[[[[|[:([70[8[|H[X[? `[ < p[Wx[[|[l[P? [@? [p[5[|[b[[L[| [|H[P[eX[|h[[[|[|[ۺ[[[|[ [([0[|@[h[p[x[|[[[[|[[@ [< [[[|[([@ 0[< @[0H[P[|`[[[[|[[[*[|[[ [B([|8[ۺ`[Th[Up[|[k[? [A [T[l[|[k[? [A [{[|[|[ [? ([A 8[-@[H[|X[F[M[[|[f[M[[|[f[[ [|0[@[? H[? X[`[h[|x[[? [? [{[[|[[? [A [[[|[:0[M8["@[|P[Gx[޹[2[|[[-[C[|[F[p[T[|([bP[X[d`[|p[[w[s[|[ع[[[|[p([0[8[|H[ɸp[x[[|[|[T[[|[Z[g[[| [mH[GP[X[|h[[ֵ[[|[[[[|[ [([0[|@[h[p[x[|[[['[|[|[7[6[|[([? 0[ < @[XH[HP[|`[]p[= x[p= [G[W[|[M[P> [P@ [[g[|[#[> [> [~ [x([|8[H[0? P[> `[h[p[|[[B [ C [w[[|[[W[[|[l [P? ([@? 8[5@[H[|X[0h[`? p[@A [[[|[[[[|[[[ [|0[@[ > H[= X[`[h[|x[[ > [= [[[|[%[`> [@ [[1[|[%[`> [@ 0[T8[C@[|P[k`[? h[A x[T[Z[|[k[? [A [W[u[|[l[P? [@? [W[[|([l8[P? @[@? P[X[`[|p[[? [? [[[|[[? [? [7[[|[[? [ < ([70[8[|H[X[? `[ < p[x[ [|[[@ [< [[&[|[[@ [< @[H[0X[`[0p[x[[[[ڶ[[G[0[S[X[[[[[b [p0[8[H[(P[`[*h[5x[/[5[:[G[6[G[[[~[~[[[=[ [v([8[I@[0P[X[0h[p[0[[0[R[[[[[[Դ[[\[G[N[G([Y0[G@[<H[GX[e`[wp[}x[w[[w[l[w[n[[[[[[[[w [ֵ0[ݵ8[ֵH[P[ֵ`[˵h[ֵx[T[T[M[T[g[g[`[g[[[[[[ [([8[w@[wP[X[wh[5p[5[D[0[?[?[[?[[[[[[ [o 0[2@[ P[ `[ p[ [ [ [ [ [ [; [P [ [ [  [ ([8[` @[ P[p X[1 h[` [ [ [X[ [^[ [[ [][^([`8[H[`[h[gp[lx[o[[t[< [y[w[~[[h[p[x[@p^[ _[_[ _ [(&(['&0[&& [%&([$&8[ <&X[ ;&[ :&[ 9&([ 8&8[ 7&H[ 6&[ 5&[ 4&h[ 3&[ 2&[ 1&[ 0&[ /&([,`@[D*[C*8\B*@\@1H\:1P\41X\,1`\&1h\ 1p\1x\1\1\1\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0(\00\08\0@\0H\0P\0X\|0`\r0h\n0p\h0x\b0\^0\Z0\P0\J0\D0\>0\80\20\"0\0\ 0@\0H\0P\/X\/`\/ \/ \/ \/ \/( \/0 \/8 \/H \bh \`e \^d \]d \\d \[d \Zd \Yd \Xd \Wd \Vd( \Ud8 \TdH \SdX \Rdh \Qdx \Pd \Od \Nd \Md \Ld \Kd \Jd \Id \Hd \Gd( \Fd8 \EdX \Ddh \Cdx \Bd \Ad \@d \?d \>d \=d \ )\)\0& )\ )\ )\ )\1 *\ (*\`]0*\ 8*\`]@*\ H*\@r]P*\ X*\ b]`*\;xh*\R]p*\ x*\R]*\ *\R]*\ *\A]*\$ *\A]*\F *\]*\ *\0e+\ +\(e +\/ (+\A]8+\< @+\\P >\l >\@n >\ >\Ц (>\ 0>\@ 8>\0 @>\ H>\P P>\` X>\ `>\ h>\ p>\0 x>\ >\ >\ >\ >\ >\m >\l >\p >\m >\p>\s >\p >\ u ?\0 ?\@ ?\P ?\ ?\ (?\ 0?\ 8?\ @?\p H?\ h?\ y p?\@q x?\z ?\0 ?\@ ?\P ?\0 ?\P ?\ ?\ ?\ ?\p ?\ ?\s ?\r ?\pv @\а @\@ @\P @\ @\ (@\ 0@\ 8@\ @@\ H@\ h@\ y p@\w x@\| @\а @\@ @\P @\0 @\P @\ @\ @\ @\ @\ @\P @\Щ @\` A\P A\~ A\Ѓ A\ A\Ц (A\ 0A\@ 8A\0 @A\ HA\P PA\` XA\ `A\ hA\ pA\0 xA\ A\ A\ A\ A\ A\ A\p} A\p A\p A\pA\@ A\` A\ B\0 B\@ B\P B\ B\ (B\ 0B\ 8B\ @B\p HB\ hB\ pB\ xB\ B\ B\@ B\P B\0 B\P B\ B\ B\ B\p B\ B\@ B\ B\P C\а C\@ C\P C\ C\ (C\ 0C\ 8C\ @C\ HC\ hC\ pC\ xC\ C\~ C\@ C\P C\0 C\P C\ C\ C\ C\ C\ C\0 C\0 C\`D\@ D\@ D\ D\ D\ (D\p 0D\ 8D\ @D\ HD\ hD\ pD\0 xD\` D\P D\ D\0 D\ D\0 D\p D\ D\ D\ D\P D\` D\ D\ D\ D\0 D\ E\ E\ E\ E\ E\` (E\@ 0E\ 8E\@ @E\p`E\@ hE\` pE\ xE\ E\ E\@ E\ E\ E\ E\p E\ E\ E\ E\ E\@ E\` E\ E\ F\ F\@ F\ F\ F\ (F\p 0F\ 8F\ @F\ HF\ `F\ hF\ pF\0 xF\` F\P F\p F\ F\ F\0 F\p F\ F\ F\ F\P F\` F\ F\ F\ F\0 F\ G\ G\ G\ G\ G\` (G\@ 0G\ 8G\@ @G\ hG\P pG\Щ xG\` G\ G\P G\ G\ G\Ц G\ G\@ G\0 G\ G\P G\` G\ G\ G\ G\0 G\ H\ H\ H\ H\ H\ (H\ 0H\p 8H\@ @H\ hH\ pH\ xH\` H\0 H\@ H\P H\ H\ H\ H\ H\ H\p H\ H\H\P H\@I\0 I\@ I\P I\0 I\ (I\ 0I\ 8I\ @I\p HI\ hI\ pI\ xI\ I\а I\@ I\P I\ I\ I\ I\ I\ I\ I\ I\I\I\J\а J\@ J\P J\0 J\ (J\ 0J\ 8J\ @J\ HJ\ hJ\ pJ\0 xJ\` J\P J\J\J\ J\0 J\p J\ J\ J\ J\P J\` J\ J\ J\ J\0 J\ K\ K\ K\ K\ K\` (K\@ 0K\ 8K\@ @K\phK\@ pK\pxK\`K\ K\@ K\ K\ K\ K\p K\ K\ K\ K\ K\@ K\@ K\`L\p L\@ L\ L\ L\ (L\p 0L\ 8L\ @L\ HL\ `L\pihL\0pL\P1xL\L\2L\L\p L\@L\ L\'L\ L\p L\ L\piL\0L\.L\M\2M\M\p M\@(M\ 0M\'8M\ @M\ HM\ `M\pihM\00pM\`0xM\`M\6M\M\p M\@M\ M\2M\ M\p M\ M\piM\00M\`.M\`N\+N\N\p N\@(N\ 0N\'8N\ @N\ HN\ `N\pihN\pN\pxN\N\N\N\p N\@N\ N\N\ N\p N\ N\piN\N\N\O\O\O\p O\@(O\ 0O\8O\ @O\ HO\ `O\pihO\PpO\xO\pO\"O\O\p O\@O\ O\0O\ O\p O\ O\piO\PO\O\pP\P\P\p P\@(P\ 0P\8P\ @P\ HP\ `P\jhP\*pP\+xP\sP\<P\P\P P\@P\ P\@/P\ P\p P\ P\jP\*P\.P\sQ\<Q\Q\P Q\@(Q\ 0Q\@/8Q\ @Q\ HQ\ `Q\jhQ\*pQ\+xQ\rQ\6Q\Q\P Q\@Q\ Q\1Q\ Q\p Q\ Q\jQ\*Q\p.Q\rR\3R\R\P R\@(R\ 0R\@/8R\ @R\ HR\ `R\jhR\ pR\ xR\R\` R\R\P R\@R\ R\R\ R\p R\ R\jR\ R\R\S\` S\S\P S\@(S\ 0S\8S\ @S\ HS\ `S\jhS\pS\xS\S\S\S\P S\@S\ S\ S\ S\p S\ S\jS\S\S\T\T\T\P T\@(T\ 0T\8T\ @T\ HT\ `T\ihT\`pT\PxT\p{T\@T\T\P T\@T\ T\T\ T\p T\ T\iT\`T\@T\p{U\@U\U\P U\@(U\ 0U\8U\ @U\ HU\ `U\ihU\0pU\ xU\@{U\ &U\U\P U\@U\ U\ U\ U\p U\ U\iU\0U\ U\@{V\@#V\V\P V\@(V\ 0V\8V\ @V\ HV\ `V\ihV\0pV\xV\V\V\V\P V\@V\ V\ V\ V\p V\ V\iV\0V\ V\W\W\W\P W\@(W\ 0W\ 8W\ @W\ HW\ `W\ihW\pW\xW\`W\@W\W\P W\@W\ W\W\ W\p W\ W\iW\W\W\`X\@X\X\P X\@(X\ 0X\ 8X\ @X\ HX\ `X\pihX\pX\pxX\X\X\X\p X\@X\ X\X\ X\p X\ X\piX\X\X\Y\Y\Y\p Y\@(Y\ 0Y\8Y\ @Y\ HY\ `Y\pihY\PpY\xY\PY\Y\Y\p Y\@Y\ Y\0Y\ Y\p Y\ Y\piY\PY\Y\PZ\Z\Z\p Z\@(Z\ 0Z\8Z\ @Z\ HZ\ `Z\pihZ\0pZ\xZ\Z\Z\Z\p Z\@Z\ Z\ Z\ Z\p Z\ Z\piZ\0Z\ Z\[\[\[\p [\@([\ 0[\ 8[\ @[\ H[\ `[\pih[\p[\x[\[\@[\[\p [\@[\ [\[\ [\p [\ [\pi[\[\[\\\@\\\\p \\@(\\ 0\\ 8\\ @\\ H\\ h\\ap\\ax\\L\\ \\]\\]\\ \\9\\Ѐ\\^\\_\\f\\PC\\D\\0`\\9\\P<\\>\\A]\c]\F]\b]\@L ]\](]\a0]\08]\]@]\ph]\p]\x]\0]\ r]\]\p ]\@]\9]\ ]\~]\ ]\p ]\ ]\`]\]\^\P{^\^\p ^\ ^\9(^\ 0^\^8^\ @^\p H^\ h^\p^\x^\`^\t^\^\p ^\@^\9^\ ^\0b^\ ^\ ^\ ^\^\Љ^\P_\ }_\_\p _\ _\9(_\ 0_\@8_\ @_\ H_\ h_\`p_\@x_\_\`_\_\p _\_\9_\ _\@_\ _\ _\ _\p]_\]_\U`\ `\pU`\`\ `\9(`\Ѐ0`\@8`\y@`\pkH`\PCP`\DX`\e``\9h`\P<p`\>x`\A`\c`\X`\b`\z`\W`\X`\0`\`\p`\`\`\ a\a\a\p a\` a\9(a\ 0a\V8a\ @a\p Ha\ ha\pa\xa\@a\0wa\a\p a\a\9a\ a\Va\ a\p a\ a\a\a\b\b\b\p b\` b\9(b\ 0b\@8b\ @b\ Hb\ hb\pb\xb\pb\b\b\p b\b\9b\ b\@b\ b\ b\ b\Qb\ Rb\@Uc\ c\Tc\vc\ c\9(c\Ѐ0c\M8c\P@c\fHc\PCPc\DXc\ e`c\9hc\P<pc\>xc\Ac\cc\Fc\bc\@Lc\Pc\Qc\0c\vc\pc\c\ c\d\d\d\p d\q d\9(d\ 0d\R8d\ @d\p Hd\ hd\ppd\xd\`d\ qd\d\p d\pd\9d\ d\Nd\ d\p d\ d\d\`d\e\e\e\p e\q e\9(e\ 0e\S8e\ @e\ He\ he\ppe\xe\кe\se\e\p e\pe\9e\ e\Oe\ e\ e\ e\Qe\ Re\Lf\ f\Mf\vf\ f\9(f\Ѐ0f\M8f\P@f\fHf\PCPf\DXf\ e`f\9hf\P<pf\>xf\Af\cf\Ff\bf\@Lf\Pf\Qf\0f\vf\pf\f\f\pg\g\g\p g\q g\9(g\ 0g\R8g\ @g\p Hg\ hg\ppg\xg\g\g\g\p g\pg\9g\ g\Ng\ g\p g\ g\g\g\h\h\h\p h\q h\9(h\ 0h\S8h\ @h\ Hh\ hh\pph\xh\0h\h\h\p h\ph\9h\ h\Oh\ h\ h\ h\P h\Щ h\` i\i\i\i\ i\Ц (i\ 0i\P8i\@@i\ Hi\P Pi\` Xi\ `i\ hi\ pi\0 xi\ i\ i\ i\ i\ i\i\0i\p i\`i\pi\0i\`i\j\0 j\@ j\P j\ j\ (j\ 0j\ 8j\ @j\p Hj\ hj\Ppj\xj\@j\0 j\@ j\P j\0 j\P j\ j\ j\ j\p j\ j\0j\j\ k\а k\@ k\P k\ k\ (k\ 0k\ 8k\ @k\ Hk\ hk\Ppk\xk\k\а k\@ k\P k\0 k\P k\ k\ k\ k\ k\ k\P k\Щ k\` l\ l\l\ l\ l\n(l\0q0l\058l\2@l\ Hl\P Pl\` Xl\ `l\ hl\ pl\0 xl\ l\ l\ l\ l\ l\l\l\p l\ l\pl\Hl\7l\Nm\m\m\P m\ m\ (m\ 0m\ 8m\ @m\p Hm\ hm\\pm\0Cxm\0bm\mm\m\P m\pxm\m\ m\@<m\ m\p m\ m\Hm\p?m\`Rn\n\n\P n\ n\ (n\ 0n\ 8n\ @n\ Hn\ hn\\pn\pXxn\fn\n\n\P n\pxn\n\ n\>n\ n\ n\ n\P n\Щ n\` o\ o\ Mo\o\ o\(o\0o\08o\@@o\ Ho\P Po\` Xo\ `o\ ho\ po\0 xo\ o\ o\ o\ o\ o\o\o\p o\o\o\` o\ o\p\}p\p\P p\Px p\@V(p\ 0p\ 8p\ @p\ Hp\ hp\P pp\Щ xp\` p\ p\ p\0p\ p\p\p\0p\@p\ p\P p\` p\ p\ p\ p\0 p\ q\ q\ q\ q\ q\(q\0q\p 8q\0@q\phq\ pq\xq\q\pq\q\P q\ q\ q\ q\ q\ q\p q\ q\%q\Pq\,r\1r\r\P r\Px r\@V(r\ 0r\P8r\ @r\p Hr\ hr\ pr\xr\ r\|r\r\P r\ r\ r\ r\ r\ r\ r\ r\Pr\0r\ps\zs\s\P s\Px s\@V(s\ 0s\ 8s\ @s\ Hs\ hs\%ps\"xs\)s\0ys\s\P s\Pxs\@Vs\ s\ s\ s\ s\ s\`xds\`hds\`pdt\pt\pt\` t\0(t\@ 0t\p8t\ @t\ Ht\p Pt\ Xt\ `t\ ht\ ~\@r]\( \]\ \R]0\ 8\.@\A]H\` P\ `\ h\ \x\`]\P( \ \d\( \P \ b]\ \ `\~p\~Ѐ\~\~@\P\]X\e`\e\\^ȁ\T\Ё\T\ \0\^\&\8_\e\e\;\_p\A\O\e\e\h\_\Me\MeP\t`\bh\`dep\`de\Є\@b؄\R\\R\0\@\`b\\b\e\e\ \b(\e0\e\\0c\e\e\\`c\Le\Le`\p\cx\He\HeЇ\j\\8e\8e@\P\d\\@dȈ\eЈ\e \0\pd8\e@\e\\d\ e\ e\ \d\] \]p\6\@\e\e\V\dP\n`\ e\ѧЋ\`e؋\e\e0\@\vH\@eP\@e\\\e\e\ \e(\e0\e\\e\e\e\\@f\S\\S\`\p\`fЎ\\f\\e\\e@\΀P\fX\xe`\xe\\fȏ\PeЏ\Pe \0\(g8\e@\e\\Ph\pe\pe\\\e \ep\0\h\\hP\`\0j\=В\jؒ\(e\(e0\H@\jH\`eP\`e\M\Hk\e\e\b \k(\e0\e\s\ l\ e\ e\\Pl\]\]`\zp\lx\e\eЕ\\m\H\\H\@\P\XmX\e`\e\\mȖ\P\Ж\P\ \0\m8\e@\e\\m\e\e\\n\e \ep\ǁ\hn\e\e\Ӂ\n\Xe\XeP\`\n\Й\oؙ\e\e0\@\H\eP\e\\@o\ \o(\Pe0\Pe\&\o\e\e\*\p\e\e`\1p\@px\e\eМ\<\xp\e\e@\EP\pX\e`\e\P\pȝ\eН\e \X0\p8\e@\e\`\(q\xe\xe\l\`q\pe \pep\x\q\he\he\]\\e\eP\Ń`\r\Р\rؠ\e\e0\@\rH\0eP\0e\\r\/ \(s\\Ps\e\e\Ȃ\s`\p\͂x\e\e@\_`\h\p\x\\t\\\\#\~\\2\9\pz(\s0\F@\ QP\tX\h\wx\0t\6\pl\L\e\iȥ\jХ\\\pt\\ ;\ \0\@\tH\~X\h\p\\T\t\Ã\0T\Ƀ\Ц\~\t\\c\ u\ \p0\8\sH\pSX\`\p\ ;\#\\t\/\\}Ч\nا\H\`\`u\p\ \u(\O8\kH\uP\Ń`\ip\ux\z\{\(v\y\\oȨ\V\|\c\|\{x8\|@\s`\|h\\|\x\|\ة\|\\|\(\|0\P\|X\x\|\\|\Ȫ\|Ъ\DŽ\|\̈́\| \Մ@\|H\h\|p\߄\|\\|\\|\\|\0\|8\X\|`\\|\G\|\Ь\|ج\ \|\ \|(\H\|P\,p\|x\3\|\7\|ȭ\>\|\D\|\O8\|@\W`\|h\Б\|\\|\]|خ\|\T\|\^(\|0\cP\|X\kx\|\p\|\vȯ\|Я\y\|\|\| \~@\|H\h\|p\\|\ѕ\|\\|\\|\0\|8\X\|`\ڑ\|\\|\б\|ر\\|\. \|(\H\|P\Džp\|x\\|\ͅ\|Ȳ\Յ\|\߅\|\8\|@\`\|h\\|\$\|\س\|\\|\(\|0\P\|X\%x\|\0\|\;ȴ\|д\H\|\F\| \O@\|H\Wh\|p\^\|\d\|\i\|\v\|\0\|8\X\|`\\|\9\|\ж\|ض\\|\^ \|(\a|H\|P\p\|x\\|\ņ\|ȷ\Ն\|\\|\8\|@\`\|h\m|\|\\|\ظ\|\ \|\(\|0\P\|X\*x\|\1\|\6ȹ\|й\?\|\L\| \Z@\|H\dh\|p\l\|\t\|\}\|\\|\:0\|8\u|X\|`\\|\\|\л\|ػ\\|\ \|(\H\|P\p\|x\\|\Ç\|ȼ\ʇ\|\y\|\Ӈ8\|@\ڇ`\|h\||\|\\|\ؽ\|\\|\(\|0\P\|X\x\|\\|\Ⱦ\|о\\|\%\| \.@\|H\4h\|p\9\|\?\|\K\|\F\|\L0\|8\|X\|`\R\|\Y\|\`\|\f\|\j \|(\pH\|P\xp\|x\~\|\\|\\|\\|\|8\|@\`\|h\\|\\|\\|\ň\|\̈(\|0\҈P\|X\ڈx\|\߈\|\\|\\|\\| \@\|H\h\|p\\|\\|\(\|\\|\30\|8\:X\|`\\|\\|\A\|\I\|\P \|(\VH\|P\_p\|x\f\|\l\|\x\|\\|\B8\|@\`\|h\\|\\|\\|\\|\(\|0\P\|X\x\|\\|\\|\Ɖ\|\Љ\| \׉@\|H\߉h\|p\Z\|\@\|\ \|\\|\0\|8\X\|`\\|\\|\\|\\|\ \|(\VH\|P\p\|x\ \|\>\|\ڍ\|\&\|\,8\|@\6`\|h\\\|\E\|\K\|\|\|\P(\|0\YP\|X\bx\|\g\|\t\|\{\|\\| \@\|H\h\|p\\|\ˊ\|\׊\|\\|\0\|8\X\|`\\|\#\|\5\|\D\|\P \|(\VH\|P\op\|x\\|\\|\\|\\|\8\|@\ɋ`\|h\Ӌ\|\ދ\|\\|\\|\(\|0\֏P\|X\x\|\ \|\\|\ \|\$\| \)@\|H\2h\|p\\|\9\|\I\|\T\|\a0\|8\X\|`\g\|\m\|\v\|\~\|\ \|(\H\|P\p\|x\\|\\|\\|\E\|\8\|@\`\|h\\|\Č\|\^\|\\|\ь(\|0\֌P\|X\ߌx\|\\|\g\|\\|\h\| \@\|H\h\|p\\|\\|\Ȍ\|\\|\0\|8\YX\|`\\|\'\|\/\|\4\|\< \|(\GH\|P\Qp\|x\Y\|\e\|\\|\k\|\q8\|@\`\|h\w\|\}\|\\|\\|\(\|0\P\|X\x\|\\|\Í\|\Ѝ\|\؍\| \ߍ@\|H\h\|p\\|\\|\\|\ \|\0\|8\X\|`\!\|\)\|\2\|\9\|\@ \|(\HH\|P\Op\|x\U\|\[\|\d\|\k\|\8\|@\`\|h\s\|\~\|\\|\\|\(\|0\P\|X\x\|\\|\\|\\|\\| \ʎ@\|H\юh\|p\ގ\|\\|\\|\\|\0\|8\cX\|`\\|\\|\\|\ \|\ \|(\H\|P\p\|x\%\|\-\|\ݤ\|\6\|\C8\|@\L`\|h\W\|\f\|\x\|\\|\(\|0\P\|X\x\|\\|\Ώ\|\ݏ\|\\| \@\|H\h\|p\\|\!\|\\|\.\|\40\|8\=X\|`\D\|\I\|\Q\|\Ә\|\_ \|(\gH\|P\op\|x\u\|\\|\}\|\\|\8\|@\`\|h\\|\]\|\\|\\|\;(\|0\P\|X\x\|\ΐ\|\א\|\ߐ\|\\| \@\|H\h\|p\\|\\|\\|\\|\0\|8\X\|`\"\|\.\|\8\|\=\|\E \|(\KH\|P\Rp\|x\Z\|\a\|\j\|\p\|\w8\|@\`\|h\\|\\|\\|\\|\(\|0\P\|X\x\|\\|\ʕ\|\Ƒ\|\͑\| \@\|H\בh\|p\\|\\|\\|\\|\0\|8\X\|`\ \|\\|\\|\\|\$ \|(\H\|P\Ȓp\|x\$\|\\|\'\|\2\|\;8\|@\?`\|h\D\|\L\|\T\|\`\|\l(\|0\qP\|X\vx\|\\|\\|\\|\\| \@\|H\h\|p\\|\\|\\|\\|\Ē0\|8\̒X\|`\ђ\|\֒\|\ޒ\|\\|\ \|(\H\|P\p\|x\\|\7\|\)\|\%\|\/8\|@\=`\|h\B\|\\|\@\|\M\|\Q(\|0\WP\|X\_x\|\g\|\o\|\x\|\\| \@\|H\h\|p\\|\\|\\|\\|\ē0\|8\̓X\|`\ؓ\|\\|\T\|\\|\ \|(\XH\|P\p\|x\\|\ \|\\|\\|\8\|@\'`\|h\2\|\8\|\D\|\ \|\(\|0\JP\|X\Tx\|\b\|\k\|\u\|\]| ]@]|H]h]|p]]|]ؔ]|]]|]]|]0]|8]X]|`]]|]#]|]0]|]V]|]C ]|(]JH]|P]Tp]|x]^]|]d]|]i]|]r]|]{8]|@]`]|h]]|]]|]]|]]|](]|0]ŕP]|X]Еx]|]֕]|]]|]ܕ]|]]| ]@]|H]h]|p]]|]ߕ]|]]|]]|]0]|8]X]|`]]|]]|]]|]]|] ]|(]H]|P] p]|x]1]|]A]|]E]|]Q]|]]8]|@]f`]|h]t]|]]|]]|] ]| ]( ]|0 ]P ]|X ]x ]| ] ]| ] ]| ]˖ ]| ]ٖ ]| ]@ ]|H ]h ]|p ] ]| ] ]| ]- ]| ]@ ]| ]R0 ]|8 ]gX ]|` ]{ ]| ] ]| ] ]| ] ]| ] ]|( ]H ]|P ]p ]|x ]Ǘ ]| ]͌ ]| ]w ]| ]˗ ]| ]֗8 ]|@ ]` ]|h ]2 ]| ]E ]| ] ]| ]ږ]|](]|0]WP]|X]lx]|]]|]]|]]|]]| ]@]|H] h]|p]]|]]|]']|]-]|]70]|8]<X]|`]B]|]N]|][]|]c]|]r ]|(]hH]|P]lp]|x]q]|]w]|]]|]]|]8]|@]`]|h]]|]]|]]|]]|](]|0]˜P]|X]ɘx]|]И]|]ژ]|]]|]]| ]@]|H]h]|p]]|]]|]]|]]|]'0]|8]X]|`]]|]/]|]5]|]@]|]T ]|(]6H]|P]Zp]|x]i]|]o]|]t]|]}]|]8]|@]`]|h]]|]]|]]|]Xz]|](]|0]P]|x]|]]|]9]]]].}]$]+}])]:]]x]0@]0 H]@ P]P X]` `]p h] p] x] ]!]<] ]@]p]] ] ] ]!] !]0!]P!]]W]^] :]U]&]* ]P(]_0]n8]@]pH]P] pX]`] h]p]`x]]@]]^] ] ] ]]Ш]]"]$]U]h]]]]]]]9 ]U(]@!0]!8]!@]:H]`WP]!X]!`]Ph] p]!x]']<]&];]J ]0=]P0]9]"]^]@]]]]$]`]`]]0 ] ]" ](]P0]`8]@$@]`'H]P]@X]`]`h]0p]@x]]0]]]P]]@]]]p]']] q]n]P]`f]]@i]f] ]P(]0] 8]p @]H]PP]X]`],h]@*p]@]x]@]]3]]x3]]H]]]0]H]`]x]]]j]]ئ]P]< ]*8]1P]Xh]`]x]t] ]]] ]( ]E@ ]΀X ]p ] ]# ]; ]I ]Z ]ǁ!]h!]0!]=H!]`!]x!]!]!]!]l!]!]"]˧ "]ק("]8"]P"]/h"]"]"]"]"] "]"]#]((#]/@#]:X#]Bp#]N#]Y#]h#]t#]ק#] $]($] 0$]8$]@$]"H$]*`$]nh$]sp$]xx$]}`%]$]x%]$]%]$]%]$]%]$]%]$]%]$] &]&](&] ']0&]']8&](]h&]pp&]x&]&]&] &]F&]&]&]'] (']\0']h8']P']x']@$ ']s']']ʳ']']`% ']P% ']% ']% (](](]0(]@(]& H(] & X(]`(]`(]/ h(]0& p(]+ x(]' (], (]P+ (]( (] * (]0 (]' (]' (]& (]`& (]& (]( (]* (]P( )]G)]D)]M)]G()]D0)]D8)]M@)]GP)]SX)]H`)]Xh)]]x)]b)]h)]p)]b)]v)])])])])])])]*]0*]*] *](*]00*]@*]H*]P*]0X*]h*]˴p*]x*]0*]*]Դ*]Դ*]*]*]*]Դ*]*]*]*]Դ*]*]+]+]Դ+] +]0+]8+]@+]H+]X+]'`+]h+]p+]+]+]+]+]+]2+]+]+]+]<+]<+]G+]N+]Y,]<,]G,]N ,]N(,]<0,]G8,]NH,]cP,]<X,]G`,]Np,]lx,]l,]w,]},],]l,]w,]},]},]l,]w,]},],]l,]w-]}-]-] -](-]8-]@-]H-]P-]`-]h-]p-]x-]-]µ-]-]-]-]˵-]˵-]ֵ-]ݵ-]-]˵-]ֵ-]ݵ.]ݵ.]˵.]ֵ.]ݵ(.]0.]˵8.]ֵ@.]ݵP.]X.]h.]x.].].].].].].].].].]$.]$/]//]: /]$0/]/@/]/H/]$X/]/h/]Dp/]$/]//]M/]M/]T/]Z/]T/]M/]T/]Z/]`/]`/]g/]m0]g0]`0]g 0]m00]s80]yH0]yX0]y`0]yp0]y0]0]0]0]0]0]0]0]0]0]0]0]0]1]1]1] 1](1]Ƕ01]81]жH1]ڶP1]ǶX1]`1]жp1]x1]1]1]1]1]1]1]1]1]#1]*1]01]52]02]:2]@ 2]G(2]M82]S@2]Y`2]`h2]hp2]`x2]v2]2]#2]2]#2]~2]2]~2]2]2]2]2]3]?3]3]?3](3]03]83]?@3]3][3]ht[3]o[3]w[3]3]3](3]h3]3]3]3]4]4]`4]4] 4](4]04]"84](@4]PH4]P4]X4]@`4]h4]p4]0x4]74]X4]|4]4]|4]̫4]S4]4]4]H4]h4]q4]4]4]4]4]5]5]5]5] 5]0(5]p05]85]@5]0H5]|P5]|X5]|`5]|h5]|p5] x5]5]|5]|5]75]`5]Q5]|5]`5]5]y5]5]5]|5]|5]|5]|5]|6]|6]|6]|6] 6]|(6]06]|86]|@6]0H6]|P6]XX6]`6]h6]p6]Px6]x6]6]6]|6]6]_6]Д 6]V7][7] 7](7] @7]xH7]P7]X7]? 7]:]7]e7]97]e7]W7]e7]7]e7] 8]e(8]88]e@8]P8]eX8]h8]|ep8].8]e8]J8]e8]a8]te8]r8]xe8]8]e9]9]e9](9]e09]@9]eH9]X9]e`9]p9]ex9]9]e9]9]e9]9]e9]%9]e9]39]e9]C:]e:]S:]e :]c0:]e8:]pH:]eP:]~`:]eh:]x:]e:]:]e:]:]:]} ;]|;]@;] ;] (;] 0;]`e@;]HH;]LP;]S`;] h;]Xp;]G~x;] ;]|;];];];];];]<]<]@ <] <] <] <] (<] 0<]0 8<] @<]P H<]` P<]p X<]@ `<] h<]P p<] x<]` <] <]p <] <] <]` <]а <] <] <]г <] <] <] <]p <] <]0 <]@ =] =]P =]0 =]` =]з (=]p 0=] 8=] @=] H=] P=] X=] `=] h=] p=]0 x=] =] =] =]б =] =] =] =] =] =] =] =] =] =] =]P =] =]0 >]@ >]@ >]P >] >] (>]е 0>]` 8>]p @>] H>] P>] X>] `>] h>] p>] x>] >] >] >] >] >] >]0 >]@ >]P >] >] >] >]ж >] >] >]0 >] ?] ?] ?]@ ?]в ?]` (?]P 0?]` 8?]p @?] H?] P?] X?] `?] h?] p?] x?] ?] ?]` ?] ?]0 ?]P ?]@ ?]P ?] ?]` ?]p ?]p ?]д ?] ?] ?] ?] @] @] @]p @] @] (@]@ 0@] @@] `@]h@]p@]0x@]X@]@]@]@]|@]@]<@]@@]`@]@]@]@]@]8@]Z@]`@]A]0A]`A]A] A]((A]h0A]8A]@A] HA]HPA]pXA]`A]hA]pA]@xA]A]A]uA]A]`]A]1A] B] B] (B]$ 8B] HB] XB] hB] xB]~ B] B] B] B] B] B] B] B] C] C] (C] 8C]0 HC] XC]0. hC] xC]P( C] C]( C] C] C] C] C] C] D] D] (D] 8D] HD] XD] hD] xD] D] D] D] D] D] D] D] D] E] E] (E] 8E] HE] XE] hE] xE] E] E] E] E] E] E] E] E] F] F] (F] 8F] HF] XF] hF] xF] F] F] F] F] F] F] F] F] G] G] (G] 8G] HG] XG] hG] xG] G] G] G] G] G] G] G] G] H] H] (H] 8H] HH] XH] hH] xH] H] H] H] H] H] H] H] H] I] I] (I] 8I] HI] XI] hI] xI] I] I] I] I] I] I] I] I] J] J] (J] 8J] HJ] XJ] hJ] xJ] J] J] J] J] J] J] J] J] K] K] (K] 8K] HK] XK] hK] xK] K] K] K] K] K] K] K] K] L] L] (L] 8L] HL] XL] hL] xL] L] L] L] L] L] L] L] L] M] M] (M] 8M] HM] XM] hM] xM] M] M] M] M] M] M] M] M] N] N] (N] 8N] HN] XN] hN] xN] N] N] N] N] N] N] N] N] O] O] (O] 8O] HO] XO] hO] xO] O] O] O] O] O] O] O] O] P] P] (P] 8P] HP] XP] hP] xP] P] P] P] P] P] P] P] P] Q] Q] (Q] 8Q] HQ] XQ] hQ] xQ] Q] Q] Q] Q] Q] Q] HR]$ XR]p xR]! R]` R] R]p- R]` R] R] S] S] (S] 8S] HS] XS]0 hS] xS]0. S]P( S] T]0 8T] HT]` XT]: hT]0& T]P% T] T]8 T] T] T]p U]P U]( (U]( 8U]( HU]( XU]( hU]( xU]( U]( U]( U]8 U]P% U]p V]& (V]! 8V]/ HV]. XV]$ hV]8 xV] V] ' V]@ W]( (W] ? 8W]> HW]8 XW]09 xW]p" W]6 W]1 W]P% W]8 W] X]@ X]`& (X]! 8X]/ HX]. XX]$ hX]8 X]` X]% X] X] X]0 X]? X]@ Y]( (Y]@= 8Y]> HY]8 XY] xY]p" Y]2 Y]1 Y]) Y]p3 b]! Hc] xc]9 c] d]< d]= 8f]P Hf]P Xf]P hf]P xf]P f]P f]P f]P f]P f]P f]P f]P f]P g]P g]P (g]P 8g]P Hg]P Xg]P hg]P xg]P g]P g]P g]P g]P g]P xh]@= j], r]! r], r]p r]0 s]0 hs]09 s]3 s]~ t] Ht] xt] t]" t]~ u] (u]* Hu] Xu] hu] xu] u] u] u] u] u] u] v] v]~ (v] 8v]~ Xv]P hv]P xv]P v]P v]P v]P v]P v]P v]P v]P v]P w]P w]P (w]P 8w]P Hw]P Xw]P hw]P xw]P w]P w]P w]P w]P w]P w]P w]P x] 8x]* hx] xx] x]p, x] y] (y]p Hy] hy]09 y] y] y]( (z]" 8z], h] x]P ]` ] ]` Ȃ]0 ؂]! ] ]~ ] ]p- (]` 8] H] h] x] ] ] ] ]0 ȃ] ؃]0. ] b]]P( ]@r]8] X]9 h] x] ] ] ] ] Ȅ] ؄] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] ȅ] ؅] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] Ȇ] ؆] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] ȇ] ؇] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] Ȉ] ؈] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] ȉ] ؉] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] Ȋ] ؊] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] ȋ] ؋] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] Ȍ] ،] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] ȍ] ؍] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] Ȏ] ؎] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] ȏ] ؏] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] Ȑ] ؐ] ] ] ] ] (] 8] H] X] h] x] ] ] ] ] ȑ] ؑ] ] ] ] ] (] 8] H] X] ]@A ]D ]L ] ]# ]c]i]!  ]n(]w0]zH] h]`> ]>]I]]]Г]]]j9Г] ؓ]]!{ ]H0]|@] zH] yP] xx][].\]/\]!{]#]| ] z(] y0] x8] wX][].\]`0\й]!{]]|] z] y] x8][x].\]0\]!{]tк]|] z] y] x] w][X].\`]`1\]]]]]]]A}]m]|]@|]@{]@{]s\8]1\@]2\p^a^^|^`^`^`~^[^`4\ ^`5\P^a`^p^|^`^`^`~^`}^[^`4\^5\0^a@^P^|`^`h^`p^`~^[^`4\^`6\^a ^0^|@^`H^`P^`~X^`}x^[^`4\^6\^` ^^`^^`] ^`] ^`]P#^`]#^`]#^H9$^ػ$^| $^`($^`0$^`8$^`H$^`P$^ [X$^s\$^`F\$^`7\l^Al^Wl^|m^@m^@m^@8m^[xm^7\m^8\m^Am^Km^|m^@m^@m^@m^@n^[Xn^7\`n^`9\n^An^n^|n^@n^@n^@n^[8o^7\@o^9\po^Ao^o^|o^@o^@o^@o^@o^[p^7\ p^`:\Xu^`^hu^T^xu^H^u^<^u^0^u^$^P_h!`_1p_|_`!_`!_`!_[_:\ _;\0 _h!@ _P _|` _`!h _`!p _`!x _`! _[ _:\ _`<\ _h! _0 _|@ _`!H _`!P _`!x _[ _:\ _<\ _h! _ _| _`!( _`!0 _`!8 _`!X _[ _:\ _`=\_@^_@^_@^_@^(_@^_@^_@^_@^_@^_@^X_@^`_@x^___|_`T"_`S"_`R"_`Q"(_`O"8_s\x_`F\_E\___|_@N"_@M"_@L"_@K"_@I"_s\@_`F\H_E\`_0p__|_ H"_ G"_ F"_ E"_ C"_s\_`F\_E\(_8_H_|X_B"`_A"h_@"p_?"_="_s\_`F\_E\_T_Ӹ_| _;"(_:"0_9"8_8"H_6"X_s\_`F\_E\_G__|_5"_4"_3" _2" _0" _s\` _`F\h _E\ _ _ _| _/" _." _-" _," _*" _s\(!_`F\0!_E\H!_MX!_+h!_|x!_)"!_("!_'"!_&"!_$"!_s\!_`F\!_E\"_ "_0"_|@"_!H"_!P"_!X"_#"h"_!x"_s\"_`F\"_E\"_0"_"_|#_`""#_`!"#_` " #_`"0#_`"@#_s\#_`F\#_E\#_#_^#_|#_@"#_@"#_@"#_@"#_@"$_s\H$_`F\P$_E\h$_x$_($_|$_!$_!$_!$_@"$_!$_s\%_`F\%_E\0%_G@%_;P%_|`%_5"h%_4"p%_3"x%_@"%_0"%_s\%_`F\%_E\%_g&_&_|(&_ "0&_ "8&_ "@&_ "P&_ "`&_s\&_`F\&_E\&_&_O&_|&_!&_!'_!'_ "'_!('_s\h'_`F\p'_E\'_w'_ǹ'_|'_ "'_ "'_ "'_ "'_"'_s\0(_`F\8(_E\P(_޹`(_p(_|(_"(_"(_"(_"(_"(_s\(_`F\)_E\)_G()_c8)_|H)_5"P)_4"X)_3"`)_"p)_0")_s\)_`F\)_E\)_M)_v*_|*_@!*_@! *_@!(*_!8*_@!H*_s\*_`F\*_E\*_ֵ*_ *_|*_!*_!*_!*_!+_!+_s\P+_`F\X+_E\p+_+_&+_|+_!+_!+_!+_!+_!+_s\,_`F\ ,_E\8,_pH,_tX,_|h,_!p,_!x,_!,_!,_!,_s\,_`F\,_E\-_-_ -_|0-_`!8-_`!@-_`!H-_`!X-_`!h-_s\-_`F\-_E\-_-_-_|-_@!._@!._@!._@! ._@!0._s\p._`F\x._E\._._Ǻ._|._ !._ !._ !._ !._ !._s\8/_`F\@/_E\X/_h/_x/_|/_!/_!/_!/_!/_!/_s\0_`F\0_E\ 0_00_@0_|P0_!X0_!`0_!h0_!x0_!0_s\0_`F\0_E\0_0_1_|1_! 1_!(1_!01_!@1_!P1_s\1_`F\1_E\1_1_1_|1_@!1_@!1_@!2_@!2_s\X2_`F\`2_3\x2_޹2_ɼ2_|2_"2_"2_"2_!2_"2_s\ 3_`F\(3_E\@3_0P3_`3_|p3_!x3_!3_!3_!3_!3_s\3_`F\3_E\4_04_(4_|84_!@4_!H4_!P4_!`4_!p4_s\4_`F\4_E\4_4_*4_|5_!5_!5_!(5_!85_s\x5_`F\5_3\5_5_5_|5_!5_!5_!5_!5_!6_s\@6_`F\H6_E\`6_p6_56_|6_!6_!6_!6_!6_!6_s\7_`F\7_E\(7_87_GH7_|X7_ !`7_ !h7_ !7_ !7_s\7_`F\7_3\7_-8_48_| 8_`!(8_`!08_`!88_`!H8_`!X8_s\8_`F\8_E\8_M8_8_|8_@!8_@!8_@!9_@! 9_s\`9_`F\h9_3\9_M9_T9_|9_@!9_@!9_@!9_@!9_@!9_s\(:_`F\0:_E\H:_X:_th:_|x:_!:_!:_!:_!:_s\:_`F\:_3\;_M ;_0;_|@;_)"H;_("P;_'"h;_$"x;_s\;_`F\;_3\;_޹;_ǽ;_|<_"<_"<_"0<_"@<_s\<_`F\<_3\<_-<_ҽ<_|<_`!<_`!<_`!<_`!=_s\H=_`F\P=_3\h=_px=_ݽ=_|=_!=_!=_!=_!=_s\>_`F\>_3\0>_@>_P>_|`>_`T"h>_`S"p>_`R">_`O">_s\>_`F\>_3\>_w?_?_|(?_ "0?_ "8?_ "P?_"`?_s\?_`F\?_3\?_?_?_|?_@"?_@"@_@"@_@"(@_s\h@_`F\p@_3\@_@_@_|@_B"@_A"@_@"@_="@_s\0A_`F\8A_3\PA_`A_pA_|A_`!A_`!A_`!A_`!A_s\A_`F\B_3\B_T(B_#8B_|HB_;"PB_:"XB_9"pB_6"B_s\B_`F\B_3\B_gB_-C_|C_ "C_ " C_ "8C_ "HC_s\C_`F\C_3\C_GC_JC_|C_5"C_4"C_3"D_0"D_s\PD_`F\XD_3\pD_ֵD_UD_|D_!D_!D_!D_!D_s\E_`F\ E_3\8E_HE_`XE_|hE_!pE_!xE_!E_!E_s\E_`F\E_3\F_F_k F_|0F_@N"8F_@M"@F_@L"XF_@I"hF_s\F_`F\F_3\F_F_uF_|F_!G_!G_! G_!0G_s\pG_`F\xG_3\G_G_G_|G_/"G_."G_-"G_*"G_s\8H_`F\@H_3\XH_hH_xH_|H_ !H_ !H_ !H_ !H_ !H_s\I_`F\I_E\ I_0I_@I_|PI_ !XI_ !`I_ !xI_ !I_s\I_`F\I_3\I_0I_J_|J_! J_!(J_!0J_!@J_!PJ_s\J_`F\J_E\J_޹J_J_|J_"J_"J_"J_!K_"K_s\XK_`F\`K_E\xK_K_p!K_|K_!K_`T"K_`S"K_`R"K_`O"K_s\ L_`F\(L_`E\@L_PL_P`L_|hL_!pL_@N"xL_@M"L_@L"L_@I"L_s\L_`F\L_`E\M_M_g(M_|0M_!8M_B"@M_A"HM_@"`M_="pM_s\M_`F\M_`E\M_TM_|M_|M_ѝ!N_;"N_:"N_9"(N_6"8N_s\xN_`F\N_`E\N_GN_N_|N_!N_5"N_4"N_3"N_0"O_s\@O_`F\HO_`E\`O_pO_O_|O_!O_/"O_."O_-"O_*"O_s\P_`F\P_`E\(P_M8P_HP_|PP_!XP_)"`P_("hP_'"P_$"P_s\P_`F\P_`E\P_Q_Q_|Q_9! Q_@"(Q_@"0Q_@"HQ_@"XQ_s\Q_`F\Q_`E\Q_gQ_aQ_|Q_T!Q_ "Q_ "Q_ "R_ " R_s\`R_`F\hR_`E\R_wR_R_|R_n!R_ "R_ "R_ "R_"R_s\(S_`F\0S_`E\HS_޹XS_hS_|pS_!xS_"S_"S_"S_"S_s\S_`F\S_`E\T_ֵ T_0T_|8T_!@T_!HT_!PT_!hT_!xT_s\T_`F\T_`E\T_T_T_|U_!U_!U_!U_!0U_!@U_s\U_`F\U_`E\U_pU_5U_|U_۞!U_!U_!U_!U_!V_s\HV_`F\PV_`E\hV_xV_LV_|V_!V_`!V_`!V_`!V_`!V_s\W_`F\W_`E\0W_@W_ePW_|XW_!`W_@!hW_@!pW_@!W_@!W_s\W_`F\W_`E\W_X_|X_| X_+!(X_ !0X_ !8X_ !PX_ !`X_s\X_`F\X_`E\X_X_X_|X_H!X_!X_!Y_!Y_!(Y_s\hY_`F\pY_`E\Y_Y_Y_|Y_b!Y_!Y_!Y_!Y_!Y_s\0Z_`F\8Z_`E\PZ_`Z_pZ_|Z_@!Z_@!Z_@!Z_@!Z_s\Z_`F\[_`3\[_([_8[_|H[_!P[_!X[_!p[_![_s\[_`F\[_`3\[_[_*\_|\_}!\_!\_! \_!8\_!H\_s\\_`F\\_`E\\_\_B\_|\_ !\_ !\_ !]_ !]_s\P]_`F\X]_`3\p]_-]_]_|]_!]_`!]_`!]_`!]_`!]_s\^_`F\ ^_`E\8^_MH^_X^_|h^_@!p^_@!x^_@!^_@!^_s\^_`F\^_`3\__M__ __|(__!0__@!8__@!@__@!X__@!h__s\__`F\__`E\______|__!`_!`_! `_!0`_s\p`_`F\x`_`3\`_M`_"`_|`_)"`_("`_'"`_$"`_s\8a_`F\@a_`3\Xa_޹ha_2xa_|a_"a_"a_"a_"a_s\b_`F\b_`3\ b_-0b_C@b_|Pb_`!Xb_`!`b_`!xb_`!b_s\b_`F\b_`3\b_pb_Tc_|c_! c_!(c_!@c_!Pc_s\c_`F\c_`3\c_c_dc_|c_`T"c_`S"c_`R"d_`O"d_s\Xd_`F\`d_`3\xd_wd_sd_|d_ "d_ "d_ "d_"d_s\ e_`F\(e_`3\@e_Pe_`e_|pe_@"xe_@"e_@"e_@"e_s\e_`F\e_`3\f_f_(f_|8f_B"@f_A"Hf_@"`f_="pf_s\f_`F\f_`3\f_f_f_|g_`!g_`!g_`!(g_`!8g_s\xg_`F\g_`3\g_Tg_g_|g_;"g_:"g_9"g_6"h_s\@h_`F\Hh_`3\`h_gph_h_|h_ "h_ "h_ "h_ "h_s\i_`F\i_`3\(i_G8i_Hi_|Xi_5"`i_4"hi_3"i_0"i_s\i_`F\i_`3\i_ֵj_j_| j_!(j_!0j_!Hj_!Xj_s\j_`F\j_`3\j_j_j_|j_!j_!j_!k_! k_s\`k_`F\hk_`3\k_k_k_|k_@N"k_@M"k_@L"k_@I"k_s\(l_`F\0l_`3\Hl_Xl_hl_|xl_!l_!l_!l_!l_s\l_`F\l_`3\m_ m_'0m_|@m_/"Hm_."Pm_-"hm_*"xm_s\m_`F\m_`3\m_m_m_|n_Ο!n_ !n_ !n_ !0n_ !@n_s\n_`F\n_`E\n_n_n_|n_ !n_ !n_ !n_ !o_s\Ho_`F\Po_`3\o_s\p_`F\p_E\0_#@_gP_|`_#h_#p_#_[ج_=\_>\_# _x0_|@_#H_#P_#X_#x_[_=\_`?\_#__| _#(_#0_#X_[_=\_?\Ю_#__|_#_#_#_#8_[x_=\_`@\_ __ _д_ _ش_ |__ p__ &_x_|_&_&_&_[X_@\`_A\_ &__|_&_&_&___[8_@\@_`B\p_ &__|_&_&_&_[_@\ _B\P_ &`_p_|_&_&_&___[_@\_`C\0__8__P__X__0_/&@_P_|`_.&h_-&p_,&_)&_s\_`D\_`3\_/& _0_|@_.&H_-&P_,&h_)&x_s\_`D\_3\_/&__| _.&(_-&0_,&8_#&H_)&X_s\_`D\_C\_/&__|_.&_-&_,&_+&(_)&8_s\x_`D\_`E\_/&__|_.&_-&_,&_+&_)&_s\X_`D\`_E\(`A*(`(`|(`@*(`?*(`>*(` [8)``G\@)``H\p)`A*)`)`|)`@*)`?*)`>*)`=*)` [*``G\ *`H\P*`A*`*`ƾp*`|*`@**`?**`>**` [*``G\+``I\0+`A*@+`MP+`|`+`@*h+`?*p+`>*x+`=*+` [+``G\+`I\0``0``0`` 0`_07`\*@7`P7`|`7`6`h7`5`p7`4`7`s\7``J\7``3\8`\* 8`608`|@8`6`H8`5`P8`4`X8`G*x8`s\8``J\8``K\8`\*9`Ͼ9`| 9`6`(9`5`09`4`X9`s\9``J\9`3\9`\*9`~9`|:`6`:`5`:`4`:`G*8:`s\x:``J\:`K\`39`ZЋ`|؋`|` a`s\X`e\```M\`39`C`|`|`s\8`e\@``M\p`39``|` *؍`s\`e\ `M\P`39``p`|x`|` a`s\`e\`M\0`39@`P`|X`\*`` a`s\؏`e\`L\`39 `0`|8``*x`s\`e\`M\`39``|`*X`s\`e\`M\Б`39``|`@*8`s\x`e\`M\`39`uВ`|ؒ`*`s\X`e\``M\`39`d`|`*`s\8`e\@`M\p`39`^*`|`*ؔ`s\`e\ `M\P`39``Qp`|x`*`s\`e\`M\0`39@`@P`|X`*`s\ؖ`e\`M\`39 `10`|8`*x`s\`e\`M\`39``|`*X`s\`e\`M\И`39``|``*8`s\x`e\`M\`39`^*Й`|ؙ`*`s\X`e\``M\`39``|`*`s\8`e\@`M\p`39`ݿ`|`*؛`s\`e\ `M\P`39``̿p`|x`*`` \`e\`M\0`39@`P`|X`*`s\؝`e\`M\`39 `0`|8`0*x`s\`e\`M\`39``|``*X`s\`e\`M\П`39``|`*8`s\x`e\`M\`39`uР`|ؠ`*`s\X`e\``M\`39`c`|`@*`s\8`e\@`M\p`39`R`|`*آ`s\`e\ `M\P`39``?p`|x`*`s\`e\`M\0`39@`.P`|X`|`s\ؤ`e\`M\`M\``M\`L\``L\0`-9@`P`|X`|` a`s\إ`_\``O\`-9 `0`|8`|x`s\`_\``O\`-9``|` *X`s\`_\`O\Ч`-9``|`| ` a8`s\x`_\`O\`-9`Ш`|ب`\*`` a`s\X`_\``N\`-9``|``*`s\8`_\@`O\p`-9``|`*ت`s\`_\ `O\P`-9``p`|x`@*`s\`_\`O\0`-9@`P`|X`*`s\ج`_\`O\`-9 `0`|8`*x`s\`_\`O\`-9``|`*X`s\`_\`O\Ю`-9``|`*8`s\x`_\`O\`-9`{Я`|د`*`s\X`_\``O\`-9`l`|`*`s\8`_\@`O\p`-9`^*`|`*ر`s\`_\ `O\P`-9``\p`|x``*`s\`_\`O\0`-9@`HP`|X`*`s\س`_\`O\`-9 `80`|8`*x`s\`_\`O\`-9`)`|`*X`s\`_\`O\е`-9``|`*8`` \x`_\`O\`-9`ж`|ض`*`s\X`_\``O\`-9``|`0*`s\8`_\@`O\p`-9``|``*ظ`s\`_\ `O\P`-9``p`|x`*`s\`_\`O\0`-9@`P`|X`*`s\غ`_\`O\`-9 `0`|8`@*x`s\`_\`O\`-9``|`*X`s\`_\`O\м`-9``|`*8`s\x`_\`O\`-9`zн`|ؽ`|`s\X`_\``O\`O\``O\`N\``N\` 9`&о`|ؾ`|`:`` a`s\X`k\```S\` 9` `|`|`:``s\8`k\@``S\p` 9``|` *`:``s\`k\ `S\P` 9``p`|x`|`:`` a`s\`k\`S\0` 9@`P`|X`\*``:``` a`s\`k\`R\` 9 `q0`|8``*@`:`x`s\`k\`S\` 9`]`|`* `:`X`s\`k\`S\` 9``|`@*`:`8`s\x`k\`S\` 9`{`|`*`:``s\X`k\``S\` 9`h`|`*`:``s\8`k\@`S\p` 9`S`|`*`:``s\`k\ `S\P` 9``>p`|x`*`:``s\`k\`S\0` 9@`+P`|X`*``:``s\`k\`S\` 9 `0`|8`*@`:`x`s\`k\`S\` 9``|`* `:`X`s\`k\`S\` 9``|``*`:`8`s\x`k\`S\` 9``|`*`:``s\X`k\``S\` 9``|`*`:``s\8`k\@`S\p` 9``|`*`:``s\`k\ `S\P` 9``p`|x`*`:``` \`k\`S\0` 9@`P`|X`*``:``s\`k\`S\` 9 `0`|8`0*@`:`x`s\`k\`S\` 9`n`|``* `:`X`s\`k\`S\` 9`\`|`*`:`8`s\x`k\`S\` 9`G`|`*`:``s\X`k\``S\` 9`3`|`@*`:``s\8`k\@`S\p` 9` `|`*`:``s\`k\ `S\P` 9`` p`|x`*`:``s\`k\`S\0` 9@`P`|X`|``:``s\`k\`S\`Q\``Q\`P\``P\ `S\(``S\0`R\8``R\P`@9``p`|x`|`:`` a`s\``p\``W\0`@9@`P`|X`|``:``s\``p\``W\`@9 `0`|8` *@`:`x`s\``p\`W\`@9`I`|`\* `:`@`` aX`s\``p\`V\`@9``|`|`:` ` a8`s\x``p\`W\`@9`6`|``*`:``s\X``p\``W\`@9``|`*`:``s\8``p\@`W\p`@9`^*`|`@*`:``s\``p\ `W\P`@9``p`|x`*`:``s\``p\`W\0`@9@`uP`|X`*``:``s\``p\`W\`@9 ``0`|8`*@`:`x`s\``p\`W\`@9`K`|`* `:`X`s\``p\`W\`@9`8`|`*`:`8`s\x``p\`W\`@9`'`|`*`:``s\X``p\``W\`@9``|`*`:``s\8``p\@`W\p`@9``|``*`:``s\``p\ `W\P`@9``p`|x`*`:``s\``p\`W\0`@9@`P`|X`*``:``s\``p\`W\`@9 `0`|8`*@`:`x`s\``p\`W\`@9``|`* `:`X`` \``p\`W\`@9``|`*`:`8`s\x``p\`W\`@9``|`0*`:``s\X``p\``W\`@9`{`|``*`:``s\8``p\@`W\p`@9`i`|`*`:``s\``p\ `W\P`@9``Tp`|x`*`:``s\``p\`W\0`@9@`@P`|X`@*``:``s\``p\`W\`@9 `-0`|8`*@`:`x`s\``p\`W\`@9``|`* `:`X`s\``p\`W\`@9`^*`|`|`:`8`s\x``p\`W\`U\``U\`T\``T\`W\``W\`V\``V\`(9``|`|@` aX`s\``\\``Y\`(9`u`|`|8`s\x``\\``Y\`(9`N`|` *`s\X``\\``Y\`(9`:`|`|` a`s\8``\\@`Y\p`(9``|`\*`` a`s\``\\ `X\P`(9``p`|x``*`s\``\\`Y\0`(9@`)P`|X`*`s\``\\`Y\`(9 `^*0`|8`@*x`s\``\\`Y\`(9``|`*X`s\``\\`Y\`(9` `|`*8`s\x``\\`Y\`(9``|`*`s\X``\\``Y\`(9``|`*`s\8``\\@`Y\p`(9``|`*`s\``\\ `Y\P`(9``p`|x`*`s\``\\`Y\0`(9@`P`|X`*`s\``\\`Y\`(9 `0`|8``*x`s\``\\`Y\`(9aa|a*Xas\a`\\aY\a(9aa|a*8as\xa`\\aY\a(9awa|a*as\Xa`\\`aY\a(9aga|a*a` \8a`\\@aY\pa(9aWa|a*as\a`\\ aY\Pa(9`aGpa|xa0*as\a`\\aY\0a(9@a6Pa|Xa`*as\a`\\aY\a(9 a'0a|8a*xas\a`\\aY\a(9aa|a*Xas\a`\\aY\a(9aa|a@*8as\xa`\\aY\a(9aa|a* as\X a`\\` aY\ a(9 a a| a* as\8 a`\\@ aY\p a(9 a a| a| as\ a`\\ aY\@ aY\H a`Y\P aX\X a`X\` a[\h a`[\p aZ\x a`Z\ a, a@a a* a@ ah a,p a@a a <` a* a@ a a;`@ a,H a,P a,X a,` a,h a,p a,x a, a, a, a, a, a, a, a, a, az, at, aj, ad,a^,aV,aN,aH, aB,(a:,0a2,8a(,@a,Ha,Pa ,`a,xa+a+a+a+a+a+a+a+a+pa+xa+a+a+a+a+a+ a+(an+0af+8ab+Ha\+XaV+`aP+aJ+aD+a>+a8+a2+a,+a&+`a +a+a+a+a +a+@}a*H}a*@a/Ha/Pa/Xa/`a/ha/pa/xa/a/a}/aw/aq/ak/ae/a_/aY/aQ/ȕaM/ЕaG/ؕaA/a=/a9/a3/a-/a'/a/a/a/ a /(a/0a.8a.@a.Ha.Pa.Xa.`a.ha.pa.xa.a.a.a.a.a.a.a.a.a.Ȗa.Жao.ؖa].aW.@aS.HaO.PaK.XaG.`aA.ha=.pa7.xa1.a+.a%.a.a.a.a .a.a- a-(a-0a-8a-@a-Ha-Pa-Xa-`a-a-a-a-a-a-a-a-@a-Ha-Pa-Xa-`ay-au-Ȟaq-Оam-؞ai-ac-a]-ȣaW-УaQ-أaK-aE-a?-a9-a3-a--Ȥa%-Фa-a-a-a -@b-Hb,Hb/Pb@\0b(9@bPb|`bJ1hbI1pbH1bs\b`\\b`]\b(9 b0b|@bJ1HbI1PbH1XbH1xbs\b`\\b]\b(9 bھ b| bJ1( bI10 bH1X bs\ b`\\ b`^\ b(9 ba b|!bJ1!bI1!bH1!bH18!bs\x!b`\\!b^\!b(9!b\!b|!bJ1!bI1!bH1!bH1"bs\X"b`\\`"b`_\"b-9"b"bH1"bs\8#b_\@#b`\p#b-9#b#bH1#bs\$b_\ $b`a\P$b-9`$bp$bH1$bs\$b_\%ba\0%b-9@%bP%bH1%bs\%b_\%b`b\&bK1 &b0&bH1x&bs\&bb\&bc\&bK1'b|'bH1X'bs\'bb\'b`d\'bK1'bH1'bH18(bs\x(bb\(bd\(bK1(bH1(bH1)bs\X)bb\`)b`e\)b39)bl)bH1)bs\8*be\@*bf\p*b39*bU*bH1*bs\+be\ +b`g\P+b39`+bqp+bH1+bs\+be\,bg\0,b39@,bZP,bH1,bs\,be\,b`h\baP9 b0b|@b`O9Hb`N9Pb`M9xb@ \bh\bi\baP9bb| b`O9(b`N90b`M98b`L9Xb@ \bh\b`j\КbaP9bb|b`O9b`N9b`M98b@ \xbh\bj\baP9b<Лb|b`O9b`N9b`M9b`L9b@ \Xbh\`b`k\bbbbbubbibb]bbQbȩbEbЩb9bةb-b_d 9_d9_dӓ9_db_db_db`ds\X`dk\``dl\`d 9`d`dӓ9`db`db`db`db`ds\8adk\@ad`m\pad 9adadӓ9adbadbadbads\bdk\ bdm\Pbd 9`bdܼpbdӓ9bdbbdbbdbbdbbds\bdk\cd`n\0cd@cdPcd|`cd9hcd9pcd9xcd9cds\cdn\cdo\dd@9 dd60dd|@dd9Hdd9Pdd9xdds\dd`p\dd`q\dd@9eded| ed9(ed90ed98ed9Xeds\ed`p\edq\ed@9eded|fd9fd9fd98fds\xfd`p\fd`r\fd@9fdfd|fd9fd9fd9fd9gds\Xgd`p\`gdr\gd@9gdDgd|gd9gd9gd9gd9gds\8hd`p\@hd`s\`hd dhhdcphdcxhdchdchdcPidcXidchidcidcXpdc`pddhpdcppdcxpdcpdcpdcPqdcXqdchqdcqdcXxdc`xd{chxdocpxdccxxdWcxdKcxd?cxd3cHyd'cPydcXydchydcydbydbydb}db}dbXdbdb`echecpecxecececPecXechececXecpe`9ee|e9e9e9e9e`9e\es\ e`F\ et\ e@ e eD e0 eH eH eP e` e\ ex ep e e e\(\*X\Wp\\\\\\\\0]w\ w\(w\0w\8w\@w\Hw\Pw\ Xw\ `w\ hw\ pw\ xw\w\w\w\w\w\w\w\w\w\w\w\w\w\w\w\w\x\x\ x\!x\" x\#(x\$0x\%8x\&@x\'Hx\(Px\)Xx\*`x\+hx\,px\-xx\.x\/x\0x\1x\2x\3x\4x\5x\6x\7x\8x\9x\:x\;x\<x\=x\>y\?y\@y\Ay\B y\C(y\D0y\E8y\F@y\GHy\HPy\IXy\J`y\Khy\Lpy\Mxy\Ny\Oy\Py\Qy\Ry\Sy\Ty\Uy\Vy\Xy\Yy\Zy\[y\\y\]y\^y\_z\`z\az\bz\c z\d(z\e0z\f8z\g@z\hHz\iPz\jXz\k`z\lhz\mpz\nxz\oz\pz\qz\rz\sz\tz\uz\vz\wz\xz\yz\zz\{z\|z\}z\~z\{\{\{\{\ {\({\0{\8{\@{\H{\P{\X{\`{\h{\p{\x{\{\{\{\{\{\{\{\{\{\{\{\{\{\{\{\{\|\|\|\|\ |\(|\0|\8|\@|\H|\P|\X|\`|\h|\p|\x|\|\|\|\|\|\|\|\|\|\|\|\|\|\|\|\|\}\}\}\}\ }\(}\0}\8}\@}\H}\P}\X}\`}\h}\p}\x}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\~\~\~\~\ ~\(~\0~\8~\@~\H~\P~\X~\`~\h~\p~\x~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\HHlVHtH5cV%cV@%cVh%cVh%cVh%cVh%cVh%cVh%cVh%cVhp%cVh`%cVh P%cVh @%zcVh 0%rcVh %jcVh %bcVh%ZcVh%RcVh%JcVh%BcVh%:cVh%2cVh%*cVh%"cVh%cVhp%cVh`% cVhP%cVh@%bVh0%bVh %bVh%bVh%bVh%bVh %bVh!%bVh"%bVh#%bVh$%bVh%%bVh&%bVh'p%bVh(`%bVh)P%bVh*@%zbVh+0%rbVh, %jbVh-%bbVh.%ZbVh/%RbVh0%JbVh1%BbVh2%:bVh3%2bVh4%*bVh5%"bVh6%bVh7p%bVh8`% bVh9P%bVh:@%aVh;0%aVh< %aVh=%aVh>%aVh?%aVh@%aVhA%aVhB%aVhC%aVhD%aVhE%aVhF%aVhGp%aVhH`%aVhIP%aVhJ@%zaVhK0%raVhL %jaVhM%baVhN%ZaVhO%RaVhP%JaVhQ%BaVhR%:aVhS%2aVhT%*aVhU%"aVhV%aVhWp%aVhX`% aVhYP%aVhZ@%`Vh[0%`Vh\ %`Vh]%`Vh^%`Vh_%`Vh`%`Vha%`Vhb%`Vhc%`Vhd%`Vhe%`Vhf%`Vhgp%`Vhh`%`VhiP%`Vhj@%z`Vhk0%r`Vhl %j`Vhm%b`Vhn%Z`Vho%R`Vhp%J`Vhq%B`Vhr%:`Vhs%2`Vht%*`Vhu%"`Vhv%`Vhwp%`Vhx`% `VhyP%`Vhz@%_Vh{0%_Vh| %_Vh}%_Vh~%_Vh%_Vh%_Vh%_Vh%_Vh%_Vh%_Vh%_Vh%_Vhp%_Vh`%_VhP%_Vh@%z_Vh0%r_Vh %j_Vh%b_Vh%Z_Vh%R_Vh%J_Vh%B_Vh%:_Vh%2_Vh%*_Vh%"_Vh%_Vhp%_Vh`% _VhP%_Vh@%^Vh0%^Vh %^Vh%^Vh%^Vh%^Vh%^Vh%^Vh%^Vh%^Vh%^Vh%^Vh%^Vhp%^Vh`%^VhP%^Vh@%z^Vh0%r^Vh %j^Vh%b^Vh%Z^Vh%R^Vh%J^Vh%B^Vh%:^Vh%2^Vh%*^Vh%"^Vh%^Vhp%^Vh`% ^VhP%^Vh@%]Vh0%]Vh %]Vh%]Vh%]Vh%]Vh%]Vh%]Vh%]Vh%]Vh%]Vh%]Vh%]Vhp%]Vh`%]VhP%]Vh@%z]Vh0%r]Vh %j]Vh%b]Vh%Z]Vh%R]Vh%J]Vh%B]Vh%:]Vh%2]Vh%*]Vh%"]Vh%]Vhp%]Vh`% ]VhP%]Vh@%\Vh0%\Vh %\Vh%\Vh%\Vh%\Vh%\Vh%\Vh%\Vh%\Vh%\Vh%\Vh%\Vhp%\Vh`%\VhP%\Vh@%z\Vh0%r\Vh %j\Vh%b\Vh%Z\Vh%R\Vh%J\Vh%B\Vh%:\Vh%2\Vh%*\Vh%"\Vh%\Vhp%\Vh`% \VhP%\Vh@%[Vh0}H}t EM\H%}H}t E2\H DH0t ƅD\,Ht ƅ,[HlHXt ƅl[H% Ht ƅ[HxI$% H=߼_lH5c iLHLAH5 HH HL0H HLyLH5w HPU)H5] L<H5D H#+H5+ L OUHA1HAUATSHH8L-WHw(H}IEHIMtIELH8[A\A]]ú0H5> HcywH5% Lt{UHAкHAUATSHH8L-VWHw(H}IEHIMtIELH8[A\A]]UHA1HAUATSHH8L-WHw8H}IEHIMtIELH8[A\A]]UHAкHAUATSHH8L-WHw8H}IEHIMtIELH8[A\A]]UHAкHAUATSHH8L-3WHw8H}IEHIFMtIELH8[A\A]]UHAкHAUATSHH8L-WHw8H}IEHI4MtIELH8[A\A]]UHA1HAUATSHH8L-rWHwhH}IEHI}MtIELH8[A\A]]UHAкHAUATSHH8L-WHwhH}IEHI}MtIELH8[A\A]]UIA1HAVIAUATSHH@L-WHV(Hw0H}IEHLIMtIELH@[A\A]A^]UEIȹHAWIAVIAUATSHHHL-7WHV(Hw0H}IEHLLIMtIELHH[A\A]A^A_]úH5} HxAH c LHU>ynyxH% UHAVAUATSH0HHdH%(HE1H_H IH=X{V C{VHd{V1Ҁ-uH(x-t Hxu3VVH,{V1ҀCuH(xCt HxuVVHzV1ҀduH(xdt HxuHUVH=T UVH^H5S HtH=S H1V1HH^VL%Ƀ_H=S  ^Hm^ut^A$R^H^stdofE^@^Ht 81*q^K^^HSV/^H;Hcy_HHH54yVH=IV t21QI1ZHH=^^HHH^HIH=R IHtH1VUH?^H=UR H\HH=^{H5^H=^hIELH V7HHTVLHH^IEHH^H$IEH^HIEH^H=^t\Ht^HQ SVHHW^H^HHƹ^`SVFSV^u0H=!^~^=RH1H0TH^=K^t1`H^=(^t ^=^t ^=^t RV=^t RV =^^tH=^=^HvVH5^# to11I1LH0H=^l1FH;6^H=^A$uHt^ƀH=9^tE111@H5!^|D^H v^Hw^H5x^H=y^E;=^u^=^H5,~H5)mH5\H-PVH8LT1Luft HPVf=^HncWH H=N HxH_H5zL HH΂_H HX H5aH=N HH_H[=^u^ ^ ^AH5, HH==X^@茝=Y^^1(H=c^^ 1yD=^~H^H5M OVHpOVgOV11G1p'HvNV@H0H^H11H=* ^=^'H=^1j W^H^H=+ <H=[^IH=L^It 5r^MMH=Y^H1H*  H=A^t<H= h<H=L 7HH=L "1HcOH^L% ^MH5L L]uH^A<$=/^6LH%f1HٺH=^1HHHpKH^H'L^HH :L Hھ1\H=ס PH;H=¡ I7LHD1HHHpKH^Ht,H= H=^LH K I1NLH5^1L_H5^K LH=^KH^H;LH5/K 1L%x^1TJHKV,H=) H U1H6UH5^H^H^HATL%}WSHL%^Hf^^1HH5^f^H;6UL%t^Hq^Hn^l^L%(^1HH5U[A\H^H5^]H ^ ^f ^uD1I^HHPTL H  H=hJVH=^H^H9tHJVHt H=^H5z^H)HHH?HHtHJVHtfD=U^u+UH=IVHt H=4U9d-^]wtuE9nuI~HUL uH{EHt?IvHMUHpHIFAF'DHS(HHUIHuH([A\A]A^A_]DHUL`DhD8H|IFHtHM1HIFHMH@AFHCPHIF HCPL4ff.UHAVIAUAATSHLSH1A3HCPHHu6fDH[ Ht'D9#uD9kuH{LHuܸD1[A\A]A^]ff.fUHAWAVIAUIATASHLHSH1A3HCPHHtODHEfDH[ Ht7D;;uD;cuH{HULDuE&HH[A\A]A^A_]A1ff.fUHAWAVAUATIHSH8HuȉHMAT$H1AA4$ID$PLtKUHAUIATIS1HfDSLLLHA<uH[A\A]]ff.D1ff.f6^UHAWAVAUATSHLhVI@@DtfDHHDu\t:u@DHu1HH[A\A]A^A_]fDDgH_EtعI@@ADtfDHIDuAD$<>H!@HHtIA%f. EuV9tcAEIt%<\uA}tA`t?AEIuEL9 @A8uE:et9uE1NIA<\t*D Et9tAEIw<\uA}u EtO\AEIDt @H?uDgEOH_1LfVjIH1^fDIE, EtD9tPAFMnMM<\uA~uEt\fMnLL AFMAE~I( EuN9tM~AFMMC<\uA~tA`t-M~LLM AFfA8uE:ftAff.@UIɿѸH5_ HATS^9w0L%A@V I4$I<$^[A\])H = H5_7 14fUHAWMAVMAUIATISHH=Y^Huw=h^H^H~5L^H^Ht :H^Ht:uj1H߾ ;H߾!H H6 zAWHuL5^LMHD ^lRZYHHe[A\A]A^A_]DH뇐HcfDH^ H/L A^LJ^HH H^H1^H5^H^H߾YH^H߾EH^]H1@H^sfUHHHy>VH8iHUT1uEft H?Vfff.U H荒1]fUHATASHb f/b f/b f/s`Et+HH[H 4 A\]fDD,H1[H 4 A\H]ff(%b -Tb ^f(fTf.fFb f/H,HfH*YѺ HH\E E minHxfPf(%b -a ^f(fTf.Fa f/H,HfH*YH H\E HH3 H53 HFHBEHgDf(%da -$a ^f(fTf.a f/s`H,HxifH*YH H\Eh HH2 H52 HFHEHD\H,H?HyHHfHH H*XH,f5_` fUH*f(f(fT\fV=` f/fD\H,H?HHHfHH H*XH,f5_ fUH*f(f(fT\fV_ f/{bfD\H,H?HHHfHH H*XH,f5?_ fUH*f(f(fT\fV_ f/cfD=C^tfDUHSHH=^9H5 1 H==^H^]?t H[]fH=^HHtHDHtH0Ht1{;H\^HH[]"fDUHVL 0 L0 H5+ HATASHh_H0H0 PH0 PHVHH1H Et He[A\]fH= H1H53 H5^VH=,; [H=y5 oH=9VHeH=9V[A\]O$ff.@=^u=^uH5-f1ff.fUHAVAUATSHH^^L%^^tFH ^x1HHtHHHpH9u5^L%^ML5^LEnL#L A9H[Hl^HuIF Hd^HL`L%H^MtcHtHH[A\A]A^]fD2^L%^qMt3I<$HID$H^HH[A\A]A^]fDHuH1H[A\A]A^]fLxLcHL%^M^IF H^H:^=^Pp^9sCH5M^H HPHH@H pHH9u=)^L%*^DHHMH=^+HH ^HL`L%^M5^LbH^L%^^LaH ^L%^Sff.UH=^HATS5H=^5H5- H=^;t [A\]DH=^HHtH1H0IB7I<$H5, Hx^+1H7HHR^H[A\]QH^HtUH5h H=Q^HAUATSHp:t\H^HtH[A\A]]DH=^D1H6H^^HuHHC1 [A\A]]H=^HHtHIHtsH8tmH=^HI<$I1It2H^Ht0H=r^H=^H fI4$Hx)H!ff.UHAWAVAUATSHHHXVHP@DtHDu=o^uH5+ HjHH5:4VHRHt4L=YE1HA H X ILPH5* H HYHWVII)Hr@DHDtHHDu=^%H=RXVEt]H6XVL=YE1HEIDIE1MLI $HLPuI$B<( I(AI|$uH1[A\A]A^A_]=%^L%WVH=WVLetEE1L=YYI(AI|$tIE1MLI $HLPuI$B<(uA|$t1HHtkH =^tuOVHX@DtHDu (HufDHDuHHH H9HNVHJ@PD(uRfPD(tEHH9uƅH=! if1HudH34%(,H[]Ð=^HHHH=^H^ H(VHH5^Hý^HH(VH5 H81-=^GH=`^1^HG^"fHA(VHH5$ H81uH=9 $f.UHSHH=|^uH[]H5Ѽ^HH[]UHATISHH޿ =.^u[A\]H5^LH5z^[ A\]ff.UHAUIATSHHQ'V=^L#tM=^w=^u$H1[A\A]]fDLP=^tLoH1[A\A]]f N^uD^LuADδ^tr^uXLL^s1gH # H5 1辺H;պ^ ~@1HUܾȻ>^G^ff.UHSHwH=^=d^u|^ k^ d^H=:^=H=v^A1H=h^sxH= H HD(=}^=P^HQ^HN^L^T=^H^H^^H=:^H^H^^U%H=^I%H=2^=%H=^1%H=^%%H=^%H=^ %H=^%H=2^$H=^$H= ^$H=^$˸^~-H^^HH<$^H=^w=z^=w^H=^^_$H=^^G$H=^^/$OH^H:=^u1H=^|?H5^H=^4Hx#VH5 H81ff.fUHAUAATSH8L%A#VdH%(HE1=^I<$iH5|C31[1$H %^H&^E1H5,^L HH^ ^bH=s^Lm=^(LIL4 H H 3 LE1^L H!%tHDHJHDщ@LHL)?H'=X^H I<$H5 1A=k^u(HEdH3%(H8[A\A]]f.9^H5S y1H= `謙f.I<$LH  1H51 H=^H=O~^wI<$H5 1n(fI<$H H5~ IDo^赼DUHAWAVIAUIATASHH?!V=8^HHHٺH= >EuiH ^Ht =!VLH H1wH迼=^T=پ^H[A\A]A^A_]ÐMMDH  H߾1mfDN^2L=VI?C ͭ^=O^^EMLDH5 H1H ^HtE= Vt=G^cV1@H=Դ^Hʹ^h H^H1qHVH90^1LfHVH90^1,fHyVH90^1^HQVH90@HWz^1]^1fH=A^f =^HHlHH^f.H=A 蔸1wDe=^X ^K=^0fD{V1f~^f^`^1D=V1f_^11^^}DH=^1H;H^tHfDH@x8u;tCݵ^1>@HH=aV H5UVHH H!%tH=^DHJHDщH1H)V@HH5VH>@l^薳fD;^@^1y ^1df.^1IH5h^H=a^ܰ1/H=.^1^H^;f54VH=^{^ H5^H=^t1H1fDH=ٳ^ H5 1H^;1f.=^u=^uHFfD1D11H=m hU11AHj HAUATISHHHdH%(HE1nAT$AŅu^LIt$D81DH= 贱H;L0E1HHL1HG LbH0H6Hto1HAŅxY`AT$I|$H9wu AT$It$1D!DHH1AD$H1HMdH3 %(Hĸ[A\A]]Md1HH H11HDH5Q^¹DJ7DH= dH HHDff.=^u_UHo8VHHATSHP@DtHDu HHt+HˬÃt31ۉ[A\]11H= 11H= D D豨1DHfUHSHHHdH%(HE1A HH8H\H肨Ht511H=b =1H}dH3<%(H[]fDHH=V H5 VHH H!%tH=ϯ^DHJHDщHH)VqfD11H=u V>ff.UHATSHH=^HHt [1A\]H=^ 8tH=^۳H=ԯ^IܲH=ů^޲L[HA\] ff.fUHAUATSHHV=E^L#u ^t.=M^u H1[A\A]]LH1[A\A]]^ILu8m^ti{^uOLLf^t1c닐H I H5 1fH;}^ &@1HUܾp^^ofUHAWAVAUATASHHdH%(HE1H=¡^t H^H=N^Hg5V1H=9^L-2^=H5F5VHtLH(H3HuH5 H=^)H5 H=^t*HEdH3%( HH[A\A]A^A_]DH=^贲HHHHKL%|^!f.H0LHHH荭HuH1HH蟯H=(^pH\Hu^H>H1Hf.HI^HHHIHRH01H=^7IHtH$H^H=^LcG,$HAuHHcH赺HHHH^McLLHJJE1Hf.IH IHLHH  LL1L腥H.^LH=ġ^L,H=^MIEH^HJ4 HI6H=^M,Hݞ^L<贾MIHǞ^HN<(LgLH=M^VH^H=0^HJ4(fDLL#@H=^L-^HHuH0LH|HHuHfH踢HH=^6HH=^p"LSHGH^HyHH=F^1p@֩^EHb VH5 H81@H=^HL H=^H3HȦ=i^u'=^uH=^tU1H1]D1ff.fUHAWAVIAUIATISHHdH%(HE1=^tH=1^ ^uH=^yHb^HtH=^H}^L^LuC>Ȏ^tt֤^uZLH= ^t1躕H H5 1趔H;͔^ v@1HU6^?^dfUHATSHHV=^^L#u Y^t1=^uH1[A\]DL@H1[A\]D^LuC^tt^uZLH= ^t1蚔H y H5 1薓H;^ V@1HU蠔^^dfUHATSHHU=g^l^L#u 9^t1=h^uH1[A\]DL H1[A\]D^LuC^tt^uZLH= }^t1zH Y H5 1vH;^ 6@1HU耓^^dfUHSHP=]^uH[]H5^H[],ff.UHAUATISHH= HH{HDk{LuOBH}%H[A\A]]f.Hx1 PA9^DH=i^H5 HH;^HOL%+UH5 1I<$aI<$H=^&UHAWAVAUATIH SHdH%(HE1Ht9HHVHH@HDtDHHDuMH= H= =^L=CVL%DVL`A Mtf.LLuLHD)HT  HfCH9uI|$tnHUA $LI(MD$H5 H81%M|$Mu=d^uM1HudH34%(~HĘ[A\A]A^A_]fI(M|$M>=^tH=.^H=vH= uH=, g<'H貲 HHt+H bV@HI@DtHDuBL`E1H1L H eLij =M^uHH^I9t0I$=^I\$Md$Hc^L%^^H_^H=P^sw=^uELH!%tLDHVHDHL)VÅ\HXÅFHXH1HXAAHHX•IH=UHUHH^I$HH5^ 1IT$H=^1H5N IT$H=e^Ht :1H53=UHXcL`E1H1H eL 'H=^ɓ^HFAjHa=U2HUHH^AHX蜔IHVHH=^H5 1H=A IED EtAYH= H HEdIU1AAH=3^H5! oL= YJ(D8t8YH H= H@HDOOH@AJ2H=ω^L1 HX豓HHuH=^1H53=USH=^+HXBH=l H5j L近tH= _E1E1H=H 1AHXH5 H='^H^HZL-UH5 I}+IEH؈^3HXH= E1AE1H= rH5# H=^^H^HL-oUH5@ I}IEHT^H50 1H=:^UHAWAVAUATIS1H(H}@HH9HH@BL輑HuH}1]蹓EfH]HđHEH^1HE1|UH=^1H5 HlHEH]H褓A9KH#=UI DHEL =^HL$M$M=^t A}l? H]H;AME)!Lο C{^HHL"L+H5 {^MuH=Q 묋CHtHVMd@HAMHt#:HzVu 6fD: t,HHHuIH5z^M9uQHxHt蒽UHAUATSHH= HHzUL L觽H{HDk{LuUBHuVH HHt fH 1(tAW GE_NOHHON_UPDATHGAfWHBINCMP HAHGf.HPART_KEY DHHG fwA P G GROUA?HfH@jGAHGNUM @Dfop A HAfDOGGAHGSET DAP G H HTIMESTAMHGAfDWfo HAGk@A ENUMAHfD_9HBINARY HAHG D H AHZEROFILLHGf_@A H AHUNSIGNEDHGfDof.A BLOBAHfDwqfG_KEYAH HMULTIPLEHG fG:DGEY AH HUNIQUE_KHG fDGAHHPRI_KEY HGfHNOT_NULLL%g^AHg^ I|$ ff^fDH{HrVH HHoqH1lyHUH5 HHHxYH&wH1ۀ=UtXH=v^HsUHH9P8HFP8H9HCڃw @dDڀ=v^Ppt xl?QAHH@ HWyH-D$ tHHx] X;$H +H8vH X;$H HH53l^f=qUfHHvHH3u^HvH5k^H= H1HwDžDHw96fDHJL HM9HF,HuIH=UDLH@@LHHP DH k^)€=t^t A~l?XDAHB<8EE9s!@H޿ AHj^E9rEtNAEMl IHj^M9t&A<$H@tIHij^M9u@HH=\ IDH9X@HCX@f. DA5(=w (H4HHxBQhH P H+>Jv\(=HH4HPH P HHfH5!i^H= AEM|EuH IHh^M9t.A<$H@tfH޿ Hh^AE9rFfDDAEM|EuI IHsh^M9t.A<$H@ttfH޿ cHDh^AE9wfDAL%` fDAVpv HHٺH=, NH=0 2H= &H=$ H= H= H= H= H= H= H= H= H=H H=2 H= H=o H=1 ~H= rH= fH=+ Z()@i@H=J HA(iHqHqU1HAWAVAUATSH8H}nH5%b^H= L-j^LctbHfVMdHAMHt':HrfVuS: HHHHuH5a^IM9uH5a^H=N 艤H}mHE@H]HlkHEHj^HE16lH5Ga^H=L HE/H}fmA9DH=a^D1H5# IMILeM<$LbtbL5{eVIDHEfIAHt(:H[eVuD@:8HH HuH5`^IL;}uHEHH=|`^L4I>1H5 訞H]M>=i^HLH`^t A|$l?Mt^L5dVLI\IAHt$8HdVu w:tlHH HuIH5_^I9uIH5 L1H}AkA9H5_^H= 苢fDHzHtrHzH5m_^HWfH5 1蒝AD$pv LM$LEȾH=Z mM9LEv)MAHA L1IjM9uMLdMI9s@L II9uL^^fDLH= 艡L^^DHxH5u^^H_f.H5Q^^H8H= [A\A]A^A_]/ff.@UHAWAVAUIATSHHdH%(HE1=sf^1g^uEHf^H9t-H=f^H_LgHf^^ L%}f^H~f^H=of^HIMAEHH9szHUHr@PDtbf.PDuMHH9uAE1ۀ=e^uHMdH3 %( HH[A\A]A^A_]fDH)AEt=f^D5af^E =f^t=A} H=UE1IuAH ? HPj 5AuI}!f^I[^ADžk =d^AEI1HS㥛 DžLLHHIFHHHf.=e^cH=e^lHH/=He^RD%7e^EBHƅHgHuCe^ e^N=UHUHH[^=e^L=d^=d^=d^uD d^Et =d^LHH2L2gL HHIEgH c LII16^=UH=rd^}gtK=)d^lH=Ud^PhH=Id^HQgH=:d^ARgHDH脤L H=d^IgHLL_LɝH=c^gHtH=c^ gH褝H= 蘝HH83f+=[c^6H=c^gH={c^IfH=lc^AfLDH趣H$H==c^舁`~K=b^H=c^gH=c^IfH=b^AfLDHI=b^H1ۀ=va^u.f^db^@11H=/ tf=Gb^HUH8` (fHHHH+[fH*H^ yL} A)fDHHdH=a^dH!H=a^H2dL H=a^HLIE|dH V LIIپ1fDH4ÉAǀ=a^DUo, Iw fA?HY H warningHLx@HLx @sfHЃfHH H*XfH=V^`LH5J H=X^WHV^HHUH5g H;ϔHH}V^L(GL13bLA9LfD=^^D_^EwHUH8t]H}ULH3RH;Z]IDLƅHQuery OKH^@H=q_^Lb1=^^5^^H~UH8\L%ULI4$I<$\DHEmpty seAt=^^LHfD=_U!H UHHT^H=5UH=T^^oDHU1D L^HG1Ҁ=UtPH=3^^t0H9P8HCP8v @dDDH9P@HCP@D=]^LfD=]^fD =TUAEۃ=x]^H5< uJH5UHH!ကtDHBHDЉHH)H5ULAELɍ@=\^H=\^,\^諾fDH=9 1RDH)ULH0v!H  H5{ 16RPR^lH5y H=T^SHR^HHŽUH5 H;HHR^=[^u =\^( [^H|UH8YL%ULI4$蹿I<$Y薃a YDUHAWAVAUIATSHHdH%(HE1=Z^A[^uEHZ^H9t-H=Z^H_LgHZ^^ L%Z^HZ^H=Z^<IMAEHH9szHUHr@PDtbf.PDuMHH9uAE1ۀ=Y^uHMdH3 %( HH[A\A]A^A_]fDH)AEt=Z^D5qZ^E =Z^t=A} H=%UE1IuAH O HPj EAuI}1Z^IξO^ADžk =Y^AEI1HS㥛 DžLLHHIFHHHf.=Y^cH=Y^`HH/=XY^RD%GY^EBHƅH[HuSY^ /Y^N=UHUHHO^=Y^L=Y^=X^=X^uD X^Et =X^L,HH2LB[L HHIE'[H s LII1FR= UH=X^[tK=9X^lH=eX^`\H=YX^Ha[H=JX^Ab[HDH蔘Ls H=X^I\HLLSLّH=W^-[HtH=W^[H贑H=" 訑HH8CZ+=kW^6H=W^[H=W^IZH=|W^AZLDHƗH4H=MW^u`~K=V^H=*W^%[H=W^I&ZH=W^A'ZLDHY=V^H1ۀ=U^u>Z^tV^@11H=? tf=WV^HUH8T (fHHHH+[fH*H^ yLq A)fDHHdH=U^XH!H=U^H2XL H=U^HLIEXH f LIIپ1+OHfDHDÉAǀ=U^DUo, Iw fA?HM H warningHLx@HLx @sfHЃfHH H*XfH=J^TLH5Z H=L^KHJ^HHUH5w H;߈HHJ^L8GL1CVLA9L+fD=R^DS^EwH$UH8QHULH3bH;jQIDLƅHQuery OKH^@H=S^\V1=!R^5R^HUH8PL%ULI4$˶I<$PDHEmpty seAt=R^LHfD=oU!HUHHI^H=EUH=H^RoDHU1D LRHG1Ҁ=UtPH=CR^t0H9P8HCP8v @dDDH9P@HCP@D=Q^LfD=Q^fD =dUAEۃ=Q^H5L uJH5 UHH!ကtDHBHDЉHH)H5ɳULQ9Lف@=P^H=/P^hH!@HEEPf=I^tAHCAACMaL9LH=KH^LD) 1DGE1ƅHzf.D)H^MaEWA*HAy/^A*uE1ƅHfA#6 A-MaA/Ay*Ay*HAy!D@HETLH5UD(L0 A L0D(dD%]UM̀=G^L9t5LH=F^LD)/=G^tA$<# <-H=F^HD5F^=F^LuB<7t9F^B7H=F^ tA<$t=B^4H58^H? 55^H=@^=IHH@^=5^Ls8uH%:L9H.A^u A?H=A^H=Ut61D:%UHUu H(D:`ZHxuEĺP1LpH L(LL0 ;L011L詁L(DcMaHC\DH5n @Dž E1AbfAy!jmA|$-!HMUAD$HR@DL8LH=?^IH(MDH=?^DHIvDH!H|?^B0f.HH=UUL$@=?^H>^1H>^>^;HPHPHH0:H0?^HHADGD86>^;>^p5}>^H5n>^D4DsLEt5LcA\uDsAy H= AHcHDGD8>^;>^P{>^H=^H=^efD=^A=5=^H==^LEH=^B(=^pDHcU@H=^H H =^H)=^H @@D@<^NE1=^:fDAAIIHDžuHH<^M{@' ]<^LLH5LHH=<^HL%E E1LD5<^E@L9t"LH=o<^LHD)@%LH=<^D5[<^uE1E1Lf.FD%;^E1ERH_8~HtH8LE1~<)LE1E1XL9f;^=w |;^H4H=a;^$bHM;^K;^P8H=1;^>;^ݝE1E1DH=:^ L5:^MfL4HLH=:^H#D3_f:^;:^HKP:^H:^'DsHfH043H5'2H=HIz3HmfHHQH)kd)щʃ BLpHcf L33 L)=:^ L5 H=:^=IHHHcPHTL4L2HfHH*A H)R)t4Lc ,f9^;d9^PYQ9^HB9^0fDLp LLY2 L)H9fDHH fDLpHc8^;8^HKPG8^H8^ DsHOf=9^L5  L?U D)D=i9^L5} H=p9^XIcHHH52THc@L4LR1EDHHH5< H=7^x H HLH!D3DHH@ 7^;7^P9 7^H7^0HH@7^;7^HKP7^Hr7^;DsHfL5A7^M`;dL5,7^M L57^M; L57 5f.HHLp@l(Hc6^;6^HKP6^H6^\f-^-^@L57^ML5 L56^t@HH@ MG6^;E6^P 26^H#6^0HH@ 6^;6^HKP5^H5^ DsHofHHLp@x(HcfD=6^LkH=6^8H5 HI-HL5)9^L.LHH=D5^_DsLf:5^;85^HKP5!5^H5^ DsHf4^;4^HKP4^H4^"DsH_fD54^D;54^AH=4^DHIvNDH4bf.j4^;h4^LCH  Q4^H B4^D4DsLfH)1ۉe4^H=F4^3^'3^L%Uj@D54^LoE1H=4^ 7H5 HIJ+HHC{hIH!^HubH=!^35H5!^H H!%tDHJHDщ@HH)HR!^H5k!^H=3^DsLLLH,LHH=3^HLf.H=2^22^E1Hk2^Hf.62^ H5p H=^2^yDsL2^O2^=w ;2^552^H=2^L H(HH(L H1^1^H1^;1^H 1^H 1^01^A=w 1^51^H=1^H(L=H(H_1^B0\1^PV1^A=w ?1^591^H="1^H(LH(FH0^B00^P 0^A=w 0^50^H=0^H(LyH(H0^B00^Pi0^A=w {0^5u0^H=^0^H(LH(H90^B060^PW(0^;&0^P0^H0^0HH/^A=w /^5/^H=/^H(LH(H/^B0/^P/^A=w /^5}/^H=f/^H(LH(HA/^B0>/^P8/^A=w !/^5/^H=/^H(L H((H.^B0.^PH5$ Le&HH5 LA&HeLpHc=2^ L' L) H5ˏ H=R.^mDsLH5 H=-.^HDsL[HVHPH5l -^HHP1HDžXHDž`DžhflD--^MMt}H-^D`HHdMI9r+h=w hJ4 H{, u/HXLB HH`HX@)D`LQ&LHH3H5 HHXHcD`lLuB<'t-9dwIt$H{ HXu B'HX11nlHXƅl?,^A=w u,^5o,^H=X,^L )HA,^B0>,^P8,^A=w !,^5,^H=,^L H+^B0+^P+^A=w +^J40H=+^(o (~H+^B0+^H+^A=w r+^5l+^H=U+^L H>+^B0;+^PsL5/^ML/&)HPHLEL#$+^A=w *^5*^H=*^L(L L(vH*^B0*^PEH= (1HLHHHPNEEpKH1UHAWAVAUATSHxdH%(HE1HUHX@DtHDu "HuffDHDuHHHF H9v2H7UHJ@PD(ufDPD(t HH9uHH211HEIHvHƿ@IHH(^=*^fH(^5(^H (^M)^HxH(^D=(^D)^)^1Hp(^D5(^hH(^H`Do)Z(^t(^D=o(^L-^(^`)^hDoLH`~xfD50(^5 (^1pD<)^H '^)'^D=(^(^(^FLt=)^EHudH34%(Hx[A\A]A^A_]LIH h D<L1s"11Li1LE11H=h hx11H= h hZ|%ff.='^uH11H=\ hUHSH='^'^!'^H[]@u fUHH@H|]f.UHAUIHATISHB$HP蟃u{h%=@ti0H1訇HHtPLGLk01C(zHCHtHCHC @HȈ1HĘH[A\A]]ff.fUHAWAVAUATSHH(HG uHGH8 LkuH8 L9uC,E̅C(ML{II)IDeM)M)AHH9S0E;EJ40J C(HsHKIL+EAHH;S0>C(L1PLU=LUHIHCuC@H(L[A\A]A^A_]ÐC@fDE1L9{,CDLhIω}Lk DmL)HPHH)HtH HpL1A8  HC8zDLDL9t$EHLLEL'HsLELHs;LxH>HKHugC,EuIDHS~CHUECfDC, HKIECDIfy t HKHSEHHKHSLHS HC HKDHHt+}uHH: LHfH1fDHt+UHSHHHƅHH[]鸅ff.@UHAWAVIAUATSHHHL{LcLH1M)LIBT օHE~EHCflCHDHH{EuIELLkHCB HSAEC,HC0HCHH[A\A]A^A_]ÐG H{fD0H1OHH31H蠄HEH[A\A]A^A_]f.UHATLfISL9sTW HGL9s4HuI{LH1f1HƂHHtDc C1[A\]@[A\]fDGHf.W 1H9UHATDfASDH9sxHWuFHH1f1H4HHtIS1u[1CH 1Dc [A\]DH7HH1f1HۃHHu[A\]fH3H}sH뒐@UHAWIAVAUIATISHH D4AD$ tI9v LTu%IMLIt$LPpM,$AD$1H[A\A]A^A_]ff.UHATIS @Hv-H3L Ht!H+C[1A\]fDAt[A\]OAIHHL9s>L 2DHHIIAGDAAAI9uыGPGÐfDHg2GHAȃAMcFD HAȃAAFD@ HAȃAAFD@ H H2PGff.UHAUIATISHG Fڍ4tH9v LxuAD$LL1H[A\A]]ÐUHATASHH ]vH3D1y CH1[A\]^E EtH[A\]ÐfD1tUG HATDgSHIt$QuHB"[A\]UHATISFHW ptH9vHuAD$CH;1Ʌu1[A\]I4$g H;Kݐff.UHAUIHrATISHHG tH9v HuH;L9t6DcEuB'1H[A\A]]LLH;CL9uLƐfUHAUIHrATISHHG tH9v HuDcH;EuB'1H[A\A]]LLuH;L VHL9AD H9ADuLRL9Vt L9t f1DH1HH҉ÐUHAUIATHMISHHuHvVI9H9 uH[A\A]]9u1LHHǐff.UHAWMAVIAUATIHSHAHuH)L,AT$IuH9wu 9u8I|$H1&I\$HuLHID$B(1El$M<$H[A\A]A^A_]ff.UHHATSH1HDIHu>HMIHuuM~EA\$1AD$EA$H[A\]fDHIHH[A\]f.HAD$|뢐ff.UHAWMAVILAUIHMATMSHLH(HuLL;-+|UtiE$CH{MޅtI9vLL]L]u)HH{HMLAWMEDz L#CX1ZHe[A\A]A^A_]ÐM̅tAMLHHufDAHuH{LL#He[A\A]A^A_]Ðff.UHAUATISHHdH%(HE1Hv[Lp1ɾ]L H XMLLlHHMdH3 %(u(HĈ[A\A]]DLp1L ~ff.UHSHH8LAtH XLMH8[]fDu*LE~E1Hu؉SCEH8[]HCHUHuLEzHUHuLE믐UHAVAUATSGH9vHwE10[DA\A]A^]@IHvAH>AƄuHLAB {H)H;DcD[A\A]A^]f.GtFH7LGPHHN@ADu"(f.PHN@HADtGuÐ1UHAWAVAUIATISHHHHWDCEEDsI9r#C=w CsL>u8HCHELL UXDB0HE̋{H{PHI CX1ZHe[A\A]A^A_]EMtDsCMI9r!C=w CJ40uHCLLB0{H{Dc1닐ff.UHAVIAUATSGHDhIu_AĄu!HLB(sH3 H+C[DA\A]A^]Ðf.UHAVIAUATSGHDhIuAĄu!H LB(sH3M H+C[DA\A]A^]Ðf.UHAWE1AVAUATSH(HuHeD[A\A]A^A_]DHI͉IHIHMLH{ADŽL;-vULKAL1HAHIHCH9s9HCHHE̋{H{PHMELDE1: CXZIC=w CsLUHMHHCHMLUDkCMI9r%C=w CJ4(|HCLLB({H{DcEȅEA)DmMLHqHM$uHMHC1E1Uȋ{H{l {ELLHH{$Dk4A)UHATIHSH]HsHPdH%(HE1E( HL)HP)HMdH3 %(u HP[A\]ff.GD A9UɉHAUATSLHI< LH)LLL9tfDLfLn DHI9t`HGD8PuL9t6DFD8uL9t'DFD8GuϹDHD:DuH9uL)؃[A\A]]fDD[A\A]]øff.ыVH6fF99WLH6I|ILLLHH9UHATMaSIYE fDH9tkHD8AuH9tgLYA8AuL9t`HAIQEE8YtfDHHDZD8XuH9uL)[A\]DD[A\]HظL͐@DOD21E9UEALHAWEAVE)MAUMATASHH(L)xltIG G9I9HB{LHML]HI48HD)LD)HiHML]EuLD{1H([A\A]A^A_]H?Eu@K4 DMHD)L0fDDLH;H DLLHLEDUL] DKH;LEDUL]fww 6wLHHML]HULE 2HLEHML]BHUf.UO1HHATS_ H9s+H9IHBHH¸u I$D1[A\]ÐUHATIHRSHH; Dc[A\]Ðf.U1ɾ]HSHHWH CH[]ÐfUHHHEE]f.UHATSDgHL'HcLo L)C[A\]@U HATSHHDcL#L? L)C[A\]@DAD9IBIL9UHAWIAVIAUIATMSHHw H9wuHHuSs IMMLHHHEPIp(AWH;D H CHe1[A\A]A^A_]@Heظ[A\A]A^A_]@f.HDFWHLIHH7HAff.@UHATSDg^A9܉IFԅtH6H?uD)[A\]ff.UHAWAVAUAATISHHFtA9~I9HTs{EL{HtgIT$HKH9rYH<1H9sPCA|$E1HHHH)H)H k L)Ɖs1PIvLuMtAIIIL;mr@LH+EH[A\A]A^A_]f.Ivڸ\xIIIfAGAEH52HƒHAWAGM1fHMUHL9LVHLAL9HAEu;M9t6LHM9Jt,HLGLMAPILWHu H fDHGLHLMLEWHAZYff.UHAWAVL4AUIATISHL9siA] "~p'ty\ttI<$LLHHcLLH=MlIM9wH1[A\A]A^A_]fDt\ unAD$IL$PA;D$It$AT$\AD$PA;D$IL$AT$f.0fZfAD$E}PA;D$IL$AT$D<5DrTfDAt$Aׁw 6At$LHHMHMȄtmH[A\A]A^A_]fAt$Aׁw 6At$LHuID$B8AD$IT$HAL$ID$B8AD$IT$pAt$\At$Ӂw 6At$HI|$;ID$AD$IT$HAL$D<@UHHAWIAVAUIATISH8HEHEHEHGHEfDHMLHuLIP(Hc؅EILuȋAGHHrI I'I\IH}HU2HULIGLI?AGIWHHHHP0AGI4@MI uAnH}HUIGHU\I?AGIWHHHHP0IAGAGH}HHrHULunIGHULI?AGIWHHHHP0%u1I?AG?IWHHHHP0H8[A\A]A^A_]fDAZDA0DuI?AG?IWHHHHP0ArDxI?=iH81[A\A]A^A_]Ðff.HWHwHff.UIHATISHLH@HwHdH%(HE1HCHWHHHH1DžfDžLHR%HEdH3%(u+H@[A\]f.HƅfHR ff.UHAUATSH\7I9MH9HN, HH9L9IIdDHH)H~t\xL 02HfFAIÃIAGD^AFHH)HLMIH9v&M9v!A<~AuH)HI9r [A\A]]fA$...[A\A]]Ð[1A\A]]III1ff.HÐ@UHAWAVAUE1ATSHuHD[A\A]A^A_]fDHHMAHuSH{IL<IwtAńuHCLEDE1HULB8{H{7CftJHFW HH9s:U1HHATISHH71HsdDc H[A\]Ðff.UHAVAAUAATISG HDwI9s}HB0It$E{LH;J6I9D$s9HLt4sH߅HD4[A\A]A^]fDMt$Dk1[A\A]A^]ww 6wLH [[A\A]A^]f.DHL'GM,M9sDI<$IM9wHHHHHHHH~HrHfHZHHNHBH6H*HH HHbLg(Mt(I|$8?LHH@(HH?HHxHHHHxHHxHHsHH`HHMHH:HH'HHHH0HHHtH0"HHtH"HHPHHXHH1HǃHǃH)HH[A\A]]ff.@UHAVAUATSHHtFL-: VII@H{IUM1ɾ1HG8跬H[HuIdž[A\A]A^]f.UHAWIAVIAUIATSHH(HHEHHEHHEHHHEHL%Q MMDHLMMDHL111HHMHǃ H5\y HAEuEH} H}H}Hu MH(1[A\A]A^A_]fDHHH~EDE~EEH([A\A]A^A_]f.H=x @LHHaHI VHǃH0CH,VƃHHp@ ƃfff.@UHAUIATAHSHHLPLXt&)`)p)U)])e)m)u)}DH1HMt`HELMH H0Dž Dž0H(H[A\A]]A$wA$/v $t)%A<$HH @H1HMdH3 %(He[A\A]A^A_]@d, lzp *r s t Džp LhLL .Mt HHLhM9HHLpD  HHHxM HLHC ZH.ML}H  CHMzL&H*f.GyHHH8MHLHfA$f  vUl A$P}DnLHVfD   A$)fhTf|HMLHZ^ `p Zbnc HHHMBHL>HBfj4 HMELHD\HHHbM HLHfD*vEp)Y o HHL]D(II$HH00HHH)HhHHHpH%HHǃHǃHǃHǃH-UHfHHvAH\&H HH&@HHWHtMb HLHHDM LHHM E$E $HHHA<$@xGHHFHM LLIƃ8fHtM LHLHHhHtHhHh|@Džp LhHH H0M M LL I0HHLLH0HL8HH A$HHx HxGM HLHCfDA$HM LSHWHM L#H'HHM LHA$;HH A$xƇ9H @HHM LkHHoHHt%Lh(MtA}I}8LIH} MtI4$HHDI}8yE HH Lh(Hx IIH LHIW\HOl>LH1LHUHǃH0 HUƃHHƃ&@HH HxM\HLHCfDDžp DhHH HXFM?LLIXHHqfD`zf.I$HUH]DHMHW2 LDL&H*f.Džp LhMMHH) HLHLHLIH~Ml@A$HMKLcHgA$8PHHHxH5Hx0|HH@xHHA$yLMI}H1Mt LLI}0IHHLmpLHIHK|4L)HQxL)H)HQx@LHI貚HLL)HQxL)H)HQxHH02fHHA$HMrLHHHwL@@A$HHA$HH!UHǃH0HUƃHHƃ6@Džp HMHLIHPIMxLIMdH[LmILLHXLLL)HXHXHXL)L,HHHPxLHHxHoK|7>IHLHLHPI|HLHx0HLhxH M]LH HHLH(DMTHLH(HHHuHPMKHL oHHHǗH:HHEH,HuHbEfDHH1H}HLe L LIHEMi'HxH} LIHEHxH}yKHITH+@Ht;HH@Ht#HG Hj HDHffDH@HEHUHBHEHHGHR(H:HzH-HuaEfMbP1fUHHHEHtHuHMaEHHtHR(HtHzHtHuaEff.@U1HAUATSHHH}Ht`Leغ Lо LHHEHi'HxH}譾 LIHEHxH}葾KTHHHH[A\A]]fDHwUHATSHHHt-L Mt%I$H@`HtLBHHHHtHPH5E HHHtWE1 fHD1AHH|[AuHHxH@HH@`)Hh1HH褻H蘻H茻H耻HtHhH\fHHǃHHXE1 HD1AHH| [AuHHxH@HH@`)Hh1HHHtHGHtHP`H蠺HfHǃHHǃ)1HǃHǃHHHt;HHǃHǃu[A\]H[A\]@ff.@H+w H9w H)H9IIHvDGHwA#tCI)HLL9LHF骶f.HUAHA@AAÐGHwAGAAHvEtGtbHP HPPH@fHPHDHPHP@HPHPP@HHHÐUHAWIAVHEE1AUATSH(HEI?t LCIƸI9:M1I_ ;I CSLcIfLEnLeAIHxHjHCDSH}HECDUEHCHEKSDKMHK UHMDMSHMDIHL9]DmfAUMLAuD*U^F AI?I9fDI?Ht ZILIIt 1HkH1Ҿ AiAILJALJ|ILJt]gHULDEH11*f1ɾLAHQUH1_H(L[A\A]A^A_]DH)U1ɾLH1-AAD/,L,HH|LA讯HHHu\f.Hx,IޢHuL\HH3IHL8H fHx 1轪AD$I1LH5w 賮HH]HZHHSHXI$:H5HuE|$fLMPHDžHDžƅLH1 "H[H1 "HGH1 "H3H1 "HH1 "H H1 "H!H1H 1 Hn1 *!H1H 0 H^1 1!HH z HQ1 M袩H`ILc1HLQ LL!HH 1 11!HH ! H0 x;HHt8uHHHVHHt8uHHH(L ~ ǃ(DP)@HXMc H= LEHDžHEuH]D8MHs LDL%UH`ML@DPDžTIL$XHHǺd1脡H@HH GIHBH HsJ;LHHHtH@(HtHxtH@IMuMH. "HE}YH. "HEH. "H1H. "HH. "H H. "H!H1H . Hl. (!H1H - H\. !H1H x HO. A>LH:. H1!fDD@HBmfHDžAHDžZH(H0 H@H(L%UHHH`L DžTIL$PHfHH(DHHHH=Q- 蕣HHwH HdfHDžHEH]HHtH L H@DA A/MEEL}Mt 1LʎEEL}Mt 1L詎EyHKdLH}H̎UH"E1MDUHAWAVAUIATISHH(Hu H蘆HH{蜍IHutHEUI$ADŽ$H0LLm襁?LLH?HFHDžXLgHrIH L`IHLHHHMHLHP)HPHHHL(IEXHuHpHHXAWDdLhHxY^IHLHH8WHH*@HUHnDMI@AI9H5 LLXLXtLLHLE1̅HuLHHxAWDdLhHpIXZxfLLHM蟂AM9waE1ME1IH1jfDF@=0<{X<}0(MIpM9v Ax}A1IfM9II0HDr u@=@;LHLPXM;AI@H5 LH@荃XLPLH`L@E1E1^fDHDžX1L)?LmLH?fLHO)E)E)E)E@;u IIPMuMEIfMtkIPuM9vIIйfLEAHE1HɛUHHUH1蜔]HqUM)1H߾H1rLE1G(fHHǀnfII!DLLHLPE1E1L@XLPHDHUHE1ǃH0}HUƃHHp@}ƃGLLLHIL)LPHX薆XLPILHIM5BfUHAVAUATSHH dH%(HE1HHt HHtHHtH@xHt1;HLLLHooƅloooo)po)o)oo )o0o@)HoP)o`)op))))) )0)@)PH`HHHtHUHHHLf)MtMv(MtA~3E11H hHHD`LHHPWLZYHtHLHpt XMd$Mt5I|$GPtHUGP1ɾH1+;Md$MulHHǃHEMt 11L-$HHǃHǃH)1HƃH{HLHHHHX@.HtH1H 1Hǃ8Hǃ01ɾH߉HUH1褏HudH34%(He[A\A]A^]Mt 11L7#I1pHIHIH7LH@HHLH5,HLH"DHUHǃH0xHUƃHHp@xƃLƅl|ff.UHAWIAVAUIATISHDEH?tA;HAAIHHHxHDELLLPpAƃI0ALJALJ0000fAAƇHt@_VILJLILJ8xMH LDIL8Mu LGvHE1LL$A+I?Ht NILϼIItH1HE`0HE1HǾ ].LILJALJ|ILJduEMu LuIE1LLLmIu }FE1HD[A\A]A^A_]fAIIyx}HMMVA$IvN4DL9rRExMwHpLLPB*LPDH@HMDHHHLBL9wfDHxH0A8H@@fDHEHH6HHp HEHL@(HEMHο5DH% fHp HEHѿH몐HELƿHHEHuNLffIFyHH;hgH8軿{A8HqLK@UIL HAUATLSHLHdH%(HE1HH HD1RjcnLE1ɾHcAHZY%HHHBp1҃P(IHHLt 1L&L1Ҿ $Hǃǃ|HǃnIHoIT$(LHoo A@(H8PHH0AƄ$ID$XIMHAL$ID$Ht'HudH34%(Lu/He[A\A]]f.LqE1LؽApUE1E111Ҿ HAUATSHH<HLt 1Ly%1Ҿ Lz#HC H}Hǃǃ|HǃHE91HIHP(HtME1DLHHHHt-D|HǃdwH[A\A]]fH1[A\A]]UHAWAVAUATSHHrHH1HtHpxHHM~:HMHHHHHG8E1fDDH0HMA脭HIiHHI:LLO|/HIelLMziLHI9LLHH;lHMLHD9w8{HH[A\A]A^A_]ÐUHAWIAVAUATLXSHHHXLo DLIdH%(HE1oI8woHLI@HX艴HXBAI@AALJAƇD9t$IHhH; Tt Hp11HXHLHpHXaHXB HHXAL90r6ArH1HMdH3 %(Hĸ[A\A]A^A_]ÐL(HXIHuLHLWArtIHte1HP @I1HH| uIHPHxH@HH@`)Hh1HLXMLXA@ M9E1fIcMAHII}2 IEIHCHCAu@IH1 @I1HH|, uIHxH@HH@`)Hh1HPfDI@LLH聲HXHLHI蹱)HXIJ 0HPtLHAHXH;PH`HHHpH@HEH(f.LLAֱHXHLHI~HXLhH`EwJ6IINHXH= H9LAaHXHLHI虰 HXM1LxL@HHHpIp1AhALXMLXI?wREtMILxL0LpHxLL8LdL8L0DL9PLsIŃnLVHXHLHI莯HXLhH`MD1HHIpAhALXMLXAIIiI~LjLhH`IHLeLXB(L耯HXHLHI踮u,LXMLXfDCfDIHtY1I1HH|TuIHxH@HH@`)Hh1HHUIALJH0 cHUAƇHIbAƇ@LL(@LLlLBD-HtILXIHtQ1I1HH|TuIHxH@HH@`)Hh1HHUIALJH0 bHUAƇHp@fUHAWAVE1AUATSHH(HtHE1Bx<A<HIĸI9HHHEt 1HH}1Ҿ HEHǃǃ|HǃHE:@HHuDHxHAdIĸI9tOEuJL{ H}L}葬IHuHuLHH([A\A]A^A_]Bx H([A\A]A^A_]@HDHApDH}K'H9HH}ȅu ADH蕬H9tHK HMHq9hAQEQA҉D9HHhH; [TtqHp11bfuADHAp1HH1Q(HHUADHHEHHD|1ǃH([A\A]A^A_]HApUHAWAVIHAUATISHHHJHEHMIE1rfLxIG(HHs HiLVIG HHs0H\L4IG0HH3HOLIHHsHBLIGHeHsH5LIGHCHsH(LIGH!C\AG\ClAGlCXAGXChAGhC`AG`HCxHt HLIGxCdIHIAGHCIGHCIGCAGȋCAG̋CAGԋCAGЋCAGM9Hs(HIG(Hs HIG Hs0HIG0H3HIHsHIGHsHIGHsHIGHEHEH[A\A]A^A_]DHHHFHt*HxH@HFHH1HtHWH1f.HHL@L@fDHFxHtwHo1Ðfo 8 ff.@1鉂fHt#H?HtHGHHtHHt@fff.@ ff.Kff.1ff.fHibUHHt HHtHrHHHHxfDHHxff.HFHHHt HAHVHHtHH f.Ht[UHATSHu%DLcH_LMu[A\]H{Lc_HL_Mufff.@UHATISH`HtL`HH[A\][1A\]fHHu &fDHoHPfHuff.@1HtfHHuff.@HtPUHAUIATISHH H[HtH{LAՅtH[A\A]]fDH1[A\A]]1UHAUATSHv1HH[A\A]]DIHeH5 pIHt˾piZHHH&oIEXHSPAT$HCHS HHtDIT$1HߋID$HߋHCHID$HߋHCH@YHCHtHCHHCH[A\A]]@LCPMtHhxUI|$1ɾH1AHD]H9xUI|$1ɾH1;nfDHtHGHH@pHt@f1ff.fHtHGHH@PHt@fHtHGHH@XHt@fHtHGHHHtDfHt[UHSHHH8Ht H{8X\HCHH@HHtHH{Ht8\HH[]*\f.ff.@HtHGHH@`Ht@fHtKHG@HtbHHtVUHSHHX(Ht{uVHGHH@0Ht!H@[]Df.H[]@HGHH@0Ht@D@Ѓ @уxFSHC Ht Hs(H{8RHC HtHs(1ЋCD @HtHGHH@@Ht@fHt&HOHHI8HtU@H]ff.@UHAWAVAUATSH(HIH@HIHt1HHt%Lp(MtA~HUϾLcI8HujIGHH@HtmHLLIHa]HHt MDIw@LL1SH[HuM~Mo`H(L[A\A]A^A_]DHL5 IHya]IMHHuIfDI8tLIbIGHAO(H@MHJIV8E1HUy!D1Iv(AFutIGHH@HtHLLIMP t EA AFIF Ht Iv(H}mPIF HuAFtH`]IHHHU1Iv(AFuIGHH@HtHLLIMN8Pt 9IF AHt Iv(H}OIF HuAFtRMOPMEHsU1ɾH1A*UHAVAUATSHHGHt&H_HOIIIHH9Hv [A\A]A^]@HHH~GIt$L9vID$J.LID$LsftAt DfADH[A\A]A^]H)LHH9HOH8TI\$H[A\A]A^]HI~HIHLILI)B 0L)H됋ADADHtUHAWAVAUATSH(HHG@HIIHt.HHt"Lp(MtA~HUϾvI8HumIGHH@ HtpHLLIH]]HHtMIw@LLSH[HuM~MohH(L[A\A]A^A_]f.HLUIH]]E1E1HHufH8t IjG,IN8HMEfDIGHHLLP(IH2/M t EA AFIF Ht Iv(H}LIF Ht81Iv(AFtH\]IMHHIAFXHMfIGHHLLP(IHLt uOIF AHt Iv(H}LIF Ht1Iv(AFtVfAFtHH \]HH@ff.HtHGHH@hHt@fHt#HGHtH;GrHGHH@xHtDfUHATSHHG@HǀHG@0fǀ0000HG@ƀHG@HHt BHG@HH.HC8HtmHAĄuFHC@HxurHHHtO>tJH{81[ADA\]H{8SHC8AD[A\]f.Ht:t@H{8guHC@HHtlff.HUHSHH@uFH?Z]H8Ht&HH;_uIH1[]H9^tHvHuH1[]SHt)HXHY]HH;HH1[]H[]@fDJLWHMcLQQHDAA vDAAvYDAAw]DAD:uOHHL9tL1Ҁ8:HHH)L9,QЀ vQwQfDDAD:t@1DUHY]HATIS8t:kMHHtI$LHCHCHt"H[A\]fHoDH1Pff.UHATISÄu [A\]@L[A\]Ðff.ff.ff.;ff.{ff.{ff.ff.UHwHXUH]HHXU]H@(UHAWIAVIAUATISHdH%(HE1HG@Lh@Q@LHHtkAMuZL:=ILHEAA;ID9u1LHdAHEu&E1OfDL`HtH#OAH&hUL LHHjUH1`H]dH3%(DH[A\A]A^A_]MtLH5y LIHmAL@LLH7 L"HH:L HLH; H!%tDHJHDщHL)9sLH`LHHMf. LsGHu+LLH] LHGHtfD L+GH DHPMLfDf.fHHGHG Hw HG(HG0HuUHAULjATISHLH)NHCHHtLe~ELmHE@H[A\A]]fDUHAWAVIAUIATSH^HHHHtMHJH9G,HO,HJv HH9wpfDHJH9saIHHuE}(Me DILHCI9LBLSMHHAE}(ILbILbHIHJHH)H)HBHJI;MsH IIMH IUAE,H[A\A]A^A_]HHHGHHWHG,H@HJIU01HtHEHEff.HUHATSHGIHHu$D KID$HtHHH9uHuI<$HuvfDJID$HtaHHH9uHufA$I$HHHQHPI$HID$([A\]HG1VffA$HuID$([A\]@ff.@UHAUIHATISHeDLHXHvHHtHLH GHHH[A\A]]ff.@UHATIHSH+HHtHLHFH[HA\]f.U1HHPHEHuHEHEHUHƺHMHMLELMEHE/DAЍBJ<t;/HHHHHǃ/vH9HAtHHfEXJHtsHuEH}HuHuHuIH.AȍQOMt9I0/w3LʃHHHHփ/vHWH?Ht H7HzÉHH^f.wH4QUHDH!QUH@ff.UHAWAVIAUIATISHH(\(HHHHH)HHHHHHz H9>IIHt5HMLLLHxH@Phu4IUIH9s IIEHL[A\A]A^A_]IELE1GH:vWHHxtIUHAVAUIATISHIHt8HHLZDL2G1[A\A]A^]H1fDI<$fDUHAWAVAUATSHHHuHE1HHD[A\A]A^A_]@IHHIIHIHt\IMLHLHxH@PpAńuHLLI$CLmFLAZFwDAgDHN]8uHM]Ddf.HHt$GPH@HHHH1fHdGPff.UHATISHH8H9t HC8H@ 8t3I$1H[A\]HYHH[A\]H9I$HHdUHSHO`H_8t8uctbH`UHǃH0@H]UƃHHpp?ƃH1[]fDuPu0Ƈ LJLJ 0000fGPuHHH@HHHUHAUIATAHSHHLPLXt&)`)p)U)])e)m)u)}DH TA$/A$wH Mt(H[A\A]]<<H\UA$0L,HELMH H0Dž Dž0H(-@H[A\A]]xE1L >DH[UA$xL,XUHATSHHdH%(HE1P)HIHtBGPH@HHHH1HMdH3 %(H[A\]D"G@HUIAEH8EHPHHC8HǃHǃHHHHP`HHCPHRI$HHH DH\U1ɾH1fDHC8HߋHH1@$I$dfDI$dCPl @UHAVAUATSHHLo8dH%(HE1MA@H{@u.E1HUdH3%(DH[A\A]A^]EAAHHHC8HǃHǃHǃǀCPEAtHC8Htf@A8HspH+{d 11f.H yft)AfKdHHpHH9HspH yfuHHpH9wfEV{PuHXCPHC8K`DIHPxADžADžHG8A0ǀ0000fDHG8ƀHG8HHt@0ƃ ǃǃ 0000fAH8S@HLIE1UHUPAńbHC8HߋHH1HYU1ɾAH1Z0=w s#vUHHAWAVAUATISHHHEHHEHEHE@M}I$I|$8фIǸI9 ID$8Lp Iw A>H}IwIH6H@LLIEHELmL(I}:A$uA|$`I1һG LHEȅPAutIt$XL}]HH΋FpH@MIc@LN@Fd@tuM@LV8IM9MBM9v"LF@ID$XA|$`DpH $]H@HcDHEu#I9AujD9UMuI@HF@ID$XH@d @pA|$`H@IcDfDH}UHM舂HMIL$XH΋IpU w9Hǀt)H=j]H IHLHN@HEA|$`8H9F@sHF@@pp~wHvA|$`IcDf.Hh@fDID$8LIDŽ$HH1HH[A\A]A^A_]DHUUL1ɾH1}HH[A\A]A^A_]fHEHAFAvIT$8IT$8A$AFAvA$ID$89t$HHhH; ٝTt Hp11I$I$HH1[A\A]A^A_]ÐUHAVAUAATE1SHHGPH8A@;L9H{8HW DHUEu :Hwˀ:uEtnHUHK8BRHC8D9t$HHhH; Tt Hp11EuH{8A蘀L9]CPH[A\A]A^]LeHLHULHUHK8BHC8D9tHHhH; STtHp11xUHAWL~AVLuAUE1ATASHH(W`HEB LHEȅE'tDHHCH1DEIAD9k`AE'uDHCxHUH H)HHT HCxH@XH8HPHHHsXHϋFpHc]HMH{xH@HLHC8QHHCxHMHDHHEE3AD9k`H}H(1[A\A]A^A_]fDHHHLD@DHKxHH)HHHQHHSxHD HSxHH:HBPHSxHHhDHSxHHBHHHsXFpH5/]H@HHc@HSxHEHH:HBPHSxH HfH(e[A\A]A^A_]@HJPH HSxHLDHQgHQHSxHTf.HPgHPHCxHTf.HPPHHCxHDHrPH2HSxHODHBgHBHCxHDf.LHM|HMff.Hv7HvHv5HG HwfHGfw@@7HGfwHHG@wff.UHAVAUATSHHcH LGpLdH%(HE1HH)HLL`@`MHW8HpHBphLI)IOT MMNA2 [L+@'L.ILLHMtLLH0HLH 1fH]dH3%(H [A\A]A^]à gX+j!I$H ƈH HH @qH @qH AHPHHHHHP1H@uHA$1H&fDwbL+HH)HIHUM,L0Iftw9   u]HIIHc@HxHItvH@@HxHIpHH}D4:fHEȃpHEHHHMA9wd,fDm7AIpH8HHHuH47H[H~HFQHMD4 fHU1ɾLH1XHxAhL ]HIIHc@HEH<IpHtHEHff.fH`tVHHH`HW@HW@HPHW@HPHW@HPHLJ`HLJUHAUAATISHHht@Et+H`Ht HEA"HEH`I$HH[A\A]]+fHtXv.t^rlttu4HH1tctouHH1Dfx1DHpH1h1DGP1HGHH1fD1@UHAWAVAUATSHHH8QWPIrx\HpQCdMHH{pLH)HCdChE1L%{(]L-)Uf.HC8HSpHHH8DL4I)ILHtz`фHSpLHzzft BfHSpLH:B`|HB@@AD9{dRf0Ch1ƃǃǃ 0000fƃ H[A\A]A^A_]D CdvHB@AD9{dfDWqHB@AD9{dVfD tw9 : uEHB@AD9{dof.=r=-H9UH1ɾH1uH[A\A]A^A_]ÐHB@HHSpLdDLbHSpL4H9U1ɾH1H[A\A]A^A_]@HB@AD9{dEDHB@ AD9{dz%DLjAD9{d^ fHB@ AD9{d:DH8U1ɾH1hfDH4H)HHCpHt*x1HHH)HxhHb8U1ɾHH1ff.UHAWAVAUIATSHOPHuȅ]W`H}HxHH)HHHuE1L%Ϭ AU`f.IE8HHH8DHH)HEHL<HtA`фIExHHxH8xHx]A` w6AG`IcLfIExHDP(IExHH(@AE9u`RAƅ0ADžADž 0000Aƅ fA1H[A\A]A^A_]fDIExHDPIExHHf.IExHDPIExHH_IExHDPIExHH7IExHDPIExHHIExHDPIExHHHHdHHHHPHIExHuDHHgHHIExHR@H5U1ɾH1HH[A\A]A^A_]@H5UL1ɾH1H[A\A]A^A_]ÐI@HHIExHtaAE`HH)HDDH5U1ɾH1H[A\A]A^A_]@H[A\A]A^A_]H4U1ɾLH1iff.@HHVHufDHHHtHuHGPfH Hf.UHSHHGPw`HC8HuHHPhHC8HuHHPpHS8CP0ǂHS8ǂ0000fHS8ƂHS8HHtB0ƃ ǃǃ 0000fH[]f.XCP.fH13UH1ɾH1H[]fHS8CPǂH[]@dfUHAUATSHHGP9W`HHCxL$I)ILHx HHHHHHGHHGHHHOHHsXFpHSxH ]H@LHLj H HCxNl H1[A\A]]fH2U1ɾHH1H[A\A]]DHW1HtHGdHGiHGgHGLHPH-@G`ff.UHATSLg8HMADŽ$HG80ǀ0000fHG8ƀHG8HHt@0H{@ǃǃ 0000fƃ u 1[A\]@HHHC8HǃHǃHǃǀCPHC8H{pHtsdz11H yft)AfKdHHpHH9QH{pH yfuHHpH9r/f{PuHXCPrDC`tI$HPxADŽ$UfDH/U1ɾH1hff.UHATISHH8H@HLc8I$H H0HC@ճCPHߺI$0fǃ 0000HǃHH@H[A\]H1H.UADŽ$I$H0H,UAƄ$I$Hp@H[AƄ$A\]ff.@UHSHHH8ZH9H{8HG 8PHPP4 Hs@PH҉S`PH҉SdP @ KdtmHC8HHPXuHS`uXCdumCPH1[]f.Ha-U1ɾHH1DH[]@C`tHC8HHPPuԋCdtxtc9C`vH4H@H)H5HCxHhK`1HHH)H -H4HH)HHCpHKd1HHH)H `HY,U1ɾHH1xCdf.UH81HHHPpHHP(HǸHt]1]ÐU1HATISH@H8HHPpHHP(HƸHt AL$`I|$8E1H(HID$X[A\]fUHAUATSHHH8dH%(HE1HS`E1A{P8DC@HUIAEEHP0H{8HHP`AąAHC8tu HC8HH5QHHHǀHHHCPHC8H8HMdH3 %(DH[A\A]]CH)ULJL HC8LH HC8ƀH'UHppHC8H HC8L1ɾHAƀ1#NfD1ɾHAHY)UH1"fHA)ULJL(HC8LH4 HC8ƀH 'UHppHC8H HC81LHƀ1zDH1AlHC8HǃHǃǀcHC8HߋHH19 @UHAWAVAUATSHHLg8I$E$H@HHtoLЅtfHC8I$I$HH8HA$1xtCdCPH[A\A]A^A_]f.A$|tI$HC8H8HI$@HA$D9t$HHhH; oTt Hp11A$0I$ADŽ$ADŽ$0000fA$AƄ$Ht@0ƃ ǃǃ 0000fPChCPA$|{C`tA$tL@1L6A$|LH4H)H跾HCxHA$|LH薾HCXHwA$|H{x1HH)HWA$|C`E1I$EHCXILLooJHoR P oZ0X0ob@`@ojPhPor`p`ozpxpI$LHp Ht&HSXLLHU*HUHB I$LHpHt&HSXLLHUHUHBI$LHpHt&HSXLLHU̿HUHBI$LH0Ht%HSXLLHU螿HUHI$LHpHt&HSXLLHUpHUHBI$LHp(Ht&HSXLLHUAHUHB(I$LHp0Ht&HSXLLHUHUHB0I$LHpxHLAfHSXJD*xD9{`#HCH@Ht HHXHC8ǀCPC`A9$|[1ҐI$ЃHtpHKXtpI$Ht8HKXHt8I$tdHKXtdI$thHKXthI$tlHKXtlI$Ht@HKXHt@9S`r1H[A\A]A^A_]ÐHHƃ8ADŽ$HXs`uC`H{XI$賣I$HH"UH1ɾH1GH[A\A]A^A_]HCXAJD(xD9{`uMHa"U1ɾ HH1H¸@ff.UHAUATS1HDo`Et.I6HHt&ƀID$XDkHCHH[A\A]]@H!U1ɾLH1Mff.H HGdff.HHÐUHAWIϹ0AVIAUAATSHHHG8ǀHG8ǀ0000fHG8ƀHG8HHt@SP0ǃǃ 0000fƃ HCpHD9kd DL$I)IIMu1A|$ftH[A\A]A^A_]DIOHHMLLI‹C@fEjIzALURLUIHMAD$fH{8ALHPLUȅAuJLHD[A\A]A^A_]HUH1ɾH1uH[A\A]A^A_]ÐHC8HߋHH1>LUHUH1ɾH1H[A\A]A^A_]ÐHH1ff.f1HtHW8Ht fUHAUA1ATSHHǐHLdH%(HE1艸1H1LuHS81HǂHC80ǀ0000fHC8ƀLc8I$Ht @Lc8EA$ubCPt3C@H{8HUIAEHP1HMdH3 %(H[A\A]]@Lc8I$HPxHuHC8ǀCPrI$H tI$Lc8A$2fDHC8HߋHH1:ff.@UHAVAUATSHHLg8HEMGPWd"HHHǃHu1HIH HC8LIAhHMLH@PLAjEI$uI$HtzHD[A\A]A^]f0H$U1ɾAH1赼HtSH誵HǃHǃHpHA[A\DA]A^]D8u$HC8HHPxH_uHC8CPǀHf.HQUI$ADŽ$L(LEH.UAƄ$I$HppLH1AƄ$1ɾA茻HD[A\A]A^]@HHHXrCPf.HA[DA\A]A^]f.HC8HAHH1HD[A\A]A^]HAU1ɾAH1Һff.fUHAVAUATSHG8HHPCPCPH{8?AŅLLc8A$aA$|I$8A$HI$@HA$9t)I$HhH; aTtHp11Lc8A$H߉HC8|HǃC`[DA\A]A^]fD HfDǀHUAL HG8LHHC8ƀHUHppHC8HHC8LH1ɾƀ1[DA\A]A^]ADŽ$Lc8A$|fDCP@S`L@I$1L襱A$|I$L轘HCXHC`LH4H)HHHCxHS`H 1H)HHƃ\fDHC8CPHAHH1[DA\A]A^]DH)U1ɾAH1躷 DH{xd1ɾHAHUH1Aff.@UHAWAVAUATSHHLg8MoADŽ$HG8A0AE$ǀ0000fDHG8ƀHG8HHt@A0H{@ǃǃ 0000fDƃ HC8CPE1I$8HI$@HA$D9t$HHhH; T^Tt Hp11A$ADŽ$HD[A\A]A^A_]Ð{PnHC8HspHtI{dtB11H yft%AfKdHHpHH9vHspH yfuHHpH9rH{@HC8SPv;t1C`u1E1EtKCPHC8ftփuhHtHC8E1ǀEuH葸A@s` I$HPxADŽ$fDHXCPKH!U1ɾAH1貴zDHXCP}UHSHHvVv(ulH1H[]@uPHHp1f.t[touGPCdx1@H9UH1ɾH1ͳH[]ÐHHwHGH1a@1Mh16H1'fH1fHHuH@H1f.HU1HhCPHUHCpUHATASHt@HG8HHtH8t rHH@AHD[A\]fDUHAWAVAUATSHHLg8dH%(HE1MhIIHu HIź0ƃ 0ǃǃ 0000fADŽ$HC8ǀ0000fHC8ƀHC8HHt@HI$8HCPu}IALLI$LPSHC8CPHߋHH1zHMdH3 %(|H[A\A]A^A_]I$D8EHuH.H@1 C@HUIHCXALHC`HCpEI$P"IALLI$LPI$EtDu/I$HuI$H@@Ht HЄ1fI$uLdI$딾LdfDHYU1ɾH1qqHG@HHv 11aUHAWAVAUATSHdH%(HE1HLg8HMIIA$pt>LLHHMdH3 %(<H[A\A]A^A_]fDI$@ptA$uLcBIu LIHC80ǃ0ǃ 0000fƃ ǀHC8ǀ0000fHC8ƀHC8HHt@HI$8HCPGIILLL{@I$ALP#CPHL{@?u{LbujI$HuYI$H@@Ht HЄu?HrfH! U1ɾH1踭FfDHXHC8HHPxHuH[tH_HIHI9LLL1CPfDHtoHuHC8HߋHH1i@HkH U1ɾHH1譬CH裥H@1蕥C@HUIHC`ALHCpEI$P.DHC8HߋHH1ff.1HtHGX@Ht+UHSHHH?HtR|HH[]@ff.@UHSHHHHtHs Q3CH[]H5 43H[]UHATIHSI $|HHtHe[A\]CHUHM$I|$ AD$LB(P19XZHe[A\]ff.UHAVIAUIATISMHt)ILH50 LLHy1HHtHe[A\A]A^]LLs t8Ku1LLCLH1;HMLH~UCLB P1:XZdff.UHhHH HHU~EHEHEHMX~EHEEh]ff.UHLxHUHu~ELEEHMX~EEh]UHAVIAUATASHH dH%(HE1HXHDžt!HhtH`t HpuHxHEAHxHLIXt!NfDIcLH1LH`Aą1H5M H1H%0HE1EtwLLpHJULHDH1UH r| HE1AH1'1H5L H&1H/HhLDHMdH3 %(H [A\A]A^]HU1ɾHH1AHfDLHALpH_ULH߉1He1H5K Hd0H.H9[f.ff.@fHG GHD pD7pwpG$w v!HO HOHG$O9v)PHP @ HHGDG pD@HAA4HG$HpOvDIHB O HO@GHg@ff.@UHAWIAVAUIATISHH9s*HIM9kIEDB uM9VEM1A-IM9IIMA< 9IL10HNQЀ w1L9wnHAE$TI9(HPЀ HpI14"M9H9A}D1@UHAWAVAUATISHHH({` EC`Hl HcHf{eN,&L9Hu0H}HHL9HHDA uL90 HI1?A$B< I9K 0HHHH9HILtM9uE1Bf.HUJ4&DM̺Eu{eH=HKHSHC@H([A\A]A^A_]HUJ4&[DE̺Eu{e#H=HKHSHSbHC@H([A\A]A^A_]HUJ4&}̺u{eH9HKHSHSJHSJHSBHC@H([A\A]A^A_]DHUJ4&cMHCHCfHC@H([A\A]A^A_]HUJ4&#UHCZHCf~HC@H([A\A]A^A_]@HSLH([A\A]A^A_]DHCHL9w/H4LHS@H9rwE1I9s HCB(HS@HCL9HL H([A\A]A^A_]LHUuIƅAHCD8HCL0HC@H([A\A]A^A_]MI)HtI9H{IF5HS@h@HH9FHHf.HHXf.E"AI9tLM9s3HIM9#I$DB uM9AIE1E"AM9rfDE1UHAUIHATSHHH3LHIdL#H[A\A]]fDUHAWIAVIAUATSHHLoHdH%(HE1xAOpIAF`HRh HcHDHLEL#HEdH3%(,He[A\A]A^A_]f.DHPH>IVPIVbfDHLIEAE{DHPDHAGp Av/  t&E1LmLL-uAGht'2dLmDT<DPH Sh LP`P\PXP1 H Hcu@AGh'HhHDPdHo6 L3 QLmpH g P`LD¾D\<LP1H HcDXHLmDTDP<LPH g 1@^_HcfDpH5 LmD\L!3 H g <LLDdP`P1HcXY:fHcHff 4HhH1HDTDPPdQP`P\PXLm<PH f L1iH0HcDHcHe 4HhH1H_HhHixUHAUATISHHXdH%(HE1f/;f \ f(%\ f(fTf.w+{` HK=C`Hd HcHf.H,f%_\ fUH*f(fT\f(fV~%e f(T\ -\ fWf(fTf.v3H,f5[ fUH*f(f(fT\fVfW3fD{e[ f/H,HHSHHfHH H*Xf,{ef*f.ȹHSEHC@HEdH3%( HX[A\A]]{eH,fHSH*f.EHC@D,{efHSsf*f.EHC@Zf.Z.f~HSJHC@'A|$hH{@++HFs@L1LEAD$d@tYI|$8H9H+ItHLHMd$8,LH0LH)LHLHKvfDH,HHSfH*f.EHC@=D,f*HSif*f.L1L_?f.\H,H?VxUHSHHH`Ht HEEHH[]HWHHG@HH[]ff.U(HAUATISHHXdH%(HE1/b va (%b T.w,ZɃ{` HK C`Ht` HcH,f%a U*(T\(Vf.W ya aa %}a (T.v,,f-fa U*((T\VZfW a A{e/+a yH,HHSHHfHH H*XfD,{ef*f.ȹHSEHC@HEdH3%(HX[A\A]]{evH,fHSH*f.EHC@D,{efHSSf*f.EHC@Zf.ZfHC@;A|$hZH{@++LHFs@L11AAD$d@tYI|$8H9H+ItHLHMd$8,LH0LH)LHLH"DH,HHSfH*f.ED,f*HSf* f.L1L?; f.\^ H,H?uT@UHSHHH`tEEHH[]ÐHWHGHG@HH[]UHAWAUATISHHH0dH%(HE1{` C`H\ HcH@1Hy8KeHSHCH8HC@fDHEdH3%(He[A\A]A_]HC@8{euHHHCˆHC@DHSLjHSb{euHHHCˆHC@vfDHC@8HCPHCPHCP{eH9HCHC@DHSHfH*E̋EE\ \ (ȉT.v,,f(%\ U(*TXVM.E/P\ \B\ H,H?H91HS|HfH*EHEElR ,R f(HfTf.v3H,ff(%R fUf(H*fTXfVMf.QKE Q f/*\H,H?H9 I|$8ICD$8HHH)Ll$IL )L)AD$d@toI9T$8IMC|$8ADH9K@wLHHCD I| ItHMHEAHEDL0)HMHE1f Q P H*EHEEf(HfTf.Mf.zuEH,HCHC@hHHH9fY Y H*E̋EE(ȉT.w-M.zuEH,ffD,f(%Y U(*TXVfH,ff(%O fUf(H*fTXfVHHfHH H*X HHfHH H*X-f`UHSHHHNdD@P ED@AAEAPDD@H ED@AAED@EDH/HH[]@fDG`t` t[UHSHHL AIEAAAA AANdHЃ HHDHH[]~ff.G`tH tCUHSHHHNdBЃ HHDRHH[]fD`t:UHSHHHNd HHDHH[]f.fDUHAVAUATIS~l?Ht)HA H3LHIL+[A\A]A^]@L7H IIHIT$HH4LH9r;E1IT$@L9vAD$`=tJ=tCID$L9L+[A\A]A^]@MI)IT$@HtI9I|$IFDID$B0IT$@Hh]1H5HHHH gHHHHBH'HB0H8HHHBHHHH5HB`H HBxHHB HB(B8HB@ǂ@HǂHǂHǂBPHBX ǂHǂBhHBp,ǂHǂ,ǂHǂǂHǂ H HH5H`(HhHHHHHHxHPǂXHǂ0HǂHXǂ`HǂHpǂxHǂHǂHǂHhǂpHǂHHHBH H8HPHH\HǂH BHǂH(ǂ0H@ǂHHǂf.@UHAWIAVIAUATISHHHLDHHƺDhEI9rbHIDHI$HtzMIL$MtLLHgH]~E1LuEAD$H[A\A]A^A_]KD51IIHDAEtfDH[A\A]A^A_]@HUHAVAUATISHHH;IDpL;swALLLk諼1[A\A]A^]HK1IDHHHHt.HCHHHuHG1DHKHff.@1Ht HwH;wwfDU1HSHHHOHDHHHCH?HKHHH[]ff.UHAWAVIAUAATSHH(HGHUMHtHEmHUAHCH3MHxH{ HLUE11#@HCH3HxH{D$AGIH9saE$E8tA\uMtHCH3IHxH{\HuHHUDMuHLUHUDMfHCHHHHKM H(D[A\A]A^A_]AUHAVIAUATISHWHH?J"H;Cr+Hs1HHHIHHt;HHSLkHLLRHLcLcB 1[A\A]A^]fUHATIHSH+HL[HA\]IfHHt(UHSHHH贼HH[]fDff.@HHHNL@t LH9uft1uTtmfuKuuuuu DD1DU1HAWAVAUDoATSLcNE9jEQLH1IcHMHAD3D`DAAE9AE1E1IAPD HILIԉLI I)LDIH IM9sD#HEHSH9v"[t@D Eu HAH9wDWLELcNE9IJ M H9vIHA9trqDx1@IApHHH)H‰AH M9sHIcH DEu/HAH9v"qtfDu HAH9rDWD[A\A]A^A_]xDDDoLcNLE90fUAHAWAVAUIՉATISH(DwG OAE~A9~ A9!HcIDHXHtH HH7I]<HcH;I;EIEKs LCHCL~.BL1DMH HHM蕴HMDMIII4$IcD$HAA 1E)DDIHD A@~H9wޅA8EEDsM;erkM;eseIcD$IDHPI$L`H(H[A\A]A^A_]DMuUĉM޹DMuHËUċMfLhfDHIxHFHHH9H~AI9@AH9AH@AHHH9иHG1HHHoAHH9uHHH<HIH9AHFH9FA@HFH9FA@DLǥIH9LǥIH9rff.@UIHAWAVIAUATSHLc_LcVE9|DIMcILcE1CA9^ AEnA$IcHL`MtI$HPDf.ADLbAB<HcItLM@ANHcHH8HHH8HwW1GH7IcFMMIM4IcGM<fLIAJIAAL^H)H)HʉAKH M9wM9v;MLHNIH)HʉAIH I9wIM)IK43uf.HDAEtODG)E}E)u?IEMcIJL @H97IHA092tADBDH90YH9@LHcGHH8HH8@HLw 12 *EAFL9-HL AIL9ELH߾ LLL H IL@H'=fDH(l, )狍( AMDꉕ,1ɅAUAMEHcDAD0uuux@ D)EA2 @)AAD fAH*fH~H f~H H H~DžDž1Ʌx,DDE1fDDž1Ʌt1)ffDHDDDHHHuHH iE1HHcPHT1uuu @p) գf.H8HLL;@wyL8Ow 'IM1DAHH߾ HI1fHljVHNjZ@fA*f.z*A!f.IM MLEAD$EDDDHx@HcDDD董DHDD7fDHHH HHHHGGAHHHG6(AU, )Mf.1@Af*YX 5 fH~fH~H @H H fD\x5 Hf/fW O3 f/vAH0HDDI9rKL;@sBIcEHHIEDHHH@L萠fDH=i3 AABljY;  b4 YA@ AY 34 @ AY 4 @\ AY 3 tk@ AY 3 tL@ fAYt-L62 @tAYH0AIuEf(H92 EP B "Yg3 f/ HDžE1H1HXHH0ML9L;@IcD$HH8I$L8H0E}AE HAMHEwA9~DA9H8<HcH48H;@ H8HP HxH@H8IcUIuL1҉DHH ʉWNI9wɉEEDxL;0L;@IcU%HH8IML8DxfHHcWA)EYH0HH HfH9 HH:99tfHf.H9HKHS9t H0IHH9H9@HHc@HH8HH0H8MHHI9H9MH9@@HHc@HH8HH0H8uDf(ŸfH8HH H;@H8HHHxADžDžAL踛H0Y / 1[Y / %f(ŸHcHH8HHH80Y d/ HHHzEd$A~IcHH8HfHH8HHCHCH{HHcFHHҗD{C KEwA9~A9EHcHL8M-I$H8ID$It$I4$HcCH H<1‹HH ЉFQH9w҉EEE|$H;0wH;@jHcCgHH8HH8K@HӀ{0HStLHD袙HDI& D迚DHLfDHDH0H,H0PLHHDxHDžDErDEB- fɋ*YƒYX , fH~fH~H @H H !DE@HHAUHH@)…HcIMHHHfDH9HH9tL)lj H8HG H;@H8HHGIEHu A}0E'EEAE AMExA9~ fA9HcHH8HHH8H{HC1H;IuIcEHHH ʉWNH9wɉEEDCL;0lL;@_IcEHH8IUL8DCHGA)EHcH HHHH9HH:98tIHLH0IH8HH H;@ H8HHHxH1fHf(H_^,f*ɍA0Y\f.{LH) H|DH9"YfHf(^,f*ɍA0CY\f.z*AHDL"8D9HHLH0H0Hf(ȸE1cH苔ADH8AB<HcH;H;@H8DcDs _L8<HcI]ATSMMuI$Ht&HCH@HHtH{HtX#~HHuIM9ufH=\1Ɖ\A)EA)EA)E A)E0%6[H=-\A\A]A^]!HHuIM9qfff.@UfHAWAVIAUIATSH(=F\EHEH=\`AEM}ef dgh"LE11LLI@H=Q\,}H(L[A\A]A^A_]f.HiTLFL  E1 HH@TH1N@1H<]HMu 4@HHbLcLI|$Ӂubf.H5LcMB#DffpfD`fDPfDUHAWAVAUAATISHH=N H(LdH%(HE10ǃIHǃ0000fƃHt@=/\H=\UEHHLLM@H PLL 1ATLzH5 LZYHLȀIHH5 H轄IHED9(oHpLLHLLH=\HzIL-z H=\uzHΖTMHHTHM 1H1趎HUdH3%(HZHe[A\A]A^A_]ÐML  MEDHaTL  H덐AAeAfAdAgAh8H9]LMsH=\uH=6 syHHHuHH9}:uH.IHIAf;LcrIHt#L1DH1Ml$aH1ɺL1DL\xE1AG9M9IG@Ht>LD1HLLLDHH=\D-LcH}KTHKDpM:AIcH50 T7AAAAIGHHtL HTHDž`H0rHTHƅlHp@qnvUHAWIAVIAUAATSHethftcdt^gtYhtTHT=~\HHpTHL ML1 E1cHL[A\A]A^A_]Ð=q~\AeAfAdAgAhHDLL[1A\1A]A^A_]IL  1ۆ1=}\Hs2]HMu 0HHtLcLI|$Wwu+fDHnLcM\D뗸됸뉸낸xH+THHTHDUHAVAUATSHdH%(HE1H~?ItvIH5I|mHtGL5}\IHtxHCXLLHHMdH3 %(HH[A\A]A^]LLsIHu D1@uHHt5L`fHd1]HIHfpLqr1ɾLHTH1Hsff.UHATSHt t=tA[DA\]f.H{\[A\]HH@XH@HHqHAisD[A\]ÐHt t,tfH{\HH@X`Hvff.@Ht t,tHH9{\HH@X`HIuff.@Ht t$t1@Hz\HH@X` HRWvUHAVAUATSHHpdH%(HE1*nL3IjD MEuFHGTHHHhH,TH1AVPHEdH3%(Hp[A\A]A^]LpDdLlEMH׌TH  HH1AVPf.LxH\IHT1H߾H1AVPbpUHATL%+y\S1A<$t [A\]f1H=y\sH=y\s1@UltE1tH#.]?HdH1HuH5 HiHtA$1H=Ey\m[A\]fUHSHHxx\;u H[]@H= y\sH=x\5mHH=x\[]CpUHATISHc1HkIMtHLHckILxj[A\]UHAWAVAUATSHH=x\H(rvHcoHIHTHLMH5ELhH5>LHMAI*HMXhAH5LI:HMD4hH5LI"hMTlAHtALHLchHLLHEMtMH Ht >yHHLsu_Ht5HE1JH=3w\nkLvH(L[A\A]A^A_]@HuLftf.HHtTHxLsIHt9HLHPHp2re LsPDMH}LuA>HE8HnLqH1LPtLgIHHH1gH=v\tt?jf.LpwH Lm`@Hx H}M}LuiLstLE1sMH=iu\E1i6@HI>DH=1u\liLtH}MMA>ME1L}L@H5kIHCiHu1LLHElLjHuLzrt1@kH}IDkD @AAe/H}kMDLLrHELuILLuHEf1H@DHTLEHHH HTH1|H=s\hLrHE8uMWwHLErWf.U1HAWIAVAUATSHH_HmL IID$HLPhEτuID$H11LP8HAhLAH߉WcHjuZDHOft*t%HoHLVDID$HALP0uIxt3HcoHu>I_ID$8HX1H[A\A]A^A_]fDIuIufHǻSpLIHTHH˄TH1z}uID$H11LP8fUHAWAVIAUAATSHHG@Lg8HHX(HC8HEI|$DLnjI|$ADž~HIc[A\A]A^A_]f.dtDuӃ HC Ht Hs(H}`HC HtHs(1{f ff.UHAWAVIAUAATSHHG@Lg8HHX(HC8HEI|$DLNmI|$ADž~HIc[A\A]A^A_]f. dtDuӃ HC Ht Hs(H}_HC HtHs(1{f ff.UHAWIAVAAUIATSHLg/I}cuPID$@L狐ID$HP0~1I}DLhÅ~HHc[A\A]A^A_]f.I}1%jHff.UHAWIAVAAUIATSHLg/I}buPID$@L狐ID$HP0~1I}DLkÅ~HHc[A\A]A^A_]f.I}1iHMff.UHAUATSHHtnLgMtMILeaHtHmL^Ln^uBu1L+mIEH[A\A]]fDH[A\A]]fD@UHAWAVAUATSHHH_AH1HhHIL0HbHHM$L_E11LHH~jtiI$1HftRH*_H~TLHDHaTLH1AVPHD[A\A]A^A_]fDHE1^H)~TLHfAH}TL"HvfDHtHHtUHh]Ha1ff.fHHO1Ht|UHAVAUI1ATASHHHgH{IaHHA?vD^HMLHHE`tyH]EH[A\A]A^]fH}TLHH~TLH1tH]H1[A\A]A^]1DH|TLBH뮐H|TLHfHtHHtUHyi]@f.HH1H@8Hx+]f.UHHSHH?HHHpHHZ(HPp8p0DH(L@ HCXH]ZDUHHSHH?HpHHZ(HPICH[]fUHSHH?HGxHHX(dHCH[]ff.@UHSHHHwHHHZ(]CH[]ff.fUHSHHHwHHHZ(}CH[]ff.fUHHSHH?HpHHZ(HP)CH[]fUHSHH?HHX(hHCH[]UHSHH?HGxHHX(`H[]UHSHH?HHX(4H[]UHHSHH?HHHpHHZ(HPpCH[]DUHSHHHwHHHZ( CH[]ff.fUHSHHwHHHZ(CH[]ff.UHSHH?HHX(CH[]@UHSHHwHHHZ(^CH[]ff.UHSHHHwHHHZ(CH[]ff.fUHSHHwHHHZ(>CH[]ff.UHSHH?HHX(CH[]@UHSHH?HHX(CH[]@UHSHH?HHX(HCH[]UHSHHHwHHHZ(=HCH[]ff.UHSHHHwHHHZ(HCH[]ff.UHSHH?HHX(4HCH[]UHHSHH?HpHHZ(HP9HCH[]UHSHH?HHX(_CH[]@UHHSHH?HpHW8HHZ(HPfCH[]DUHSHH?HG8HHX( [CH[]UHSHH?HG8HHX(CCH[]UHSHH?HG8HHX(LCH[]UHSHH?HG8HHX(peCH[]UHSHH?HG8HHX(`hCH[]UHSHH?HG8HHX(ECH[]UHHSHH?HHpHW8HHZ(HPUCH[]fUHSHH?HHX(CH[]@UHSHH?HHX(CH[]@UHSHHwHHHZ(=CH[]ff.fUHSHH?HHX({CH[]@UHSHH?HG8HHX(\CH[]Hw HW(UHAWAAVIHuAUAATISHHG@HHX(11L}DLWEąkRIċPv E HC DkHt Hs(H{8QHC HtHs(1Cun}HMLEȺEVuIEąu>1H[A\A]A^A_]Ë}8aEH[A\A]A^A_]fDE1^A$UHAUIATISHhHUHHUHu~EH5^HX(ELEEHMEHEH{8)E~EHEиH E ELM)EHECO1fSu-HSIUHh[A\A]]fCHh[A\A]]H tTI$ADŽ$H0THqTAƄ$I$Hp@S1AƄ$IEHh[A\A]]ff.UHAUIATISHHHX({tLCH{8SLOC$CHSIUH[A\A]]H[A\A]]H!sTHdžH0SHqTAƄ$HppI$R1AƄ$IEH[A\A]]HrTI$ADŽ$H0RHpTAƄ$Hp@fUHAUIATISH8HHUHUHu~EH5^HX(HMECH{8)EM1fSu-SAUH8[A\A]]CH8[A\A]]HqTI$ADŽ$H0QHoTAƄ$I$Hp@Q1AƄ$AEH8[A\A]]ff.UHAUIATISHHHX({tLCH{8S,MC$CSAUH[A\A]]H[A\A]]HqTHdžH0PHnTAƄ$HppI$P1AƄ$AEH[A\A]]HpTI$ADŽ$H0PHqnTAƄ$Hp@fUHAUIATISHHFxHtdHHuHUH5~HX(CH{8K1fSuQHSIUH[A\A]]fDCH[A\A]]H8WIEH1[A\A]]ID$xǀID$xHHoTH0OID$xƀHymTHp@ID$xHtOID$xƀ1IEH[A\A]]UHAUIATISHHFxHHY({tHCH{8SJC CHSIUH[A\A]]H[A\A]]ǀHFxHHnTH0NID$xƀHlTHppID$xHNID$xƀ1IEH[A\A]]fID$xǀID$xHH!nTH01NID$xƀHlTHp@uDUHAUIATISH(HHUHUHu~EH5^HX(ECH{8)E5I1fSu1SAUH([A\A]]CH([A\A]]HimTI$ADŽ$H0`MHIkTAƄ$I$Hp@:M1AƄ$AEH([A\A]]ff.UHAUIATISHHHX({tLCH{8SHC$CSAUH[A\A]]H[A\A]]HlTHdžH0{LHdjTAƄ$HppI$UL1AƄ$AEH[A\A]]HlTI$ADŽ$H0LHiTAƄ$Hp@fUHAUIATISH(HHUHUHu~EH5~HX(ECH{8)EG1fSu1SAUH([A\A]]CH([A\A]]HIkTI$ADŽ$H0@KH)iTAƄ$I$Hp@K1AƄ$AEH([A\A]]ff.UHAUIATISHHHX({tLCH{8SFC$CSAUH[A\A]]H[A\A]]HajTHdžH0[JHDhTAƄ$HppI$5J1AƄ$AEH[A\A]]HiTI$ADŽ$H0IHgTAƄ$Hp@fUHAUIATISH8HHUHUHu~EH5HX(HMECH{8)ED1fSu-SAUH8[A\A]]CH8[A\A]]H)iTI$ADŽ$H0 IH gTAƄ$I$Hp@H1AƄ$AEH8[A\A]]ff.UHAUIATISHHHX({tLCH{8SlDC$CSAUH[A\A]]H[A\A]]HAhTHdžH0;HH$fTAƄ$HppI$H1AƄ$AEH[A\A]]HgTI$ADŽ$H0GHeTAƄ$Hp@fUHAUIATHUISHHHuH5HX(CH{8B1fSu2HSIUH[A\A]]CH[A\A]]HgTI$ADŽ$H0GHdTAƄ$I$Hp@F1AƄ$IEH[A\A]]ff.UHAUIATISHHHX({tLCH{8S\BC$CHSIUH[A\A]]H[A\A]]H1fTHdžH0+FHdTAƄ$HppI$F1AƄ$IEH[A\A]]HeTI$ADŽ$H0EHcTAƄ$Hp@fUHATSHHHteHGxHt\HH}HUH5L`(AD$I|$8@1fAT$u1fSuH[A\]fDCH[A\]ÐHcTI$ADŽ$H0BH`TAƄ$I$Hp@B1AƄ$H[A\]ff.UHATISHHX({t5CH{8sU>C Cuw[A\]f[A\]fHAbTHLJH0;BH$`TAƄ$HppI$B[1AƄ$A\]DHaTI$ADŽ$H0AH_TAƄ$Hp@fUHSHHHtH?t $u H1H[]ff.@UHSHHuH߉EEH[]fDUHAUIATISHHHUHUHHu~EH5LEHX(EHM)E~EH{8E)EC`<1fSu,SAUHH[A\A]]ÐCHH[A\A]]H`TI$ADŽ$H0@Hy^TAƄ$I$Hp@j@1AƄ$AEHH[A\A]]ff.@UHAUIATISHHHX({tLCH{8S;C$CSAUH[A\A]]H[A\A]]H_THdžH0?H]TAƄ$HppI$?1AƄ$AEH[A\A]]f.HA_TI$ADŽ$H08?H!]TAƄ$Hp@fUHAUIATISH(HHUHUHu~EH5HX(ECH{8)EE:1fSu1SAUH([A\A]]CH([A\A]]Hy^TI$ADŽ$H0p>HY\TAƄ$I$Hp@J>1AƄ$AEH([A\A]]ff.UHAUIATISHHHX({tLCH{8S9C$CSAUH[A\A]]H[A\A]]H]THdžH0=Ht[TAƄ$HppI$e=1AƄ$AEH[A\A]]H!]TI$ADŽ$H0=H[TAƄ$Hp@fUHAUIATISHHHuH5+UHUHX(CH{8381fSu/SAUH[A\A]]DCH[A\A]]Hi\TI$ADŽ$H0`THp@ID$8H ID$8ƀ1AEH8[A\A]]UHAUIATISHHF8HHY({tHCH{8SXC CSAUH[A\A]]@H[A\A]]ǀHF8HH@TH0' ID$8ƀH>THppID$8HID$8ƀ1AEH[A\A]]fID$8ǀID$8HH?TH0ID$8ƀH~=THp@uDUHAUIATISHHF8HtdHHuHUH5HX(CH{81fSuQSAUH[A\A]]CH[A\A]]H!AEH1[A\A]]ID$8ǀID$8HH>TH0ID$8ƀHZLuLMDE4HpĀ  AE0MhHuLLM+fDHAlH$ t AD$DHD[A\A]A^A_]I|$HTDHTLIHH1fDHx@HgHYHKH =80Ax@;DH8HHp@FAxuIuI$HTLHHHTH1LAI\$IcHG-I\$wfAHCXMoAGHCXHAGHCXHAG9fDAMhIt$(HpHt$LHkt(HHtyq@FшHL)LHHFu#HCEAŅuLCH|TLDHH\THH1bDID$ HpDHx@HwHiH[H M8TBfDID$ LHp"DLhfHBpHBhHH@hAGHH@hHAGHH@hHAGHH@hHAGfHCLLIDLsCfDL[CI|$(Lh=HHpf.LLHL)DuKHSCu?H;跫f.McHuLLIVfD+HdTL͖DHfDH1ɾAH)TH17LI\$D膶LhHHIEHdHhHH HhG;hHLHԇHIEHh+H HhHG0HtHG8HG0G@@UHAUATISHHG@Lou 11uZLEH¸H9tESLIM I $Ht1@t*@tC@H[A\A]]1@HBI $ܸ@UHAVAUATSHH HwdH%(HE1DEudA LLHx11HSuAuEuc1HMdH3 %(H [A\A]A^]fDHHƗ?HHFfGFGEgHSHHHHHHMHH)HH)ƉHƂEUHAUATISHH8dH%(HE1HtXLLmHtI$:11HSHMdH3 %(H8[A\A]]DHu1xϸuLmI$L?I$AƄ$:~LefLEL)EEYLHSRHG tu-HNfDH9fff.@HGH8@UHAWIAVAUAATISHxHpHpLxtZHHt HZHuZHpt;HpLHALJIHuWHpL5cTGH<HKHDغHL諃IH?HpALJt#HpHDELEHDmHpH L}Hh~hHhHHEIHEhE)E~xLxLexHxEDILuHtHPHtHBAusAtA tUt[tW8sHU1LEA}HMLE̺xgDuEDDHHD[A\A]A^A_]f.Hx11cAL$$ULHu近Af.AF@D3AHH?HѺMbUHH )HciHE~E)iHcHME)Et01t ?HMA?HMAf.Ht;H~iABD$1Hu fiDf.UHAWAVAUATSHdH%(HE1HIHHIHHM|$L{@Et$Ds EA<S$S, S(1PH;EuAtDAEH;HtHDHMdH3 %(H[A\A]A^A_]fD1ҾAAEM|$LrIHkHPHELHHxH1HDžRLH)lHfPA?@kLLnHHQ LsPMgI|$MD$HTDHTHJH1AEufLKPMHTTI|$LI1ɾH1AѸL{PMTI|$1ɾDHTH1AEu(HCfDHDž1HDžEL$fHP  HL E1H)P)`ZfH) H(ID$)0HH)@H[HDžHH HG1DH+DH9qID$ѥHHHH1gA A҉u1DlH+DH~LSPMHtSI|$HHH7TLHH1AEuXHs81i@HjIwLHxLAPH HHH4f1DH+DH9|hDE~HHHI<$ AA҉u1D%H+DH~LSPMt(HSI|$M$HH(HTH1AHH EufS$H 11ҾH! H DGLM7A}tDsDA~AV DAvDAEnHHIHtH@(Ht xQAVIvH_AE#HC@HHtH@(Htxu#11HDDHDHDHt vDEuA%EL{PM\HSI|$DHSHJM$H1AEu#fQHqHHA}HI(HuщAEDMv(M; H1HHP0AF1INHC@HHH@(HXK$HH'AIH@(H@0PLsPMVI|$HSDHSHJ H1AEu A}DDAUfUHSHHu1ҸCȃw5D{ CKsHH1HtH[]@?9GfDC H[]ff.fUHSHHWOH;W trщsHH[]wH0HtSKHS Sf.UHSHHO;O t$WσKH;1H[]DHu_HHtSHufD͐W1tHWWHfDUHAVAUIATASGHwH?9w(9S vBD)H15AD$sH;CDLL1[A\A]A^]K1AHHtHsDs CffH֋W9wvH7HuD1HfDHHt0UHSHHH$HHCH[]fDWGW)ΉHHH:f.HHtHUHATASWDEgD9g u [A\]fDDwHHDc H[A\]ff.D1H9s3y*v%w(HWH9rG<@D1DwHOH9rwN?wO?w@wtɸf1H9s8y2v-w0HWH9rG<@1@1Dw3HOH9rwN?wO?w@wtƸÐwHOH9rwN?wO?wO?wxu @vP_1XwH)H~WJ>v_]vDf.1Yff.PvP 1v f.H)1H~WJ>vلyv1G<v @vf.f._1@^@_]v!t1Dff.P_1Vw%H)H~Gv}ff.1@~øf.f.@_]v!t1Dff.1Df.f.f.v"1vv v21v(vv1H)1H~?yGv@y@u01@ f1@}H)1H~WvMtHWJ>vD|?H~30 w+Gvلyv1=wKH 'RHHH|1t%w H5mpHHcH|H*Rf.HHt9uÐ1||||빐UHAWAVL4NAUL, ATSHHuL90IHI!IT$L9wxA$HIL9svBAU8A>v5@uYfIGL9A?IIL9vUA}4wA>@]@ @ tm@u0IGI9}IA\AIL9wLH+EAH[A\A]A^A_]D@'t@\t@"ZrfnfLI9s.AHH[A\A]A^A_]@ZNfDIVpI9IWI9901HDAoAHH9uAA)M L9AEBAAABAAABAAABAAABAAAtyBAAAtkBAAAt]BAAAtOB AA A tAB AA A t3B AA A t%B AA A tB AA A t BAAHGII1 f.HAAHPH9uI1ff.@U1H52HAVAUATSHtT8IHtBL-ISI}Ht2I] E1f;t Lt'H(H{AHu[H6jA\A]A^]fDK[A\IDA]A^]fDUH5z.HATISZt^LH=iGH0$RHiLD HHtH{LuH[A\]fD1H[A\]fDIff.UHHE_H]ftH}u?DHMHHDAvAuHfDMHX[A\A]A^A_]@HED+HCUHAWAVAUATSHH_uHH[A\A]A^A_]@G IILEHG0H3HuL1ЋuHAT$@MDAD!9w ʃ!HLL9juf.HڃjHIL9kuAD$DpAD$ Et$A9sAD$ AD$HIL)LuMHEHL91ID$0I~HDEHu1ЋuDEHDEAT$@AT$ DEAÍBD!A9D$wBD!HMHL9ID$0IzHND]Hu1DELUHMЋuHMLUDEHD]D]DELUHMAT$@At$ A|$HMLUVDED]!9wV!HI4I9AoHHHAoA f.HI9uEI|$CIT$81HELEHH[A\A]A^A_]w?uLnЉUHLHpHs03HNDAt$A$uHf@At$A$uH@DwD!9w UD!A!D9w uDFA!A9t?AoEA:@HI9uE:ADAoHHD9tAo&Lu#IHI70A9uMH1UHAWIAVAUATISH8G LoEGEHG@uOHЋMQA։UA!D9uw !AID$0H2HuL1ЋuHAT$@DUA!D9UwDUAAA!1E91f.D3HADHLL9{uAD$H{H}HEID$0IO|IHDUHu1ЋuDUHDUAT$@DeDUA!D9ew UDbA!E9AoIKD%D E9uD0HEAIG1H8[A\A]A^A_]@At$A<$uL@H8[A\A]A^A_]@At$A$uHF@AHEHC1E7H8[A\A]A^A_]AHLo H@19wvHHwHFf.UHAWAVAUIATASHHHMHOHHOƇIIEIII)t@H;LLriHƃAƃHL[A\A]A^A_]}uH{HsHD7C`Cdt'D7D7T7IEH{HsHD7L47D7AD$LEM9eICEHH9sPvEM'H;sXr0L1ɾAHSƃIx@H1APPLIIvHtHCHCLsPIHCHLsIƃAE1ff.@UHSHAVAAUIATSL HL"HCHHHSLLcPƃL9"HC L+IHSLcE1HKXHHCxHC`SlHC HCƃƃƃƃHC0HCHǃMt#Hs(LcL1Ҿ/dL'b[DA\A]A^]ff.UHSHHH۾HCH[]ff.HuHGHG`HGfUHAVAUATSHHXdH%(HE1IIIƇIL9wLHL9LLI}HH)bgHصHpdD AƅHD薸MU1EHSIؾIz@H1ARPAAƅ;HMdH3 %(>HĐ[A\A]A^]HzǾHHL@LLLyHhHXLHuHhHLXCIXSKfLIHLXI܈CAEdPCAUdL9@AtLƼAƅ1HSME1ɾHIx@1APPAƅAƅLh111-萻H1uAUHSHHHwHWH9tH)HSHStSdS`H[]fff.@UHAVAUIATISHHH{Pv LsI)M9sPH9{t7LLĸHsHSHH)LHCMM)HCuIL9cPryH{LLzLc1[A\A]A^]LHu4IIIwHAH+CI)I[A\A]A^]fLLHBDUHAWAVLuAUIATISHHdH%(HE1HfDEH{fEċC`PEHCPS`H=#HAH+SI)I H9{LLGHsHSHH)LqH{HCPK4>L)H{H9Aхt1DDD9rHSLHIIILLHfDeHEƋC`PEljS`zunMtnLLHcVfL{I)IL:fLH9'Hg7HMdH3 %(uH[A\A]A^A_]UHAWIAVAUATISHYH8DEdH%(HE1@uHHEAAHEDAIEfEAG`PEAW`MWI)M9I9HuLLUAIwIWLLUH)LgLUufHEM)ANIGIGIw$LEIII}LLLEtɻHMdH3 %(SH8[A\A]A^A_]IPEHAI+GI)M9 LELEM9wPr^ILL?MwLLLlHMAAHjIݺ8LLL"t fHEIͺHEf]1HA]u AG`HAO`HuLEÅMtLLLb}L1gUHAWAVIAUATSH(Lo01M0HEEILeHELH)HIvH<GAGDDALUEIBH9rd}HCII-IFMMn@I)JT8MN0HCIV L)H AH([A\A]A^A_]@MuSMnHLLLHEH9HUIvHLLIvm[LmE1I~M)L)LJ4?"HG@HWHL)Iň HCMJT>Mn@I)L)}IV MN0+HHI輸LULIEMTI~M)LJ4?舸<LmLDMfHH=t0MfMf H9AH([A\A]A^A_]fDL1IFHHLLHIFHH=tغMfHMfH9t@H덐HSMAƆ1ɾHIx@1APPH([A\A]A^A_]Mf H@Hu DHG`@AAHRt$9t"HPH1HH9t u1@HcHHff.UHHtHo\H1]@]fUHAVAUL-qRATAUStNII]E1f.HHCAt)H3L&uMc[KA\IDA]A^]D[1A\A]A^]ff.fUHwHtHKo\H1]@]fUHATL%s[SI$Ht9H8Ht@賱I$H<HHu[HA\]閱fD[A\]ff.U8HAUATSH购L%[HI$HHHHjHHHsLkHHHsLkHHHsLkHHHs Lk Ht_H_Hs(Lk(Ht:Hǹ;11rHH[A\A]]@IDH= i茶IEH3HHh H€HsHSH H€HsHSH H€twHsHSH H€tRHs HS Hi H€t-Hs(HS(HDHǹ DH=h蜯IHI$H;H#LH{HCHLǰH{HCHL覰lH{HCHL腰KH{ HC HLd*H{(HC(HtLGf.H=@g贮IHI$HH[A\A]]fDHHH=faHfHLEHHHA?wDHt8uRff.H ff.UHAWAVAUATSHHxHxHH5H`dH%(HE1HH~HHHHHHDž)HtUHHhHtB1H5G7IHu7H}dH3<%(KHx[A\A]A^A_]HHhƅE1E1L@LL9HZHLHIHDQ tHHHDQ uEu<"t<'tL-[HL=nIEN 0MtEAWL`1j/HߢH^_II0uH=_"HtKH mnHIQL_Hj/1yH|ZYDHUdH3%(He[A\A]A^A_]DHHH|AIHmIHPL_Hj/1ܡHߪAXAY1`HHH?fDHHHA謤f.fH [HbSHPf.HjIHHG?HGHHHH)HHHHHH)H)LHLH7H)HHHHHH)I)LGfHLG1HwH@LHID!HH1HHWHxfH*^GÐHȃfHH H*X^GÐUHHH9s|AqV4AA5W0Pf< t.< t*LMÃ?ILIHLI1LHL1IHH9uAALMLE~EE]fDHEqV4HE5W0P~EE]f.LL9HFLWH9AL9A HBH9L9AD AHAHI1Ioo fHL9uHHHHHH9Z2HFI9FF2BGHFI9/F2BGHFI9F2BGHFI9F2BGHFI9F2BGHFI9F2BGHFI9F2BGHFI9F2BGHF I9F 2B G HF I9v{F 2B G HF I9vhF 2B G HF I9vUF 2B G HF I9vBF 2B G HFI9v/F2BGfD1fDDD2DHH9uÐUHAWIAVL@AUIATISH`HHdH%(HE1LƛLHL HHL&H^LHnHLH;LHKLH;HLLLL=HEdH3%(uHĸ[A\A]A^A_]UHATIHSHHH}HH8LMLELH eH1cH[A\]f.UHAVIAUATSH@Ht:HuAH@L[A\A]A^]DHIMniHH}LLH}LeHUHuH3UH3uLLY(e(-(f(fTf.v3H,f5i(fUH*f(f(fT\fVXdH,CI9uLYd G(=(f(fTf.w1,A0A0FA0FA0FA0FA0FA0FA0FMfDH,f%'fUH*f(f(fT\fVf.UHHPdH%(HE1B"HFIHEHLcLc1IL])A:HLjUHIHIHƉ)@A:HAHuDIIACIPBuHudH34%(LurDB$"wHHFHxIHN0If@HV-HHHIfE1L]LcL c4МUHAWAVAUATSH0H8focoovon fofoof0OfffoDW fqfqf͋fgfofgDffqAfqfgfofgfofEffqAfqfg扽@EfgfofDLffqfDoDDfgfqf҉HfgfofD`DPf`fDofofD`fhfhfhf`fhfoffEofafDafEofArfrfDafAfDofifDafDififArfrfDifArfrfEfAfAfAfA~)}Deff~)mfofoA9yZfafafrfrfoffofiʉD1fafiD1D!D}D!fiD1frfa1frfrfiCyZE4yZfrfffщff)mf~fA~D)EA1ADA!D1A1ADEDDmA!A1Duf~EGyZEAAEDyZ1!1A>yZDEADAA1E!AA1AA}yZD1!1DϋM1yZD1D!AD1FyZΉΉD1!1DAADDUEyZD1!D1DAADDUGyZAA1A!A1EAAEDUE:yZ1!1DEADE3yZ1AD!A1ADDD]E yZAD1!1DAE1DD]A1D3MEyZDAA1A!D1DDD]GyZAAA1AA!A1EDUEEE9yZ1!1DEADEE1D3MD3MAEE1yZ1A13E3ED!E1D3UA1AED1DAD|ADeDE yZD1!1DAADEEE1D3MA1E1AEyZDA!AD1DDAA1FnEAA1EAA1AEEDEA1EE1D3EAE1AA8nA}EDmA1D1AA1D1EE7nE1AAuAEDmD3mD1A1E1E1AnADA͋M1DD1D1D1ADE1AnD1ADD1AAԋU3U3|1FnDEADD]D3]E1A1ADlG;nEE1E1EAAAED]D3]E1A1ADhG3nEE1A1EEAED]D3]A1A1AD]G+nEA1E1AEEAED]D3]E1D3lADdG#nAE1E1EEAEAD]D3]A1D3hAD]EnDD1D1AADDD|D3]A1D3]AD]G;nEE1E1AEAAED}E1A1D3dAD}G7nEE1A1EEAED|E1A1D3}A1E1AD3lD3U1D|G/nEAA1Dx3EG"nE1AAD3hEEE1D3MAE1A3|EEAnEAEEAEEEE1E1AADADADA1A1ED3dD1A1D3xA3}1AD1Dt3uGn3tDG8nADEA؉pE1E1AEAAEDnDD1FnD1DD1AމD1DADhދlE!D13|13MD13]D1A׍ܼlF ܼD !D DxAɉD!A1D3pAɉD! DÉhBܼdEA A1DEAEA!!E1D3lD AEAAAD]D D3]D3t!DdA:ܼE1D!A D`DA3ܼDEA! D!EA ADAAA3]E!Ë]3|D13hBܼAuE A!E D]D3]DE1ED3dAAAAܼD DA!D! DƋp13`|BܼEȉ\UE DEE!!D A3xA3lA3UDAD1AA8ܼDXDxD D3tD3hD3\D!D! Љ‰؉D1!D1؉lj D!ȉ}Bܼ DljE1B ܼAAA DAA!!D AADAdA A!D13XAtADeA4ܼAD1A!E ADAAA`13uƍܼىTD AȉD!A!A DDAȋpAD3lD13MD1A΍ܼDD D13UDAA!D!Aŋp DD1DD C%ܼDhDAD!! ΉƋ\13TD!MܼlD D! D1ȉX1D1B ܼA|dA DAA1A!D!D3}D AE1AADAGܼA DAA!!D AAADADED`E1E1D3EAA 3]E1DxA8ܼAA!A!E DAAA}1߉3| A؉Í7ܼ!A!ȉtA DDA؋]ATD1D\D1D1㉵pbʉ1D1ADD13xD3eƉubʉD1ΉDD1A׉D11DDXD1D13tbʉlDƉD13|3UƋEAӋUD13phBbEA1DA1ADAA3UA1CbDdDxEAA1AAĉTD13lEAAA bʉDM1ADA1AAD1A1ȉD3h1AAA8bDً}E1AAD13tA3dD1ፄ7bAʋpME1D1AD3uA1D3uD1lAbDD1D1ED3|D1AD1DE11E1EAB!bE1AƉA1ABbD]ADE1D3tAŋhD1EA11ED|D3xFbE1D3dAEEA1AAEAGbE1E1AEEAEDUE1A1AEbDD1D1DEADADxD3pE1A1AG0bEE1E1AEAAEEDtD3MD1EA1AAC+bEE1A1Ap3l1EE}A1A1AE1AC"bDhADD1A1l3dD11Eȋ}D1AAbʉD1D11D1AA1bDAD1DډD1AڋPBbʉLDEE1A1AH8AD0PHDDD@HDH DhH0[A\A]A^A_]ff.foOGHG@UHAWIAVAUI4ATS@HG1?Aw@AGЃ)AAGMtI9v HLL[A\A]A^A_]釆tAEAMwLHULMMȸHU)H9w AKt%LHUdHUȍC[@H9rIH)Zf.IEI~MHIKD%KD&I)M)AAAdA1ƃM1L7D9rGML)AEACD%CD&&CD%fCD&ff.UHATISHHdH%(HE1HFHHEF?7#8)HH5S HHuH{HA$AD$AD$AD$CAD$CAD$CAD$CAD$C AD$C AD$ CAD$ CAD$ CAD$ CAD$ C AD$C AD$CAD$CAD$CAD$CAD$1HHCTH)K\HHEdH3%(uH[A\]x)f.Dff.@HGHHG@UHAVAUATISHI$HIHLm߻I$0ADHHt ID$@tADHHuAAo #AofAF&1fo MAofAF*foMAF!! ftftAF,$"ftAF: fAN>AF@ffo LAF\fAV_fAF|AAo^ftfAof fAAo^ ftftfAof0fA Ao^0ftftfAof@fA0Ao^@ftftfAofPfA@Ao^PftftffAPAo^`Aof`AoAFXftftAFBfAofpfA`Ao^pftAFxftfAofApftAoftfAofAftAoftfAofAftAoftfAofAftAoftfAofAftAoftfAofAftAoftfAofAftftAoftftffffAAAFbAFN AFn H[A\A]A^]DCHULLEI$jID$@<ADH[A\A]A^]ff.fDH=C\HHP8HC\H8f.UHAWAVAUATIH@SHH(HLpHtDpI~H([A\A]A^A_]@HB\HL8LIHtL=-SLHHHH5A\LI6HHH1HLƅIHXIH]HLLHIHXHHH=L;uTHLLuL@LL11H5F!LxIHǺ%H5NFH1LHƉIIHH(H5E HSHIH(fILLL'HELHLꋽ:HLHtHIDILUHHEff.fUHHHHU~EHEHEHEHS~EHRHHH]@UHSHHH[H0Ht%;HHH]1IIfH=Ett(E1H EH1H H5DN@H5DH=DyuHLP L DHjLH DH5DXZbff.fU@1HATSHH[dH%(HE1HL?Vy@1H=[CyHE1H5jH YVA@jH58=\jPHV>\j8u8H01f.H;HtH@ttHHL9uH LHLIlLHHIndex.xmfP1HHEdH3%(u He[A\]Y|fHׅ[HH<ЁO H=b<\<ff.fUH[HHATL%9<\SHH<ЁO L<u [A\]HSHsL:o@C[A\]fUHAWAVAUATSHLw M2D/HE;AL5[DM$MMt$MtL{LL}.C D9kaD9kGA D$ AD$ SA$H{0Ht,ID$0H^H{Ht I|$QH{ Ht)HC(Hp>ID$ H HC(ID$(fHC 1HC(HCXHC8H[A\A]A^A_]f1H[A\A]A^A_]L%[M$@IM9tI$HtHp HtH=VVLHP@uI$D(D+EtAwjC D C DA$H{Ht I|$H{ Ht)HC(HpID$ HHC(ID$(H{0HtID$0HH{@Ht-ID$@HLNH{HHt~ID$HH`H{PHtXID$PH:H{XHt2ID$XHH{hHt ID$hHH{8HtID$8HAƄ$H=fA$LCAD$ LA€ATEHgWHI$HI$wA$H "I$HI$A$A$A$AD$ A$LPE H HMWHHI$HI$wA$ LHI$HI$A$A$A$AD$ HA@A$ID$@(H[A\A]A^A_]@1lIċM$MtI|$L1I$IDŽ$HH)HD+DA$_1MLD'1HCHp]ID$H?HCID$"H=3L€IH= L€*H=uL€2EUH51WHHI$HI$wA$ LHI$HI$A$A$A$AD$ HF@A$ID$@ AL$ %DHCHpID$HHCID$f.HILW@H2WH 6JWH=L€u$EuOHjVHWH5W0WH=L€u!EHWH{VEHRI$H,RA<$ADŽ$I$HI$I|$I|$ I|$@I|$PI|$HI|$hI|$XutBAD$ Eu$HRNH"VHvR6HjR*I|$8uPW1wH<|[H<ÐHG[HfH|[HH@8ff.H=2\[j.f.UHAWIH5AVAUIH=[ATSHXdH%(HE1wH{[IL@ @IM9tWI$HtHp HtH=NVLHP@uI$t#HMdH3 %(HX[A\A]A^A_]ÐH58L,sux1LeME@AH8LL@3越 @HL9t7HHtHp HtH=MVLHP@uHQ@1Fq@UHAWAVAUATASHdH%(HE1Hcz[JHtC t4Hm[JHUdH3%(HH[A\A]A^A_]Hy6\IIHx(yHsC uH{@,H{P!H{HH{h H{XHHHtLHЄHHHtLHЄK H[J f.1H5\Hx(HjH=5\mfLL{LL&L1H6HL1ɎLLLLLC @1QfHCH x[HL@DHL9HHtHpHt@ tH=KVHHHP@HuHC w9oH #x[HH[B QH{PcH{HKH{@3H{h%HRhHShHISH`L{8MH=C5LMW]LL]hHI(LL9L)LLֹ!LHIsLBƄ=H<d;\Hw[HHF@ t1L~u.HI$E1HLH 1IeHRLH0FI<$uHH3HAHh1ZHGR4H=nHMEff.@UHAUIATSHHRH=[H MI}tlMH3 IFI|$H3EI<$uL%L[I<$u.3H3 IFI}H3EH3I<$EI}uHH=[A\A]]bIfUHSH]HhdH%(HE1HHHDKOHH!d1HRHMdH3 %(uHh[]DUHHHHEHMLEHEPPEÐUHLM~ELMLU L](E0LNPEfoaFMt@LU~EAH(L]FH%HN@1EF0HE] LQff.@UHAUATSHHHGt;HW`HGHt*Lo(HMd fDHS`II}M9wHC`H{( HCH[A\A]]fUHAUATSHHHGt;HW`HGHt*Lo(HMd fDHS`II}M9wC0HCH[A\A]]UHAWAVAUIATSH8HOHULEHHGIHP!H9wHA!AHEHELf.I9tlEt(IFKHP!I9VH!A9D;E1ADINPHI^(H{HtVHuHUHMuI~hE1IHMHPtHED8HCH8[A\A]A^A_]DIVI6HUH묍P!A9bHEH81[A\A]A^A_]DUHHLEff.fUHAVIAUIATISHHGXHuHWH{hLMLLH߉[A\A]A^]HUHHHMff.fUHHAWIAVAUIATSH8Lw(HMHuE$AHLmEILmLmDDID$PHLH{HHuHUHI|$hE1ILHPEHED HCH8[A\A]A^A_]DHEHE&fDHuHUHI9t3D#AtVDIOPHLH{HuIWI7HUHI9uIhE1MHMLHPdD#AuHEH81[A\A]A^A_]D;AfIT$I4$HUH1DUHAWAVAUATIHSHXID$PHuH'HuHUII|$hLAT$XEAD$ t-HMȉLL\HtHX[A\A]A^A_]I|$(HtIt$M\$AMT$(ILIL)HHMH1I9:LnID#mM9wH#uHI<2H9xoIL$WI\$LALKA!M9wHL)!HHI H9DHHfDHI 9uHEHGEGID$HP1IT$I;T$HIT$HX[A\A]A^A_]fDIt$M\$LnLL!I9[HHD!H;UMHWHUH}DEL9teHI<DOMȅtMu$HuL]HL^D]D^DGHwH}DEHuL9uʃuHuH}H~}~ uHMHKMKIt$M\$Lnt;uHuH HsusDGH_DEH]H@H_DEH]HHVD!HwHuHHEHDM@IT$IM,$HUDUHAWAVAUATSH8LMuH8[A\A]A^A_]fHGPIHLwLg(HHu1LHUHH{hSXIv!I9LH!HI L9iu|fHlHIL9huH{LKHIIH{IL]OL9HUL9AxHSL[LzHIH}L!I9oHH!HHHMLH9WOI!IM9wHD!HM<L9oHMHAoHf.HI9uu0H{(2HS`1HbELEH8[A\A]A^A_]HWH7HULjDLKAV!mDL}ISI!L9MIAE!H!H9wIAE!E9AoEf.HI9uE fDJ!Ao  H{HWH{IHSIHLUOH9sH{HEHȃ ЉUHLoHMHM9GAo(HU(HfDHI409ueE~E!fUHAWAVAUIATISH8HGPHUHMHHuLHUHI|$hHAT$XEAD$ #H}I\$(Mt$E|$ID$XlHUI|$hHuMVD!I9LH!ЋUD!I9aLH#}E1fD2IЃHHHL9ju9DMJEIIIH9gA@A!M9wIAA!D9AoDIJ3D0D9u0EAA@1MhH8[A\A]A^A_]L}HMHډMLIHI9u'HULHLHI9tH8[A\A]A^A_]@I|$H}f.HWHHUH.DA~#}@AV!uDALjEB1A0fADL IIIAo H9u6H9tMMhEAA@1=EB1(HLDL\1H9wv HHw(HFff.t HHG(HPff.HGtyUHAWIAVIAUIATD`SI1IHfDHI9t/IG(LH|AՄtH[A\A]A^A_]H1[A\A]A^A_]1f.fHOt%Hf/HDHuHAH)fD1ff.fUHкHSHHHt H)H=HNHSH9tP/tt /HfPH[]ff.UHAVIAUIHATSHDHLHIr[L)ILA\A]A^]U/HATIS 4.HHIDH.Ht[A\]H[A\]Rff.U/HATIS3.HHIDH3Ht[A\]H[A\]LRf.ftVHfDH u-H tuHH)f tHufDHHff.UHAWAVIAUIATLSLDHHHHHdH%(HE1`M|Ht MH1Lu=.L-Ht+L)u+LH=IH1(fDLHH=-LL1H! t€DHqHDΉ@HLL)HHw I@TL<LLH=HFP 0H]dH3%(LrHH[A\A]A^A_]ÀLχLLLLIPH1LXLHHL)LHcH)PTLL:VLLE7=1LL3.fDM9t{LLL!0LLHLOHH]/E1HLH./1LHA@LLLLL-LIU0UfHHvquDHH5\H e HDH5 HMH ~EHEHMEHуv)H]Du@tHg[HHHH]fDHHHf@LH[HHHff.UHAUIATISHHH{('8H2HHL9Lk0DH{`7HL2HHt L9s0HuHt L9sHǃHH{(HH+H1[A\A]]Lk0u&H[A\A]]H{`v7HL 2HHt L9suHtL9r{HHuiH{h&fDxLchL-DH6HL1u@HYNSH` HDNSHpfUHAWAVIAUIATSHHxH9w0t1HMSALUMEHHXILUDLLxAHpLxHIOHpL1DLxLLxHHdMSMAdžEHHXDLIIHuhLHLDHuI1Hx[A\A]A^A_]fDAdžHx[A\A]A^A_]fAfHLSLǹHLpHHLHLDvLpHHxHiLSHDLHHx6DHALSL`L1LhH2HL1DHpաLh1HxHKSLHHxL`Zff.@UHAWAVIAUATISH(L/LmmEątEH([A\A]A^A_]@I$M$L)u5DHz0HU$HUHz(HHM'L)tHuI9$LIMF$ ILL'IALJLIHEII$Hz`HXHJSHUHxHU;HJSH`HU=UHAWIAVIAUATSHHLgL+g L'M AL)L9vcE1HL)胻ItHCL)I9LGMM ǃM~C L#1flCL9cHǃHĈ[A\A]A^A_]@HISDH}HDXIH11LD2HHǃHH9DǀHH9uDHHt"H9tǀHH9uHH}L HSDL`HxHC LhDHXIDpXDpLhHIL`HxHXLDLppLpHHs I9aHLx~xHxL#xHx~xflfCMt LL$1'DLL GSDH}%HXL)DHxHL`HpIDhXDhL`HI6HpHxDLmIL9xt1IǃDDDcfL+XMMME1D)HLLpHx#HxHs L#LpDHx~xǃflCfDL#HQFSLϹs1LpHIH11LDLp1HxH FSLHHxfILLPLLhHLpD`D`HxLHXD蹕LpLhHHxLPHɸLEIHpLLLxLxHpDILLhDPH HxDPHpLHxDHpLhIL`t?HHDxILpLLpMHHEI"HHEff.fUHAWAVAUATSHHHxHDžhH`HHEIIHPDHH)%N,AtIFL)I9LGMXLLAVHCSAHHXtLHPIHN11LPHHoCSAHHXIHPHpIN HXIH!HpHXL1HIF HH HEI9IFHCHpEH`AM>IFLHMAI`AHaI0I(H3LIv HpIvAdžL9LxIGLHHhHI^HxI)MNM+N MILMρJ!II)L9H)HL%I)Mf.H`AHI^HIv IH)HCHpIF 1HDžpIF1p@HIASH`H1ASHx1HĘ[A\A]A^A_]@HASLǹLLHHHHXLHpHpLHHÃuYHHEH@SLHLhYLIvAdž@HIDf.H9@SLǹ1LXH1H11LڕLX1HpH?SLHHp[IAH{`Hu$H{0H{(Hu$HvH?SHxH{?SH`UHGPHAWAVAUIATISHHxHxHp'HP`!I]MI+] I]I9]Iu8M}@HxI)M9LIFHHhIu8HhHIu8I)MI} HxI)LIU HxIE@I}xIUHLIUIE8I]M}HHp1MHĘ[A\A]A^A_]@HQ>SEL}LHDXIH11HDH-Hڸ MADžH)L9IMUH)I)I9LGM$E1MI}xHI}PIu I]LHxJ6J >Hp~pHppAE11f.E)EpLEL%H)DHhIH`H=SHXIHH`HhDHxHMHxHI)H9h1IELLPHhIE DDXH`H`@EHC L#ǃHC@HCHC(HC9fHS@H+S(HHSHw@HH)HI9AAuLI)HCLHK@@t?H"baDAI)LHKL5(SDDxH}IDXDxHI1ɺ1DDx{~DxHCA@HHW0LJHWHHW1҃Hw+IDlL1LpH/1ɺ1D}LpI1HxLHxDl5fUHAWAVAUATSHHHHH;GH@LcHIII)L_Lc@HnAƅu_M)tDML;LHLH3ALH)IEuMtH{@L)LLLk@HD[A\A]A^A_]@AAI׆A$ǃDUIHAWIAVAUATISHHxL/I9H&SLHHpDHILxHXI9YA)H}DLxLpHInLLLDLxtLx1HtǃMMM)L+1H{ LsHI)MM9MLL)M)HM9s+LLΉxHS xLH;S@v~HS@xLLΉhLpLxaLpK'LxL)hMLC L;C@IvLC@Mt$LLH߉xyxEHx[A\A]A^A_]H}DLxLpHHLLLDsH$SL߹vLLhHHLLDLpLxLHsLhHHxH{$SIDLHHxLp)HI$SLsHHGHLLDLpLxLrHHHxH#SLEHLHxUHAUATISHHH9H{(a HDhDIDŽ$L9t&H{(HHEtDH[A\A]]ÐHHH{hH{`HH{0QHLchHLLc0 H{`HuwL H{(HtH"SHPHHC(HH[A\A]]'Hǃ!vHy"SH`Ha"SHPhHC`ofDHA"SHpH)"SHxH"SHPhHǃff.UHAWIAVAULoPATISHHxHx LI@MwHI)I9r?HLtIxI_@HL1Hx[A\A]A^A_]f.LLML)/Mw@1LAHwI@f.IIH}EAHHxH SDDpHXDpHIHxLLD貇HuUL)MMwnfDIxHLfHy SH`IxHLALJfDH1 SLLLpDl;H!HDlLLHxD܆LpHHxHSIDLHHxHSH`HSH`.ftHG@H H9OHr Hu1ÐcUHATISHH Lc@1[A\]UHAUATE1SHHHt-HLJu_H{ vbHCHC tMHǃDǃHCHHǃH[A\A]]A뒐H{xLkPHtH|SHPHHCxL@UHAWAVLIAUATSH8dH%(HE1..ƅ/fAGZLH^MLHHHSQtz/uH/L)HvFHHA?f9xH~H/Ht.ux/uHHHHuA<$f9uLIt@L)HLLHHudH34%(H8[A\A]A^A_]H/wHH!f.Aw@8p=L9PL@~.ubM9t Ax/"H=[1ҾL(QtLIHI@H5Ɍ[Lx/L@M9A8/tqL @9/tkHL9sy~tuHARID$LEfDM9tx/uHf[H2HLbP/tjL@LDy~tAf9uAG8AuIxL#H/H@@1LHfM96LEL@PL@ d@UHSHHZHH)[]UHAUATISHH(dH%(HE1H9tVHHLHH4H)L)LHMdH3 %(u0H([A\A]]fLLLfUHAWAVAUATLSHH(dH%(HE1.1ҾLNuKMAUI!%tDIULDIM)t/LDIM9AA 2LHu J4;>/.M9sMEtHHNj[LLH0u/B=/u$K4./CfDHEdH3%(u~H([A\A]A^A_]HLL1L@H,mAƅufD~H{\+HH+s.ff.UHATISHHHdH%(HE1H؋H!ʁ t€DHHHD@HH)t*/t H=u;Ƅ/ƄHL-HudH34%(u'H[A\]fHHƄ/ƄBfUHAWAVAUATISHHH(dH%(HE1~t2HLHMdH3 %(LH([A\A]A^A_]f/IL{/L/IHAUAEH{:IAUMlM M_HLL)JT0HGHIHH=+HMtC|7/IFJ<3u H<IfDL9rKI<ItHLLHf.H)[LkL8SDLfDLPIUHAWAVHIAUIATSHHH(dH%(HE1HHIMLI5J8Hw@J<;LHPHLHMdH3 %(u#H([A\A]A^A_]@LL}fDUHAULlATISHHH>HufDHH;Ht L4uI9w @HHHCHuL#1H[A\A]]UHAWIAVAUIATMSHHHdH%(HE1HL@HEtQSMHLuLDLL/HIXXXXXXfAGAGIWD)HH(1HL۽LHpLÅH}~MLG]AƅGsD ML0 +sD pfDH1I#Aƅ_Au3@ML\AEx H[HHMdH3 %(DHH[A\A]A^A_]Ð{rA$ $fAHHL1 DML\AƃjH=MIMHHHHDLpfDHٺ1H5  SfH f~8HCHFH HF HF LHHF0F(fF.1fF,Hu ULHAULiATISHLHNSHCHHtLhHL`HHH[A\A]]fU HAVAUATISHH HBH Hw HHGIHZHt H9XI<$MHtJHWH9u!@IHHt-HWH9HGHHH9uISI>HuAT$.A|$8HHcRHt6Lm~EH]E@IHID$IH[A\A]A^]fDID$H[A\A]A^]fI|$H[A\A]A^]ff.UHAVAUATISH^HHHHH9ZG,Hf fO,HBv H=H9wDHJH9IHHuEt$(HCAT$.A|$8AMt$ I9LBLf.II9t+A<$ u;IuHL9r fH; tIu AIu AuLAH)H9fHH5 71HMȿLHMH[A A\A]A^A_]L-;RHAIuZDUHAWAVAUATSH8L*M}MVHMHUuH}HEEHEM4M9tcLe3DsHUϹ_H-t 9uwIIM9t*AI$-Uu-t/_HDHEL(HEIu<H9R8tUHEu@H0EfDIpM}M?]ȃt?H8[A\A]A^A_]fDH8]IpM}MfDHEL RH5HMUL1A뙻1DfH~f.UHH}E]ÐUHAWAVAUATIHSHHIL$`dH%(HE1HHDH~ID$PH9s HuH1IT$0?HuH=~ 1Ml$HHHI9~LI9:HH9H}dH3<%(uvH[A\A]A^A_]f.HuHRHLL0"HHIMI$H5ҥH1AL@tIUHAWAVIAUIATSHHL>8HuȺ LI>A<$"t'H}tLЪIc L@LRLL1H5Z1A H1[A\A]A^A_]fDAf LLL1H[A\A]A^A_]fDAI@I@AI@A@uD E1L R1MLH51A1HH[A\A]A^A_]ff.UIHAWAVAUATISHHdH%(HE1HFPH9HHS0?HuH9EHEHK`H~ 1HHH{HIH9wC6HL[Hދ88I$[A\]@HtI$[A\]fH1HsI$[A\]f.H1HI$[A\]f.@HcH1H(A$fH1HA$oHW`HH?HH1H)Hx?I $HHH!H HHDI$.HA$DHDUHAWAVAUATISHH(?-HIHMHuȺ HIaA>"HMIt$LEAtH=HcHHH5LR11AA$ 1H([A\A]A^A_]I2@A4$u?LL1{H([A\A]A^A_]@HH5~@A$ AE1L R1IH51AA$t1qI(fIwI gIWIH=oUHdLHP@'IE(HHHfD1He[A\A]A^]I] H\H`[LR1 IMH5H1AfHRL HULLaHfD]ЅuH.`[MEL1L NRH5wH1AHe[A\A]A^]HULLH@LHUI}(MRHUIM@ARH7~]HH}XZf g@Iu(1LWHH/HULL1f.LLfDIE`Mu`LLH?I1I)I}`yH LHH!I ΅LDL3@HULLfH;/HRH5,L9 H[IE81HHLMf.HRL9 HT,IEHI$HULHuHEdHE؀8uuԅu1LH ARIU11H5:E f HuLHU؀:,IU(H9L HuLHU؀:IM(HH HHHff.UHAWAVIAUATSHH`HSRHxHhdH %(HM1Ƀ/HHH:H80wM>HxHcIHI9H*1LDžAHpƅ3f;-HDMAHHL9vvMgIMuHvtIwHW[>HpI8HDAFAHHHH4L9wDDLuIL@t.H3@_u-轼IA>@uM+4$EAD$84IL$0Hʃ?HH0HH HH5;11A|$8AtE9f.I|$@H 1H5赬M,$A}@t(H3@_u-ͻIA}@uH=Ip?I$HCH8[A\A]A^A_]H5J1A7bDH3 [AuafH=EAIAH3 AAuOL-]MD)M)HL9fMcOL)IMM9w<IM9t+A? uA}H3I诺M9r IA} tH3 A肺fH3 sAuMAM)I9gLH51LEȿID$0LEȃ?G,H lID$(L=D0IfH3 I|$1H=toID$(L=D0H@I|$H0舫H DLIT$(HRH:AAVHEHLeHUH=$AYIAH3 A?AuH3,L%%HMANI)O)HL9AO@HcMI)MM9wfIM9A? uDA<$H3I跸M9rdID$(L=,DrfH HH5q1*1A|$8AtEdDIA<$ tH3 A2fH3 #AuMM)I9LH5k1MLE諨HELuLEMH@(B4H@J<0ILuL9uMLe @H H\/CDH H[/ff.UHAWAVAUIATSHH?dH%(HE1HM"fD{9BIpI<$HuH=OAA 莳1LVH oH5蛧-L%WRDA9޿-ADI4$A诶AKuI4$ 蛶I}u:H<[1L1H=IMuIpI}AE0uMuMtM}A?@fI4$@_u-IA?@uLI+EA9sI4$ AA9rIE0?HnH HcHHEdH3%(H[A\A]A^A_]E1IE`H=9HHH1H?H)I8H#HEH=m}A>H=H#HEñAH51إAH5>}1轥IH5'}1袥tIH5 1臥YI>HH;=LI> LLI>H|HHDI}(I6[;HM>MH= ưAH5Y|֤M6MI}(~1E1:H{ H*I}(D9?v^D:EHZ HH{HEH5{1dAH+H5zHE1A>Iu ?H={"9E1 AII}(D97AtD":IH#{H5 HEH1轣FfDUHHHuکHiEʚ;HEff.U1HHHu譩HUHS㥛 HiM@BHHHHHff.@UHHHuZ1҅u'HUHiMH(\(HHHHHHHUHAUATISHHL-;[A}HHt;Hx/t/fHL1H[A\A]]AtuH*1뾐HVLH1[A\A]]ø1/~t1/uH<[H:HtUH]ff.UHAVAUIATSHH= tHfDI9v MfD蓒IAMEuEtHھ1ճ}LXfDUHATISHHHHHtHLHrH[HA\]UHAVIAUAHATISdLDHXHrHHtHLHH[HA\A]A^]ff.fUHATISHHHs'HHtHLHіH[HA\]fUHAUIATISHHQH8^AĀHZQAH3uaH+[H8Ht!͘H H=zfTH3L詘H3 輙H;H[A\A]]f.薙H+[H3H8HufH[A\A]]DUHAVAUIATLgSH_&[IL MIII9E1DHHIL9sZII9LBHuLIID$HRL9D2LCM9LFL虙HtjLpILpHHHHHH)L)HXA HHuH[A\A]A^]LH1CH[A\A]A^]E1qL襏H1AtL1ff.UHAUIATISHȑLHXHHHtHLH胔HHH[A\A]]fUHATISHHHhHHtHLHBH[HA\]UHATL%$[SI<$HtfHHHuI$[A\]UHAVAUATSHu H%[H HR;8sXH ARHcHHH‹rt=L*HHD賝Aąt{7IAtdF苝AąuH$[([DA\A]A^]DIKAMtE1HL1@H1MtLfUHAWAVIAUATMSHx5H$[H R;8s A tlH[A\A]A^A_]AXHAt8DDA@LLHD1~@HѴRHcALHLHY[I͋8ILELEIHc#[HHRHF|(?UHAVAUIATASHHu H#[H HRD0uBDDL1AILDH[A\A]A^]@HuL Ht*D}HD 1螒}AąxoADUHAWAVAUIATSLH(A}HuHMu HQ"[H 蹋IIHAHEtxMA$HMLHu},II9A$t IIGHE1DMA$HMLHu}贗II9t$WA$t-It.tNf>..tAHI9*D1%AŅx/AtDEH~ue}E1AtD辌fDHMdH3 %(LuKH([A\A]A^A_]}E1}E1$HLL)D8IVfDH=[H5[ÐUH[HAVAUATS8HI[IAHH[Ht&DÃu${|D Au:DzÃtuH8[Ht[Љ[A\A]A^]A|D fDD Eu H[HtA t$Dt A u1ۉ[A\A]A^]At=DD 2eHD1+fUHaHHAUIATSH?HD1x2LAH LDøEEH[A\A]]UHATSLHHHLH dH%(HE1NHLFHMdH3 %(u H [A\]FfDUHAUATSHHH[HB[H:LP@L1IE(.L-H[HB[H:LP@LLIE(L-oI[H4B[H:LP@LLIE(ބL-H[HHB[H:LP@LLIE(趄HHA[HG[:HP@LHHC(H[A\A]]鄄@UHSHHF[H{(HtHRHPHHC(HZHsH[H{(HtHáRHPHHC(H-HG[H{(HtHRHPHHC(HHYG[H{(HtHiRHPHHC(HӀH,H[H{(HtHHxhHLp@HtI$PHHChLLk~H{8HuZL҅H>[I$L:P@LLHChpI$H>[L:P`L1HC8H[A\A]A^A_]~I$PhHC8ff.@HMRH8韄ff.@UHg1HtHH]@H[=[tUH.Ht H]Ð1]@1D=[uÐUHAUATSH(H1HtH([A\A]]fyHHEظHtH]"{L%RH=[HLk@I$:LP@H5D[LLkHChHO=[I$L:P`1LHC8e}HޘRHB[HHH{(HTHEHH^H[H{(HHE~EH[HEflHm[HuHIyHEƀ1I$`ff.1=7[UHAUATSHH [[;uH=.R1#xHqRL% B[Hg<[H:LP@L-aC[LID$(L~L%ZA[H;[H:LP@LLID$(~H;[HH'B[:HP`1HHC0{EtH[A\A]]D{EH[A\A]]@HGQHYH81f.UHAVAUATSPL%iRHI$81Ht u[A\A]A^]fDH{hLk@HtI$PHHChLLkzH{8HL諁L-@[I}(XL}HN [*t%I}(Hut)A$uH{(HugHv"@A $u(H{(HuPHub [H[A\A]]HQHWH81}H:RH`H(RH`f.UHAWAVAUIATISHH}u H[H EHEM}LLrII9Ht HEII)pIuAkH؃߅HET8tOJ8ztEIFHv68tMEȅtQutLuHL[A\A]A^A_]fD t}XD}HD$$DE*fDAEDtE1fDIt}D XH޿@HD1H}PI3@UHSHHp>[HxH}HX>[HxHH߾[]|fUH=(>[HqH=>[]qU1HSHH]yH{(1vHCX1C`H[]ff.fUHSHH(H[}H#vH1[]f.UHSHHxCXHrH1[]f.UHATSHxSXt C\Lc(fHLEyCXuk\C`1[A\]ff.@UHSHH`tW\G`u+HKrH1[]f xkXuC\tfDH{(/mf.1UHAWAVAUATSH(L~IHAIhoL}EADmI<AE1HQUE1LJPDEL9E*L4LHHL9 =,D;DLG<9G8<t@tH9w#Et ,t=tUȅu uAuHuIJHbE)L9 A'EȅEH([A\A]A^A_]fDH9v t |HH9uEH([A\A]A^A_]fD34;(DLHHH9tKDD2LLG<G8<1tDE,{=m;Wf;LLH(1[A\A]A^A_]øDUHAWAVAUI1ATISHHAƅ~HD[A\A]A^A_]fDM|$L%Q;I<$LHnQ11wII<$HQ1I_L-Q wIOHt"I<$L1HvH HuI4$ rVfDILHQ1vyf.Hx97vHWHtHDu UHSHHHHHH[]oUHAWAVAUATSH?II1E1ADHAufDHt<,ut{HLxLHI Ā;t#AHE1HL[A\A]A^A_]E1Aff.@UHAWAVAUATSHHI HH}"IHA$H߃H4@HIFHA$HTIVA$AIt$HHȅIFHt]IFA$t{E1#fDID$AIFE9,$IFvSDH}L,=_LDIAC8HL_H9uHEHHf.ff.@1ff.fff.@1ff.f1ff.f1ff.f1ff.fff.@1ff.f1ff.fff.@ff.@1ff.fff.@1ff.fff.@ff.@ff.@ff.@ff.@ff.@1ff.f1ff.f1ff.f1ff.f1ff.f1ff.f1ff.f1ff.f1ff.fff.@1ff.fff.@ff.@ff.@1ff.f1ff.f1ff.f1ff.fff.@1ff.fff.@ff.@1ff.fff.@1ff.fff.@1ff.f1ff.f1ff.fff.@1ff.fH1fDH1fDff.@1ff.f1ff.fHHHL?cff.@H1fDff.@1ff.fff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@ff.@HRH8DUHSHHLUEua1ҸADCAvECCD9DC DFȉs{DKLS H Ht?ILS H1[]DCDC DKs{LS H HuEtALvHHuC DUHSHHC;{ tH Hȉ{H[]sHS {t,HHHts{CuFH!s &HPHHH3HHt>{CSH S |H3HHj^{HC@1WUHSHHO;O t$WσKH;&^1H[]DHuHHtSHufD͐W1tHWWHfD19w U1HATSOHHW ȉwA̋u)HPHHH3HHtGH 1Dc [A\]ÐHHt*SSHH3P]HH!C f[A\]ff.UHAUIATISHG9w'9W vOA|$1)I<$[CAD$AT$LI$H\1H[A\A]]f¸uAD$H֋W9wvH7Hu\D1HZfDUHSHHG!u H?HtHHCH[]ff.WGW)ΉHHH:cf.UHAVAUIATSGHtIE1fHAAAEHE9ew[LA\A]A^]IfHO u/H7Ht'UHATASGDEgD9g w[A\]DDWHHzDc H[A\]f.@UHSHH=SH=YH=9UH= 9UH=@7UH=T6UH=8UH=RH=RH=RH=RsH=LJZgH=\S[H=[SOH=[SCH=ZS7H=eS+H=LTH=KTH=JTH=ITH=԰SH=SH=SH=SH=TH=TH=,TH=@TH=T,UH=h+UH=|*UwH=)UkH=lU_H=kUSH=,jUGH=@iU;H=tzU/H=yU#H=xUH=wU H=$bWH=X`WH=l_WH=^WH=aWH=JVH=9VH=IVH=HVH=GVH=FVH=FV{H=EVoH=(DVcH=VH==VH=Qff.H t9UHSHLJRyH[]H1[]f.DUHAVAUIATISHHdH%(HE1>~u~/t Ht?HLoLHMdH3 %( H[A\A]A^]f;.u {/H57H"Lu ME1AH$KDL1)L螥gLH!%tJ4+LDHWHDHL)H)LnLHE1LL1LofAACjOf.UHAWAVAUATSHHdH%(HE1HHFIIDžHHHHcHHH)HD$HHHHIHxHHL)HH1H+IHH }HHHIHHHHHH(UHHHIIHHHLHHpHAHpHhHH`c HpHHAHp HHHpAԅHhHHpHHN0HLLhHHXALhHX { LJIHM9K4(I@@H9@T-IMH@H9@9-H9ƿIC1HHAoo,A,HH9uIIKJ L98DD@9HxH9xDQDP@yHxH9dxDQDP@yHxH9FxDQDP@yHxH9(xDQDP@yHxH9 xDQDP@yHxH9xDQDP@yHxH9xDQDP@yHxH9xDQDP@yHx H9x DQ DP @y Hx H9vxx DQ DP @y Hx H9v^x DQ DP @y Hx H9vDx DQ DP @y Hx H9v*x DQ DP @y HxH9vpy@x@qLXHHLPHhALX HhLP7LHHLAԅHHAԅHHAԅHLJ(M)HLL|HIEHHLHAJ +y IfDM)LLAԅxL9%ILHυt%HI6H3IM)I9]HIvHCH9HsAI9@AHAH9@AkH9AMC1LHoAoAHH9uLHHI6L9[3DD@0HsH9AsD@DC@pHsH9#sD@DC@pHsH9sD@DC@pHsH9sD@DC@pHsH9sD@DC@pHsH9sD@DC@pHsH9sD@DC@pHsH9osD@DC@pHs H9Qs D@ DC @p Hs H93s D@ DC @p Hs H9s D@ DC @p Hs H9s D@ DC @p Hs H9s D@ DC @p HsH9sD@M)DC@pI9HLH+H)HlHxHHqH9j~LHH)HxH9HEdH3%(&)He[A\A]A^A_]HL9VK<.M)JHMILHH9"LLpHH9HKD-HLIH fII4I6IML9MMLHM)LЅruHMVJ48IFHL)M9AHAELWIAH9AEwH9HG1IIfAoAo A AHI9uIIKKI9':DD@8HzH9 zD@DB@xHzH9zD@DB@xHzH9zD@DB@xHzH9zD@DB@xHzH9zD@DB@xHzH9wzD@DB@xHzH9YzD@DB@xHzH9;zD@DB@xHz H9z D@ DB @x Hz H9z D@ DB @x Hz H9z D@ DB @x Hz H9z D@ DB @x Hz H9z D@ DB @x HzH9rxM@z@pL9wfILHH9LLpHHHHHHHHH?LDA$IHAL$PI9rHL@2DHHDB@pH9rHH^LIHHHIHAԅx,HHAԅ HHHHHH0 HHHHH HAHpHHHpAԅ HhHHpHHN0HLLhHHXALhHXLX HHHHHHLHHN1HpHLLhHHXALhHXLhHHHXALhHLLhAHH+?HHHAHbHpHHHpHHAHSHHHAH_HHHAHHHHAHEHHHALHMHDHEuHH HHH~H~HL)IH LXIHHHhHALXYHhHH HHHH+HHpHH1H2HHHHAHHH HHHH HAHHHLHHHHZLh-HIHHIHHHAHHHHHHpHpHHHHHAHHpDEHHHH HDEINLHIqJ/L9HG@L9@IMH@H9@H9¹IC1HHoo,,HH9uHHHHHH9~3@0 HHH9fHs@pKHHH9JHs@pKHHH9.Hs@pKHHH9Hs@pKHHH9Hs@pKHHH9Hs@pKHHH9Hs@pKHHH9Hs@pKHH H9H s @p K HH H9vnH s @p K HH H9vVH s @p K HH H9v>H s @p K HH H9v&H s @p K HHH9vPKHSLH[HpHH H HDEvN*LJLRLMPK4(L9LQI@@M9@[IUH@H9@@H9ƿIC1HHAoo<A<HH9uIHILJL98DD@:HxH9xDBD@@zHxH9dxDBD@@zHxH9FxDBD@@zHxH9(xDBD@@zHxH9 xDBD@@zHxH9xDBD@@zHxH9xDBD@@zHxH9xDBD@@zHx H9x DB D@ @z Hx H9vxx DB D@ @z Hx H9v^x DB D@ @z Hx H9vDx DB D@ @z Hx H9v*x DB D@ @z HxH9vpz@x@rHpHHLhHHHpAHUHpLhHHHHHHB1 HXLJHHLHt>H9K (I@@M9@@kIuH@H9@@OH9IC1HHAoo4A4HH9uHHHHHH90:@8@2HpH9tpz@x@rHpH9Wpz@x@rHpH9:pz@x@rHpH9pz@x@rHpH9pz@x@rHpH9pz@x@rHpH9pz@x@rHpH9pz@x@rHp H9p z @x @r Hp H9vsp z @x @r Hp H9vZp z @x @r Hp H9vAp z @x @r Hp H9v(p z @x @r HpH9vHr@pJHH+HHHAHSHLJ4*HBHMAHHp@L9@IMH@H9@H9ƿIC1HHoAoAHH9uIHIJ LL98D D@9HxH9xDIDH@yHxH9dxDIDH@yHxH9FxDIDH@yHxH9(xDIDH@yHxH9 xDIDH@yHxH9xDIDH@yHxH9xDIDH@yHxH9xDIDH@yHx H9x DI DH @y Hx H9vxx DI DH @y Hx H9v^x DI DH @y Hx H9vDx DI DH @y Hx H9v*x DI DH @y HxH9vpy@x@qHhHHLXAHhHHHhAԅMHLHHN1HpHLLhHHXALhHX(LXHHHhALXHhDLHMALWL9J /HG@M9@IUH@H9@H9IC1HHoAo44AHH9uHHHHHHH90:@8@2HpH9tpz@x@rHpH9Wpz@x@rHpH9:pz@x@rHpH9pz@x@rHpH9pz@x@rHpH9pz@x@rHpH9pz@x@rHpH9pz@x@rHp H9p z @x @r Hp H9vsp z @x @r Hp H9vZp z @x @r Hp H9vAp z @x @r Hp H9v(p z @x @r HpH9vHr@pJLHLpHALLHHAԅ%LHHHLHTH9K (I@@M9@?IUH@H9@$H9IC1HHAoo<A<HH9uHHHHHHH9i@HL@HHHJ /HGH@L9@:IUH@H9@H9LIC1HHoAo<<AHH9uHHHHHHH90:@8@2HpH9pz@x@rHpH9|pz@x@rHpH9_pz@x@rHpH9Bpz@x@rHpH9%pz@x@rHpH9pz@x@rHpH9pz@x@rHpH9pz@x@rHp H9p z @x @r Hp H9p z @x @r Hp H9wp z @x @r Hp H9Zp z @x @r Hp H9=p z @x @r HpH9 Hr@pJ HLHt7K (H9HrI@@I9@@WIuH@H9@@;H9IC1HHAoo4A4HH9uHHHHHH90:@8@2HpH9pz@x@rHpH9pz@x@rHpH9pz@x@rHpH9pz@x@rHpH9pz@x@rHpH9hpz@x@rHpH9Kpz@x@rHpH9.pz@x@rHp H9p z @x @r Hp H9p z @x @r Hp H9p z @x @r Hp H9p z @x @r Hp H9p z @x @r HpH9Hr@pJlHN*LJLWL9LRL9 IEHM9 M9ȾIC1HHoo,,HH9uHHHH:HH9HL@INJ4+HHCL90 IUHH9„ H9ƹHIC1HHoo$$HH9uHHHH;HH9:@8 HHH9gHz@xJHHH9KHz@xJHHH9/Hz@xJHHH9Hz@xJHHH9Hz@xJHHH9Hz@xJHHH9Hz@xJHHH9Hz@xJHH H9H z @x J HH H9voH z @x J HH H9vWH z @x J HH H9v?H z @x J HH H9v'H z @x J HHH9vHr@pJHLHHN1HpHLLhHHXALhHX LQL9LRN*@L9LJ@ IEH@M9@ M9ȾIC1HHooHH9uHHH:HH909@8@1HpI9upy@x@qHpI9Xpy@x@qHpI9;py@x@qHpI9py@x@qHpI9py@x@qHpI9py@x@qHpI9py@x@qHpI9py@x@qHp I9p y @x @q Hp I9vtp y @x @q Hp I9v[p y @x @q Hp I9vBp y @x @q Hp I9v)p y @x @q HpI9vpy@x@qHHHLXLhLpAHLpLhLXHINHH9@L9@+I@H)H@M9@ LǸH)M9HB1HHoo$$HH9uIIJ J4 L98DD@>HxI9xDNDH@~HxI9exDNDH@~HxI9GxDNDH@~HxI9)xDNDH@~HxI9 xDNDH@~HxI9xDNDH@~HxI9xDNDH@~HxI9xDNDH@~Hx I9x DN DH @~ Hx I9vyx DN DH @~ Hx I9v_x DN DH @~ Hx I9vEx DN DH @~ Hx I9v+x DN DH @~ HxI9vxDFD@@~HHHHpAHGHpHHLHT:I9IPK4)@I9IA@IUH@H9@H9ƿIC1HHAoAo$A$AHH9uIHILKL98DD@:HxH9ixDBD@@zHxH9KxDBD@@zHxH9-xDBD@@zHxH9xDBD@@zHxH9xDBD@@zHxH9xDBD@@zHxH9xDBD@@zHxH9xDBD@@zHx H9yx DB D@ @z Hx H9[x DB D@ @z Hx H9=x DB D@ @z Hx H9x DB D@ @z Hx H9x DB D@ @z HxH9pz@x@rHphLp3LX_HHHpL9pINJ4+@H;HC@IMH@H9@hH9ƹIC1HHooHH9uHHH;HH9OHhcHLPHH8D HHDH@yH9w*HH0:HH@x@rH9wHH8DHHD@@zH9wHL8DHHDP@yH9wHH8DHHDH@~I9wHH0:HH@x@rH9wH:HH@xJH9wHH0:HH@x@rH9wrH0:HH@x@rH9wfHH`09HH@x@qH9wHA8HI@xAPH9wH09HH@x@qI9w#HH:HH@xJH9wHH09HH@x@qI9wH0:HH@x@rH9wfDH!>RH;:s5HW>RHcHHHHt%xRHHDHH;UHAWAVAUATSHHDRL=L#LH;H=G\L5UH=8LFL-H=&L0H5H=H5H= H5H=LH=LH=ٝLH=ʝH5sH=距H5PH=褝H5MH=葝L#H[A\A]A^A_]ff.@UHATL%ZSHI<$Ht1Hu4I$H}H6ZHHKHDZ1[A\]H0Hxg^HHI$HUH(ZHATL%LZSHHIZHHZHI$HɯZHHtHЯZH9RH8HǯZ0u HH9t}Ht HZu3HiBRt/H`ZHHt>[A\]f.Kfiq%H"ZHHu[A\]DHtHZuI4$HHBI<$H`ff.UHAVAUATAS_H>ZHtoH;ttL-ZLHx\LHh1I8L5®Zm^1LcHH=ZL*LH;t31苹Eu.HoZH'Hx^\H[A\HA]A^][1A\A]A^]ff.fUHSHH@R8uH@RH PRH9HZtHZ;HZ3u:H RHrZHEZtuH[]f.H!ZtHtZH5H90uH}ZHxZ uH[]qHRHZ OfD'#fDH ZHZHZHrZHHZ@HYZHHϬZff.U8HZHZHH@@ HP(@0*]fDff.UHSHHЫZH;HtHG(HH;HuH[]DUGHAWAVAAUIATSHwH>R8L=ZALcLHIT<<H]>RD Eu!HZ>RH5NRH90uBfE1HD[A\A]A^A_]#HTZYH ZI@H[A\A]A^A_]/72@LbMKLHxXLHH5RfHBH#H;l{Q&H ZL%ZHUA L)H @=RA$9H +=R9H'ZA'A$0HUHBH;B{QH=ZHDVE1HBHH A'HM>fDIlEt}A8HX HPLhD1IfDH:RߋH:R0A'Ayw@f4L;-xQtwHZH ZE'HAfDHL[A\A]A^A_]t LLHBD`ti HB1HU9HUȅt HBmHrAA97HMA#7HML)zHZ1H0ff.@UHSHHȦZH=ZZEt&HRHIZHZu~H$Z8t~HgZ ?<H 8R tq9?ZH8RH01HʥZuHZu90H1[]@軩HZkfHZ0u3HZHZH[]f IZ uK9fcDHiZH[]9>ZH=Z0ȅZ@Zu1UHAVAUATSHHZH0uHH;~uQt$H;uQt3H[A\A]A^]DtPHfLcIIE4$Ml$A$ID${E4$Ml$H[A\A]A^]DH}LcH}HBD`t0 H}HBUHATSHHw G0LctXtdI$HS(H HZHHtB0H߉EBEH[A\]fDLu@+HZ 1H[A\]L%iZA$tP@A$49A$$NjSHs!s 1fHZHHtB0H[A\]DPA$8A$$뮉3HZL 2HZL DUDТZHATSHZEtfHZ#9HuZHHZH5R l[1A\]DH)Z HHrH ZHHGH 8ZL%ZHHZI<$HqL%ZI<$H=xDHi4R8轍1VHOZ0uiDH=tRH=DRH=e4RHRu{HԤZH8t~uZ; fDHRtHZHuZH Z(+gH3RH8165@N{fDHRHHpfDHpQHHfDH qQHH|fDH=p贙HI$HZyNI$oUHSHHZ8t{HƒRHHt HZ:RH&Z u8;tHHtRHHtEHH[]̐51HHZHZHZGHZ~GHZHHGHZGH@ZH^ZG G0H^ZG4H2RHHG8H,ZHHG@H1RHZ~GHH1RGLH˞ZGPHߞZHZGXGhH5ZHHGpH#RGxHRG|1øDH HZWHZWHZHGH ZHZHWHZHW HZHHW(H"ZHW0H=ZW4HAZHW8H0RHHW@HZHWHH0RWLH0RWPHZHWXHԝZHHW`HZHWhHyZHWpHZHWxHRHRW|1øUHcZJHAVAUL-ZATISH5ZIE9}PL4bKHckZIIMHH уTZL!IMH4H^HD[A\A]A^]@Hlj5(ZHcH(KHcZIEff.UHATD%ZSEuBH.QH=H3HAH{HuHZZD [A\]fDUHAWAVAUATSHL=ZIHHthAE1E111HIT$IDHIDIHHt0IE9ALIcH/JIIHE1E1H LLCHL[A\A]A^A_]ÐUHIHHHHBH9u]f.UHSHH1D  HLHLHHuH[]UHwH HHfH HH9uHHHHHHf.H HH9u]fHtNUHATLSH_<uH;4HL9tC<uH;HL9u[A\]f.fUHSHH=H1[A\A]]ÐKIcHDPu@HAZH8/ff.UHSHHZt HZ;tH1[]fD3Hv H|Zt3HZH8ĺH1Z98|H"Z81fDUHR1]ff.UHAWIAVAUAATSH(L%ָZHZH ZA$ @#AuH([A\A]A^A_]H=[AHHRHEHlZH ݃ZDD53ZD;HAWIc H1HcHUHEH0&H ZHUD;HE<$3A9~A4$AHZD9AAAA9lAWAD9AD9At EYAcD9HZA$D8H(1[A\A]A^A_]AFЃ L5R A6AHMZuHRHE蠃ui'Džx#HMHHH8uH XH9H$0 w:H5Zt APAHւZ7t} }HUA%@Aj#AA!@H(1[A\A]A^A_]}UuMcƋuȋUH}H ́ZBD@dDËuȋUH}H ZBHuHHv HYZt3;A9EANE1ۉA~A;Et1[A\A]A^]fDHy{ZH8hA>D#[A\A]A^](ff.fUHAWAVAUATSHHL%ZdH%(HE1HzZA9$|*1HUdH3%(1HH[A\A]A^A_]fDHvHLZE1DD+tHZE,$D;(}H mzZIcH  I9uDIHHtTHFD;8}>AD9}AHvHIZuLf[1HMdH3 %(uAŅtfHZD0QH[A\A]A^A_]ff.fUHAWAVAUATASH(nrZdH%(HE1YrZE]A8LmD޿DA޿EtTL5QZHNZE>D;8}>AD9}AHvH9ZuL }fK1tHMdH3 %(H([A\A]A^A_]L-pZAEuN@AEAe6Hv HZuHusÐ:qZD HZHHZH3HWJfUHSHpZu1S@Ǎ|cH߾c[]gHpZpZHt HRH1UHH =HpZHHH HH9uH}H 6HHHHHH,RuH=LH9tHRH1]Hff.UHATSHoZAAt4H}ZH5E1HH}ZH0D[A\]f.@#awHZH HnZ D[A\]A믐UHATSHrnZAAt4H}ZH E1HH }ZHD[A\]f.@#`t.aw@HHmnZt/HZD[A\]@HZHZD[A\]AAf=oZ2U5oZHATSHmZH8AHLZH[mZH,oZH8f8HھDxH1mZ?oZ1oZ ud[A\]DH=oZDH=oZ8H=oZHoZH5yoZ1"nZ&nZt1H5nZ[A\nZ]@1 @ff.@UHPlZH8H1]ff.fUH(lZH8H}1t1]UHAVAULmATISH`dH%(HE1HkZH8u HHFtHL9u HHAtHIA<$u HXID$HEdH3%(u8H`[A\A]A^]A}6LTq 1fHjZlZtHH8u HNHPlZtHH8u H,HPnlZtHH8u H HPClZtHHǀ?u HHGUHAWAVAUATSHhDlZdH%(HE1EDkZAEMHiZHxH8HھTAĉ1CkLmHLDnEuHEL5 QfoEfoMHTkZEfoU)kZGkZA) kZ)kZ~ kZjZL5!iZ kZ jZkZ kZ jZA jZ jZ jZ jZ jZ jZ jZ jZf jZ jZ jZ jZf jZ }jZ jZ njZ jZL/QuM}EEEO@tHH58Q>tHH w8Q9tHH_8Q8@t!HQHH8f.iZH gZEt H5oQuU00tEtρUʃfuUt %EE;WLDxHZH-gZH8 KiZA9iZt1H5/t AD=/{HcLLHL[A\A]A^A_]@A.#{t f{.=L%`ZM-LUHHH=_ZHtH_ZH=_ZHt\H_ZH=_ZHt@H_ZL-_ZMGLE1Hg_Z,f.HZL=R_ZE7AA9EAD9D9 LcLIA9IcLLt+L%^ZMI~HL[HA\A]A^A_]^fDE8LcLsIA9zIcLLL%z^ZMd@UI΋UHDHFEUHF$UI̋UHDHEHBfDH3)-x.H]Z@LHxHHcLH5]ZHI2H]ZHc|8/$AD=/{HcLH=G]ZHK]ZHHxRHHH]ZrVH=]ZHH]ZLc1HLHHLpff.fUHHSHH`Htbx/@tK% t>#`t1@t$=t|t t1HĘ[]f.Huٸ*UHAWAVAUATSHH@LHPdH%(HU1҃!ELwMHDHXHZH`HEHxHEHpHEHhf+HvHhZDEH`IED0YEEIEE1D HEHEHEHEEu7E9IELcF<0EtsIEF$0Ete萻HvHhZDEuHEIMA؉LMHUI}HEyt%I}HhLڃ\NzE9NI]L9X`HPRHP8EE1JH@HH`:HXYZHE0t2H3YZHHt#H(Z tH{9RCDH@HcLH HxH"HPv;EALuLcL@M@ID9LKHPLH聼uH@LuHH8LD9LMH}HtH@HB0DHE1E1HEHEHEcfEGIEF4 AD9tuE,WHvHeZDEE9IELcF4 EAD9uIHDptaAHDL9t߼HEItLMȼI_HH葾uH襼IGH81[A\A]A^A_]LxHEH1BfDfDIGI>L9t;HEI\LmIIFf.UHATSHHHHRZH8Ht|HRZtoH2RtbA2@uEHnRZHUH0HtDH:Ht7H2RHHt(HUHDH[A\]fHU'HUHuHH[A\]fUHAWAVLuAUIATE1SLHHdH%(HE1THEIDHH0Hf<U<HHLHH)蹾HHtO0H8HADžDHHMZH߾EHHvHQZ0u.HMdH3 %(DH[A\A]A^A_]fDL5)QZH*1RA tHI9AMAEHt 3H HHJHPZH(HHtH(H(HӳLIȳA|HcH(HHyH(Icǀ|/H//H|LMA2H0HNH߅uH%=@H(AEIAFfL=LZ^AHI7蔿I7?臿IL=KZ^I7dID;A@HAA9t&HAH2IFfDIϋHDHtyZD(E9~HDZ1EHIcHE1h8XHxZ1D GI>D1ɺNxAHfDM"fEL5"DZ-IHHxZ0v#HUZ8uH1zIA@DnHaxZD(IcHEH}HM։UvHtHBGZUHHDEEHMDHЅXHwZI1HcIHMA1M'"fH}։UUf.1 fH}։U©Ht݋U{D1EL5BZ1ۅR1UHAWAVAUATSZHXHxZH}uȋ]ușẼt'ډЍ@9EƉE̅AEEEHc&RDE HwZDEHELhMIHEZE1D}HE@HEALt`/LHtN8tIxHxu?HxPL9v"/u /t#HHGWL9uL/L@L@I|tH}<D}̅-(Hm%REȋtHRwZ9EHM,M%HX[A\A]A^A_]HcE\DEHEHEEHEEHHEEU9U}HEHUL$MHYDZ]E1]HEHEHcHEHEDHEL0tc/衬LHtQ8tLxHxuBHxPL9v%/u/t#HHGWL9uL/L@LAD;u|fH $RE9tHuZ9U9UfEUHEHm;UEHX[A\A]A^A_]DeA)E~+L-?ZE1f.Iu A^E9u9]ZH]HEHEL$MZH=IM該I}`FAEADEȉEHEHcuȺH HxEȍDEHzHqHUHAWAVAUATSHHHH}dH%(HE1HBZ8{kH[HHEEALuHEDHIAZtc/H趩HtQ8tLxZHPHH9v)/u/HHBJH9uHڀ/aHE1E1bIEDIcHހ>t]<<UH}LD)HcݭHHt&}AcIcHHAŀ>uEDD9DMHEIJ\DmHH@Z^HHtgDH}HEdH3%(HH[A\A]A^A_]fAAI@AA HXH R9|7UH})fH AZnHfDH{L% Ztd/H?HtR8tMxuHPHH9s*/u/tHHBJH9uHڀ/u HH@sHEHH0T_eH?Z$HHX5`eH?ZH蔦@Ht;UHATISH?HtI\$@+HH{Hu[LA\]fff.@UHAWIAVAUA ATAS1HH}ȿXPIH@K&IK&H}AHHt/D9u׍s LHUDk HcHHUI@tDt'HUȉLHL[A\A]A^A_]IFIFILE1ff.UHAVAUATSHH`9ZH H9H=)=ZHtץH==ZHtvHRL%hGH{:Z1:ZH[A\A]A^]f.H}H55:ZA>5+:Z:Z@L-@H :ZHH=9ZHt貢H9Z1#:ZH[A\A]A^]fDc59ZH=9ZH 9ZUHAWAVAUATSH8H8ZL-5ZH6RAM@H8Z8H8ZH8ZH9ZHjZH4ZL MtLHxOLHԟIH8ZHHEHrH'iZEE1EE$HiZDUuMIHjZ0HiZH38ZHHUDLH8ZHHEEHtH0LELH}uH7ZH}ȋ0Aƅ*?uTH}H}RMt(H3ZLH8kL8ZuAeE1L@teHDQپHH81̤MtL*AeAH8D[A\A]A^A_]f. t!uH}LHGA8t"1HLDHMKH}HGH!@HQrH}f RHuLjGDHuH}ĉU@UEHfZD8HAHE~H]Et EHfZD0?HrfZH{D8HHL}fDLHI8>H=4,>L;3t'LH蛞H;Hu莻H}DHH;HufKMtL^5ZE1Ae(@MtL.5ZAeH 1ZIcH :DAU>0H?UMunH}DH;HUHI$=H=3=L;3L臝fH%fZDEuiH0ZHH9t>Hs4ZuQHb4Zt@f. fD 4Zu?@cK!fD?fD*vfDutUHSHHH=94ZHt诜~4Z@@@H4ZHƖHxHH肚H3Z膜H1[]D1DUHAWAVAUIATSHwH<H)HA]HIĄuL\MAD$-M|$$fA4$Mt$ÃuGA\MfeIAA]tLÍPvtXMt$M\t"uTIA\MfAA]uA$HH[A\A]A^A_]DMt$A$\eIpMM]D\CHMȃ@M|$fA$AD$-HHML0AVtzHMHUHUHMH4@9HMMt$HUHUHMHfD\CMt$AD$-?fA$IDHUt'HMޒHUHMHHMt$ffMt$HcAD^aHM蛒HHMHf.UHAWAVAUATSHsIăt{LhIƹACwPA\AE2X0M,40A\ufAT$CtMuA|>-tq@H"@Ic4LDLulA]HcL3@Ɖ9~HcAA ;tAIcA K@IcLLD"1H([A\A]A^A_]ÃMAEHE$A?tAA9sDAAIcA DAAIcA fAAIcA fAAIcA ufA\AIcA UfA}0HcL1D^AA}DHcL1D^AbADIcLA A AIcA fA AIcA fA AIcA fAAIcA ufA AIcA UfA AIcA 5fLEEeUM͊M̋UL H8IcLP{LELDBD_L?AE[HAwoAuHcLD BDgAAD$~<wWAIcL AA AIcA vf.L1AHЃ7@B|AD$~Ѓ7<B뗐H QAE tH QH PHA|\AEHAȀ LEU@u萉HűUL }HLzLEHDpG蠂M̋UL }HLyLE HE1GLEU"I̋ULEHL U}LyDHZ6UL 4}LyHLEB7A|C A|-AEHE$A?tAA9tOADȀAAIcA AAIcA AEALEU=I̋ULEHL p|LxDHtUUL S|LxHLEBȀ`ff.UHAWAVAUATSHH}HUH>HHHMH|-HUHHHEE}HMLeE1E11L=QZeADULsDU}HCHDMt!L;5HPtLE1IIA9A$DSAw'LQAtu HfDHcAHHDA9MAtAu HKHUHuI}HsIA9wH}tEHH[A\A]A^A_]fHKMIIA<" H{HME EHMu}EuH}H}ErfDH QHH1HfHHH1HHH1UHAVIAUIHATSHHH|HUHHITu(LLL[H[A\A]A^]@L+fH7UHAUATSHHBHxyHHHZIH;HtׅAu@"@'EAE< < DIEfHHUP t uMLH|HULHH;HcEHL8H1[A\A]]EAEMe@8tStODIE @@8tHHUPuof.MLSDLFUGHAUATSH\M=Z-@f 0Zt3A\t "cH ZB\"DeZ\H Z@4HZH[A\A]]Ðz@ǀA\C@Z-A@fZA9M}赂}L(AD]|HAH<tCE1eZ\H ZfD\C?Z-fZH Zf1H ZDHcH ZIcfD {EHBt:zHB<9}衁}HDX Ef.zHJcADEtzHzHBHff.UHAUIATSHxHJZHL#Mt9HHLcMt#I<$LuID$H[A\A]]H1[A\A]]UHSHHHtHHH[]ifH1[]HHHQHuzHvHHHDAt1uVHtDHFf<ueHHHDAut0HvHy1HQH0BfHtHFHtHÐHtkUHAUIATI1SLHHHHH;PuH;PtH[A\A]]HLLH[A\A]]1ff.fUHH@}H}EgDUHHH1Q@}H}HE=ff.H QH!UHAWAVIAUIH5MoATE1SHPHfDHHsAHtgL~ADžuMcHPKdLtMtAU҈UAKdE>H@H1[A\A]A^A_]@L%qBP1H5nMII7HtL}uHcH[IDHtHL[A\A]A^A_]H59L}aUπ1ZE1A}AIHH5DnH}t3H5FnHs}.QHnQtHQ8KUHAWAVAUATSHH(HufH< t< t<#<$HZ:<"I11tZ :VHc҃ u-f: {H  L$ȅuH5WHMO|E1AEE>;"-HP|H5lHLxLDE1L}L=?PfDIIwAHH}{uMcH\?PIF|(L-LQIuHu,IIuHtHkHtAAL-QIuHu!IIuHtH+HtAπA$'r"iH5NlL,{HMQHQHuοD}HE DE1H(D[A\A]A^A_]{tc\":VHc<tA\"VHc<tփ\te"|HuHZPH8IZID"ZH #Z1L >kHjA1֍FH<tHc<1뒃:u |=pVA$E1HcL, E}H5HHMUyEA A L@< e< ]HCHSuHL%PH5ifDIIt$HtbLByuHvtHTH92@ t @ t~@B< t< uHHJH9s@t H9wAHLE1 DIAE!< t< tE#A UHMt MA u6HD J)fD8IEHA tA tA'LcIAMȅH{\toD8rLcIAE\tID8`BHL,AM΅ƒ\t#A8JLL,H΅uDjMcIA}jLcIAMȅ_MIDHcL$A"HcL,AE<  HDH IuBHuH< t< t~SH{ t 'HCfD IH t tMt-HcHD)fDH td t_4IDŽuL-;P1H5fIIuHLLvAƅuHcHK;PLHT6FAHL<At t uHDIDŽuH t tbHED8L qD}EtHID8uHٜQIt$H}H!VHcL, tVA$MHcL, A$AE}zH7PD5(ZH8EttDZH Z1L fHeE1zLDHtMcHBDhPnHFHfDfHH{HufI}LHW1VkH]f.H).ZUHuH Y8\"1]HYH=A-Hmff.HyQ1H01Mff.fH-ZUHuHY8!1]HQYH=-Hmff.UHЋQH UUHAVAUL-iUATL%YSHtPL5HSHLHIՋL3tMI<$1HdViMuL-(PHTL5EVfDHIHI<$HL1IiI]Hu[A\A]A^]L5F3HSHLHIՋL6uMI<$1HU8iMuL-'PH@TL5UH&IHt7I<$HL1IhI]HVHIHuII]Hu4DII]Hf.H+ZUHuHlY8!1]H1YH=-Hjf.@UHATL%YSHcW8HHGI<$H4a)H=YHttcHC{H;WPthH;P / uGXFA_XIXHt=1H8[A\A]A^A_]1G@ƃwXIXHuWHvmHZAXu`xtA\A]G=w}辇{fۂc虇TAXx~HI|uzHcHS( S(HCIHH{(~#I H1HKH4H;S(|HcL4HYHHHHCL=)YJ0C8C(AACPC}CHCI?DcTH{pNL%YH{CxHNZI$sC|11AEuIHHsXHt71H߉EEAeI$H[A\A]A^A_]H߉EE빿1@L=)YI?aMHx蘔I7HC HQHS HCJ0E1fff.UHATSHasXHA1E~ [A\]t61HHmYHHY 1E[A\]@Hf.@UHSHH^YHc=QHN99HcH Y衑H=*YHc5QH$Y臑=QH YD9} vQHc>Hc=gQHY+=UQHYf:QsYYHc=YHYHːHc=YHYH贐HYH~YHyYH[]ff.UHAWE1AVIAUAATSH8UdH%(HE1HE~FLetQ W A t1Q W A t$Q W A tQ W A t QWIMLEAA9lH}DSEVH}HCHWH9LH+UHE1ruHLH ZD; EAMẺEHEHtD HEHt}8HEHtủ0HEHt}ĉ8HEHX[A\A]A^A_]H]AHDuHE1DD1 fH A HJH9uHCDf.UHAWAVAUATISH('ALHECHHY0{E1LE1Hc]EHEI_D<@HvHNYIAHAGM̅uHZD9(EHVKEt<.a@Hv HYt^IHAGDcBHþLAHH{聉H(L[HA\A]A^A_]EILM)DLMLMAE)AzWIWH9HSI9D1H@o AHH9uEӉADD)H4 LE9DDD^DYD^DYD^DYD^DYD^DY}D^DYtoD^DYtaD^DYtSD^ DY tED^ DY t7D^ DY t)D^ DY tD^ DY t VQfDHHIEEA9DL4HE1HAHEH([A\A]A^A_]ÐHAz1 f.H A HJH9ugUHAUATSHHH=9YHtEH= YHtEH Y1HYYYYYYH; HUDIHHxLnY11HoYH5xY'El$H1AD$E1H @YH5MYH^Y1H=PYEl$H"YYH[A\A]]ÐHYLYH1H YH5Y1HYHYHt H>‹YYH[A\A]]HaYHtH.YPYHYHYHAYHtHGY1UHAVAUATSHYH;=x1lL%5YMDH=YLAH=YLAL+ LBHIMDL=IAa;HvHYHKYD0H QE1H 3YH ZAD DAE)YH=:YH5YH11@HADA9}HcHH3IFM9ufDD)~HZHqH8DELuAEHYMlfA>H3IPFM9uNfDUHAWAVAUATSHL5LYA9tiH.Z9:|^AAA)E~hL=iY1I7 EA9uHZHqH8CHYE&H[A\A]A^A_]fL-ZI}HtՀ?tD)Å~E1 DI}HpAoCD9uUGHAWAVAUATSHL%YI4$w:HYAtOEI<$=HD[A\A]A^A_]DA@ǀuAAADHH=R-ADI4$[AA lAH@H=`0A@DA9tHI4$E5@AubH?H=0JDI4$ CA9uDvH5Y1H YfD‹HB9uHsYH[A\A]]DDHvfDH)ZHHtH:iH;DUHAUATSHuH[A\A]]@A~)L-$Y1f.Iu =A9uHYD H[A\A]]DUHAWEAVAUAATSHH}HuUDMdH%(HE1c.HH`YHhHYH=!Y9$.HvHYD0EIcH H] H}HI:tJDtA:$OHIHH)H9|D+EUED;m>;5IދU DA>tIB2)A9I9D;}{A<$Mt(M @A}tIB)D)A9M9!„$-HvHY8 M]M~M9vJI9vEAFA:Eu:A1< DEIII9vM9v AA:tE MMHYU\5YxH YDYDEVH_YH8ED9Y8HhDE%D;EH`DpL],L]DpHH`vHYGY:t GYHh9HeDEH`HHYLpH88DEH=YDFr+DELpHH`kHYZE~'H=YD1L]Hp3HpL]Hh+YYYHu}HpL]!*L]HpHv+HtY0uHh=!Y98u YLHXL)L`HHpLH)؉)É]*L`HXHHY]HUYDE H=.Y+Y9HQDEH YD EEL%YA;$)H HmYDE HcEHY<~H]HEH])HuHHHuHuH{5HH@H Hv }/d LcE~CHYx1DpIHHEIu<H8A9拍xDpHhA$HE(H]HMH}HH4H}N3HsHsH}H4H1HLHHHP4HuH}L-XE9DH]HuANHLcEL*5ELLeE9EwDžxHu}L]=L]LL`L)HHpLH)؉)lj}'HHmYL`H}E1I)A9~ DډH}LEH)9~ )ËUuNH YuAY;xUt0k'U+xU}HHYӋEfLL)HM1'HMAHv4HYDEAH}LuH)9~HMA@HYC 9}HYH8HY;E;EtHrQdA?HYtHhg&HtHYD(Et)E9t"H"PAH"H812H:YH8H1 .H&`H2uLlHhLpHcED)ƅ~1ILvlD1)څ~ 1LHhHEdH3%( HĘ[A\A]A^A_]D+EUED;mfI޺D;}@L=!YI?HAC AD9zHYDEtHhDEu E_YtHpBLkA}L]T$L]HjH*YxSEREx1L]`$L]HtHYYHhfHEHEE9'EHE8H}1DmLeH}H}HADpIHxMfD1ɺLH}D1ɺHcILLcMLeD9u; LxEDLHMHUxu+EDmED+EDpELDMiHhDMDoL}L1L)LL}L1HIHEH)HHuHLI9M9HEALHHEHEEHXH]LPIHxL@Vf.L`A? HDD1DO1DLLc?ILcML;Xv\L;PvSHUMMLLxI)M)HHEDILpL`LpaEL@LHHXLPDDM~LFhHhDMDL+uL+mEE)u!Hv7HY8u*EDE1EH}1/A)@EHQ0t?}9}}7E~#HVYE1H3 A/E9uHhD CD6fDE1E1L11LL]L]A?A;L] L]HvH YILeH]EEHYH8Ht ?L-`YI}Ht-?t(DsL=7ZI}LA,AuuLfHYH8H?HY,vE9Y;DxE+HMDMDMHMHtHYDE9A?/E$LeWH.YD;DHYHHt 8?#L-+YI?L+u@MEE1IcLeH]D}DmL]HvH6Y0/IEEDmDpDu DmDpDmDuH}D16DAEHE3@80McHHL 5HEHAYH3,HhH}A$?HEHWH*^HEL1ɺH)HlHuHLLL}1ɺL)LDL]HI ,TDDHDE%%DEH:WHD)HhDHHEHYHEA8H3v+Ew#UHAWAVAUATSHdH%(HE1HYDE#HSYH;HRYHEHH=eYwH YE17YD(HEEHY8HYHPtHYHH;tH=:YH%YHt=*YYF<+AG;QhHEH5YHcJ< McnLeHEB +YYHYHcsY1H=YD-qY\HYD;(KAE1E1DxCHyYEA9~H=PYDA)HYIDA9|wD{HvH(Y.HwYAH=Yu ɺYHYB 0YH_H8YIDA)A9}D}Dx'HvHY`HYHEHEDžlHҴYE1DžhDžpHEHYH`HEHX1fH YD90uED=YlAD$wHGY A fA AHEHuEg0^H5YAE;A?HEAMcB IcHEHYD9(?"YH=+YP;UO H YEHcUE1DHPDEtD YEu9HSYLcE11ҋ YH5nY̷YH=cYLAH/YD0 HYoY;mY~E9uD); MYE@A)EA9H5Y=YANL)߉YYHYH8yH ʷYHYѷYH5YH YH зYHɷYYYHPH5YH`H Y0Yt iY1uYYHEdH3%(^HĈ[A\A]A^A_]f{aH HYH8 HEA*AAfDHYIcEHEOf11GRHYHEkff.ʵYD9 HȵYHEH-Y AL$9LuLuDmEẢ]AD91E9}DDLH Y9~DLuE]DmH}1DeA Y$DDAD ))HZYD)F$*A9VED9AH} H}AHmHcIHEufDDuHEHMD)HXIcHcH0HEHEA9iHEHMYyED=YlYH=YP;ULceID$HDY8AEH˵Y)Dž#|YA%H=%Y)Hc5Q}RHc5QH=YHYcR=YHEHYE|@HljYHcH4-RHYHYuDf9~kD9|fLm$fHYY82H[YAID; YfofofofoHYfofo )=Y)Y) "Y)+Y)4Y)%=Y)-FY)5OYH=ǜYI}I|$H@EH=YLLH9foH0fofo)=YfofofofoHYfofo )Y) Y)Y)Y)%Y)-Y)5Y)=›YH=:YI} I|$H@EH=tYLLH9foH0fofo)$YfofofofoHYfofo ) Y)Y)Y)%Y)-Y)5#Y)=,Y)5YH=Y1ҿH5ٗYY2DH`H5YH`H5қYLH5YLH56YLH5Y|LH56Y\LH5Y<LH56YLH5YUHSHHtQt =YtfHtQt =YtHĨ1[]@HPH{HڿH5YY1@YHĨ[]fDHPH{HHڿH5yYDHڿH5ŚY0HڿH5qYHڿH5YHڿH5YHڿH5YHڿH5AYYff.fUH'HrQHHt%]ff.HrQHHtUHY:H]<@3UH7?HtH@K]饒DUHAUATSHHỲwAHpuuHĈ[A\A]]{L`LL11DLDh1LUHSHt-H6YtH=SRHH[]fkHcHQtH[]UHSH u&HЙYtH=1HH[]UHSH98##H\YHY H;tfH;uH&YH=gYHVfDff.UHg91]UHATAS9~AD){HcHc:IcHHHJYHH0_[A\]fDUHAUATSHL-YAu9|5L% YI$HAuHc:AuI$9~H[A\A]]pUHAWAVAUATSHH-YA$yYY11[A\A]A^]ff.UHAWAVAAUAATASH!5AE~15A9u5DH5HHDDIHH8tffHY8訴HQt+HHkf1H[A\A]A^A_]DDH=<跐1H(0DUHHHiYH H9tmHbY=hQ1|YhQfYt=hQ1҅‰FY@$1҅‰)YYu^@hQ~4YYxYfDYY1wډhQҏY̏Yyu}E u}ff.f1ff.f9tLUHAUATASHUDI訐1A9L@H(YH1[A\A]]HY1x\UHATSHYD#f3D9uHQ8t[1A\]@D`HmQ8uHY1[A\]f fxlUHATSHYD#薖3D9uHQD#8t'[1A\]fDHQD#8uH2YD 1[A\]fxdUHATL%YSA$t><A4$9t}HQ8uA$HƵY1[A\]D#.[1A\]@ff.xlUHATSHYD#ѓ3D9uHQD#8t"[1A\]@DHQD#8uH2YD 1[A\]fDUHg HY1H Y0HYh 1]@UHSHHҴY;AAND@H+YHHcD< t< u!Hcf։t;DH< t< tHcTH t tƉuAAuHQ8t H1[]ËHYH1[]`,H1[]AAtAA?ff.fUHSHHijYDEDINHYLHcAT/w)Is#FHATtb/  uI/VHc҄u$7H Aà Au/tALu\DtHQ8t#H1[]HIRdHYH1[]*H1[]UHSHHY;u*H1[]@1HQ8uH8YH1[]fUHATL%'YSH YA<$39t 1A9$@HH}Y1[A\]UHAVAUL-YATSH˱YAu;9ADNt'Au;I1AE9@LH}YˋD#1[A\A]A^]ff.fU1HAWAVAUATSHL-,YL%9YE}E4$蘏A$1AE'AuA<$9u+H|YE}E4$H1[A\A]A^A_]AU1A9$@HU fU1HAWAVAUATSHL-|YL%YE}E4$舐A$1AE׎AuA<$9u+HL|YE}E4$H1[A\A]A^A_]+AU1A9$@HfUHAVAAUATAS+A2,DH+HHDD@HHt|8tcHY8@H=Qt#H苇H1[A\A]A^]DH=}WD'H'UHAVA AUAATASH)H@YHH DpDhHD` HXH[A\A]A^]ff.@UHAUATSHL%YM,$Mt;LfDH I$HtHI$CuH{fDI$HL1[A\A]]/UHAVAUATISLoDw 0(DpHLhH@HMd$MtLHx'LHILcH[A\A]A^]ff.fHtgUHAUATSHHfHIIHu-fDI$HHtIH9MuHIHuHHL[A\A]]ff.@UHAWAVAUE1ATE1SHEHcYL3ML=yYL RYAVA7AA +t^uiAAA7ILH*.L"L3MzfD1H[A\A]A^A_]EAALAIH-LE DEfAAu H=YD'AF ẼH=YẼ@uD-HʫYAL3L YD IHYI~D"蝃HHxAL3L ȃYH=uYE{H=]YD'G#L#L YA'AI$LH,LH[A\A]A^A_]H1YHHt;xu"f.9xtHHuDpP 1ff.@U111HlHՂY1]ff.U111Ht1Ҿ1߉A1HD߉1{DE18f)ȃfD8 'H jY8HPjY1HiYH,jY 1UHAUATSHHiYHiYtH[A\A]]f.ÅuL%NvY hxYHcexYI$Ht89t\PH JvYMЉ؉4xYH[A\A]]D9uHMQH^iYHH:H[A\A]]@L-aYA]u=bx"I$H:HcwY;wYjAE  UHAWAVAUATSH8dH%(HE1HEHEFIL}AHHhYHEHEHE @EvH}LLCD%L# Ht Ht@Ht+HUdH3%(DuNH8[A\A]A^A_]f.AEAHEIHEL;eyE1fDUHcHAWAAVI1AULIATSH(dH%(HE1E~XAEMLmIDHE&HgYI @u#AL;etE<$LLIE—tHMdH3 %(DuH([A\A]A^A_]UHSHHoH(gYHcYHSvYu)HJQvYHHt HYfY:H[]镶DHYHHfY WvYt+H$JQBvYHHtUH]fDUHS HkH@H[]f.Ht fDff.@UHATSHHVYH8DH==YooOoW o_0)tYog@ooP) tYow`op)tYoo)tYooH)%tY)-tY)5tY)=tY)tY) tY)tY)tYHtY/H9eY€> HsYHHML%sYI<$H;~HYDE#輵HHBHQHHtHYHGtYH&dYH8,tYuPHYH8tCtYu)HGQsYHHt HcY:kfDHcY0HdYс 7€HihYH8}HcY%=fDHahY:oHGQEHDhYEHY BDI<$HtEI$EE$EV@HbYH8 H"cY%t6HbYH:H#۾ s΅E辴HgYEHחYD EfDۻfD苵 fDHFQH8gYfo%XqYfo-`qYfo5hqYfo=jqYHYHqYfoqYfo qY foqYfo%IqYhfoqYfo-EqYp fo5IqYx0fo=MqYH`@hPp`xpH[A\]ÐH92PAH=HPH9rYH8WH[A\]HqY8BfHkaYu%=u)z@HYYH0U1HAWAVHUATAUATSH(DEHpYAL-oYL%dYAEA$H=7MYMH1 HljMMA$ƅ^A $D~0A]@L-YL%YAEA4$H=pYH=A"A$A]EE}EH=RpY<H=A4$AEA$PP_AEPu]EH`oYnL%'YL-$YA4$A]fA߅U~WHCQA$uA$AEHYH([A\A]A^A_]@L%YL-YA4$A]uE1fDH=:XHto 1H`AEÅA4$TfA4$DAE~0fA4$A]f.AHL%YL-YAA$AEqDADA4$D1ALHt HYHt HYff.@UH]YH8H1]H]YufUH]YH8HaHAQHH9t]]隿f.UHAWAVAUATSH(HHߒYHL%͒YE1HH̒YI$HH\YH8HtQAHHHDH1AQH2mYH H9 2HtHUH=mYHtDH=YHAQHlYHEL5 YHlYAHYHlYHVlYH$I$HYH/lYHHYH&lYHHhYHlYHH?YHkYHHFYHkYHH5YHkYHH$YHkYHH_kYHlkYHikYHkYHkYHkYHjYHYHY]kYHHjYH+PHx?QHH+PHH\+PHH(1[A\A]A^A_]@1D\OhABDHH=jYHHHEHEHhOHELDH;HuHLsII9uHYsjYH1HtH*PI<$HYHH*PHH}YHH[*PHRH=;H;>QHNY4HAY#HTYH:H:iYH='8xiYL=_aHPH,QH=jiYLL#HEL5bH=FiYLEL-OjH=(iYLEH5iiH= iYEH5FkH=hYEH5CkH=hYEH5`{H=hYtEHPH=hYLH[EH=hYLLEH=hYL=EH5hH=hY*EH5jH=\hYEH5jH=9hYEH5zH=hYDHPH=ShYLHDH=9hYLDH="hYLDH5chH=hYDH5@jH=gYDH5=jH=gYDH5ZzH=gYnDL#fDH=NdH I$1DFHgY@AH=&E1aPL%ҌYHHЌYI$HHŒYHHVYH8HH=tgYHfYHfYYHHfYHfYHfYf.HYH:H(YH8fUHATASHH:Q;tVE~AHYD ~ZHY 2t0HJY0H[A\]2ݐ~HiYHqUYuH8^uHBY2ff.[ff.eYU@HAWAVIAUL-iOATE1SLHD?fDAHAt:HA8uH;LuIKD%HH[A\A]A^A_]DH1[A\A]A^A_]1ff.fUHlYH[YH]1]fUHSHc޾HHHYH=H9uH[]ÐH$P H=HH[] f.UHAVAUL-YATASI}Ht:E~&1L5fI}LA9u[1A\A]A^]@E~L- Y1f.IuOA9u[1A\A]A^]ff.@UHȇY H0H1]@UHSHH`SYtzHPt<1ۃt H[]@H=cYHtHH[]fH#PH3LH;1肿H[]ff"cYt&H=cYHtHYfff.@u$H=bYHt$HYH=bYHuff.H)bYHt4H %bYHt(u HP9:tHuHHUH"PHHH81HfUHǿHt]H=@UHHtHt]H萿H=³fHt &fDf.DUHHaY@HH:YPH:YP aYPaYt@]ff.fHWH{aYHYHYW GUaYGt IaY@HņYHYff.fUHAVAUL-aYATSMtQI]HtHIE1fH;ITH{IHI]AEHu[DA\A]A^]DE1[A\DA]A^]fHYfDHY98|%x!H=`YtHY81ff.fHQ`YHYHcHY;tH,`YHtHf.1ff.fH yY1tH_YHcHff.fHIYH NY;tH_YHHf1ff.fH3Q+8H Y98~xHy_YHtHcH@1ff.fUHATSHHHuIHtH蔵HxHHPHH]~ELID$EA$H[A\]fDHtHHtH^Y8t1ÐH 1мUH4YHATISHcH^YH\H{Ht貺LHx!LH覸HC[A\]ff.fUHATSHt4HH?HtdH{HtVHLcJL[A\]fE1ff.UHAUATISHXHuYdH%(HE1]YtHMY ;]YH9T1LmķL@LII?1衵LH!%tDHWHD@HL)HLHbH/]YLH1Hc H]YHHc HDHEdH3%(HX[A\A]]Ð\Y2lH\Y f.tH\YH8Ht8 H\Y1~fHLH H9Ht0Q2H=N\Y@\YHH4H0\Y获ff.UHAUATSHHt^HH?11LcIMtLKHxLHIMeHCIEHL[A\A]]f.HE1[LA\A]]ff.@UHAWAVAUE1ATSHx~HY98~sHc߿IILIHE[YL,褱HxLH`M~IMeL}HxLH9IFHZYL4HL[A\A]A^A_]|uHPYth9~dLZYMtXyZteDPA1 HI HtH;qDDHHI9uuEx McKHPDHcIHtH9ptDx1 HHH9tHI HtH9quHQff.@xDH5qY9>~9HYYHt-HcHfDHLH H91DUHAWAVAUATSHL=YIE7A9A)މ}E1AFL,DHYYYJ< IM9uHT-QADEH2YYD0)EHcH&EE1$t@fDDH=HU赬HUHAGHcAA\ZH*QL F@EucLqH5H=CAVHDEIcA\ \uAGAA| tA'DDAA9DDfD$\SuCD=;EDLcOt=AtH;Ety脦HvHSYuHuLr~LcOt=AuDA9|D}u>1HuH}dH3<%(HH[A\A]A^A_]A9| 1}׉UD)Hc\UA9HMD@|0EĉHA9}=IcHMA| ED$@\uEL D;MuMcC|ED$fHcHHu>A>,$}tD1HD1uDH1VfDUHAWAVAUATSHHHuHcUdH%(HU1H$Q8HȍIIMHcHD9HMD8`A-9AG< E1A?uEHcEALHED8E[HEDeH]HEoA:wHLVHPYH8HtAޥH5;U)  AIcLD;EIHvHwPYEt< tD9t DxIcEdEuHvHHYDEZ HQD: HGYD: t$A" A\A2 McEt'Ct%@kHQH8LHStD)HcKt%HHH)E$D;e~IcHH}ELH4tDpD9tDH@H]HL9PtLpu 01H]dH3%(H[A\A]A^A_]A'N A\ ED9H]IcAGADžxA\Hc/McK\%3tqHJQH8Ht]ED9 H]AGIcACT%ALj;HcE@H}HcuHEfDH8HHDuH`轙HcuHvHAYHlD %AYD AYIcDHDAYLAYIEDHD,E11LMHEL6D\E9AIcADD95@YHcDpA &u|@YB D9IcH5q@YHqD%V@YDDXADž\qAD/HKHDE!A: uAwArHcHILfofEfHtory modINH`AFifiefE~AF蜛H蔛H@H}L0聛L9PLEdE@DžhAIcDuAD`ED9Ct%AGH]IcAA@4HcfH=衔HAFHu1EEHQH}EEEDUI&HMfH}AHHhHH`D\IDXIH)EA$HhHEH]uEwCD=IIL9`uD\DXHh H!%tDHrHD։HH+hH}DE9|)ЃH}Hc1HEHhIcH}芗]DLھ$$DpLhMLhDpIHB=YI9 MLLhQHxLhHLHfD#-EVL]DUYfDDuD }D)H}HcEOHEXfDE@H}Hcu/HEefDHELE1E11LuMILxEIk@A\SDt A"lH7Yt*A"Eu A'A\LcHcO,f.E8t A' SfE@H}HcuHEIfDE@H}Hcu_HEEfDE@H}Hcu?HEfDUED)LcA|$HcLHIH膊KD&erC&:CD& foifPH`@2DE@H}HcuHE]DH})؃HcEHEQUE9SAH`HcCH`iH}莎HPH迈HxHH{H@H1}$ML8pLL5SHcELI|QPENAA|&5IcDp)EHHHIcsL=1YHHHH QD)F,hHIc>L=1YHIMIcLHD,LLLH\LHD%F1YLG1Y~ElHcA<')CHu'tA HuH=0YhL50YMt A>0YCHع!r@v uHtt 'uڃHcH'IHptH<'t8Pv< tHHuڿ'f>'AHF'F'\''HHuIMH})ȃHcEHEGH@HMH1L9PL迋Dž0D(DeE)A|$McHcIcILLL螆KD&C&:foCD& @ledH`PHHD(DeE)A|$McHcIcLILH1KD&HtitutionC&:CD& fo/HxH`@؊HЊ7HcUHEdDD){HcHc%Kt%HIH貅foA:AD H`ADmD E4ED+(McA|$HcHc(IHPElE1LLHxLHHH-Y)-Y`fUHAUATSHHt.HHx-HHH[A\A]]騇H={BIHtTH贃x LcHcI\$LHfH.historyB /HHH@HH[A\A]]A L-ff.@UHAWAVAAUATSH(1AHEH1FAHRYDD90N]IHQY)9SH,YD:E0HcE1)M$HDII $HyHt?tHMuHME|H9I`E|I9uIcHEHWHHHPQY+u9~\H+YD"EHc)Mt覄IHxʀDD`HIc IHfH}g2~D f.~H}D ?DwfHEH}ff.@U1HAWAVAUAATSH 1IH1,H@ƿAކUHpHHzH8H8HIHD趇DH8蟌H8ELcDHM~hM9scH)YLL1DDI9@9@tGH< uHD8t܃|LuL1f.H_E1I9w FfHL9s;{ HuHSH9s { Cu@A9~ HHL9rL1rLjHĸ[A\A]A^A_]fDH5-(YL8I:tH(00L8H(MtLH08E18H0Vۃg{DL调ACc{DD迊LwLof.+{tD荊LEDsL+fD1@U1HAWAVAUATSH#1IH1/VH@ƿAGX%=ILpI`I׃IHLDH譄DI袉EMcK|5xI9oH&YHH9 u 18)HqHυtI9rL9vZH%YfDH~HI9t u8tH^I9s'L1Aǃ1L要L螁HĘ[A\A]A^A_]f.Ky;yD衈D苈ft yDDcxmHLHDL)1H)zD/EHEY,[1A\A]A^]ÐkDqtĉf"YQ=["YTL%,PIA$u}H~EYI}1 A$tOL%0"YI<$HtH?EYI$HEY}D[A\A]A^]3몐w@H{DMff.@UHDYHATSW4HH=}!YHDYu&HthCsTH=Z!Y[A\])fC87!YHt|HYL LwHxRLHzH!Yk蔼BHY [A\]UHAWAVAUATASH}sL- YD Y]E1{A聿t:HY A}^uDLL#DCMH{CYI>1HPLL%% YI<$HtH4CYYI$HCYH1[A\A]A^A_]@諾D豾eY荾=Y萾۾I聾H=rYIHt 8mHTYL-7YD6YMͺHjBYYH_BYH>BYH[A\A]A^A_]I}D4KHp|am+fDt\UH YHATASHH;OtH;OtmYt-1؅@1Ít6[A\)]D1DD[A\]f.t\UHL YHATASHH;oOtH;Ot?Yt-1؅@1Ít6[A\)]D1DD[A\]f.UHAWAVAUAATA1SHHAuHC8DkTCPaHYEL-@YHH YHH@YAE:DDD@H=<IH1=LxL%3 YA$ЀA$HYH1L{\ !H2PH Aƅt> t9~b~'tƒu\AUD0f u:H1AŸEH[A\A]A^A_]Ðt;tt1oHv HYtyD,&F蛷v>C0S4AEH?Y=A$$H[A\A]A^A_]DY@L1HHWYA$$H1Af?Eff./E{ff.UH= YHHt]蓶]ff.UH=YHHt]S]ff.UHAUATISH ~>Eur軈HPH[A\A]]ft?mHvHwY޿!$uL-0=YAUtt޿-x uL11ÅyH[A\A]]1LHoYHHY 1H[A\A]]HcEHEA1ۄfD<~HaPLL ~iIʼnEMI$]E1LeHEAEHELmMK/DmHEHELpHEIHu IMfMLiH}LHHUiuыEIދ]BD0ELcUO,79M[HcH]LLHH]iHxPLL h A}/DpMLmMIFAHEEFM%I]HMeLmEII\$HH&hHLHxhuD ]LmEąWLcO|5{Hc,LLHHhB3HHImLgMȍ;]Hc}LH}lkLTmAM]E1E9MEMH}DpEHc豮HELmEIL9utwA?/IFtmIDIEL9mt6IfDUH}DpEHcGHE2fD]LmB+McEO,7DLm@HEHEHX[A\A]A^A_]fD1wHcE貭HEfH5P:@B 1fDUHh5YHaXH迫12H>X ]ÐUH/H5YHX]ff.UH= cHSHHP0HP01&0HX @觔#H[]ff.fUHcHAUATIHSHHRPH8uH H9HDH g4Y@FЋ wAH5^XH=PDEt DGB@H[A\A]]-uCHX0u6HPHPH[A\A]]tHxP8N0)1L-XH3DAeVAUaH2YEu?HPE@fDt3L%\XA$tYHB3Y11 fHՏP @HXD9@@A$̒A$$Ao/J0A$$H3H[DA\A]]Uff.fUHSHrHGPHX 1t.H[]{x7Hf2Y81~ttиfn@HюPHȎPHXH1Yff.UHATASHXtBH1YD81H`PH=_0HTP01,1[A\]D(-fD{x7Hf1Y81~tt[A\]fDm[A\]ÐUHATAS!H1YËu"D1V[A\]v-Q.HX߁ m[1A\]fDUH'".}1]fHt;UHSHHH?HtgH{HtgHH[]ffDff.@UHSHbH+ YH;HtHH[]UHATS4HtMHPYHH9Xt=HXL 谩HLîH8HhfH{HtZfHRf[1A\]ff.UHSHH YHHtHH81H;HYHWHH-YHHu-YH1[]fD軥H1[]fUHAUATSHH YH;tH1[A\A]]fHHXL L_HxLL+HzcHYIEHHH@HPH1[A\A]]UHSHH YH;Ht HH1[]U1HSHHH?jHSHYH5 PH e,YHH_,Y6H<,YuH[]ÐUH2]1]fUHAUATSHQL-PAEE1IătHuLMH11HYuIH+YH +Y‰H5"P6uZH!PH=:PH98tH1[A\A]]fHQ+YAUtH ;+Y9H5̉P‹6tu9кDH*YH1[A\A]]fH*YH *Y uJAUfH1[A\A]]fDH[A\A]]79D뷉fUHSH Hލx[]PUHATSu [1A\]fD L% PA$蛦HuH11qHYuLH)YH )Y‰H5}P6u]H|PHPH9o1[A\]H)YA$tH )Y9H5$P‹6t 9кDHL)YD[A\]5DH=)YH :)Y u*A$虥HK[1A\]@9D׉fHP8fDUHSHHcP޿jH1[]@UH2PHH)PHPH1]ff.HMXUHt/1~1R1]fD>1]f.HP181]fUHAWAVAUATE1SHH?IZHAąH'Y0H,X<;8L5'YIc>9HcL= XMc)I HHB Ic>9~LHcI?ZHXA6u,uHrXHHtxtW1ɿwA6H'YA6IHcHD[A\A]A^A_]fD3fH&Y0,9p u+PVP fDL=1XHff.UHAWAAVAUATSH9~AH&YD9}9AOADDIEDE)NeD)D9L5XIcIcMM 0E E 0DHE)A9HNXu4HDD1vID)HHD[A\A]A^A_]fHH^fDL59XH%YH%Y 9~*tH}%Y 9}@yDy@UHAUIATASHzsDH8%YLD )zH[A\A]]DUHAUAATISHWHHfX9~:HcXLH8h[H$YEu*H[A\A]]fDcufUHSHxCH$Yt%9)H1[]赜yH1[]H[]UHSHxcH$$Yt,H$Y:~H PƋ )Ή9|:yH1[]f )DH[]#UHAUATASH)THtcHYuVt?L-y#YAE~UL%XfDI<$ƃ$~u)AEH1[A\A]]HD[A\A]]@AEkH1[A\A]]fDHD[A\A]]fUHAVAUATAS[SHt%HXuu&[1A\A]A^]D[A\A]A^]^fDL%"YL5XڹA4$I>!L-h"YAu9| HPtIA9$t;AEA$yAE|f.D[A\A]A^]\@c뾐I>#ff.@ff.ff.H!Y1H!YH!Y1ff.UHAVAAUATSoFL%q!YA<$3L-Xf.QI}A4$HvHVX ^ ;_A$u0fD^_A$fQI}A4$HvHXuA"I}f^v^tA$lQI}A4$HvHXu!I}fAt A4$[1A\A]A^]!I}[A\A]A^] ff.UHAVAAUATStHYL-Y3A9uL%3XI<$]3AE9P3HvHX3A9u_3A;u}MI<$$]]t9O3HvHEXuI<$Ɖ3A;u|fAt 3A;u>[1A\A]A^]AE39=I<$\BO3HvHXuI<$ fDI<$[A\A]A^]UHAWAVAUATASHhu1dH%(HE1H%YHc)HYD8EyIcADHEsD9HEEL-UXHxHEHEHEHEZ@}9NHtHXu AĀ }"ArIED$IcA9~MI}7AMHvHbX8DsDL[lIcEA9HYD81HMdH3 %(Hh[A\A]A^A_]utYdMHKHX:AĀ-DIuLcHM)H}HcL Y- MHtHXEASIcHHUDPLHUHD$I}AkSIcHHUDPtLHUHD$_EAĀ_DIuLcHM)H}HcLX]Z!T@fIuDLcHM)H}LHcW}t]XQ9HUHxLHcЅ~DI}HxLNRff.@UHwKHYX1H01(3HlX1]fHXUHuzGH>X1]@1]UHAUAATSHHIX @!|#AĩttB~ICDJDDHvH/XpH1[A\A]]AucDDH1[A\A]];QIcHDDZsbJHBhDD8H1[A\A]]H1[A\A]]fDIDDHv HxXt"H1[A\A]]VfDKFfDUHAWE1AVAUATSHXdH%(HE1EAAzIHXHXGD=XE D5XELcXHXH}L5XH XLDmA[D]LcG,LL]HErXLeTL]DUHHHDAGED5XH"X=A1IAf.AELENDHADE)uL?PXDHMdH3 %(DHX[A\A]A^A_]AFDmDmE=AtGHtHrXD8Et:5sADžtDE1u끐EH}EEgH}XHEIHEHEAEHEME1HUHuLA=JIMD;u|@A~Hc|IHEHEAHEME1HUHuLAIIME9McMALE1XLNVfDHELLHHESAGBD%X=v:AYAA A~DuHc規IEDEDA~Hc}IEI=fVIIHEAH/XfLLE*XH5$XD XEJAGHX=vA}׎IAEHcI?sLUHAUATSHHTXD'HXHH,X @FvAŋƒ⿉tHDD[A\A]].fD|ސUHAUATASHHXt1DyHXH [HHXHH1[A\A]]Ðzu@uAŋƒ⿉tHDD[A\A]]|f vfDHYUHcXH0t#HoYHlY;DH)PH8XHqPtUHXuHXu,1]H YHY tHXt?1]fDWHXHt HXt\~DHc׉;D4HY;uEAHDP@tHXu8E1DfHDljNA 7vA'ff.x,H Yt&HlPt D#IUH ]fH Yt H Y;t[ff.UHATSHv YD#EH=XIcHD< t< AD$HƉAątTH t tH# Y9}}H?Hc< t< u%HcDƉ9~H t tD9tAD1D#Ex9[1A\]H Y~H.X1H8< t< tfDAEy1[A\]DYff.Hq Yt H` Y;tۧff.UHATSoHH YHHXH}t/H>AątPHvXH28uIcH?t0HH P 0[1A\]fH Y8B4'@t#AHf4~HW4ff.@fDfDfDUHAWAAVAUATSHuHD[A\A]A^A_]fDH YAEDD3LDDD+>D;D E9t{A9|vDMIDDHEII_DDD+LmLtMDD;E1LYD3_LBLB$藂EA1UHAWAVAUATSHH Y XL- YA}FA*_D;E;}L5FXQ:3HvHXFA)ljAHc蔃IE~1AG1@Hʋ I>Hc ALHJH9uIcL;B4?3I>D1L*^LA1H[A\A]A^A_]@I> IfDs93Hv HXtL5GXD~D;AL5.XI>1 Arff.fUHAWAAVIAUATSHHfY}̉uȋEEEL-=YDuȅ~ A9]L%X}I<$1ɺ|À}t(I<$1ɺV9AUI<$EL7t˃m}H YM̅_H1[A\A]A^A_]fDI<$1҉9tgAUI<$ELtԃm}tlH =YU̅t}yH[A\A]A^A_]D@1I<$1҉k3I<$1ɺD낅+EEkDUHAVAUATLeSH DodH%(HE1H&XHHXDwLY81ff.HXu H Y8DHYH Y;~UHM|]fDtH Y112f.UHATISHn6Mt11LHH@Ht6Ht0HD[A\]D1HH 4HtHuI$UHAWIAVEAUIATSHcHIHHHLM^LMȅ~~IcLΉELHHU>M9u_~[HU8uP~>AAMcMcC7C8D%u1qH H:LuH9ufD1H[A\A]A^A_]UHAWIAVAUIATASH!5EA9EA1Mu{f.HED9}7DHcL1)LHc>HPHw̓ID9|fDD)H[A\A]A^A_]@HEA9~DHc1)LHcJ2HPHwЃA9fD1뤸D)1D9|IE~5HcH1@87u6ApHDH:TuH9u1ff.fUHATSHcIHH dH%(HE1HXu 3PD9#HMdH3 %(u>H [A\]D)HMH}HHcHE"=HHwEN8ff.UAHAWAVAUATSH8dH%(HE1HEDIƅLmDƉDELIADEF$E9~ EEL}fDHtSA؃tGMcDEML2LLLHD@yOLVI9wN_@XwE~G<>v @v4@t.LIH9sMuHL)I0I@HfUHL)HHu~EflA]1ff.@H9^U9====)2_rG=Fj=- )01f.HH5Ft/HrH9ffD@2HH5OFfHH5F랐HH5GF뎐HH57F{HcH$phHH5FSfDf.HH5;F+fDHH5O'FfDHH5)'F@H9:~_LBL9O_1XwRJ>v J_]v׍^=&v.@0v@HH>HHw9BHcHÐHcHxݸø@H9sKy'HFH9r<_1XwVJ>v_]vf.ø@H9sK~#HHHBH9r!@r@2f.f.[@f[f6f[f*6f_[f\6f[f=k6fG[ Zf= U6f={Yf={5f=Vk=Wf=;f`0O4èf+fY5f*TEfv#2fDRf=fZ8/fn]fROf=+f8=Lf=f'óf_öf]*f^fS=IöfO#f>TFf=H(ff Df=]faRf N)f&f^YAf f ?f=Gf==f=If=3<f=f=;f=l f=\);f=F@ f=6:f\ * f=8:f(0f=:fc[fH9ff|9ff6x9f b^fR9f<Ff ,9f9f4ff}ftHf~fffftftf@DÉDBff.Tf.f.èf.f.øEøøøóøöøøø~ø}øyøvøløeøUøøøkøøUø_øOøuøøf.UHHAWAVAUO,ATISH(MHuMHHHwXHMHuM9H9|}MIHuWDA>A~ fAH9M AGIIL;}sLM9sG I$LLLIOAHuIAIL;}rEALLDMHMHuH([A\A]A^A_]DA>A~ fAH9MwaIIL9}vM9vtXI$LLLIOAIAIIAGIfD1-L}$IUHHAWAVAUO,ATISH(MHuMHHHwXHMHuM9H9|}MIHuWDA>A~ fAH9M AGIIL;}sLM9sG I$LLLIOAHuIAIL;}rEALLDMHMHuH([A\A]A^A_]DA>A~ fAH9MwaIIL9}vM9vtXI$LLLIOAIAIIAGIfD1-L}$IUHIHSDŽLNL9r(_@Xw~DOA>_@]I99A@AAHYI9rA_AXA)udLLH9cI9v^yOHyI9rF_v._<]v'E1۸ E1ҁEtA뛐)[][]1@I9w;fI9v9AAA@'fD9fA@yAAfDIAY_]wD AAY>v>fUL ILzHATSfDDŽ HVI9r&_@XwVz@> _]I9ׄALaM9r _@X)uqLHI9jI9vuy^HQI9rUЃ_v>_<]v7 1E1ہt#@HcH y)[A\][A\]fD1@I9v;HAAׄ&HcҿA5fI9w 뙐fqAfyDgA>w Dg_A]vUHIHSDŽLNL9r,_@Xw#~DDOA>_@]AL9D ADEyALYM9r+_@Xw"yD_A>_@]AAD)uDLLH9CL9s.E1Ҹ @AL9w uA@1[]fAAAL9F []f.fADvff.fUHIHATSfDDŽLVL9r(_@Xw~DWA>_@]L99A@ AAHYI9rA_AXA)LLH9_L9HyI9_vz_<]vs E1E1ہEt]ADL9s+9AAA@?fDL9r;1E[A\][1A\]ff)@9fA@yAADQAZ>wD AAZ_]v-DHIMDUHATSDDŽLVL9r,_@Xw#~DDWA>_@]AL9DDEy?HYI9r*_@Xw!yD!_>_@]AD)uOHLItAH9@L9s3E1۸ 뇐AL9w uALIuD1[A\]ÐfAAAL9>[ A\]fAEs1f.HIMDUHATSDDŽLVL9r,_@Xw#~DDWA>_@]AL9DDEy?HYI9r*_@Xw!yD!_>_@]AD)uOHLItAH9@L9s3E1۸ 뇐AL9w uALIuD1[A\]ÐfAAAL9>[ A\]fAEs1f.UHILrHATSDŽLNL9r,_@Xw#~DDOA>_@]AL99A@ynHYI9r.A_AXw$DID!AY>A_A]A)ubLLH9IL9sL9E1۸ A@xHcAA<:ŐHAAL9` uAD1[A\]ÐfAAAL9.[ A\]fAAA`ff.UHILbqHAUATSDDŽLVL9r(_@Xw~DWA>_@]L99A@5ALiM9rA_AXPA)HLH9`L9HyI9__<] E11ہEtAL9sC9HAAA@0HcAA<;@L9rS1E[A\A]]f[1A\A]]fHcHo:)fD9fA@yӻADQEjA>wD AEj_A]v@HIMuUL9oHAUATS@DŽLVL9r+_@Xw"~DWA>_@]L99A@ytLaM9r/A_AXw%DQD)EbA>A_A]A)usLHIteH9DL9sW91۸ A@xHcAA<;DHAL9W uHIu1[A\A]]fûL9[ A\A]]ÐfAAAG1fHIMuULmHAUATS@DŽLVL9r+_@Xw"~DWA>_@]L99A@ytLaM9r/A_AXw%DQD)EbA>A_A]A)usLHIteH9DL9sW91۸ A@xHcAA<;DHAL9W uHIu1[A\A]]fûL9[ A\A]]ÐfAAAG1fHLJ1fHff.1ff.fH9sHfH9s#1Hv@2fULH9HSIL9s>IfHDH?LIIIILH1I9uHRHH9I[]DHHvpIIL9sdPL9v uUHPI9uLVIM9v; u6I9sAx t6@x uHI9r@x u HH9rH)HH9rff.@UHAWEAVIAUATMSHH(DmDUH}HXHHtHMȋ} HMDUucL9UD9tjD9u0HHH{@88u/I9PD9t5D9tpHD9u HL9HDL9uHe[A\A]A^A_]@E9t;HI9AD9tD9L9HfDI9tHqH{L9QA9L9tHqHI9vUQA9uL9aHHI9tJD9tHA9XfD1I9He[A\A]A^A_]HI9t 1 1L9HHHHL9tL9tHAHEAD9t_E EI9tHD8uEHHMEH}MLHPARAUD]DUH DUD]iL;etHADYHEff.@HHDUHHSHH HH[]fUIHAWAVAUIATISIHH9D}HGL9IGHtL9u5A)EELHK "IE[LA\A]A^A_]T@LHL" Iff.fUI9HAVEAUIMFATISLMtHLH/u EDAD)[A\A]A^]fDUL9IGM9HATISLIFH9HFHtHHuD)[A\]UL9HATILIFSLHtHHuD)[A\]ff.UIHAWAVAUIATISIHH9D}HGL9IGL9tLHLIA)EELHK "IE[LA\A]A^A_]81I9UHAVAUATSMHN$L)LL9LiLqHfHI9Hz8_uM9t;DYD8uM9t,DYD8Zu̸DDHD:\uI9uEt*H)A}AyAyvAy DAyEA[A\A]A^]@UtIAA[1A\A]A^]DUL9HATILIFSLHtHHuD)[A\]ff.UL9HAVEAUMLFATISLMtHLHu EDAD)[A\A]A^]fDUHAWEAVIAUATMSHHH|XDmH}HHtHMȿHMȅuhL9t|1DEA9MHA9u/xHHyC8u/I9tCQA9A9tIHA9u HAI9HEI9uHe[A\A]A^A_]D1I9He[A\A]A^A_]ÐI9tHOHSI9wA9I9tHOHI9}wA9uI9tHHI9t1A9tA9H A9tHI9t.Uf.A9tA9u6I9tuHHI9u1HI9$1HI9tI9t:HGHEAA9DmMEDUfDHD8tI9uH6DHCI9tEHHMEjH}MLPHARDUH fI9DUuL;eqDWHGDmMHEEDUeff.fHt'<v$< u0H<v< uHH9u1Ðf.f.UHSHHI9IFH<H9DDHFLIE8ukH9DVDYHFLIE8t"IfHIDPEYE8u)H9uI9t/v=LLH)H[]fDHAD)[]fH1[]H)H[H]IHHfUHSHL9IGM9MGL9MLFNL9DH~HYD8unI9FDAH~HqLD8t"Jf.HHGDFD8u*H9uL9t0s>LHL)0H[]HD)[]fDH1[]HL)[H]HHf.H9HǃD_A>v[LBL9JH eH AHHu(G<v 1@wBP>v=P1|v3fHyeHBHf.Hf.ø@1H9r7HHH9vy_@>vyHHH9wDff.@H9sSy#y_@>vHFH9r;A<v 1vFP>v P1|w@øff.H9HI>@yCHFH9rDWAvXDW AvN_@>vUHL)HHu~EflA]HIH9vMuHL)I0I@@DVEZA>v EyAwHf1ff.H9sK~#HHHBH9r!@r@2f.f.~+1Hw3H9cpljft=fH9s+@2ø@HBH9rf:fDf.UHIHATSfDx_@>( H~H9rx@x @AAI9vyDP_A>LQM9rDPADP AEA)lju!LLH9B1E1ۿ E1I9w[A\]DN>EQA>vAA|CfAA=E[A\]f.AA@DQD!AZ>vA€A|fAAEtAUHIL"a HAUATSDx_@>( H~H9rx@x @AI9vxDX_A>LYM9rDXADX AEA)lju HLH9C11ۿ E1I9w[A\A]]DN>EYA>vAA|CfA=@AEy[A\A]]A<ADYD)EcA>vAÀA|fAAEtAff.UHIHSx_@>H~H9rx@ x @AL9 9DW_A>vl@ygLQM9rDWADW Av~A)LLH9[L99E1ɸ DW_A>wDADAL9e- ADQEZA>vA€A|bfA\fD~DDOA>v ǀ@|fAAAL9- []f1[]ff.UHIHAUATS@x_@>H~H9rx@x @AAL9se9__>v|@ywHYI9r__ EtSA)u0LLH9ZE1۸ E1L9r1EE[A\A]]f.Eu[A\A]]@AAH@~DDWA>v ǀ@|fAAAA YD)DcA>v À|fAAEhAD[1A\A]]HIMUHATSDx_@>H~H9rx@x @AI99D__A>vl@ygLYM9rD_AD_ AA)ulLLIt^H9UI9vP9E1Ҹ D__A>wADAI9e- uALIu1[A\]f~DDWA>v ǀ@| fAAAI9[- A\]DYD!A[>vAÀA|fAAA1ÐHIMUHATSDx_@>H~H9rx@x @AI99D__A>vl@ygLYM9rD_AD_ AA)ulLLIt^H9UI9vP9E1Ҹ D__A>wADAI9e- uALIu1[A\]f~DDWA>v ǀ@| fAAAI9[- A\]DYD!A[>vAÀA|fAAA1ÐUHIL X HATSx_@>H~H9rx@x @ AL909D__A>vt@yoLYM9rD_AD_ AA)LLH9WL99E1Ҹ D__A>wfA<9AAAL9X- AfDDYD!A[>vAÀA|VfAAAN@~DDWA>v ǀ@|fAAAL9[- A\]1[A\]fUHILV HAVAUATSx_@>H~H9rx@x @AL9sj9Dg_A>v{@yvLaM9rDgADg AEtSA)u/HLH9U1۸ E1L9r1EE[A\A]A^]@A<:Eu[A\A]A^]DAA;~D_A>v ǀ@| fAûDaD1El$A>vAĀA|fAAEiAf[1A\A]A^]DHIMUL)U HAUATS@x_@>H~H9rx@x @AI99__>vf@yaHYI9r__ )u{HLItmH9\I9v_9E1۸ __>w@A<:fAAI9`- uALIu1[A\A]]~D_A>v ǀ@|fAI9[- A\A]]YD)DcA>v À| fAA1ff.HIMULiS HAUATS@x_@>H~H9rx@x @AI99__>vf@yaHYI9r__ )u{HLItmH9\I9v_9E1۸ __>w@A<:fAAI9`- uALIu1[A\A]]~D_A>v ǀ@|fAI9[- A\A]]YD)DcA>v À| fAA1f.fUHAWAVAUATSEtL9IGHMLcIcHHuIE1L=NELH)L94EE1Ƀt`IAEMcHH)H9}$DKF$LEuNHHH)H9|DAAAEYHUA[A\A]A^A_]A6LbLH)H9R<Lu$fDHHH)H9ODB<tH9AAAAIһHULUD)A݅dE[LH)L9LceEKLF EtFAtQAIf.LEEAf.IULIXII)M9E@B<Iu#DIMI)M9EB<t}M9}+EԉELLEHEHUE1LDNcHML D8u]IQL@II)M9}EHD8uSH9M9D8D8}EEHQ MUDF EtbAAwnAIIA@HHH9tSM9tN@D8+D8"8uLNI9tFLDF EuHDF EuLG tLL)H}(HHE0L8M9IBI9I@I9ICL)HLfo \ fo\ 1L)HHA AHH9uHHIIH9.I@A A9I9I@A@ AB9I9I@A@ AB9I9I@A@ AB9I9I@A@ AB9I9I@A@ AB9I9I@A@ AB9I9I@A@ AB9I9t|I@ A@ AB9I9tiI@ A@ AB 9I9tVI@ A@ AB 9I9tCI@ A@ AB 9I9t0I@ A@ AB 9I9tI@A@ AB 9I9t A@ AB9[1A\A]A^A_]MfG HE(L8HE0L8M)1A A9HL9u[1A\A]A^A_]MUMcLNHAWAAVAUATSH8DmHuHUDLEȃADDLE11fDHcD!AHL)L9}$DI@y[L^I9wZ@tT@tNDVD׃߃A@v At4Av.LIH9sMuHL)I0I@HfUHL)HHu~EflA]1ff.@H9:~_LBL9O1}wERу߃AvJ}w,׍~=GvM]3vHfH>HcHc xHcHHH Bߐø@H9sKyDIDȃ߃A<v, 1E1EYA}t Af[]1[]I9v9AA@.I9v9fA@yAfD)@D υrADIEAAAA$D ff.UHILbU HATSDŽKLNL9r/@}w&~AAAAA@}I9J9A@ALaM9rAA}\A)uqLLH9]I9vhyQHyI9rH<}w>DIDȃ߃A<v, 1E1EaA}t Af[A\]fD[1A\]fI9vs9fA@fHcHT :)fDI9v;9HAAA@HcAA<:cfDD υJAADIEAAAAD ff.UHIHSDŽLNL9r3@}w*~DAAAAA@}AL9D ADEyHLYM9r2@}w)yAAAAA@}AAD)uFLLH95L9s0E1Ҹ fDAL9n uA@1[]fAAAL9= []f.fADtff.fUHIHATSfDDŽ LVL9r/@}w&~AAAAA0@}#L99A@6AAHYI9rAA}1A)LLH9XL9HyI9<}DQDЃ߃A<voE1 E1AZ}EtLAzL9s#9AAA@6fD1E[A\][1A\]ÐfL9s9fA@yAAD)@D EtADQDӃ߃A'D HIMTUHATSDDŽLVL9r3@}w*~DAAAAA@}AI9DDEyDHYI9r/@}w&yD!߃A@}AD)uHLItH94I9w1[A\]E1۸ pAI9^ uA@fAAAI95[ A\]fAEo1f.HIMTUHATSDDŽLVL9r3@}w*~DAAAAA@}AI9DDEyDHYI9r/@}w&yD!߃A@}AD)uHLItH94I9w1[A\]E1۸ pAI9^ uA@fAAAI95[ A\]fAEo1f.UHILM HATSDŽLNL9r3@}w*~DAAAAA@}AL99A@ysHYI9r3AA}w)DID!D˃߃AAA}A)ufLLH9=L9sP9E1۸ A@xHcAA<:DHAAL9W uAD1[A\]ÐfAAAL9%[ A\]fAAA\ff.UHILK HAUATSDDŽL^L9r/@}w&~AAAAAX@}KL99A@NALiM9rAA}lA)HLH9YL9HyI9<}DYD؃߃A<E1 1EkA}EtqAvfDL9s;9HAAA@'HcAA<:71E[A\A]]Ð[1A\A]]fL9s9fA@x6fDHcHI :)fDD EtAfA}DYEAAAAD ff.HIMUL9I HAUATS@DŽLVL9r2@}w)~AAAAA@}I99A@LaM9r6AA}w,DQD)EAAAAAA}A)uLHItH92I9w 1[A\A]]@91۸ A@tHcAA<;fHAI9> ufûI9[ A\A]]ffAAAI1fHIMULG HAUATS@DŽLVL9r2@}w)~AAAAA@}I99A@LaM9r6AA}w,DQD)EAAAAAA}A)uLHItH92I9w 1[A\A]]@91۸ A@tHcAA<;fHAI9> ufûI9[ A\A]]ffAAAI1fH9HI>@HFH9w.@|@v@t~@ts@vmH-LVI9w\@uVFLIH9sMuHL)I0I@fDHf~_@>vUHL)HHu~EflA]1fH9_]wHHzH9JH IH AHHuwR_]vf1@=tq=uHBH9rCBJH HH AHHu!B_<]wB_<]wøHHBH9r-BP_>hHHø@1H9rWt+x7HHH9vuHHH9w@HHfDHHfDff.@H9y>HFH9t1A_<]wBF_<^Àu$FP_1]v=@FH_>v71@HFH9sǀuF_<^F_<^Ðøff.H9sK~#HHHBH9r!@r@2f.f.H9@2f1HwHH=nFwffwHBH9rȃ@@rf.ø@UHIHS H~H9r'<\x_@]~DO_A]OI99@[AALIM9@t{DO_A]DIAY_]vmEA)LLH9DI99@HAI9E1E1۸ @uDIAY_>wAD EtTA@I9v;9AA@jLIM9,ARD[]ø[]1@~DO_A>I9v 9@yAA)@H~H9v<n^{_@]]^{_@]LI9`F9f @yAA@LIM9[@QYDK_A]?YDI_]*fAAEAUHIL "CHATSH~H9r'<Tx_@]~DW_A]GI99@KALYM9@tzD__A]DYEc_A]vlA)LLH9EI9 9@HAI9E11۸ @uDYEc_A>wAD ߅Af.I99AA@A<9AOA;~DW_A>I9vA 9@ DHiA:)[A\]fD[A\]fDސ1@H~H9V<N^{_@]=^{_@],I9vF9f @pA LYM9C@9DYA_A]&DaDYA_A]fAAA@AUHIHSH~H9r'<x_@]~DO_A]AL99@y2LQM9r#@trDW_A]DQEZ_A]vdA)u?LLH9^L9s)E1ɸ AL9r u A1[]DQEZ_A>wAD A~DO_A>)A L9& []ÐH~H9<^{_@]^DN{_@]fAAA LY@M9YDS_A]DQYA_A]fˁ)Lff.UHIL B>HATSH~H9r'<x_@]?~DW_A]AL9 9@ygLYM9r*@D__A]HDYA[_]A)u`LLH9WL9sJ9E1Ҹ @xA<9ADAAL9k uA1[A\]ÐDYA[_>xAD Aof~DW_A>A L9[ A\]H~H9<^{_@]^DV{_@]fAAA HY@I9DYA_A]DYDaA_A]fAÁ)H|ff.@UHIHATSfD H~H9r'<lx_@]~DW_A]_L99@sALQM9@tzDW_A]DQEb_A]vlA)LLH9EL99@HAI9E11۸ @uDQEb_A>wAD ׅtnAfDL9s;9A@jLQM9,ARfD1E[A\][1A\]ff~DW_A>L9s 9@yAf)@H~H9^<V^{_@]E^{_@]4L9HF9f @yA(LQM9K@ADQA_A].DaDQA_A]fAAAff.HIMUHATSDH~H9r'<x_@]~DW_A]AI99@y9LYM9r*@D__A]DYA[_]A)uLLItH9QI9w 1[A\]DE1Ҹ fDAI9p uA@~DW_A>9A I96[ A\]DYA[_>PAD AGHY@,I9#DYA_A]DYDaA_A]fAÁ) HH~H9v<n^{_@]]^DV{_@]GfAAA 91HIMUHATSDH~H9r'<x_@]~DW_A]AI99@y9LYM9r*@D__A]DYA[_]A)uLLItH9QI9w 1[A\]DE1Ҹ fDAI9p uA@~DW_A>9A I96[ A\]DYA[_>PAD AGHY@,I9#DYA_A]DYDaA_A]fAÁ) HH~H9v<n^{_@]]^DV{_@]GfAAA 91UHIL4HAUATSDH~H9r'<x_@]~D__A]wL99@;AAHYI9@tx__]`YDk_A]vlE)LHH9GL99@HAI9E1۸ E1@uYDk_A>w EtyfL9s39AAA@/A<:a1E[A\A]]f2[1A\A]]fH)3:)뱐~D__A>L9s 9@AA@HYI9@Y_]DiYA_A]pfELdfH~H9<^{_@]^{_@]L9F9f @AA@H 2)f.HIM4UL1HAUATS@H~H9r'<x_@]?~D__A]AI9 9@yyHYI9r(@__]JYDc_A])uHLItH9TI9w1[A\A]]fD9E1۸ @xA<:@AAI9[ uAYDc_A>n ߻g@~D__A>A I9[ A\A]]DH~H9<^{_@]^D^{_@]fAAA La@M9Y_]YDi_]fAÁ)L1f.HIM4UL/HAUATS@H~H9r'<x_@]?~D__A]AI9 9@yyHYI9r(@__]JYDc_A])uHLItH9TI9w1[A\A]]fD9E1۸ @xA<:@AAI9[ uAYDc_A>n ߻g@~D__A>A I9[ A\A]]DH~H9<^{_@]^D^{_@]fAAA La@M9Y_]YDi_]fAÁ)L1f.HH9sI>@yGLVI9wN_@VwEFHH?.BHcHfHHw)B֐HcHxŸø@H9s;y*HFH9r_1VwF_<^ø@f.H9sK~#HHHBH9r!@r@2f.f.H9\=89====)  =TMcfa=1wJHcHpfHH5Ft HrH9r fføfD@2HH5FfHH5F랐HH5F뎐HH5F{fDHH5FcfDHH5GFKfDHH5F3fDHH5aFHI|DŽLNL9r_@Vw ~_@]vdI9vd9A@yALYM9rA_AVA)uLLH9w1I9f.I9w3DI9v9AA@xAf)D9fA@yA_DIEY_A][D AVff.HIL4H9UHSDŽLNL9r_@Vw ^{_@]vyI9v|9A@yLAHYI9rA_AVA)uLLH9w1I9[]fDHcH4[]:)DI9wSАI9v9HAAA@qHcAA<:@1I9@9fA@wA&@DIAY_]'D A"ff.fHIDDŽLNL9r_@Vw~D_@]AL9D ADEy4LYM9r_@VwyD_@]AAD)uELLH9^L9s)E1Ҹ AL9r uA1DfAAAL9P @fAEAzff.HIH9UHSDŽLVL9r_@Vw^{_@]L99A@AHYI9rA_AVA)uLLH9w1L9[]DL9s 9AA@xAfL9r#1E[]1L9@)@9fA@yAODQAZ_]TD AODHIM3UHSDŽLVL9r_@Vw^D{_@]AI9DDEy2HYI9r_@Vwy_@]AD)uRHLItDH9[I9v6E1۸ @AI9w uALIuf1[]fAAAI9H []f.fDӻi1ff.HIM3UHSDŽLVL9r_@Vw^D{_@]AI9DDEy2HYI9r_@Vwy_@]AD)uRHLItDH9[I9v6E1۸ @AI9w uALIuf1[]fAAAI9H []f.fDӻi1ff.UHIL2.HSfDŽLNL9r_@Vw^D{_@]AL99A@y`HYI9r A_AVwDIA_A]A)ufLLH9eL9sP9E1۸ A@xHcAA<:DHAAL9j uAD1[]fAAAL98 []f.fAVff.HIL,H9UHATSDŽL^L9r_@Vw^{_@]L99A@LaM9rA_AVA)uHLH9x1L9[A\]L9s09HAA@xHcAA<:@L9r;1E[A\]fD1L9@HcH+:)fD9fA@yӻ(DYEc_A],D A'DHIMUULY+HATSfDDŽLVL9r_@Vw^D{_@]I99A@yfLaM9r!A_AVwDQD!A_A]A)unLHIt`H9_I9vR91۸ A@xHcAA<;HAI9j uHIu1[A\]ffAAI9([ A\]ÐfAAAL1fHIMUUL)HATSfDDŽLVL9r_@Vw^D{_@]I99A@yfLaM9r!A_AVwDQD!A_A]A)unLHIt`H9_I9vR91۸ A@xHcAA<;HAI9j uHIu1[A\]ffAAI9([ A\]ÐfAAAL1fHH9sI>@yGLVI9w@t@tFx@>vM<|IUHL)HHu~EflA]@HIH9sMuHL)I0I@@L1ff.@H9:~oLBL9r|O1}wRJ>vJ~v~=}vHfHHBfHH>ø@UHAWAAVAUIHATHSH(]IMXHuH}ȉ]KHMI9H9EMIHu}[fDA$H |f-iTIVAf-fA6H9U:AFIIAL;usQI9sLE6IHLLoH}IIAAD$AFL;urEELLDMHMHuH([A\A]A^A_]p@A$H f-iT2IVAf-fA6H9UwfIIAL9unL9eEtSIHLLtA$IIAF벐IAFIfDE1LuIUHAWAAVAUIHATHSH(]IMXHuH}ȉ]KHMI9H9EMIHu}[fDA$H Lf-iTIVAf-fA6H9U:AFIIAL;usQI9sLE6IHLLoH}IIAAD$AFL;urEELLDMHMHuH([A\A]A^A_]o@A$H df-iT2IVAf-fA6H9UwfIIAL9unL9eEtSIHLLtA$IIAF벐IAFIfDE1LuIH9sKy'HFH9r<1}wVJ>v€~vf.ø@H9sK~#HHHBH9r!@r@2f.f.H9\====)=rG=Q=01wDHcH%pHH5FtHrH9r ffø@2HH5GF뾐HH5F뮐HH5F랐HH5*F뎐HH5F{fDHH5FcfDHH5W(FKfDfUHIHSH~H9r(x@}w~DOA>ǀ@~I99@AALYM9r D_A}vKA)upLLH9lI99@yKHAI9rBG<}w;E1ɸ E1DYA[>vrA[~viEtAfD[]I9w[[]I9v9AA@5볐1@)@D EtA+f.9f@yAAff.fUHIHSH~H9r,x@}w#~DDOA>ǀ@~AL99@y=LQM9r.DWA}w$DQEZA>A€A~}A)u?LLH9NL9s)E1ɸ AL9r u A1[]fAAAL9T []f.fA}ff.UHIHATSfDH~H9r(x@}w~DWA>ǀ@~L99@AAHYI9r_}vWA)LLH9jL99@HAI9G<}wyE1E1۸ YDcA>vxDcA~vnEtKAL9s#9AA@M֐L9rK1E[A\][1A\]Ðf)@ EtA9f@yAAff.fHIMEUHATSDH~H9r,x@}w#~DDWA>ǀ@~AL99@y=LYM9r.D_A}w$DYD!A[>AÀA~A)uWLLItIH9HL9s;E1Ҹ fAL9u uALIuD1[A\]ÐfAAAL9<[ A\]fAAAk1fHIMEUHATSDH~H9r,x@}w#~DDWA>ǀ@~AL99@y=LYM9r.D_A}w$DYD!A[>AÀA~A)uWLLItIH9HL9s;E1Ҹ fAL9u uALIuD1[A\]ÐfAAAL9<[ A\]fAAAk1fUILL*RHAVL42AUATS-H~I9r(x@}w~DOA>ǀ@~I99@ALaM9r DgA}vI)uzLHI9nI99@yUHAI9rLG<}wEE1ɸ 1DaEl$A>El$A~t[A\A]A^]ffDA|9I9[A\A]A^]ÐI9v9AA@A<:1@HQ)R:){fDA EADAAFl/DEiC<,A<{f)A-i9ACf-@NAUHILL(RHATSH~H9r(x@}w~DOA>ǀ@~L9:A9@ybHYI9r&_}wYDcA>À~)uXHLH9WL9sB9E1ɸ @xA<:fDAAL9p tD1[A\]ffD-iA|9AACf-@fDAAFd'iDA<{fD[A\]ff.fUHIL&RHAWL=AVAUATSf.H~H9r(x@}w~DWA>ǀ@~ L9+9@JAALiM9r DoA}v[A)LLH9hL99@HAI9G<}E1Ҹ E1DiEuA>EuA~EAvDL9s[9AAA@0A<;A?fDfDA|:L91E[A\A]A^A_]D[1A\A]A^A_]ِH%R:)ɐA EADAAFt7iDA<fEtA@AA-i9AGf-@.HIMULi$RHAVL5]AUATSH~H9r(x@}w~DWA>ǀ@~I9RA9@yoLaM9r,DgA}w"DaEl$A>AĀA~A)uiLLIt[H9JI9vM9E1Ҹ @xA<;AAAI9` uLIufD1[A\A]A^]DfD-iA|:AAFf-@9fDDAԁAiGd%DAA<~f[A\A]A^]1ff.HIMULy"RHAVL5mAUATSH~H9r(x@}w~DWA>ǀ@~I9RA9@yoLaM9r,DgA}w"DaEl$A>AĀA~A)uiLLIt[H9JI9vM9E1Ҹ @xA<;AAAI9` uLIufD1[A\A]A^]DfD-iA|:AAFf-@9fDDAԁAiGd%DAA<~f[A\A]A^]1f.@H9sHPH@f.UHIE11HATL%SHL9EAD H9r@tNtZ1@u>HA<<;EuDHGFD8u7D8u/E1҉@[A\]fD1E[A\]E@[A\D)]L MH<HvzHHH9snGH9v< u^HGH9uL^IL9vD< u@I9 t uHI9r@ uHH9rL Mf.ULHHATSH[0fLHI?LHLHHI1H9vBD&Lȃ?LF$#LHcIMAILMbI1uHMH9w[A\L ]MH9IMff.UMAH HAWAVDuAUATSM9H9ELHL=}L-V8@AvWtSLZDbEBL9LHI9vAt=EEt5DLZL9GDDGdEBEuHLI9w[EA\EA]A^A_]VHEHE1ff.UHHIE1E1H5HSHH&DHFFE8}AH9rEt8L9rEtF1EuDHB F EtE8uGE1fDEuW1L9r>H[]DEuHH[H)]=zDEHAD)[]LHH)z밸ff.fH9sK1Hw*HHENHHHt@  t D1H@f.UHAWIAVIAUIATISLH8H$XDMHHt } ЅI9LALAMDEMI9E9Euf1f.LcOM9L]LLLLUyLUL]MMI9trA;E;E9Eu IFH9LEIHLLzM9t5IEXAI~IwA8uIII9uE1M9AAHeD[A\A]A^A_]EE9Et8LMMIIL9HLIf.EM9tYILLL~IILLLHcLLOIL9A;Eu|M9uDE8fIILHLHcHڃHOIM9A;Et;EuYL9tIILHLHA9EfuME1M9AALIHL9M9tˆE;EIHLLHLǃOLEIfIHLLHcLINHUEIFXEM9LE H]]EoHcILL9HMw}LLvHMujI͋EHDMLLEHMLLPEPEPEH M9M9uILLL~FILLL~%ILLLHcLLOIAEIVX}@8<uI7E1IGH9fAI@}UIGHEAff.UHAWIAVIAUIATISLH8HXDMHHt } ЅI9LALAMDEMI;E;Eug1f.LcOM9L]LLLLU*uLUL]MMI9tjA$;E;E;Eu ID$H9LEIHLLxM9t3IT$IGA7A84$u III9uE1M9AfAHeD[A\A]A^A_]EE9Et8LMMIIL9HLMIEM9tZILLL~IILLLHcLLOIL9A$;Eu{M9uDE7IILHLHcHڃHOIM9ED;UtD;UuYL9tIILHLHA$9EuME1M9AALMIHL9M9tD;UDUHLLI$HLǸOLEI$DUYDUHLLI$DUHcLINHUM9IE H]DU]EnHcI L9HMw~LLDrHMukI΋EHDMLLEHMLLPEPEP?H M9M9uI$LLL~HI$LLL~&I$LLLHcLLOIA;EuI>E1IGH9eEWIXIGHEAUHAWAVAUL,ATSHHML9IHMIMfILHLIWx HIHRHH5SHRHH @HIT$=)HLÏI9wLH+EH[A\A]A^A_]HLÏI9vILHL~UIWx HHRHHtuSHRHHtdHIT$=~IAL$@IHAAD$qfDIHAAD$(fDA $CIHAD$1fDA $CIHAD$fDIAL$H1[A\A]A^A_]ff.@UHAVAUIATS>LgPtyIHAIHLH~HHÀ;uH[A\L)A]A^]D{AHCHuH[A\L)A]A^]f.HH[A\L)A]A^]ff.UHAVAUIATS>LgHtyIHAIHLH~HHÀ;uH[A\L)A]A^]D{AHCHuH[A\L)A]A^]f.HH[A\L)A]A^]ff.LGHE1@LGPAqUHAVIAUATISLoPHAA$I$HLH~-HTLfHHH8KuOH9uIHfA$I$LLLA3HSIFA| A8|5t[A\A]A^]8[A\A]A^]ÐUHHEjPEPIUHAWAVAUATSHH9sZIIHE1AILHLANIHIL9wHL[A\A]A^A_]@E1ff.UHAWIAVAUATSHHHuH9spHtkIIAILHLANHIItL9wHMHCI)H)MIDH[A\A]A^A_]Luf.UHAWIAVAUIATMSHH8L9LHuIFLMLEHHHLLMHHEL0LH)HEHEHxt_HELIHEI)LmMIHEt7IHLL~;HcM\ L9]ML+MLMHEL0HEH8[A\A]A^A_]@L9wuHEHxHML?LIP0~HIIIcfDH}HHLMHM1tLMHM @HLLL]HMlHML]IMf.LpgI9v 1UHAWAVAUATSH(MHL)HH9shLMMIIHME1HufDIE1MLHMLLPtwIHLL~$HAII9r1H([A\A]A^A_]DIAL9wfUtIAAEt1HEML+U}DPDhvDP EDP@H([A\A]A^A_]@UHILHAWIAVIAUO,ATSLH8HuLGXH9r L9L9iA^L9UTLeMu? DAHIAD$AAL9M9yILHLLULELELULcO M9v MMM)LHLLULEL]LMRjALML]LULLEMAL9^LH+EH8[A\A]A^A_]@A$HIAAI9vɅtM9vyILHLLULUȃ~LcO M9rDLHLLULMLEiLELMLULMfDMMM)DML9Le'AHIAD$A/L9yILHLLELEȃ~7tdtOu3HSID$A4$HZL`fHLLeL9rPH81[A\A]A^A_]IHAD$IHAD$@A$HIA/L95yILHL~.tAt,u3HSID$A4$HZL`HLIHAD$IHAD$DUHAUIATL$SLHHMHMZHDMLjDEHHL?He[A\A]]ff.@UHAUIATL$SLHHMHMHDMLjDEHHL@He[A\A]]ff.@HHkDULH9HSIL9s>IfHDH?LIIIILH1I9uHRHH9I[]DHHvpIIL9sdPL9v uUHPI9uLVIM9v; u6I9sAx t6@x uHI9r@x u HH9rH)HH9rff.@UHAWAVIAUL,LATSHHHMLH~nLEMteHcMxI L$IthM9saIHLHeHII9@IH@uHL[L)A\A]A^A_]DH1[A\A]A^A_]Iff.1ff.fUHAWAVIAUL,LATSHHHMLH~nLEMteHcMxI L$IthM9saIHLHdHII9@IH@uHL[L)A\A]A^A_]DH1[A\A]A^A_]Iff.UHAWAVIAUATSHL<1HxHu(H} MHELmDEHxHu0H}ILEHpDMdH4%(Hu1HEHELmIHEH}HEL9LmL;e^ L9U LELIMI@:E:EJ:EAILLHLELE#HcH I9LH9UH{IL$I9DXIuAH9D AAD!I9I9AD ɄI9H9P11fo AD A H9wEDމA)L I< L9AEAAAGAAAAGAAAAGAAAAGAAAAGAAAAGAAAAGAttAAAGAtcAA A G A tRAA A G A tAAA A G A t0AA A G A tAA A G A tAAAGHHIIIL9L;et MLH+EHpH}HHxHL9ID$I9IEI9MHGL)H<L)fo 1HHHADAHH9uHHIIH9VH}ID$AE A$ H9:ID$AE AD$ H9!ID$AE AD$ H9ID$AE AD$ H9ID$AE AD$ H9ID$AE AD$ H9ID$AE AD$ H9ID$AE AD$ H9ID$ AE AD$ H9tvID$ AE AD$ H9taID$ AE AD$ H9tLID$ AE AD$ H9t7ID$ AE AD$ H9t"ID$AE AD$ H9t AE AD$ f1H]dH3%(Hx[A\A]A^A_]@H}HK3ML$tI9w`AuHIA4$MfHSL9_HiD1HATAHPH9uBfH}L`LhHMHMLhL`tFLhCHM:Et::Et5H}L`sL`HMLh 3!H}LH+EMIA@ HDEH9IHxI9HL`HWL)HOA~L)fo%R&HHflHɈfoLfiDfoHfafofafifaffg@H9uHHIH9cIH]A$ID$H9FIAD$ID$H9,IAD$ID$H9IAD$ID$H9IAD$ID$H9IAD$ID$H9IAD$ID$H9IAD$ID$H9IAD$ID$ H9tzIAD$ ID$ H9tdIAD$ ID$ H9tNIAD$ ID$ H9t8IAD$ ID$ H9t"IAD$ ID$H9t IAD$HpH}LeH]LH]IL$ H8ILIHIIAAAE IEH9NIIDH9rHs+MHtA $AMMtALfAL뺐I $I}LHIMILILI)J *L)HHHS3L`H}LhHM{HMLhHL`IL9MIHKIAEA$ID$sMIHE1L)f.AD A HH9u7H@IIAD$L9uiA $AMALALLe1o\ff.@UH1HAWIAVAUATSH1HhHEHE HEDMHEHELuLuDEIDMHEL;eLm HELeHEHEHEHxLMIHMHHuLIP(-HHuHHEH9LML9LUL9HELULMHtuH9LMLUt]LUHMHLILMHxP(LMLU~.HuI9I9H}EMHuILLLP0~5HHMLHuIILP0~HIHm@LMILLH+UH+E HM(H]0HHAHE1LAHILHLL)E1H)PxHULLIAL)H)PxHHhD[A\A]A^A_]fHMHHuLIP(HHILLLHuP0ILLLIP0HIHMLIILP0A4IH1IK<.TUH}H1LCUfDHUHuMH}wHcMHf8HEHHHLLHEILHuP0HHMLHuIILP0HuHIHufDLMI LMH}(ILH+EAG HDEHHE0H}H811LH}MIHE0H8HE(H8UHHEjPEPYUHAWAVAUATSHH9IHIE1Lm!@H-IWIH=LCL9s]ILHLLP(~YHHHEH=wHH5%NHHHHJHt8HN|8L9rHL[A\A]A^A_]@Hf.HcE1UHSHHuHHP(~ HUHvH[]HHHH VNHqHtH[]DfHtHff.L9MLWXLFEtL1"fD<D HA<:G D8u$I9u1I9пI9Bf@D)UI9HATSHL_XIFHH9DDH~LaG GE8H9FH~qE E3HAHE8t'HwHE 3pE3E8uiH9u1I9tUIGHGGH)HH9s3As A @8t9fA @8u#HH9u1[A\]A[A\D)]@[A\@8]GHuLmM9MFL9IGff.fE18HOPtH@HuH)1ff.fHOHtH@HuH)1ff.fHHWPH<H9t1fDD>FD9HH9uHHWHH<H9t1fDD>FD9HH9uLOP1Ht(<DHGA<9D8t@D)D1ff.fH9fe@H9s+HGh  HHHu:f.H9sXHGpHHHt%fD8H9w D@I9sHHHHu1fDHH)H øff.fULHATM SH_XH9L9sI1A- E1A+ME11fIE:M9t7A@ vA@wlA@9}9vAIE:M9uM9WMtMEtcwHHED[HA\A"A]A^A_]A@wA9NADx E[A\A"A]A^A_]fIAE;M9@If.UAHAWAVAUATL$SL9sRHW@IHDuDDAHDt1IM9uA!1M[A\I0A]A^A_]t>I1@-E1@+ME11IM9t7E:A@ vA@wTA@9}9vAIM9uM9SMtMEuwHHEHD[A\A]A^A_]A@wA9fAIAM94If.[A\A"A]A^A_]fUHAWAVAUL,ATSAL9sNHW@IHDu@DAHDt-IM9uA!1MtI0[A\A]A^A_]t>ILcH1IIƉ@-E@+M1E1@M@IIM9t4A{@ v {@wp{@9}M9vIM9uM9HMtMEԅtZHI9wLH؅-A"H[A\A]A^A_]Ð{@w{f9N놐LMxA"H[A\A]A^A_]@EIM9If.UHAWAVAUL,ATSAL9sRHW@IHDuDDAHDt1IM9uA!E1MtI0L[A\A]A^A_]t>ILcH1I@-E@+ME1E1!M@IIM9t5A{@ v {@wp{@9}I9vAIM9uM9GMtMEHI95LH؀}LE[LA\A]A^A_]{@w{f9NAEIM9f.If.A"IL[A\A]A^A_]@1ff.fUIEHAWAVIAUATMSHH(HIWDmD}HHt!HMH}ȋ} DML]HMDUutL9jA9twA9uAHISXsHH842@84:u/I9PD9t1D9tlHA9u HL9HDI9uHe[A\A]A^A_]øE9t;HI9D9tD9I9HI9tHqH{L9QA9I9HqHI9vYQA9uI9aHHI9tND9tHA9Tf.1I9He[A\A]A^A_]HI9t 11L9L9tI9tAHAHED9IKXEȋE E}H@8<t"I9uHHHHHEHHMELMLHPAWAUDUL]H L]DUQI9tIKXL;eaHAQHEPf.UHAWHEAVAUL,1ATLeSDLeH] IL9eAL;UA"L9HUHI>fDE8tcE82DXEZHM9LHAM9AEtMI9tHDHCLRA8uL~M9tVLPARfDABHPLH+UH}0HH}(HM9HPI9IRH9&IT$L)HLfoɸ 1L)HHDAHH9uHHIHH9IR A I9 IR@ AB I9IR@ AB I9IR@ AB I9IR@ AB I9IR@ AB I9IR@ AB I9IR@ AB I9tuIR @ AB I9tcIR @ AB I9tQIR @ AB I9t?IR @ AB I9t-IR @ AB I9tIR@ AB I9t @ AB [1A\A]A^A_]@HM(HH+EHsG HDELLHHE0HMHHBLH)H9H9@ M9@L9AD !It$H)H@@YH I9@L9@?~Hfo-g 1HfflɈfofiDfo$fafofafifaffgHH9uHHHHH9HHBI9BHCHBI9BHCHBI9BHCHBI9vBHCHBI9[BHCHBI9@BHCHBI9%BHCHBI9 BHCHB I9B HC HB I9B HC HB I9B HC HB I9B HC HB I9B HC HBI9hBHCUfDM)1 A HL9u[1A\A]A^A_]HLU1r1fH@4HH9uHH)fHff.H)HI@H9HFHI0@+u GV )ff.@H9sHW@T1ҸUHHAWAVAUATSH9/HRLP@f.HH9HADu@ըu HH9LV L9LBL9eDXA TH1DD;E_A >HEHICI9uL9E1A)E*MEeA IL9vIL9fA\HEIAIDML9wHD)E1LIEfDHI1A![A\A]A^A_]fDM@-u5PHЃ"A1*HM[A\AA]A^A_]A.UHE11EgI9&EAAEMSL9EsEnDAfMSL9~A-u`L9AsDnA 1A-u2fD4EIAtuL9E2EnA w{D3A~MMHA"H@-HIL9wMRLM1A-uMӐsEtHuHM@-jH]A"HE1A4IAL9uMZAHHUD)I9rIL9EEjA vE*AHI1@-HA"1T4EIAtuL9E2EnA AA)A~MM1A HH9;H4H6H9!HH@H9HHuHHyH5^HcH41HHH9HCI9E+EUA Mw1AE)E*E]A wCIL9uI1MA.MZL9EREjA vXDEEjA AIL9uA-MӅHH9A"Hff.f.UHHHHHLpLxt )E)M)U)])e)m)u)}HEH8Dž8 H@HPDž<0HHTff.@HHкHHDLHHH fUHHATISHPdH%(HE1EMy1ILIA@0HHэ)ЈEI L]Is@fDHȃ0HIHDED)HHuIAI)M9MGL7IH]dH3%(u>HP[A\]fI-IHKAHu9ff.@UHIHSHXdH%(HE1My1EMLUIr@y/LLUHHIr?HA)A0DEIIfDLA0HIHA)DIHuIR@H)IL9LIFH 6HH]dH3%(uAHX[]DE0HuߺfI-IHN8ff.UHHSHHH9HHHFH(4HH[]ff.UHHSHHH9HHHFH3HH[]ff.H3fDUHAUATISLHL9LmIGL9HFHu&IIEHMeH[A\A]]fHHHr.tCf.H9s[H@DuMHDuHH9uHFH9t"~0t80uHH9u1ø1I9UHAWAVAUATSMHN4L)LL9HXLyHD,HAHEf.LM9LRABD8,uM9tLAA8uL;ut5BY8uD$HB8'uI9uEt+I)AA}EQEQvEQ EEQEA[A\A]A^A_]fUtIAA1[A\A]A^A_]ff.LMxU1HAWAVAUATIHSHHHtHH=A AftAH<[HD=Et,f9=AfDF=f9=fC=ADH<[AHHfD=f=D=H=zLHI1H L;f.AIE0AW AO)ʃLcLIGHL1H/HHt;I$A0f9rfA;G wft)HHȀ8LjHuŃISAUHHHtcoLSHI HHAo $IH  HH9uHcHHHf1H[A\A]A^A_]Í{HcHHHHt΅to^똸fDHH)fHHvpHHH9sdPH9v uUHPH9uH~HH9v; u6H9s:x t/@x uHH9r@x u HH9rH)H9rfDUEHAWIAVIAUATMSHHH)WDmHHtHMȿDMHMD]u}L91DEA9bHA9u@DHIGXSHy180u/I9t?QA9A9tMHA9u HAI9HEI9uHe[A\A]A^A_]Ð1I9He[A\A]A^A_]fI9tHOHSI9wA9I9tHOHI9|wA9uI9tHHI9t1A9tA9H A9tHI9t-Mf.9tA9u7I9tHHI9u1HI91HI9tI9tCHGHEA9IOXDmMDEDUHD:$tI9uH-@HCI9tEHHMEjMLHPLARDUD]sH WI9tIOXD]DUL;e]HGWHELfLWXAHH9vAӉI9sELL9t:II9sa1A<A<:@<HH9u9D)߉9fLL9s'HAVI9uf.D)19HwhHtGHH HH9t7f8v 11fDHHt# V9tf1D0@DUHATISH~ C H{Hfƃ t1H{Pt*H{@t#H{htI$HspH{h[A\][A\]fDHWX1HtJa8JAs 1:JB HXtWUHSHHHsX C Ht1 18v HHH=uH1[]øff.1ff.f%@?uHJO fDAAA?A?ADE@@t/AEFAD!E!AD D A @t/AEFAD!E!AD D A @t/AEFAD!E!AD D A ȃ t&Fξ!A!AD A D @AEDDAD!E!AD D A AA!A%MH9tHVHHH)H)Hv6HfvHHoHf@H9uHHHH9HGH9HGWH9HGWH9HGWH9HGWH9HGWH9HGWH9HGWH9vvHG WH9vjHG W H9v^HG W H9vRHG W H9vFHG W H9v:HGW H9v.WÐt%HH9sHHWFH9rfDHH9wHHЈWFH9vfff.@UDHAWAVIAUIATISHHH9A%EEtMEtHA@tyDIHDMI)E9EGELLLAPxI9DMANjMDHLU̅tEu2HHL)[A\A]A^A_]DMDHLE̅tMLHLH)ALAPxff.UHAUIATISHHMHMHDMHjDEJ #HLHe[A\A]]fUHAWIAVAUEATISHHL9MAAEtwEtrA@u2DHLEuwHHL)[A\A]A^A_]f.DMHDMI)E9EG1ELL$$I9܋MDMADHLHEtEtfDLH1H)L#qUHAUIATISHHMHM~HDMHjDEJ #HLHe[A\A]]fH9HǃD_A>v[LBL9JH NJH AHHu(G<v 1@wBP>v=P1|v3fH JHBHf.Hf.ø@H\tUH9s`@21Hw3HIpƅt"=~HrH9r fføÐ_ff.1H9r7HHH9vy_@>vyHHH9wDff.@UAA\HHj%H9sSy#y_@>vHFH9r;A<v 1vFP>v P1|w@øff.H9HI>@yCHFH9rDWAvXDW AvN_@>vUHL)HHu~EflA]HIH9vMuHL)I0I@@DVEZA>v EyAwHf1ff.H9sK~#HHHBH9r!@r@2f.f.UHIHATSfDx_@>( H~H9rx@x @AAI9vyDP_A>LQM9rDPADP AEA)lju!LLH9B1E1ۿ E1I9w[A\]DN>EQA>vAA|CfAA=E[A\]f.AA@DQD!AZ>vA€A|fAAEtAUHILEHAUATSDx_@>( H~H9rx@x @AI9vxDX_A>LYM9rDXADX AEA)lju HLH9C11ۿ E1I9w[A\A]]DN>EYA>vAA|CfA=@AEy[A\A]]A<ADYD)EcA>vAÀA|fAAEtAff.UHIHSx_@>H~H9rx@ x @AL9 9DW_A>vl@ygLQM9rDWADW Av~A)LLH9[L99E1ɸ DW_A>wDADAL9e- ADQEZA>vA€A|bfA\fD~DDOA>v ǀ@|fAAAL9- []f1[]ff.UHIHAUATS@x_@>H~H9rx@x @AAL9se9__>v|@ywHYI9r__ EtSA)u0LLH9ZE1۸ E1L9r1EE[A\A]]f.Eu[A\A]]@AAH@~DDWA>v ǀ@|fAAAA YD)DcA>v À|fAAEhAD[1A\A]]HIMUHATSDx_@>H~H9rx@x @AI99D__A>vl@ygLYM9rD_AD_ AA)ulLLIt^H9UI9vP9E1Ҹ D__A>wADAI9e- uALIu1[A\]f~DDWA>v ǀ@| fAAAI9[- A\]DYD!A[>vAÀA|fAAA1ÐHIMUHATSDx_@>H~H9rx@x @AI99D__A>vl@ygLYM9rD_AD_ AA)ulLLIt^H9UI9vP9E1Ҹ D__A>wADAI9e- uALIu1[A\]f~DDWA>v ǀ@| fAAAI9[- A\]DYD!A[>vAÀA|fAAA1ÐUHIL =HATSx_@>H~H9rx@x @ AL909D__A>vt@yoLYM9rD_AD_ AA)LLH9WL99E1Ҹ D__A>wfA<9AAAL9X- AfDDYD!A[>vAÀA|VfAAAN@~DDWA>v ǀ@|fAAAL9[- A\]1[A\]fUHILR;HAVAUATSx_@>H~H9rx@x @AL9sj9Dg_A>v{@yvLaM9rDgADg AEtSA)u/HLH9U1۸ E1L9r1EE[A\A]A^]@A<:Eu[A\A]A^]DAA;~D_A>v ǀ@| fAûDaD1El$A>vAĀA|fAAEiAf[1A\A]A^]DHIMUL9HAUATS@x_@>H~H9rx@x @AI99__>vf@yaHYI9r__ )u{HLItmH9\I9v_9E1۸ __>w@A<:fAAI9`- uALIu1[A\A]]~D_A>v ǀ@|fAI9[- A\A]]YD)DcA>v À| fAA1ff.HIMUL7HAUATS@x_@>H~H9rx@x @AI99__>vf@yaHYI9r__ )u{HLItmH9\I9v_9E1۸ __>w@A<:fAAI9`- uALIu1[A\A]]~D_A>v ǀ@|fAI9[- A\A]]YD)DcA>v À| fAA1f.fH9s+ H1= HHHu:@f.H9s;HH 1MHHt@  tÐ1H@f.UHAWIAVAUATSHHIAHLL5},RL-v?!@HcAAHHHH_HqyHHcMLHADAT$DE tpHtjQHfADucAy~HHLELMLMLEHAAHADCD8HkHL[A\A]A^A_]fAyCfHqH_.UHAWIAVAAUIATSHLHHL9LFML LHEDMHM9LMGL9J IGHjHA)}ZYyI9wHe[A\A]A^A_]LH4ALH)IPxHeL[A\A]A^A_]ff.@UIJtHAWMAVIAUATSHxdH%(HE1HP`E1HpNl3M B3MCD=LHLLII9HIFH<3H9NDEMHSIME8H96DCEMHSIME8txHHDBDIE8uaH9u1I9tH)HH ؉DMtLtHudH34%(Hx[A\A]A^A_]AD)LHL DLLHHh Hh1H`LhqLhH`HIwDI)L .LHHfDUIHAWIAVAUMATSHHxdH%(HE1EtL9IGJt+LcHP}LpLHML LLLƄp C,HLLL|LLHMdH3 %(Hx[A\A]A^A_]1LhpLhHIHILz ALLLg C,HLLLLLHpI9`LqS= ff.fUHAWIAVAAUIATSHLHHL9LFML LHpEDMHM9LMGL9J IGHjHA)}ZYyI9wHe[A\A]A^A_]LH<1H)HeL[A\A]A^A_]ff.fUIHAWAVAUATSLHxdH%(HE1L9IGM9IFIHtHPZE1LpO|4MC4HALLtHLIfI9HIFI<4I9OA$AMT$MO8L9<AT$AOMT$MO8tzfIIARAI8ubI9u1I9tH)LH؉fDMtLoH}dH3<%(Hx[A\A]A^A_])HHLDLLLHhHh1H`LhmLhH`II}DI)L6fDMLDLc UIJtHAWIAVIAUATMSHZHxdH%(HE1HPw}LpLLLLHLBƄ=pB#LLiHL^HLs HMdH3 %(Hx[A\A]A^A_]D1LhlLhLIHHLZLHLCD=FB#LLHLHL HpI9]LmP f.fUHATISHHIL$H9xH<&<=HH91f<[<|uHK f< t<\P߀]0H=YTVHuHHP(HcHEI|$HAD$$HHs`HMMATHUMHL3ZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UMIHHHw`HHjff.@UHHAWMAVIAUIHATH)E1SHHHHHuHEfDI8L;et>HHs`HULjMMHLLZYtHe[A\A]A^A_]He1[A\A]A^A_]1ff.UHCHAUATL`ISH]HHhHLEMHp1H`HxH}LEHEHuH}CDLAHEf8uGHED9H`ftHPH`DHEf8tHPHUD9uEEIT$IL$H HcDQA9H]@HP~"A9HEf8tHPHUHĈ1[A\A]]f.qiID$IT$HHBA9ubL`fLAE~D9u;H`f8tHPH`DDHĈA)[DA\A]]@HĈD)[A\A]]ff.fMIHHHw`ff.UHHAWMAVIAUIHATH)E1SHHHHHuHEfDI8L;et6Hs`HUMMLHLRtH[A\A]A^A_]H1[A\A]A^A_]1@UIHAWAVL]AUATSHhLO`HxM2M8LpIAIIH HAH}H@HuH1HuH}HELMH}rfL~qE19L?LHcHLHHHL1Hʃ?ITIHHHHHEH1IftHPHUHxL0HpL8Hh[A\A]A^A_]Lh~9u EHEEef8tHxH}fDIwHRHfx;M9wNLL9vDHAA,$H@[A\A]A^]IHuH@L[A\A]A^]fDfE+E4$ICIE^E$HEtIMLMILMH^=HuHEH}L9vIHC=Lu1M)IMfuffDL…`ICA M9uA,$)DIASA$A$L9&HEftHPHULLMHUCIUHAWAAVIAUIATL$SLH(E@HLLPHM^`IPLLELLLD}L]Y^HI9D}uAL]ICISHH BLH)f9GօDBA@HH HH HH HH HH HH ȉHH HHEHEHL Hf.foEH@H9u։у)HC9t9f8t1fxt(fxtfxtfxt fx tfx J\CU1LH=EtiI9vdIF`HPH@HHBHDHHw`MLAQLMLEIHXZI9w/U1HLHeHL)[A\A]A^A_]f.D}AU1HLEtIF`HPH@HHBI9vHHI9vIt$H)HHtpHPI9v/HXH9eU1HL"EEH=HwfUHAWAVAUIATL$HSH0L`DuMAQLMLEL&ZYHI9pE̅A@A0Lу A0EH)9GAnDBA@DHH HL HH HL HH HL HH HEHEHHH|;foEH@H9uAщADD)HCD9tN@0HtC@pHt7@pHt+@pHt@pH t@p H t@p H J\C1DLHsEt6I9v1fLH1H)L 1DHL8HeHL)[A\A]A^A_]1DHLAtD1DHLEtfHfDUIHH0HwHWL]H9sTxMHAB(HMIJIrAB$HyHI HHHAIf8tHPIfLx~dIJHcIrIrHEH;HHAB(AR$HyHcHHHs`HMMATHUMHLCZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UMIHHHw`HHjff.@UHHAWMAVIAUIHATH)E1SHHHHHuHEfDI8L;et>HHs`HULjMMHL\ZYtHe[A\A]A^A_]He1[A\A]A^A_]1ff.UHX3HAVAUL`IATLeSHĀHhHLEMHp1H`HxH}LEHEHuH}AfDL`HEf8uDLL9H`ftHPH`HEf8tHPHU9uƅIUIMH HcQ9LeL~!9HEf8tHPHUH1[A\A]A^]@{sIEIUHHD$BD9u[L`f.L8Å~A9u5H`f8tHPH`H)É[A\A]A^]H쀉D)[A\A]A^]fDMIHHHw`ff.UHHAWMAVIAUIHATH)E1SHHHHHuHEfDI8L;et6Hs`HUMMLHLrtH[A\A]A^A_]H1[A\A]A^A_]1@UIHAWAVAUATSHxLO`HpM;M0LhIAIIH HAH}HR0HuH1HuH}H}H}HELMHxlfH}~qE19L?LHcHLHHHL1Hʃ?ITIHHHHHEH1IftHPHUHpL8HhL0Hx[A\A]A^A_]H}~9u'EHEEef8tHxH}fDIvHRH@8dEIFIOI~B4(IGH H<B(HA@HH4wrH>H8LD>LD8HxHH)H)HH5:H4PHH5%H  HH@HHc‰tf H5WHH H58H H5/HH5Hj HDž0{fI$H L@HNH$HGxHSHƇfDH5H HH@HPxHc‰tHDž0PML$AAD8fD>ɉ8ttDtftI$HIGH1H<蓾D1IGIWB(HHEHs`MMHMHUHPLAWsZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHHAWAVAUATSHHuLUHh]HPHXHMLEMȃHHHuH`1HPH}LEHEH}H0H@H8\HPA1HPDHEMfHPE1HUA)FHPM)I)MFfuHEp HhAHPH@HHD BHEMxfwHEH}E1H9aHUHEMHELjHRIMHcHQHUf: HBAHEM9HE@uHEHPH@HHBA)EEu-AL8AGttM9?AEHĨD[A\A]A^A_]fDfOHXH`1H96HhHxDžtHXLGH?I8HHGHPf8HPHPDI9HEE1@uHhHPH@HHD BDAf.H@L%H LhHXI9HHxtMHM MM@A<8HIAHPf8|H9E1ɅtHhHPH@HHD BFAHI9HED@DE@EHs`MMHMHUHPLAWZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHAWIAVIAUATSHHHuHUH@(LEDMHEHCWHHt } ЅHEHEHEHEL;uuL9uHMLHuLHEЅLeHcUL9HIHcEL9u L9uHMHULHuHEЅDHLeHEHcEL9tELmElDI_`DDeEE1ALHHHpLHHhDHxH9w HCLMtHCAM@I9HCJHHs}BHBH`HMA8f98]HpHh<>HXH9HPH?HLL0H8D@LH赗HPH9XLHD@H8L0]AHS8E1H9xw HCHLMtHC@AM@I9HCHJHHK@uBHBMHfA9uJHpD$HhD,M9AK$HLʖM9}YfHe[A\A]A^A_]@1M9HMLHuLH]Ӆ~HHMHULIHuӅ~HLeHEf1M9{pH`pH`HLL8H@DHLPL`ڕ"HXL`L8H@A@DHLPfDKT-HLLE脕LECh fDH]1H9]He[A\A]A^A_]ÅBcqH]L;utaH]LmHMLHuLAՉÅUHEI9tXHcUH9uWHMHULHuAՅ)HHELcML;uu1H]1H9]He[A\A]A^A_]LcMH]H9]LmLHuLHELЅHIHcEH]H9Eu I9bHEHXE PHMHULHXHEЉEhALuLmh LI_`EDHDAE1HELHHHpHxDH`H9w!HCN$MtHCABM$DH9pHCH4HHSA L FMMA$fA9HEDHxDM9KLLL(H0L8L@LHL@L(LHL8M9H0k%hHS8E1H;`r!HCHN$MtHC@ABM$DH;pHCHH4HHS@ AHFMHfA9$HED,HxD4M9KT-HLM9u[HcEHEHLPHuDMLEHMHUPEPEPH H]H9]dHcEHE1M91M9K6HLeuCtcuCYKLLH8L@LH%uLHH8L@CT@eBkHMHHuLHEЅ$HHH]tfDUHHEjPEPHG`Ht)HcHH)HH|t HD1ff.fHG0ff.HG0ff.UfHAWAVAUATSHH)ELw)E)EHAHUIL~HuA5DHI|$IIHW(NtI%t<IL9mt0I|$0IL$LLHP(II|$HEHN4JttSIL$HAHY HHPLAEHD[A\A]A^A_]ff1LfHhHHXH H;pHztBHHr( t)HLLH5H HhHHxtHrHcH4H2HR HHFHPf8(H}H`LHXHP(!HXH`H9:E1tHhHPH@HHDEHs`MMHMHUHPLAWZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UH(HAWAVAUATSH HLEMDMLuHHPHXAHHH]LEH`1HPHhH}LEHEHuH}HHHYHPA1HPD(HEMfhHPE1HUA)dHPM)H)H^fuHEX .HhAHPH@HHD,BHEMxfwHUHuLRI9+DBE1zIHLLBHLH H=H9HEHH9HGAHUM9HE@uHEHPH@HHBA)EEuEHs`MMHMHUHPLAWZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHxHAWAVAUATSHH}H]HXHʋMHI܃H}H LEMȉHMHHPH`1HPHhLEHEHuHHHeHPE1DžHPD8HEMfHPHU01A)HPDI)H)HfuHEH AHhDžHPH@HHDEHs`MMHMHUHPLAWCZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHHAWAVAUATSHH}LmHH}}MHXHʃLEMȉH HHPHH}H`1HPHhLEHEHuHHdDžHP1HPD8HEMf|HPE1HUA)HPM)I)MfuHEX JHhDžHPH@HHD@HUHEH99HuHH9HCAHEfHXH`H9sHMAHH9HCƒHXHAHEHAHP@HxP0tTHxtHx tqHx(AKHxDx0tBHxt/Hx tHx(xeYM떸AEDžqff.UHDUARAQMIHHHw`ff.fUHHAWMAVMAUIATE1SHH(HUHH)HuHHHEf.I8L;et>EHs`MMHMHUHPLAWZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UH8HAWAVAUATSHH}L}HH}}MHXHʃLEMȉH HHPHH}H`1HPHhLEHEHuHH`HPA1HPD(HEMf8HPE1HUA)HPM)I)MfuHEX HhAHPH@HHD,BHEMxffoHUHuE1H9(HH HUHUHztHHJ( t8HHLD!DH)H HUEEHJHRHHHBHEf8"HPAHUM9HE@uHEHPH@HHBA)EE3AHLuEML}@ M9AEfDfHXL`1L93HhHH HXHzt=HJ( t-HHLH H HhxDžtHJHRHHHBHPf8$HPHPD(I9HEE1@uHhHPH@HHD,BDAH%H H HhHXH9HytFHHq(t-HHLHH HhHHxtHqHcH4HHIHHFHPf8*HXL`L9"E1tHhHPH@HHD,BCAHI9HED@DEfDEHs`MMHMHUHPLAWZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHAWAVAUL-ATSHEH]HXHH LEMHIHPHHMH`Lꉅ1HLPHhH}LELmHuH}LHc@HBE1DžHPD:HUMfHBE1HEA)HPDM)H)HfuHEH AEHhDžHPH@HHDHx HE1Hx(AA@0Ef.M9BHE@uHEHPH@HHBA)EEGHD[A\A]A^A_]fDfHXH`HNH9vHXHhHcH H97IE1@LGM#HO(%H%<H;txHc%H(@HG K I HH H9r pHXH9vgxRtH;uH9puHDžtHP2HPHxHxHx 1Hx(Dx0F4)@HtHHH-HuH Hhf.H@EuHxtHWHHHHw4HcHrHPf:HXH`HNH94vHXHcH H;7E6fDH'tHHLMHH H}fH@EMHMEHWHHHxHw4HcHrHUf:(HuHEHNH9vHMHcH H;7 EHE@uHEHPH@HHBA)E1EH@L9AEwf.DžE1E1?HYADžYE1tHhHPH@HHDEHs`MMHMHUHPLAWCZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHAWAVAUATSHHHHGHL@(A<yTHmH9tHW$W(LcLFHGLH(A@t#HPHX L JJHH9fDHuIIHHx1(fMt$I_A)EA)E)EI|$0IL$LHHP(VHIL$IHHQ(NtI%D<tEHIu@HEHyN<JtFtSIL$HAHY HHPL4L9s5It~fDJ<u{RuHuLHHHs`HMMATHUMHLZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHHAWMAVIAUIHATH)E1SHHHHHuHEfDI8L;et>HHs`HULjMMHL\ZYtHe[A\A]A^A_]He1[A\A]A^A_]1ff.UH(HAWAVAUIATMSH]HHL1HO`HuHM8HE1HuHMH}bfH~aL?J9HcHLHHL1Hу?MtILHHIHEI1ftHPHUuMuM<$HH[A\A]A^A_]ff.UHHAWAVAUATSHH8TLXLHdHUUEMIIE1L@?`E@PHEHE2ULL1LpLpMID9d`t EDsJIU`L)HHhAEHXHEH5THEHuH}H@LmH}L9PDTE@L)1HHILHpHfuPfDH}~LLK#H;pHCAH9]EHEftHHHMPHhHMx0փ x0H)D9AG̅nQ@DDHL HL HL HL HL HL HL AAHpAHxHINDfopH@L9uAAADE)HCA9t[@8@pAtN@x@pAt@@x@pAt2@x@pAt$@x@p At@x @p At@x @p LLCHƋEHMLLXDTLIPH:ZYID9dzL9uvEuHHs`HMMATHUMHLZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHHAWMAVIAUIHATH)E1SHHHHHuHEfDI8L;et>HHs`HULjMMHL\ZYtHe[A\A]A^A_]He1[A\A]A^A_]1ff.UH}HAWAVAUIATMSH]HHL1HO`HuHM8HE1HuHMH}bfHx~aL?J9HcHLHHL1Hу?MtILHHIHEI1ftHPHUuMuM<$HH[A\A]A^A_]ff.UHHAWAVAUATSHH8TLXLHdHUUEMIIE1L@?`E@PHEHE2ULL1Lpy LpMID9d`t EDsJIU`L)HHhAEHXHEH5{HEHuH}H@LmH}L9PDTE@L)1HHILHpHfuPfDH}~LLK#H;pHCAH9]EHEftHHHMPHhHMx0փ x0H)D9AG̅nQ@DDHL HL HL HL HL HL HL AAHpAHxHINDfopH@L9uAAADE)HCA9t[@8@pAtN@x@pAt@@x@pAt2@x@pAt$@x@p At@x @p At@x @p LLCHƋEHMLLXDTLIPH:ZYID9dzL9uvEuHHs`HMMATHUMHLZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHHAWMAVIAUIHATH)E1SHHHHHuHEfDI8L;et>HHs`HULjMMHL\ZYtHe[A\A]A^A_]He1[A\A]A^A_]1ff.UH(iHAWAVAUIATMSH]HHL1HO`HuHM8HE1HuHMH}bfHx~aL?J9HcHLHHL1Hу?MtILHHIHEI1ftHPHUuMuM<$HH[A\A]A^A_]ff.UHHAWAVAUATSHH8TLXLHdHUUEMIIE1L@?`E@PHEHE2ULL1LpLpMID9d`t EDsJIU`L)HHhAEHXHEH5TgHEHuH}H@LmH}L9PDTE@L)1HHILHpHfuPfDH}~LLK#H;pHCAH9]EHEftHHHMPHhHMx0փ x0H)D9AG̅nQ@DDHL HL HL HL HL HL HL AAHpAHxHINDfopH@L9uAAADE)HCA9t[@8@pAtN@x@pAt@@x@pAt2@x@pAt$@x@p At@x @p At@x @p LLCHƋEHMLLXDTLIPH:ZYID9dzL9uvEuHHs`HMMATHUMHLZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHHAWMAVIAUIHATH)E1SHHHHHuHEfDI8L;et>HHs`HULjMMHL\ZYtHe[A\A]A^A_]He1[A\A]A^A_]1ff.UHXUHAWAVAUIATMSH]HHL1HO`HuHM8HE1HuHMH}bfH(~aL?J9HcHLHHL1Hу?MtILHHIHEI1ftHPHUuMuM<$HH[A\A]A^A_]ff.UHHAWAVAUATSHH8TLXLHdHUUEMIIE1L@?`E@PHEHE2ULL1Lp)LpMID9d`t EDsJIU`L)HHhAEHXHEH5SHEHuH}H@LmH}L9PDTE@L)1HHILHpHfuPfDH}?~LLK#H;pHCAH9]EHEftHHHMPHhHMx0փ x0H)D9AG̅nQ@DDHL HL HL HL HL HL HL AAHpAHxHINDfopH@L9uAAADE)HCA9t[@8@pAtN@x@pAt@@x@pAt2@x@pAt$@x@p At@x @p At@x @p LLCHƋEHMLLXDTLIPH:ZYID9dzL9uvEuHHs`HMMATHUMHLZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHHAWMAVIAUIHATH)E1SHHHHHuHEfDI8L;et>HHs`HULjMMHL\ZYtHe[A\A]A^A_]He1[A\A]A^A_]1ff.UHAHAWAVAUIATMSH]HHL1HO`HuHM8HE1HuHMH}bfHH~aL?J9HcHLHHL1Hу?MtILHHIHEI1ftHPHUuMuM<$HH[A\A]A^A_]ff.UHHAWAVAUATSHH8TLXLHdHUUEMIIE1L@?`E@PHEHE2ULL1LpyLpMID9d`t EDsJIU`L)HHhAEHXHEH5?HEHuH}H@LmH}L9PDTE@L)1HHILHpHfuPfDH}_~LLK#H;pHCAH9]EHEftHHHMPHhHMx0փ x0H)D9AG̅nQ@DDHL HL HL HL HL HL HL AAHpAHxHINDfopH@L9uAAADE)HCA9t[@8@pAtN@x@pAt@@x@pAt2@x@pAt$@x@p At@x @p At@x @p LLCHƋEHMLLXDTLIPH:ZYID9dzL9uvEuHHs`HMMATHUMHLZYtHe[A\A]A^A_]fDHe1[A\A]A^A_]1@UHHAWMAVIAUIHATH)E1SHHHHHuHEfDI8L;et>HHs`HULjMMHL\ZYtHe[A\A]A^A_]He1[A\A]A^A_]1ff.UH-HAWAVAUIATMSH]HHL1HO`HuHM8HE1HuHMH}bfH~aL?J9HcHLHHL1Hу?MtILHHIHEI1ftHPHUuMuM<$HH[A\A]A^A_]ff.UHHAWAVAUATSHH8TLXLHdHUUEMIIE1L@?`E@PHEHE2ULL1Lp虻LpMID9d`t EDsJIU`L)HHhAEHXHEH5+HEHuH}H@LmH}L9PDTE@L)1HHILHpHfuPfDH}/~LLK#H;pHCAH9]EHEftHHHMPHhHMx0փ x0H)D9AG̅nQ@DDHL HL HL HL HL HL HL AAHpAHxHINDfopH@L9uAAADE)HCA9t[@8@pAtN@x@pAt@@x@pAt2@x@pAt$@x@p At@x @p At@x @p LLCHƋEHMLLXDTLIPH:ZYID9dzL9uvEuLHHHL1Hփ?M\7IIIIII1ML9v=HLHuH}HEЅ~%HUI9$gHE{HEL(HEL8HH[A\A]A^A_]UHAVMAUIATISHHPMLLHH[A\A]A^]UHAWAVAUIATISHHHHK<HUH}M}xHH(H@0HMHMHEHHEHMH9r[tHuI97r$HIGHHHt@HvtHuHMLLHED9u*McLMH9]vHMHHuLHEAƅHEHH[A\A]A^A_]ÐUIHLHHHHuP(ff.@UHAWIAVAUATSH8HMLEHtoIILmH HIHtUILLLLP(M9L}~EIGHEHEEHEH8H)[A\A]A^A_]ÐHEH@L8HEH8[A\A]A^A_]ff.UHAVIAUIATE1SHHIHILHL[LA\A]A^]HtkUHAWIAVIAUIATISHHIHLL~HIIuLL) DHCL)H[A\A]A^A_]f1ff.fULH9HSIL9s>IfHDH?LIIIILH1I9uHRHH9I[]DUHAUMATISHHHPI4$MULL9s8L@H IH?IHHHLH1I9uH@II4$MUH[A\A]]@UHAWAVAUATSH8HuLMH9 HHEIMH)HEIIHHH]H@HMLHuLIP(HUHIHHHHUHHHtHRTHUHC H;]uA,$H+EH8[A\A]A^A_]DHSA$A$L9sYHH+EH8[A\A]A^A_]HE1HBH9ro:L(H>Iw+1Hw LBL9rFRHHHvHH %H HH@øff.HHVH9w HH9vfx tH)ff.HBH9r? BzHHHH BHHH=HDfHHVH9w"xuxuxuHH9vx tH)ff.HHFL MH9UHAWAVAUATSDF^IHLLFHLH=vL M[A\A]A^A_]@LwxHIH]MIH9EM1E1MIMM1LM?IM\LMM1L?ML I IMIIM1H9i~FHD^HHII<FHHH=0OII~MMzIA?Ju1~f.HtsH~H9r>t-1UH9HGHHu~EHUEA]@~wHHt&HwH9r ~u~v H)HH릐HHI@HI0fHUHAWAVAUATSHH)L@LIIIL9>~~FH< t< u*HI9c?u.uu G< t< tրuu -V?t!1H2[A\A]A^A_]u݀u +E1ɻA A\/+u0G0< wLg$HwM9MFI9t37~u1~0@ w$H@HHGL9>u~tH2H[HEA\A]HEA^A_]fD~q~g~0]HHwI9u1!1H2HI9??LOM9HLAA_A?|xmHDLM9M|$$LM9MMFE1=u5u/w0@ w"@OlN,nHwI9H?tHH5!H:L)HHILHEIDLOM9HLA\/+A E1!HH(I9IF1IH9;'DH(II9IF1H9I9>~~D~EgA HEI9~~~D~EwA H~H:I9t"~u~ u~ uV 0 I9Ik AHI9MkdH HLHHI9oHiʚ;H2LHHEHE[H:H HIk HJ4 EtYH?H9w@t0HH M9uH9l"HEH?"H@H)HHDH)HH9HJHGfHH9HBH9rRHHøf.HBH9r1Hwff2fUHIHSHHWxH9sUHH9rD~DNHLZDLcMIOMt@H<E I9r Iv[]I9rDQDIH9w[]MIff.@HHGxL MH9HH9UHAUATSHXfDHH9rDVFAAMcMIJHtEKH)uHEdH3%(u6H([A\A]A^A_]HEdH3%(uH(1H[A\A]A^A_] @UHAUATISHHcL,HUHJ H8dH%(HE1HP0L9svIuHLHHI vAHʉufnMHHfpHf.HH9uHHHH9tHC3I9vHCsI9vsHEdH3%(u H8[A\A]]ff.UHAWAVLtAUIATSHHLELMdH%(HE1HEDžh HpHEHxL}LZ!f<%t\I9t'IHCAD$IL$uHL)H}dH3<%(HĈ[A\A]A^A_]fALaPӀvPЀ w!IA$PЀ vPӀvL CHL9@H9@@HpHHx11HHo fofoHf`fhS\SHH9wHHHHHHH)H9CHCACHCACHCACHCAC HC AC HC AC HCACHtsCACH tbCA CH tQCA CH t@CA CH t/CA CH tCA CHt CACfLH LK LH !HHCH9u1ofHpHBHpfHpHQHpL蜪L;!f H %!kff.UHAWAVIAUL,ATSHLELMdH%(HE1HEDžh HpHEHxHL}L!f<%tmHCI9w4L)HH}dH3<%(HĈ[A\A]A^A_]fE1CfD#ÏSHAD$IL$uHC@ALaPӀvPЀ w!IA$PЀ vPӀvIfHDH?LIIIILH1I9uHRHH9I[]DUIL1HAWAVAUATSH(DLuIHM9MLEIHMHL]MI)1ILLLUBLUHuLK<>LHHLL]LE9HLLH߾?P0;L]LEtD~E1flAHe[A\A]A^A_]fDHeL[A\A]A^A_]**f.HHuȉLAVHH)MMJ >M)I4)HuIv^_He[A\HA]A^A_]DHHMȉLAVH)MMLLM)H)ZYD1ff.fHI\HF>H9AAI9v?LYM9s8EtnA)ljuLLH9w1E1ҿ E1I9w@fEt1Af>AAfwf.UHIHSPH~H9AAL9sLLItQH9wI9vGLQE1۸ 9M9r9Af)tÐfI9w uHIu1AyDfHIMuQH~H9stI9ALQ9M9s:A)u>LLItQH9wI9vGLQE1۸ 9M9r9Af)tÐfI9w uHIu1AyDfHBH9r'1Hw!HfHfrBÐf.HHH9s>L^L9r5DDVIMDNvAMcHcMLHvDLWxIHI92r0IIzIJH9r @uF<vwAAI9vPLIM9r u YvrEA)ljuLLH9wE11 E1I9w[]~AA~ǸxAADDIDEtAwD[]UIHAVL42ATS^fDHF>I9AAI9vCLYM9s@EA)ljuLLI9wE11 E1I9w[A\A^]fLTfMMt H[ADEtrAf.L TfM Mt#AH@A|A0AAf.[A\A^]@HIH9sjH~H9ru DNAvzL9sLALI9M9r@uDYA~A)uLLH9rL9r1fE1Ҹ fDFAADDNDL9u uH4fDyAADDIDAgUHIHATSjH~H9ru ~@vvAL9sNLQ9M9r@u DaAvmA)u&LLH9rE1۸ 1L9r1Eto[A\]fFA~xfDyAADDQDׅtA|D[A\]fD[1A\]ÐHIM UHSwf.H~H9ruDVAI9ALQ9M9r@u Yv?A)uLLIt H9wI9w 1[]@E1۸ fDyADDQDADFAADDVDI9Z uH}fD[]1@HIM UHSwf.H~H9ruDVAI9ALQ9M9r@u Yv?A)uLLIt H9wI9w 1[]@E1۸ fDyADDQDADFAADDVDI9Z uH}fD[]1@UHIHAVSH9sSH~H9DL9ALI9M9s1AD)uLLH9rL91[A^]L TfMAMtH<[A|L fTfDM Mt H[EtL9r!D uHE1A =fA0D[A^]DUHIHAVAUATSXDH~H9AAL9sBHY9I9sVDEAD)u,LLH9rE1۸ E1L9r1EE[A\A]A^]fDL%VTfDM$Mt H<[EtEtiAfLTfILNL9r%AAALNL9r <%AAI9voHYAI9r%ÃHYI9rAAE?A)lju!LLH9T1E1ۿ E1I9w[]FL jTHcHIH@AAH<|AAI9vpHAI9r)AAAALIM9r <E.A)lju!LLH9S1E1ۿ E1I9w[]fD>L {THcHIH@AAH<|=D H2TDLcIN Mt H@ADEt~AKF<AAfDA<Et,A@AAf[]UMHAWAVAUATL$SHHDmL9MPM9A0A@IAxHHHH4A@HHH=vMEAA@1DLHFE8I)MHL[A\A]A^A_]HAHH=HH5THH4HtH@DIwA?I9uII)1DH#F뇐IAGM9IM9*ArABAzHHHH4ABHHH=H=LDǸdfDLL1DHILEEM9fDLLM$I)E1EIAufDEA`IDMLI)UHIHATSfDHFDH9r+~AAALNL9r <AAI9vtHAD I9r+AAAAAu{LaM9rAAAE,A)lju HLH9I11ۿ E1I9w[A\]ADdDDEA뛐D^D؃<AADAA DB~A8DaEAAA% AAD E C!DIBEtAf[A\]fDUHIHS>LNL9r%AAALNL9r <AAI9vkHYAI9r!ÃuxHYI9rAAE#A)lju!LLH9X1E1ۿ E1I9w[]FAAǸkDIDEA@DNDȃ< FAA AA B~8DID˃YA% A AAAEtAf[]HIH9LNL9r'~<HFH9r @AL9bHyI9r+yAAALIM9r @9A)LLH9_L91@LTHcHIF<A@y@t#AA[A^]fD[1A^]fHIMUHSLVL9r'~<HFH9r @AI9QHyI9r+yAAALQM9r @9A)uLLItH9]I9w1[]E1۸ fDLTHcHI@HFH9w.@|@v@t~@ts@vmH-LVI9w\@uVFLIH9sMuHL)I0I@fDHf~_@>vUHL)HHu~EflA]1f1H9rWt+x7HHH9vuHHH9w@HHfDHHfDff.@H9_]wHHzH9JH |'H AHHuwR_]vf1@=tq=uHBH9rCBJH M|#H AHHu!B_<]wB_<]wøHHBH9r-BP_>hHHø@H9y>HFH9t1A_<]wBF_<^Àu$FP_1]v=@FH_>v71@HFH9sǀuF_<^F_<^Ðøff.H9sK~#HHHBH9r!@r@2f.f.H9@2f1HwHH=nz%wffwHBH9rȃ@@rf.ø@UHAWAVAUATL$SHHMLML9jIHMIfDILHLI~xHcSHHCHH@HHH}HIW=A7"HrLzI9gLH+EH[A\A]A^A_]fIHADAGfIHHtHRHHeECIHAG=RLIlfD@:DHuEHDIDH1[A\A]A^A_]LLGHE1D@LGPA1UHIHS H~H9r'<\x_@]~DO_A]OI99@[AALIM9@t{DO_A]DIAY_]vmEA)LLH9DI99@HAI9E1E1۸ @uDIAY_>wAD EtTA@I9v;9AA@jLIM9,ARD[]ø[]1@~DO_A>I9v 9@yAA)@H~H9v<n^{_@]]^{_@]LI9`F9f @yAA@LIM9[@QYDK_A]?YDI_]*fAAEAUHIL Ru)HATSH~H9r'<Tx_@]~DW_A]GI99@KALYM9@tzD__A]DYEc_A]vlA)LLH9EI9 9@HAI9E11۸ @uDYEc_A>wAD ߅Af.I99AA@A<9AOA;~DW_A>I9vA 9@ DHs):)[A\]fD[A\]fDސ1@H~H9V<N^{_@]=^{_@],I9vF9f @pA LYM9C@9DYA_A]&DaDYA_A]fAAA@AUHIHSH~H9r'<x_@]~DO_A]AL99@y2LQM9r#@trDW_A]DQEZ_A]vdA)u?LLH9^L9s)E1ɸ AL9r u A1[]DQEZ_A>wAD A~DO_A>)A L9& []ÐH~H9<^{_@]^DN{_@]fAAA LY@M9YDS_A]DQYA_A]fˁ)Lff.UHIL rp)HATSH~H9r'<x_@]?~DW_A]AL9 9@ygLYM9r*@D__A]HDYA[_]A)u`LLH9WL9sJ9E1Ҹ @xA<9ADAAL9k uA1[A\]ÐDYA[_>xAD Aof~DW_A>A L9[ A\]H~H9<^{_@]^DV{_@]fAAA HY@I9DYA_A]DYDaA_A]fAÁ)H|ff.@UHIHATSfD H~H9r'<lx_@]~DW_A]_L99@sALQM9@tzDW_A]DQEb_A]vlA)LLH9EL99@HAI9E11۸ @uDQEb_A>wAD ׅtnAfDL9s;9A@jLQM9,ARfD1E[A\][1A\]ff~DW_A>L9s 9@yAf)@H~H9^<V^{_@]E^{_@]4L9HF9f @yA(LQM9K@ADQA_A].DaDQA_A]fAAAff.HIMUHATSDH~H9r'<x_@]~DW_A]AI99@y9LYM9r*@D__A]DYA[_]A)uLLItH9QI9w 1[A\]DE1Ҹ fDAI9p uA@~DW_A>9A I96[ A\]DYA[_>PAD AGHY@,I9#DYA_A]DYDaA_A]fAÁ) HH~H9v<n^{_@]]^DV{_@]GfAAA 91HIMUHATSDH~H9r'<x_@]~DW_A]AI99@y9LYM9r*@D__A]DYA[_]A)uLLItH9QI9w 1[A\]DE1Ҹ fDAI9p uA@~DW_A>9A I96[ A\]DYA[_>PAD AGHY@,I9#DYA_A]DYDaA_A]fAÁ) HH~H9v<n^{_@]]^DV{_@]GfAAA 91UHILg)HAUATSDH~H9r'<x_@]~D__A]wL99@;AAHYI9@tx__]`YDk_A]vlE)LHH9GL99@HAI9E1۸ E1@uYDk_A>w EtyfL9s39AAA@/A<:a1E[A\A]]f2[1A\A]]fHYe):)뱐~D__A>L9s 9@AA@HYI9@Y_]DiYA_A]pfELdfH~H9<^{_@]^{_@]L9F9f @AA@H 5d))f.HIM4UL d)HAUATS@H~H9r'<x_@]?~D__A]AI9 9@yyHYI9r(@__]JYDc_A])uHLItH9TI9w1[A\A]]fD9E1۸ @xA<:@AAI9[ uAYDc_A>n ߻g@~D__A>A I9[ A\A]]DH~H9<^{_@]^D^{_@]fAAA La@M9Y_]YDi_]fAÁ)L1f.HIM4ULa)HAUATS@H~H9r'<x_@]?~D__A]AI9 9@yyHYI9r(@__]JYDc_A])uHLItH9TI9w1[A\A]]fD9E1۸ @xA<:@AAI9[ uAYDc_A>n ߻g@~D__A>A I9[ A\A]]DH~H9<^{_@]^D^{_@]fAAA La@M9Y_]YDi_]fAÁ)L1f.1HD1HHff.HF1HH@ff.H9:@yo1@ve@vq@wYLBL9rKDBAH?wBR€?w6Aw@t*HH H%H H HøÐH>LBL9r-R€?wHҸH H>fø@HH9HHBH9H@@H=?H0i)DBEHPH? HJd)DBEHGH9%HHb)H WHHWHH0WGDHb)<0HBH9@HHLH'd)DBE]DB0GA)A0DGHH=wHd)DBEuHH?Hb)DBE@2øøff.UIHLHHHHuP(ff.@UHAWIAVAUATSH8HMLEHtoIILmH HIHtUILLLLP(M9L}~EIGHEHEEHEH8H)[A\A]A^A_]ÐHEH@L8HEH8[A\A]A^A_]ff.H9W:@y1@vv@}@LBL92DBAH?wGR€?w;Aw@t/H ҸHH H H1AH>LBL9R€?wHҸH HfD@wLBL9DJEAA?wJ?wR€?y@cAv 1@]HEɁI I HL H HøøøøH9Hw!HzH9@2fDHH1Hw`HzH9H?HȀBH?HɀJH?@ɀ@2JÐf.HzH9sʸ@HzH9rϸff.@UHAUIATSH(dH%(HE1,HEdH3%(,H([A\A]]fH]HL$HcHS HHHMLM9HIMA2f.HHt AMIIM9rBMHrH IxHIHIHLILLIH)H)HHHM9sM9HEdH3%(uFH(LL [L)A\A]]" ALALjDLfALUC&UAA\HHj腾H9v_1wTH~H9~W?w;V€?w/V€?w#t@u{f1@y1vwHFH9rdF<@H~H9rC~W?wV€?w@wtfDføøøLGxHH1t.Dy)@v7@}HHuL)H9~EHuEA[]fD@@v@H~H9rF@y8@v%@LNL9r^DKA?uH)[]MJM Mt_LC@y8@v%@LNL9r^DKA?uH)[]MJM Mt_LC|HvPHw_LXM9rIIADAA?AɀDHLHcHH9_H)[]fI9z@8HfDH^LXM9QII ADI?IπA?@xAɀDHLfD@LNL9^DKA?D^AÀA?w @H EɻIL EL MJIIO M@HEɁL MJIIO Mt@vD1ULHAUATLgxSHIH9s1@y9I?.Aw AI AHI I Ll1UHAWAVIAUL,HUATILSLHMLM}II9v|D}UAE@MHI)L9LF1LLULUU1LLHEt-I9v(LH1H)LU1HHHL)[A\A]A^A_]fDU1HLEtfHIMUHAUATS@ A:>AEIHIA<@8uL~I9t~L봸DH]LHu(H+MC HDMH]HHM0HL9IKI9IJ@I9@HJL)HHfo 1fvL)HHA A HH9uHHIIH9.IJA AH9IJAB ACH9IJAB ACH9IJAB ACH9IJAB ACH9IJAB ACH9IJAB ACH9IJAB ACH9t|IJ AB ACH9tiIJ AB AC H9tVIJ AB AC H9tCIJ AB AC H9t0IJ AB AC H9tIJAB AC H9t AB AC[A\A]A^A_]fDL)1A A HH9u[A\A]A^A_]fUHAWAVAUATSH(]Hu؃DHDMIMcM1E1fLL)L9|uE<UAMH c )AA t]IDHuHP HI9wH([A\A]A^A_]@AEuH )A uLLdKcE1L)HMH +L;MLA:2t$HL)I9@:2H1H@uEMcH KIBL)II9H([A\A]A^A_]I9 H}L1H)HH(L[A\A]A^A_]fISAI2H@LEZfMcH FKIBL) Lu|1uUHAWAVAUATSHtE| HzHt1| HBt!sf.| HPaHHuE1MgB| I@iHNB| Ixt(D|9 HGHHuEIIEE1DE1Eu5DmEE~)IH)AD AILH)H9$DeDEu7]ą~0IHT)EDAIDD)؅ELH)H9QAE^H)D AdMAcE1I)L%UKL (L95LE:t%(HH)H9D:IEHEuEMcHKIFL+ILH)H9D]AEH8)DALлcE1H)L-KL(HEH9}LA:t#II)I9:IAHuDUEMcH*KIF\3 IaID$AIDIELEMcHֈKIFL+ [A\A]A^A_]DIEAIIÄLDUERfDMcHvKIF\3GH@EHcHf}HcD1UHc~DEIcfUHAWAVIAUE1ATL% )SH HH}ȉuH9s$fMDA7L謃HtIL9wH1[A\A]A^A_]DL9vMwL9w"IL9tGA6L[HtM9tD9mr1L܂HMB)IL9gDIff.UHHAWIAVAUATL%gKSHOHL@@HLHHM讃HMȅAuB<;tLII\$HuML1E1H5 )AHD[A\A]A^A_]f.A$ =-uIIHS@I;r8IH@HHIIHIH111H5 )H袀HZIBfD/IDžAƅI1IDžIDžHA)AHADUHAWIAVIAUATL%KSHMHH}LHLAŅuB<;t$II\$HuE1HD[A\A]A^A_]ÐHEH@A$===4=uLHIT$@H;r9HI$@HHHHHILI1H5T1L@==,HHG@H;rIafDIHEAmDIEI9vA}uuHSHP@AE|yIEI94AE|$LAL)fDCD5|y II9uHEIEIt$MHI$ITITLH)I)ȃ1҉уI< H<9rgHEH5LHHNH9XA$E.IEIt$(MHID$ ITHTHH)I)ȃ1҉уM L9rIEI$JMHI$BITITLH)I)ȃ1҉уI< H<9rmIcHlKM$Ly@fUHAWIAVAUIATISHu F MM4 AEIEM9s[H]H}vAMHIEIM9v7ILLHLP(AUAUu$IIEM9wH[A\A]A^A_]|HLLHAEH[A\A]A^A_]@AEIEfDUHAVIAUATSHHtjL$LmH}w9HHILHLLP(ڸH[A\A]A^]H[A\A]A^]fDG uff.G %ff.t!fHOhHtf{uUHAWIAVEAUIATISHHHDMdH%(HE1HFH^vH.H(H=vILLHLP0EMHLI9HH7)AH  HH<HڃHAG ML@}UEDuAILHLH@0A;Eu#EHADtAD1fDH}dH3<%(HH[A\A]A^A_]fD)HFHH 9EuEHøyD)fAEEuAMA}AUbeff.fUHGhA\HHtf\tA.H\u.HAjff.@UDA\HHAQfUMHAWIAVHEIAUL,7ATIS1H8H}LELMHEHMHUHuH}U~bHHuHEfDu.H}?t'HE??LLLAօ~HIHE LH+EH8[A\A]A^A_]@uHE?HE?}+HEHMH9sH?HE?HEz؃?HE?HHE\UB HATSA A LU A9AEFAD㩀tKu?HHwu)AHeD[A\]fDHHGtyLHD)M[0ARMAr(AQE ILH HeAA)[DA\]HHH@0ARMAr(AQEIHH HeA[DA\]D2UMHAWAVAUL,ATSHXHLe HuH}HMH@(LELMHEHLx0HEH@I$lHEIHLHEHMHuH}HEЅ~|HHEHuHE@HE??LHLAׅsu!H}?tI<$uHEI$fHH+EH}HMHHX[A\A]A^A_]uFHEHxHEHHEvfDHHHmtwHEHEH*@|+I<$tkHE??HHEHE3fDHUH9URHEHx|HPsH}HxfH}HH+EH} HUI$1UHHAWMAVLuAUMILATISHH(HLMHEMLLMKT=HL)HEHLLELLHHUHM)PH([A\A]A^A_]ff.M9HMFL9IG`U1HAWAVAUDoATSLcNE9jEQLH1IcHMHAD3D`DAAE9AE1E1IAPD HILIԉLI I)LDIH IM9sD#HEHSH9v"[t@D Eu HAH9wDWLELcNE9IJ M H9vIHA9trqDx1@IApHHH)H‰AH M9sHIcH DEu/HAH9v"qtfDu HAH9rDWD[A\A]A^A_]xDDDoLcNLE90fUHcL MQHEADAuuux@ ) ~d I9v( H( Љ@f(^)Htu~tet Y tNt Y at7t fYt"H (tYI0HufD^t f/f*YX fH~fH~H @H H EDH,fҍQHcH5( ^ H\*Ѓ0HV\((f/-f(\f/tcATHLYfHY,*؃0\(B(f/df(\f/%H9u($x 3E@ F HPHHHPHCCHHHCE~~D9DNA)A))EHDH߉DDDHHLHHsL;0DHDDpL;@cIcE8HH8IuL8IHPHH HHPHHGGHHHGE#HH(u",tAEA`A )ƒ~)AAE~=HLD։DDDDIŅ~8HHDDJDDHHGA9EHcIMHHH H9s^HH290tsNHL1Ҿ DH1Ҿ HIDDHAu E E IE HACLdHLHLaEe0HcCA)u/IuHHH @H9sHH89:tEAHHLPHcPAu)I}HLH @L9HI A9tBTH;0lH;@_HcxHL8LH8(HL E A  AGL9HL1Ҿ IL9LH1Ҿ LLL1Ҿ HILCH'fDH( E1HH H?H H `DžE1Ʌx,DDE1DDžE1ɅA1A)HDDDD6DDHDHH(u,E1HHcPHT*1uuu @p<) 2DHlj$DPHH1Ҿ HI 1ffA*f.zAfEAD$DEDDHPHcDDDDDDHDDD D)AA f*YX fH~fH~H @H H D\Hf/(O fW f/HDžE1A1DLH1(؉ ʉY -¸Y Y ; YM YIYl5fYKH (t YA0Hu@!f(@HcH(E E{ |Y9AHDžf/(cH11L`H0HH9H;@V'HcHH8HH8H0fDMHtJI9tEH9H;@S'HcHH8HH8H0fDL9L;@zAV!HcHH8IL8H0I9L;@ IcEHHIEDHA$HL AuAE LAMD~A9~fDA9H8<HcL 8L;@ L8HP HxH@H8IcUIML 1A@HHD ‰WDAAI9wEDAEpL;0WL;@JIcU!HH8IML8pfDHHcW)օH0HH H H9 HH:99tHf.H9HIAL$IT$9tIň <f(ĸ2fH8HH H;@H8HHHx1DžAANY 6+ Y \f(ĸHcHH8HHH8Y rHHDDDHDsAIcHL8MI$H8ID$I|$ID$I$HcCHsDH9EL$AD$ AL$DEyA9~ fA9HcHL8MIH8IvIFI6IcD$I $H<1f.HH ЉFQH9w҉EEENL;0dL;@WIcD$HH8I$L8IA|$0IT$tILHDDD.;HDDDIՋt DDD/H;@H8ANAV ADL8AB<HcIH1EMNLjOH8<HcL 8L;@L8HP DDDD4DHDDDIf(TIfBDD^4IDDD04DI@3LIH0B<)‰eUHAWAVL`ALXAUMIHTATHPISHdH%(HE1IPL9IAI`L9A 'HXTLL)Aυt A$-IT$DQLƸxLD9t-H~LZ@:A9~9uۍxB.HD9u9sDSA)9DO׉)ǃ9HzHH~HHHHDfofofo HHHffoHffH9uDfI~HA9Lz09LzB0pLzB0x9LzB0p9LzB0x9LzB0p9~LzB0x9|oLzB0p9|`Lz B0x 9|QLz B 0p 9|BLz B 0x 9|3Lz B 0p 9|$Lz B 0 9|LzB 09| B0LzEȺ)HA)9PA.IELAOA~}IWLH~HHHfofo$fo ,HHLfDfoHffH9ufsA)L9 Lx0ALx@0ALx@0ALx@0ALx@0ALx@0AtLx@0AtqLx@0AtcLx @0A tULx @ 0A tGLx @ 0A t9Lx @ 0A t+Lx @ 0A tLx@ 0At@0LxAMtAEEtL.LL)HMdH3 %(HĨ[A\A]A^A_]f.0.LRfھ0LL0D?LZH@LLH(LHH@D?L0JIfE"fEtL3-0fA<$MAELfI~.,ff.Uf(fIHAWAVIAUATLcSLIHdH%(HE11f/)Éރt NL`f(L@HPLXMHHTHL(H0H8uDPHL9HI`L@AH9A A'MtAHXAwbE1HH)ρAwA@@ET1EbwA9AM9A9A9@@E)9A9~ DMtAEtHHS+DPHD)ML(H0H8f(YXH)L9AI`L9A DTPEM9A-IvI9Å2*IɸLDXD9DILVEYM9D9u9~DŽtLVF.M9L볉AD)E)HA9PE11;HA~EODPEE1Ar)1@)9EtHH)HH0Mf(H8L(PHHXA)AI`DPH9AL9@A TtM9}M^A-MM9sYHqI{A~(I9v#I{AC.H9sI9w H9sI9wL9siL_eM9v EtG-L_Ac~YM9MLM)EtH(HMdH3 %(L)Hĸ[A\A]A^A_]IAcfDA &M9sDȺI[A)A0E IM)낐EtHLH,(LHA0AfEM]ATAE)ADPfEJA9AA@MDȺQI[B0kdAA)I9QDI0ASDAA)L9AI`DPL9@A M9wDI0ASf1M0A'@A9HI9HC0T)9}A E1@D) DA9@A@TfI^A0ADLxL9svHF0I9HFF.t+I9wDI9tSH@0uDžPHƅI9}1'LIf.MLM)fA9ApAk$IHƅDIHM)ff.fUHIHAWAVL`AUATSHHxHHdH%(H]1I`L~HHHpflH1H)HHDžI9>MH (AE <$dHcHDždIL9AM10AЃ M1E1E1*CBYI\YHH(PYfH~H ||HDžH1ɐ xf/p{Ǻ%D)D)9Hv(D)HcYʉ)HcYfz DžAQ98A 1Ƀ9 I`<A׃HcI;H9HMAt$ID$E|$ I$HEt$ID$A  M} EpLEDPOl5 LXHHLL@HSL Hǃ0%L9uEIHXDPHHNl0E9}?ALLE)Ot DIAULHǾ 0M9uIċp1H(+hLIIXID$HHHH8HH@HhH0HDhA+IcHHHHHHCHCHHH{HHHc@HFH0LH8H@HwQLIMIHIFAFIHIFhXD$8+D3<0| A6A)GHf(fI~茺AWA+V+fH~ƋPfH~DH H H HP~P^o(f/eHHHHM(fցVDE ܲ(f/r(H,t fH*҅ufWfH~)fH~H ΉHH H H H  HPYPXf. UHI9oL;bIcMHHIUHLH9IH;<HcK#HHHHHDI9L;IcNHHIHLI9L;IcWHHIL@ADHAB<HcH;H;HDkD{ f.LHI9^LKLHH9HH@HLDPHLHIL;DPL;tIcUOHHIuLIXDh)k@Y Xf(f(хfW0fH~H )HH H HP~P-HLMMLIH(H… сL%@HH HXLIF H;HHIF fDLH DPH DPIt@P@H HPPYXfH~H ׁ|HfH~H9 HHH HPPYX9,f*\f(ȅuPHHu=ŭ(f/TLLMMHIH(x(f/wf/ r( fH<f(L0LH@LHt@LH4@HHmfDPI A If8f/&Y f(f(fW! I=fDHcHLMI $ID$H2f.IIP؉ƒtHcH (^[ T(DžYfNY 0(IY (,iY (Y (f(tPk)х~4Dž49 DžpfDff.RLHDžf%=1DEu  AF DNANA9~A9HcHLMIHIxI@I8IcFIL1@HH ЉGQI9w҉HAEHApI9L; AN/HcHHIHLApHAM)΅HcI8HH 7Iu fDH9sHHDD9tBMDHHHHH%DHHI$HLt@HHIEHL$@HHIHLDH(KHHD(HcH(YtDEt!сwAkA)D9zDžfpDD+hH~(Ic^fσ.L9I]H9!EEA0)DA0u HH9uH2fDA@σvtE11E1E1Džf.DHPDXDHPIDXIC A1A0E1I1E11DDžPfDHHHMDE΁MƁpHDžHLL LHApHL<HcI8H;HAHAP $H1 D1 f(AA<ApAOA fDEG4AEzEA9~D9~6HhDf.WE?E)D9HhpDA1AGA<Ap눁MDžLLMMHIH((Džjf(1;XnUtADXIE1E11AXC D4O1Hpp@HH H\f.<F (DžjYUXDhp XDhIp>HLMMLIH(KHHH2!]LpA0IIL9v)EEiA wANGIGTQL9wLLpDhH)HLANCt.IhL !ЉILDžhNLL9gE11E11DžE1HDEff.UHHHHUHuHEf.@UHAVAUATISHPdH%(HE1L5ޠ(HF"LcH1EIH]Hlj)@AEI9w"LHdAHLjHuLHHSHHQuHudH34%(uWHP[A\A]A^]fDL5q(HSF$"w&Hx KfA$-HI6D1ff.@UHHPdH%(HE1y HHEIIG0HH)H H}Ev5f.Hȃ0HIH)HHu@HHGHVBuHHudH34%(ufD-HH]$@1@ H8uufD1DUHSHHHH[]U HSHHHH[]UHAWAVAUATSHjLL9sPH[NLP@HAD Hu:@DLCDt'HI9u!1H>[A\A]A^A_]tH<-<+AA\/+ E1<0tz0< wLQ LAM9MFM9yHIHAM9A8OЀ vHLHEHE[A\A]A^A_]Ðy@0LLAM9u1LHHEHEfLAM9AALA_A-f.t;H NLA@ADHuAD0HuHuDMM9IJ I9IMFME1"fD@O4N4wIL9IA?0@ vDH(L>D)HI[A\LA]HEIDA^A_]LAM9A LE1AA\/+LHu<-H I9IMF1M93,fM9A8OЀ MWM9Ax0@ IL>M9tAp0@ H9H @H OHvHHKHHH MI9Hiʚ;LLHHEHEH TLHKH9EwDHE1E1}oJ)fIE1@Hw2ALE.LHHMHMITAE1LuMIE$fDLLHIIL9eDAwA$LLtŰRHU)IALOЃ`uIFH9EA`IHcIH9EofHuH} HMH)L)HMHELuHHEI9EA@HLŰIHfHUHAA@HLŰHPHׅt1ƃ1.9rL,IEHAE`H+MLuIH@I9wHMHAA@HTŰIHt>Eg^HHI9E{HJHʸ6fUHATISH~|B׃Pw*HH JHVHH4;t1H[A\]@HHMH9tIT$HH;uIT$HH5(oH[A\]HVH͖(H5(HEEH[A\]ff.fUfHAWIAVL@AUMATMS1H H0HdH%(HE1HNL(L8IHx@H@IIHYAAB `uAB HqAHH-u AHHAB*TE1D7u>f.LK4BL pMuAJ ALYHDuMJAIs.xIBLH]HDŽ DL lzpuAǁtf.LAHMB @Ir(<%OuFfDHFHVt<%u5HJRIr0IE1HDt.KH0LPHDuM9MBHI8]DD1H0HPHuAJ H HDuI9LBHHHIRSLL[dHs@CAJ .AK<*D1BDufDLNHL^0HPHDuNIRH‰2AǁtASHHLIVHHH18fUHAWAVAUATSHH0H8H9v9L%(AtKHCDHAt2HH0H9uHH8HFEH[A\A]A^A_]ÐH]~EHCfl)L8I9s`HC I9I3IH=!(@uzUHHI0II^H[A\A]A^A_]f;!END-OF-INPUTunknown tokenCDATA'=''<''>''/''?''!'IDENT%s unexpected (ident wanted)%s unexpected ('?' wanted)%s unexpected ('>' wanted)ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃ{rÃÃÃiÃÃÃÃÃÃÃÃÃRKxxxxxxxxxxxxxBxxxxxxxxxxxxof]Txxxxxxxxxxxxxxxx|sjaX8OP\\\\\\\\\\\\\D\\\\\\\\\\\\8, \\\|\\\\\\\\\\\\\\s&///////////////////////// ////~~~///~/////////~~unexpected END-O ;FPFHF VJ;VPVVhRV@SV[V\V fVlW`WlWWWWWVX,oXXXIY<Yd ZoZZ0[[,\_\ p\XSfSg0FhpF iFiFjFpk Gl4Y >HY?Y@Y@Z A4ZPATZpAtZAZAZBZB [ C0[D[E[0F[H,\pKd\Kx\L\M]M0]PN\]N]O]`P]P]P]P^ Q0^R`^Rt^R^S^S^ S^0S^@S^PS_`S_pS(_S<_SP_Sd_Sx_S_S_S_S_T_ T_0T`@T`PT,``T@`pTT`Th`T|`T`U`U` U`U`UaU(aW\aYaZa0ZaZa`]b]0b_hb0abpcblbmc mc@m,cnXcolc0ocpcPpc0c d4d@Hdldd d0dd0eLe`epte eee fDf`pff0ff g@g@Tgg@ggg` h@h`hкhhh@h`i(ipPipiiпij08jppjjpjk(kPPkkkkl4ltll`llllmm ,m0@m@TmPhm|mm0mpmmn@Hnxnnnn0nnoxP>x`AxG(y HPy0Hdy@HxyPHy`Hy`JypJyJ zJ zJ4zL`zOzSzU{`W@{Wd{Z{Z{`^{p^{^ |_4|_`|`|`|0a|c}c}d(}fX}j}j}l}m}r,~v~v~z~~~<h@`(L̀0 ` ԁP,P\PК0Hx@HhЄP,@T0h@@ <l̆P,\0` 8XxP؈@p8Xx `؉P8Xx `؊8@Xpx؋0`8Xx@p،$ \@@Ѝ` L4p 0X0PĐ 0PPp  X ̒@x(` Ԕ0 H@0PP0plp !"#T$%ȗ&'<)|P*p+,4-t/00p1,2l346$07d`89:;T<=Ȝ>?<@xACD$@E`E@FFG G@P(PT R0SSSԟ`WpXHX\X|Y0Y@YԠPYYYY$0ZHZxZp[[ء\@]8]lp^^̢_P`< blb0c llm,pmPmd@npnnȤnܤ@oo$p8pLp`@qtpqqqrĥrإPr`rprr(r<rPrdsx0spss`tȦtܦ@uuv@v,v@0wTy|ħ@}}$}H@~\~pP\ȩ P|`ܪ4dpԫ PМx0Рج@PHp`t@ĭ@H pp0dx0P0Яp<P0|0Pа` <P4 `pHPxP̳0p,@p8@ `p ̵ @ (` H t Զ P@x0P @l` t@#$ܹ* /<5<=к>> ?0?\@@C0G, HX0KMмOO8PhSSPTVW<`Yl ZZȾ@]] _X`a@cؿcc d(PdLdxdegg< ihjjjPk k,kPmmn0pppp,p@qprstPv(wXwlw yz|(`}l~8d0 04X`ХP| Pdx0p@дl`@hий P`@(<phP0 4h@@(<Plp@@X@(pHhP8Lp`p 4H\p 0@P$`8pL`t (0<@PPd`xp,@T h0|@P`p0DXl 0@P`p 4H\p 0@P`$p8L`t 0(@<PP`dpx,@ T0h@|P`p0DXl 0@P`p 4H\pT@p0(Pd x@(X/@0`113$4T5P5p55560;<P;P =>`?A`B<pCPDh@EE`FFF(PGHGpHHIJpJ@Kl`KKKKMMN,`N\NNOPQS0U`U VWX4 XH@X\pX|PYYZ@ZpZ< [h[[\]@]a\bdef iLjkkl`m m4`ppr@rss`tHuuvPw`wx }H~t P$@\`0DP`HpP0 б4H`pp@0l p,P@tP`$8Lx`8L @<l p0DX xP ` Pd`0X``p(Xlp <t `4P`pp<` @*CH@C\PDE@FFGPG<QhRR SPSS PTHTlU U0UUUW4XdXx X0XpXXY PY8YXYxp[[\](^P^d __`` aPPap`bcdPd dHe0fg`g g< `hd h 0k k k k, Pl\ l m @m m n n4 @oX o| `p q pq q  r4 @rH r\ rp r s t t @u w@ wT xh  y  z zP{${D{d|x@` Hx@pЍ8ph0p0P4Th@`0@0DX0lГ0pHtPHx0P$8 P0` @@|@<P`@PpH| ppHl0`$Dphp `@P0@p 8`PP`p(@X@D t    p!!P!!!!0"<"P" " " " " " " $# d##0##$,$ @$p`$$$$$ %L%`% %%%0&@,&P@&h& &0 & &"&#&# '@$ ' *4',d'-'/'p1'2(4L(6(`7(8(:)) >)0>)@>)`>)>)>*?,*Bd*Bx*0B*B*C*PC+C<+Dh+0E+pE+E+PH0,HD,I,J,PK,K,L,L-0M0-MD-POt-Q-R-`T.V<.Wt.Y.@[.]/^H/bt/b/e/ph/m 0m@0pnT0nh00o|0q0r0 u0v1pxH1y1P{1|12P2P202P2222 3P830h3033@3p,4d44405П05D5X5`l505`5Х55@6L66@66 7X70x7б770788(8 T8`88p8п 9T99@909 (:P<:p:`:P:P:;PD;x;;;P<`0<pD<Pt<p<<<0 =pT==P=== >,>d>x>p>>?0?\?`??? ?@?P @ @4@H@0\@p@@@@@@@$AP`A AAA(B@ `BP tB` B B B BBC@0CpDClCCC0C@C D D4DxDpDDDE`$E8E@ dE` xE E E@"E#E$F@%0F &`Fp&F@'F'F(F0(F(F`)G),Gp+\G0-G.G0G02$H3\H5H`7H 9H:0I ;DIp;XI@ȁ CpE@PIppL@PЂQR0UlX\̃_cDdtePhk4`odqrPv؅{@DX`4PlpР<СlPЦPԈp4HP\ L܊ PT` X@̌P8LP`@ԍ<l`D0t0p؏4Pd!p)ĐGGIDIhJ J@JPNP0UhU`_̒0gPg g,h\illȓlm0m `m8n`opqȔ0s wT~~0ĕ@ؕP`p(<P@xؖzRx !/D$4FJ w?;*3$"\X"C(p"qAJ BHC H P ,"DAC FEF F ($sAC BGF_ ,\$AC DEGDl D ,($_AC HG4 I $X%=AE A] D P & AC AV (&QFC BEDr JH&D&zPLRx5#  $&NQN F (8%QAC Mp G $d0)~A[ Cy H ,)AC BEEED F +BAC } H+AM H ,H+ AC BHW K b N (,(/QC Et C DA (X/A_ BIB C \ P0#8l0AC K G A G V J (2AJ Cl F j ,T34QQ I_ F x H 40d4AC Is H  C 0x6gLAC Mj E ,zPLRx#  48 L$@9=AC A_ D T , X9AJ BJLDi H (<:AC C D O h:(|:AK E] B A ;RAJ ] H ;KFe _  ;AC H B $ ==AC A[ H P (4>TAC BDb D _ ,`D>6AC BJq G e C T?AH A(BkAC BJu K 4LDyAC DEEH B E K $GAC J B 8LI(LXIRJ AC H k x O8(8OAT DDS H 0 QJM CJ DP  Q"AH A G (RsAC C] D F ,<RAC Ir A T D ,lSAC HK F xX3]E H F,XAC DEED D ([AH FD E $ ]AJ W N O Q @ 4^AH Ah F $d _1AM Cx G ( 8aAC Gw F R F ( ,bAC Gw F R F ( cAC Gw F R F $ d4AC AZ A O (8 ,dAC DDq K 0tdYFAC HEEH2 A dF, eoAJ IK A  K , $gAC HSG J ( mrAC HDa ,< (pAC HI~ E $l qCAO Iw H , @wAE M E $ zAC E D , h{AC M5 A 4, ~DAH I A .p@D(l XAE M , L AC FM G , AC FM G 0 ̭$>DAC P B N$!D D  AC N,h AC PK A  ( ,AC Eb $ Ai BH $ AC BHK ,AC I B L81FC AXA 0pTAC DH B R ,@AC BIT E I G 8OC BIU F n JH (4AC BGEHi (<XAC BDo G W hY|$_AC BEDO (YAC BDj D `  @QJ BE] $,aAC BD~ H (0t}AC BIDA D (\`AC BID| A _(HsAC BIDq D (AC BEGLs ,AF CO G Q O 4$AC BEHID B P (\XAC DDv F (AC Al G l D ,@vAC G` E E O@#KC FED DH $<UAC BHF $dUAC BHF ((AC BNV F $bAC BGO A <4YG E GH K A  T4FC BEr FH I AA E F HhTL BHEEDp H h H  GAK Cw  %AC BHV  -AJ A` @AC M  `,AH C_  ,AH C_ 8 kC BEEEDp E S E! 4AC Cl 4SAC FED D m K $zRx  ," (AG M K G] } G i 44|AC DFEH~ G  J 4|AG BGEH G  P(t:AF BD K $zPLRx"  ,$:4"AC E C N B H H  (AC FJU G $HQWH BDc H8p$AC BEEDe G X H p KAJ D #,AC CO J L D L`$?tP\XTPLHD@(<<8P4d0x,($ ($   ,@XT`h\|XTP LAC } G  AC BDS 0AC G D ] C 0H|AC G H ] K |XT#$pVAJ Ea G ] $AC E $PfAC GZ 4AC BEEF G U K (T`UAC BEG H (9AC M_ H , AC LD H    ( AG C D x D X ($l qH AX F` ?aC M ( AC I E (4$AE BLID  $ $% 4$6AC Ey F X &yQE EJ K (|h& AC Ok B \, X,aAC c I p $,AE Iz , -JC C_ A DBA 8l/Lx/`/,t0TAC BILG F 31AC BGc ,3AC DEED E   X51FE AXA (0 t5FC AJA S ,\ 5AC HK F  h:( t:AC DK F h $ :TAC BHE  <4!<AC DEED A \ D ,@!<AG BEH G p!P'AC BGU $!PAW BDo A $!QAW BDo A $!QAC BH D  "8R%A] F ,"HRAO F L"HRAO F (l"HR AC DD A ",S'AN W "AC DGD7 F ($bAC G H 8$f]AC BGED  J  J $j AH V $%jZAC BFM ,<%jAC DH C (l%hpAW DHq K (%qAR E J L (%rAC I ,%s AC BIHg B < &{AC DH D c E a A (`&$~kAC DKDS &hF&&1&܀&؀.&'','@'T'4h' &(|'(aFC Cd H h ('l7AC BI[ F F '1'!4'ȁXFC BEDm G L A,4(ZAC IU F  E d( #x(<(H(T (`aFC AFA (8([C EeA W K EX ()l<)x1XG C N(\)AC M F 8)8AC G@ E g I h H () tAC M K )t*.,*2AC C D e K 8H*JC Aq A W I p H K E* $*tAJ BD| C (*/AC BDQ E N *++(+ <+P+d+ x+-AC T H H ,+AC BEGK  H +$+yC BFDA , ,TAC DEF H ,<,JF C H s E$l,QAC BHHz  , 6AC BGh  ,<#AE   A ,H$,,dAC DEED H 8 -zXC DEDp HP ,\-8AC Mb E -Ȕ-Ĕ --D,-}AC BDu A W I .HAC Ex G 00.AC BEG D  H $d.`AC Ck F (.(AC G\ I .98.AJ HH F n J  (/iAC DHD D 84/РEAC BFFEGS G   E p/d(/@AC GD A ,/gAC BSg H /4,/AC BN F ($0aC BEDP A P04d00<x0ܶAC I F  B [ E L0AC FJ] G 3 E n B c E S A 19101D10X1 WAC A K v J [ E ,18<AC E C j F 1H$1DAC C E (1QAH BI H h ($20AC A K k E P2$?AP m  p2DhAE BD[ 2(2 AC EW H <2p4AC I K  B  D $3puAC EJ E <3P3d3x3@3AC BJEF F  A n B ^ 3t3p3l 4h( 4tAC BH E DL4AC G C  F  E } K w I 84QAC G G  I  F ,4AC I1 B (5AC EB E ~ B ,5ZAC BGL ,P5TAC I? D 5(5AC Mp G 5 51FC A\A $5HAE Aa H W ( 6AE BGa H K ,L6(AC BJEIF D |6RAX x 68=AC x ,6XeAC BGD D 67!,7AC BGEHX F @D7P]F FKw E  P 7*7,7AC BGF J 47|AC DEIi A G I `8mAC HDP H X H r F w I { E Z F L D | D $|8:AC BIj ,8AC BEH K (8AC DD H $9dRAC Ak H Y ((9AF DD H $T90PAC Ai B _ (|9XNAC FD A 9|KC A| E 9rNC AN H 9T ZNC Av H : JGC Aj K08: AC FDm E [ E l:h 0:P AH BEGD H C @: JC FDx A x P :xUYE Au ,;(AC DEF I (L;AC BGDg H x;'AC BGU  ;(1IC A\ G;D.;`,;AE FG D ,<lAF FJHH I ,H<AF DL K (x<wAH I_ G ,<AE BID F ,< AJ DEEK A ,=:rAC DVSRB K ,4=?AN DGD: A ,d=PGAC FEF A <=INC DJm IBBA F ` ,=IAG DEJ K ,> KOAC FED B 4>@OxAC s (T>OAG PP H 8>TSAC BEEJt B Z E (>T$AC Nz D ,>UoAC C^ K K U ^ ?VA,?XVA@?V9(T?VAC Gy D (?WAC BHO C  $?(XMAC ER E h  ?PX=AC BDr ,?lXAC I~ E ,(@L]~AE BN G ,X@^AC DEJN K ,@<_AC DEJN K ,@_AC BEEJ[ K ,@L`AC BEEJ[ K ,A`AC Il G Q G (HA,aJAC M G tAPb#OC F TA`bUC DGD_ JH D DH A(c&OC F H B8c$B@cKAF E~ DBpc7AF Ej dBc1AC Eg Bc3AC Ei Bc3AC Ei Bc7AF Ej Bd-AC Ec C d-AC Ec $C0d)AC E_ DC@d;AF En dC`d3AC Ei Cd2AC Eh Cd,AC Eb Cd2AC Eh Cd3AC Ei Dd2AC Eh $De,AC Eb DD e,AC Eb dD0e-AC Ec D@e4AC Ej D`e4AC Ej De-AC Ec De8AF Ek Ee,AC Eb $Ee;AF En DEe0AC Ef dEe0AC Ef Ef0AC Ef Ef0AC Ef E f0AC Ef E0f0AC Ef F@f>AF Eq $F`f,AC Eb DFpf,AC Eb dFf3AC Ei Ff,AC Eb Ff0AC Ef Ff 4Ff8AC BEIEH A Y G 4Gg$AC BEH C P H k 8HGhAC BEHE H L D h H 4GiAC BEHY D P H k 8GhjAC BEHD I L D h H <GLkAC BEHN G P H X H | 88H,l;AC BEHI D L D v J 4tH0mAC BEHU H P H k 8HmAC BEHD I L D h H 4HnAC BEHU H P H k 8 IoAC BEHD I L D h H 4\IpAC BEHY D P H k 8IPqAC BEHD I L D h H 4I4rAC BIHA H P H k 8JrAC BEHE H L D h H 0DJsAC CU D R F R F 4xJtAC BD{ K F J h H 0JuAJ BLp G N B a 4J vAC BDs C F J Z F Kv1AC Ak AC BDs ,|xAC BEH~ O j 0%AC DEE H X A $NAC BEHz  <9AC BDn $,X=AC BHn (TpAC G F ,4AC DGHu D (AC DEDb E ,܅AC FF D , hAC DEED F 4<3AC HDq G f B ,taAC DEEKg D (nAC DEDY F (ІTvAJ DGDY E ((AC DJGa F 4TAC BEED^ F ^ J | h;AK l (AC DJD] E 0؇AJ r , zAC FJ F ( $AC M J (LAF IJ F 4xLFC Ay E P ` K 9AC t й p4AC  I AJ c  (LLHM Y B [ ,Lx AC HH~ F (|XAC DHz F (iC IN E B ,Ժ0AC BGM D , )AC Pi C 4A%(HA AC GL I 0tBAC M J f J ,DNQC EoA  ̻XDxAC Ej DK D;AC BDp (( E) AC NS K (TO3AC Hw E y G $P%AC \ 4P-PL C DP+AC b (TPAC L A $ P]AC Ax C \  4QHAC AB X,QjAC EtQ|Q AC H  lQJAC BD $̽Q`AC IN (QAC M E , DS|AC DHa G PS dS xSS8QC A[ S8QC A[ (̾SFAC CP I e (SFAC CP I e $T5QC A\ D0T-AC Ac ,d@TAC DEJ C UCAK j A K (UAJ G D ,VAC DEEH F $pWAC _ E X H <XX(PTX]EC DD A,|XgEC Ch E e C,XwEC Ck J g I,YrEC BH@ F K E, hYzEH Ck E g I<Y<AC w 0\YAE E A S A M A ,Z=AC E H f A M $[WAC EZ E n  [IAC BHz $ (\sAC DJ` 44\IE I` I ` 4l\IE I` I ` ,p]AC BGD{ D (^QAC BJEDw $D^yAC Ig $(^sAC FDd (P^qFC E] A|R04_MAC FEH H t PaAa"AN R a"AN R ,anAC DDX A H $HanAC EQ F M  p4b7EC Aj APb8AH n pb9AC As $bAC E\ K S  bAC Ew  dcAC Aa J DcrAC Eh $hAC y  9HE ^ E H DJAC BJl D \ D D D Q G o A ,0mAC BN D $`oAC IP K ,LAC DH~ B { E  $HP ` H i G `0\$AC M D @ H D<XIC HD{ E x P (0AC MG H @ %IC GD I p P  GxC K (<%,<XAC C A ~ A l8%$TAH Cz J    ( AC BNU G <KC M EH 4PDAC BEL G r F (AH FIj F $`AC Cb G $AC Cb G &,E[C K G$LmAC BDx F (tPAC BEEF ,AC BGEH E S$AC CP I ( AI M D 08lAC HH D (lAC BQx A $lYAC BHz H ,AC M4 K  $,NAC DED| ,T0^AC BKDo L `*xqI R A\V , AF FFD J ,PAF FFD J (DAI A D G A ,AQ C D I G (x CAI A D ] K , AI CO D F J 48L VPC C B _ A S 4pt VPC C B _ A S ,dAP C B _ A ,AP Ep J H H 4PJ E) H ^ B T 8@$PJ E) H ^ B T |xtplx. [AJ AN 4\aAC BEGD E  A P dAF AU ,AF FEDQ I (JAF BEIDn  @AM BDk  05AF BK` ((LxAF FED] <TLC G EH j  5AF BK` (JAF BEIDn 4AC BEGD F V B F80TAC A G M C H H L E <lAC E H I G H H L L tAd DI R AVf,0T AI C D U K ,`!AP E D \ D (d#AI A{ J D 0$AI E K S E  4T&PC C J @ H t 4('PC C J @ H t (`D)AP C H F 4*AP G E Z F  4`,PJ E H  A q 4-PJ E H  A q (4p/AC I I `D3 4t@3 AF BJM A S A ,(6xAM BQ= A ,x8AC I< G  <I R A,h=@>VT`>Vh>(|x@AI A  I D D ,,B"AP C G F J (,DSAI A  D ] K ,`EAI CW D F B 44 GfPC C I O A S 4lXHfPC C I O A S ,ItAP C* B _ A ,J2AP Ex B H H 4LPJ E E n J T 4<XNPJ E E n J T tOI R APQaQRVR(SAI Ad A G I ,$VAP C G I G (TXAI A D V B ,ZAAP C  B ` H ,\AI Co D F J 4D_0PC C F ` H  4 I 00AC BEEED> I 0d`AC FK D ( 4<AC DFL F e K Q 4AC DFL F e K Q , (,0$AC BGD A P `ԟAC T (ԟuAC MZ E ,(AC BJw I ,AC BGED E 0 <QC M F  8@{AL BEEG+ E q A $|XQAC BEH} $QAC BEH} Ȧ Ħ[AJ AN 4AC DEN F P H P$4d AC DEN F P H , AC DH E ,IAI BJ0 J ȶAC T (ȶAC M E (H|wAC Ar I j F tзܷh08/AF C D K E K D 4@<3 h3 040H̹C\ p60c aAG BDR غ1<AJ HER A  D U C 8AJ HEV A  H n <LAC FGY A  B K E 8xAC FG] A  I k 4AI DGD A  A 4pAC JHE E  A L`t)4AF IQ G O I AL s '$0$AF BH J X "AI E F |2AF Ai 82AF Ai X $T`AC DDz J  @ TELC I CH l 4d`MJ HR A u 40AF BEGD B V J 4k($jAC BDN H I P ddHC AQ A,(Yt,AF DEED F $NAC BED~ ,AC BGEDO K $LNAC BED~ tvADAO L DdDI R A@V,AI C D U K ,H AP E D \ D (xAI A{ J D 0AI E K S E  4PC C J @ H t 4PC C J @ H t (H|AP C H F 4tAP G E Z F  4PJ E H  A q 4 PJ E H  A q 60F,D AC BN C 0tAC BEEFv D p ,AK BEL! H ,lSAF BGF D 0AC BEEFv D b ,<( AF I@ H ,lDAK BEGD F $(!AC BH H 0<)Xp,(AJ DH H Z X%AG \ 8xPJ BEEEEq G P Ap!AS L 8PJ BEEPG[ H P A4AJ DK; K  E R H8\PJ BEEPGS H P A,\AF Q A $AJ JD 0AJ FD H Y G 0$ AC BEEEE  K ,X *AC FEL D 8 EAF f C  F P H I A J ,AJ DII H Y %AG \ 8PJ BEEEEq G P APD!AS L 8pTPJ BEEPG[ H P A8AJ DLI' E  H Q 8PJ BEEPGS H P A,8  AF M  H (h AJ FED 4 `AG FED H [ E 0 AC BEEEE  K , *AC FEL D ,0 &AC P D ,` AG BN F , AC FKB I , "AC FKB I 8 &AG DH C D D  G ,, ,VAF HK I \ K8(p DK&AC A E K E ( HL&AC A E K E , LMAJ P F  S#AC ^ 8 SPJ BEEEDr G P A,T TjAJ P G  [#AC ^ 8 [PJ BEEEDr G P A< T\ AC BEO E S A  A  $eAC T @ $e3T Peh \e,| heAG Mn E @ fiC BIDaBBA  L A, g"AJ P J  n#AC ^ 8@nPJ BEEEDr G P A,|8oAJ IK A v#AC ^ 8vPJ BEEEDr G P A,\wAJ P B 8,#AC ^ 8X<PJ BEEEDr G P A,RAJ P D #AC ^ 8PJ BEEEDr G P A,  AJ P A P#AC ^ 8p$PJ BEEEDr G P A,AC FQ G x#AC ^ 8PJ BEEEDr G P A,8 kAC M G 8hLlAC C E W I P H R A ,AF M  H , CAJ DL E ,@AC BGEDe E 84AJ DLI' E  H Q p8PJ BEEPGS H P A,AJ DII H Y %AG \ !AS L 80PJ BEEEEq G P A8lPJ BEEPG[ H P A( AJ FED ,AF PE D ,@AJ DEK H 44ЮAC BH K X H S E ,l8AF M  H ,رCAJ DL E ,AC BGEDe E 8AJ DLI' E  H Q 8L8LXPJ BEEPGS H P A,̶AJ DII H Y %AG \ !AS L 8PJ BEEEEq G P A84@PJ BEEPG[ H P A(pĸAJ FED ,xAF PE D ,AJ DEK H @WC BD F ! G p H ,@AF M  H ,pCAJ DL E ,AC BGEDe E 8DAJ DLI' E  H Q  8 PJ BEEPGS H P A,\xAJ DII H Y H%AG \ X!AS L 8hPJ BEEEEq G P A8PJ BEEPG[ H P A(DpAJ FED ,p$AF PE D ,AJ DEK H $4AC C G ,AF M  H ,(CAJ DL E ,XAC BGEDe E 8\AJ DLI' E  H Q 8PJ BEEPGS H P A,AJ DII H Y D`%AG \ dp!AS L 8PJ BEEEEq G P A8PJ BEEPG[ H P A(AJ FED ,(<AF PE D ,XAJ DEK H ,LAC C| E  G ,AF M  H ,CAJ DL E ,AC BGEDe E 8HLAJ DLI' E  H Q 8 PJ BEEPGS H P A,AJ DII H Y P%AG \ $`!AS L 8DpPJ BEEEEq G P A8PJ BEEPG[ H P A(xAJ FED ,,AF PE D ,AJ DEK H <H<AC BH> D ^ B P H S A ,AF M  H ,CAJ DL E ,AC BGEDe E 8 \AJ DLI' E  H Q T 8h PJ BEEPGS H P A, AJ DII H Y  `%AG \  p!AS L 8!PJ BEEEEq G P A8P!PJ BEEPG[ H P A(!AJ FED ,!<AF PE D ,!AJ DEK H "LC,"@"TT"{AF FEDY A C E l D _ I ] C m C Z H"+AF FEDS G H H ] C m C Z T"AF DFF] D B F l D b F b F m C Z ,P# 4AF DFFk F ,# AC FED  B ,#$AC FED F 4#AC MD K e K ($,QF BEHGj D$)X$(l$XAC FED ($ AC DH  ($=AC BEEDd ($AC FED %!AL S 0<%AC BNz B a (p%dPAC BEED{ 0%sFC BEEEDO C %[AJ AN $%|AC BEDl 0&h0AC M F t D P&dd&$x&N&854&dWC I@ E _ &&&VO V EL 'JC I H  G x L \'# p'#' #'#&'8#.('T#AI Ad A T D ('#dC E D((|$AI Ae H T D D($brN  Ad(@& x(<&(H&RPC i D (&~AJ Aq ,(&7AC BGID A ,)')AC FID  A 40)(AC BEHMHg A b E (h)|)AC DD A ,)0*AC DGF C ,).hAC DEN C )3AC U *3AC T ,4*3AF DEIH D ,d*4AF FEIy D ,*06AF FIH~ D ,*6gAF FEIq D *8+8,+9^AF DHH A L+H;`+4<,t+<AF DHH C ,+>AF HE D +@[AJ AN 8+<@AK M G Q O J F 4,AH,A,\,XBAI Av G  I D ,C,C,D,_K C~ E  ,`>$AC DEJN G D>TF CF E  E  H  D i D>\TF CF E  F  H  D i , ?_AI E H k E (P?KC FED C |?X0?AI E H a G 4?pAI C J F J  F 0?SAI GO H J F 0@RHD@@PC G F  H _ C H@PC G F  H _ C @h%,@BAI A  D  C 4 AcAI E B ^ B H H @XA PC C  J W A  C @A(PC C  J W A  C DAtQ_K IJ C  C ,(BAC DEJN G XB\lB<B4|AC BGEDz H S E  I Bt"AC S Bt"AC U Ct"AC U  Ct"C4C"N,HC"AC FJN G ,xC#AF HD H ,C&AC FJN G ,C&#AF FFH* K ,D)AC FJN G 08D\*AC M K E A (lD+AF BGL E ,D ,AF DEIH D D,,D-AC I F 0 Eh0AC I G e 8@E28AC M E  I v J ,|E4AC IM F ,E8AC DEEHH F ,Eh9AF BIH{ K 4 F:AC BEGHT B  L ,DFpAAC DGHg B ,tFUtAL BEEEP E F@W>4FlW AC BGEH H s E 0FDXAC BHY I Q G $GX8GX90LGXAC BEEEDH G GZAAM r GZAP L ,GZAF BIEFD E 4G[)AF Cg G ` H @ A ,(H\AF FK H ,XHl^AF BEIHDq H^,H^AE FG D 0Hx`AN  G h H m C ,IaqAC BD( F  E ,0I4eAF FJHH I ,`IgAF DL K 0Ii7AC GS B  A (IkwAI If G ,IlAE BID F , Jn`AJ DGK E ,PJrAC DVSRB K ,J4AN DGD: A ,J"AN W K J"AJ V (K!AC FJ G 0KAC  G TK`+lKx AH AU Kx AH AU <Kx AC I` A  B @ H ,KHAC DHF G 4LؽAF DEHH E  K 0TLAC BDy E @ H b ,L, AG BEND F (LAK P D L0L<AC z ,MAC BEIEG F HMAC  ,lMAJ BEEF] F MM$M7FC A_ GM. N+$$N AC | H X 4LNAF G A y B S ,Np`AI DL G @NAC DID G h H _ I l D DNAC Mm B v J h H  A (@O|AC I E lO^AW E  OH9MC A` GOdO`O\OXPTPP4(P|;$ P@ g|jUm|#> > wǹ|oع޹|~|0? > ֵ | &|:!7D|? < #W\|lP? @? $pt|bb%||&|-''Ǻ|'ۺ(|T)|o3|9-4|F;MT|f?mm|G@t|:\|_| > = a|λ`> @ Gػ|T0||0|||(|oG;|TO|Gc|TMv|f0|"޹|*|o+|-',޹ɼ|-ܼ|@ < .|@ < /0|00|10|2*|45|5G|'ۺ6TZ|k? A 7Tq|k? A 8{Z|? A :M|f<|? ? =|? ? >{q|? A AM|GB޹ǽ|C-ҽ|FDpݽ|bbE|Fw|oعG|H| I||JT#|QZKg-|jUmL77|? < MGJ|oNֵU|O`|oPk|RQu|TR||]|S7|? < TX|]= p= UG|MP> P@ V|#> > W~|0? > Xƾ|B C YwϾ|jZWھ|lP? @? [5|Q0`? @A ^0|`| > = c޹|b|%`> @ eT.|k? A fT?|k? A gTR|k? A hTc|k? A iTu|k? A jT|k? A kT|k? A lT|k? A mT|k? A nT̿|k? A oTݿ|k? A pT|k? A qT|k? A rT|k? A sT|k? A tT1|k? A uT@|k? A vTQ|k? A xTd|k? A yTu|k? A zT|k? A {T|k? A |T|k? A W|lP? @? W|lP? @? W|lP? @? W| P? @? W| P? @? W'| P? @? W6| P? @? WG| P? @? WW| P? @? Wg| P? @? Ww| P? @? W| P? @? W| P? @? W| P? @? W| P? @? W| P? @? W| P? @? W| P? @? W| P? @? W | P? @? W| P? @? W)| P? @? W:| P? @? WN| P? @? Wa| P? @? z|? ? |? ? |? ? |? ? |? ? |? ? |? ? |? ? |? ? |? ? )|? ? 8|? ? H|? ? \|? ? |? ? l|? ? {|? ? |? ? |? ? |? ? |? ? |? ? |? ? |? ? 7D|? < 7|? < 7-|? < 7@|? < 7T|? < 7i|? < 7{|? < 7|? < w7|? < 7|? < 7|? < 7|? < 7|? < 7|? < 7|? < 7|? < 7'|? < 78|? < 7K|? < 7`|? < 7u|? < 7|? < 7|? < 7|? < 7|? < 7|? < |@ <  |@ <  |@ < 3|@ < G|@ < \|@ < n|@ < |@ < |@ < |@ < |@ < |@ < |@ < |@ < |@ < |@ < +|@ < >|@ < S|@ < h|@ < {|@ < |@ < |@ < |@ < `|v B B `|v B B `|v B B 7|@ < !|@ < 4|@ < M|@ < c|@ < y|@ < |@ < |@ < |@ < |@ < |@ < |@ < |@ < )|@ < ?|@ < U|@ < k|@ < |@ < |@ < |@ < |@ < |@ < |@ < |@ < !|@ < 7|@ < M|@ < c|@ < y|@ < |@ < |@ < |@ < |@ < !|@ < "|@ < #|@ < $)|@ < %?|@ < &Z|@ < (p|@ < )|@ < *|@ < ,|@ < /|@ < 0|@ < 1|@ < 2 |@ < 3 |@ < @7|? < A76|? < B7I|? < `]|@ < aq|@ < b|@ < W)| P? @? W| P? @? W| P? @? T|k? A T|k? A T|k? A |? ? |? ? |? ? X#|]= p= 9|P|Rg|ɸT||nZ0|R G|T |N| M|G 5|Q0`? @A |B C |pw6|jGK|MP> P@ ga|Qmx|#> > w|oع޹|~|0? > ֵ| |:!7|? < #W|lP? @? $p5|bb%L||&e|-''||'ۺ(|T)|o+|-'-|@ < .|@ < /0|R2|3*|5B|'ۺ6TU|k? A 7Tl|k? A 8{||? A 9-|F:M|f;M|f<|? ? =|? ? >{|? A @|:AM"|GB޹2|C-C|FDpT|bbEd|Fws|oعG|pH|ɸI||JT|nZKg|QmMG|TNֵ|O|oP|RQ|TR'|N|S76|? < TXH|]= p= UGW|MP> P@ Vg|#> > W~x|0? > X|B C Yw|jZW|lP? @? [5|Q0`? @A \|]|_| > = `| > = a|%`> @ b1|%`> @ eTC|k? A {TZ|k? A Wu|lP? @? W|lP? @? |? ? |? ? 7|? < 7|? <  |@ < &|@ < 00ڶG0SXbp(*5/5:G6G~~=vI0000RԴ\GNGYG<Gew}wwlwnwֵݵֵֵ˵ֵTTMTgg`gwww55D0???o 2           ; P    `  p 1 `  X ^  ]^`~glot< yw~hpx@p^ __ _(&'&&&%&$& <& ;& :& 9& 8& 7& 6& 5& 4& 3& 2& 1& 0& /&,`D*C*B*@1:141,1&1 11111100000000000000000000|0r0n0h0b0^0Z0P0J0D0>08020"00 000//////////b`e^d]d\d[dZdYdXdWdVdUdTdSdRdQdPdOdNdMdLdKdJdIdHdGdFdEdDdCdBdAd@d?d>d=d 0&    1 `] `] @r]  b];xR] R] R] A]$ A]F ] 0e (e/ A]< AcFb@L]a0]p0 rp @9 ~ p `P{p 9 ^ p `tp @9 0b ЉP }p 9 @ `@`p 9 @ p]]U pU 9Ѐ@ypkPCDe9P<>AcXbzWX0p p `9 V p @0wp 9 V p p `9 @ pp 9 @ Q R@U Tv 9ЀMPfPCD e9P<>AcFb@LPQ0vp p q9 R p p` qp p9 N p `p q9 S pкsp p9 O Q RL Mv 9ЀMPfPCD e9P<>AcFb@LPQ0vppp q9 R p pp p9 N p p q9 S p0p p9 O P Щ `  Ц P@ P `  0 0p `p0`0 @ P  p P@0 @ P 0 P  p 0 а @ P  Pа @ P 0 P  P Щ `   n0q052 P `  0 p pH7NP  p \0C0bmP px @< p Hp?`RP  \pXfP px > P Щ ` M 0@ P `  0 p ` }P Px@V  P Щ ` 0 0@ P `  0 p 0p pP  p %P,1P Px@V P p  |P  P0pzP Px@V  %")0yP Px@V  `xd`hd`pdpp`0@ p  p {&>  Ohj[xj[o@9  w\h1 oo8ooo,pt\FVfv&6FVfv&6FVfv&6FVfv&6FVfv&6FVfv&6FVfv&6FVfv&6FVfv&6FVfv&6FVfv&6FVfv&6FVfv  & 6 F V f v         !!&!6!F!V!f!v!!!!!!!!!""&"6"F"V"f"v"""""""""@r]( ] R] .A]` \`]P( d( P b]  P;~?~~I~]ee^T\T\A^&8_ee;B_AOeeh_MeMetb`de`de @bR\R\N`bbeecbeeC0cee`cLeLecHeHejD8e8e #d @deeTpdeed e e  d]] 6@ee V&dne e ѧf`eeehv@e@e Heeieeeeee @fS\S\L`f f\e\e΀fxexefPePe@BG(geePhpepe@ bee0ohh p0j =j(e(e HPj`e`eMHkeebkees l e e Pl]] zqleemH\H\rXmeemP\P\UmeeUmeeneeǁhneeӁnXeXen oeeees@oSoPePe &oee* pee 1 @pee <xpee E pee Ppee X pee `!(qxexe l`qpepe xqhehe]teeŃr nreeur0e0e vr/V(sEPseeȂwsX͂ee_t#~?29CpzsFc Qtrw0t6dplLeeijGptq ;gt~hnTtÃt0TɃw~tPc uppsRpSq ;##t/-}nH.``upsuO!kuŃTiuzu{(vyWoV|c|{x|s||x||||||||DŽ|̈́|Մ||߄|||||||G|| |||,|3|7|>|D|O|W|Б||]||T|^|c|k|p|v|y|||~|||ѕ|||||ڑ||||.||Dž||ͅ|Յ|߅||||$|||||%|0|;|H|F|O|W|^|d|i|v||||9|||^|a||||ņ|Ն||||m|||| |||*|1|6|?|L|Z|d|l|t|}||:|u||||||||||Ç|ʇ|y|Ӈ|ڇ|||||||||||||%|.|4|9|?|K|F|L|||R|Y|`|f|j|p|x|~||||||||||ň|̈|҈|ڈ|߈||||||||(||3|:|||A|I|P|V|_|f|l|x||B|||||||||||Ɖ|Љ|׉|߉|Z|@| |||||||||V|| |>|ڍ|&|,|6|\|E|K|||P|Y|b|g|t|{|||||ˊ|׊|||||#|5|D|P|V|o||||||ɋ|Ӌ|ދ||||֏|| || |$|)|2||9|I|T|a||g|m|v|~|||||||E||||Č|^||ь|֌|ߌ||g||h|||||Ȍ|||Y||'|/|4|<|G|Q|Y|e||k|q||w|}|||||||Í|Ѝ|؍|ߍ||||| |||!|)|2|9|@|H|O|U|[|d|k|||s|~||||||||||ʎ|ю|ގ|||||c|||| ||||%|-|ݤ|6|C|L|W|f|x||||||Ώ|ݏ|||||!||.|4|=|D|I|Q|Ә|_|g|o|u||}|||||]|||;|||ΐ|א|ߐ||||||||||"|.|8|=|E|K|R|Z|a|j|p|w||||||||||ʕ|Ƒ|͑||ב||||||| ||||$||Ȓ|$||'|2|;|?|D|L|T|`|l|q|v|||||||||||Ē|̒|ђ|֒|ޒ||||||7|)|%|/|=|B||@|M|Q|W|_|g|o|x||||||||ē|̓|ؓ||T|||X||| ||||'|2|8|D| ||J|T|b|k|u|||||ؔ||||||#|0|V|C|J|T|^|d|i|r|{|||||||ŕ|Е|֕||ܕ|||||ߕ||||||||||| |1|A|E|Q|]|f|t|||||||||˖|ٖ|||||-|@|R|g|{|||||||Ǘ|͌|w|˗|֗||2|E||ږ||W|l|||||| |||'|-|7|<|B|N|[|c|r|h|l|q|w||||||||||˜|ɘ|И|ژ|||||||||'|||/|5|@|T|6|Z|i|o|t|}||||||Xz|||||9.}$+}):x00 @ P ` p    !< @p   ! !0!P!W^ :U&*P_np p `@^   Ш"$Uh9U@!!!:`W!!P !'<&;J 0=P09"^@$``0  "P`@$`'@`0@0P@p' qnP`f@ifP p P,@*@]@3]x3]dHefhgijjkئP<*1X`xt nE'΀(  #l;mImZǁh=YZZ[]l#&˧rקi/egfYZ (/:BN[Y&htrק* "*nsx}qo#ſt[Am-jd8n헧?O>. 8/t#ڰͼ3&N|.[Ӿr؇/PkpnJؕnq&fƭ$6ZB<TcsUe(U܀n_S$]$]$]$]$]$] $]&] ']'](]p F \h@$ hsʳ`% P% % % e& & `(]/ 0& + ' , P+ ( * 0 ' ' & `& & ( * P( GDMGDDMGSHX]bhpbv000˴0ԴԴԴԴԴ'2<<GNY<GNN<GNc<GNllw}lw}}lw}lw}µ˵˵ֵݵ˵ֵݵݵ˵ֵݵ˵ֵݵ$$/:$//$/D$/MMTZTMTZ``gmg`gmsyyyyyǶжڶǶж#*050:@GMSY`h`v##~~??? <@[ht[o[w[(h`"(P@07X||̫SHhq0p0||||| ||7`Q|`y|||||||||||0|XPx|_Д V[ 7] 'x? :]e9eWeeeee|e.eJeaterxeeeeeeeeee%e3eCeSecepe~eee} @|@;] `eHLS XG~ |;]<]@  0 P ` p @ P ` p ` а г  p 0 @ P 0 ` з p  0 б    P 0 @ @ P е ` p  0 @ P ж 0 @ в ` P ` p  ` 0 P @ P ` p p д p @ 0X|<@`8Z`0`(h Hp@u`]1 $  ~ 0 0. P( (   $ p ! ` p- ` 0 0. P(  0 ` : 0& P% 8  p P ( ( ( ( ( ( ( ( ( 8 P% p & ! / . $ 8  ' @ ( ? > 8 09 p" 6 1 P% 8  @ `& ! / . $ 8 ` % 0 ? @ ( @= > 8  p" 2 1 ) p3 ! 9 < = P P P P P P P P P P P P P P P P P P P P P P P P P P @= , ! , p 0 0 09 3 ~ " ~  *           ~ ~ P P P P P P P P P P P P P P P P P P P P P P P P P P * p, p 09 ( " , P ` ` 0 !  ~ p- ` 0 0.  b]P( @r] 9  i@A D dL # ci! nwz `> ^!>I]Г]j9  @@0AA0BB0CC0DD0EE0FF0GG0HH0II0JJ0KK0LL0MM0NN0OO0PP0QQ0RR0SS0TT0UU0VV0WW0XX0YY0ZZ0[[0\\0]]0^^0__0``0aa0bb0cc0dd0ee0ff0gg0hh0ii0jj0kk0ll0mm0nn0oo0pp0qq0rr0ss0tt0uu0vv0ww0xx0yy0zz0{{0||0}}0~~00000000000000000#$%&'()*+,-./012345Q6789:;<=>?@ABCDEFGHIJKLMNO`$a$b$c$d$e$f$g$h$i$t$u$v$w$x$y$z${$|$}$??@WAXBYCZD\E]F^G_H`IaJbKcLdMeNfOgPhQiRjSkTlUmVnWoXpYqZr[sD\E]F^G_H`IaJbKcLdMeNfOgPhQiRjSkTlUmVnWoXpYqZr[stt1uu1vv1ww1xx 1yy 1zz 1{{ 1|| 1}}1~~11111111111111111 1!1"1#1$1%1&1'1(1)1??££?ãã?ģģ?ţţ?ƣƣ?ǣǣ?ȣȣ?ɣɣ?ʣʣ?ˣˣ?̣̣?ͣͣ?ΣΣ?ϣϣ?УУ?ѣѣ?ңң?ӣӣ?ԣԣ?գգ?֣֣?ףף?أأ?٣٣?ڣڣ?ۣۣ?ܣܣ?ݣݣ?ޣޣ?ߣߣ????????????????????????????????@@AABB<CCDDEE0FFGGHHII JJ!KK !LLiMMjNNkOO3PP3QQ3RR3SS3TT3UU3VV3WW3XXYYYQZZ[Q[[^Q\\]Q]]aQ^^cQ__U``taa|bb%cc%dd%ee%ff%gg%hh%ii%jj%kk%ll%mm%nn%oo%pp%qq<%rr4%ss,%tt$%uu%vv%ww%xx%yy%zz %{{%||%}}%~~m%n%p%o%P%^%j%a%%%%%q%r%s%`!a!b!c!d!e!f!g!h!¢¢i!ââ!0ĢĢ"0ŢŢ#0ƢƢ$0ǢǢ%0ȢȢ&0ɢɢ'0ʢʢ(0ˢˢ)0̢̢͢͢DS΢΢Ϣ!Т"Ѣ#Ң$Ӣ%Ԣ&բ'֢(ע)آ*٢+ڢ,ۢ-ܢ.ݢ/ޢ0ߢ123456@7A8B9C:ϢAТBѢCҢDӢEԢFբG֢HעIآJ٢KڢLۢMܢNݢOޢPߢQRSTUVT!{H| z y x[ .\/\A!{#| z y x w[ .\`0\T!{| z y x[ .\0\a!{t| z y x w[ .\`1\]]]?1A}m|@|@{@{s\1\2\J@p!KAq!LBr!MCs!NDt!OEu!PFv!QGw!RHx!SIy!J@`!KAa!LBb!MCc!NDd!OEe!PFf!QGg!RHh!SIi!TTUUVVWWXX12YY!ZZ!![[5"\\~]]^^H__``܄aaObbpcc1fddheefffggE_hh(NiiNjjNkkOllOmm9OnnVOooOppOqqOrrOssOtt@Puu"PvvOwwPxxFPyypPzzBP{{P||P}}P~~JQdQQQQRRRRRSS$SrSSSSTTTTUYWeWWWWXX YSY[Y]YcYYYV[[/u[[\\\\']S]B]m]]]]!_4_g___]````` a`a7a0aabbc`dddNeff;f f.ff$fefWfYfsffffffg)fggRhghDhhhiii0jkjFjsj~jjjk?l\llollmmom@@rAA$sBBCCwsDDsEEsFFsGGsHHsIItJJsKK&tLL*tMM)tNN.tOObtPPtQQtRRuSSouTTvUUvVVvWWvXXvYYZZFw[[R\\!x]]Nx^^dx__zx``0yaabbccddyeeffyggzhhziijjzkk{llmmH}nn\}oo}pp}qq}rrR~ssGttuuvvwwbxxyyǃzz{{H||}}S~~Yk !7yߊ"Sv#ώ$%gސ&'ڑבޑ :@<NYQ9gwxגْВ'ՒӒ%!(pWƓޓ1EH)3;CMOQUWe*+',Nٚܚurpk-ў??Tp!Uq!Vr!Ws!Xt!Yu!Zv![w!\x!]y!@@`$AAa$BBb$CCc$DDd$EEe$FFf$GGg$HHh$IIi$JJj$KKk$LLl$MMm$NNn$OOo$PPp$QQq$RRr$SSs$T`!Ua!Vb!Wc!Xd!Ye!Zf![g!\h!]i!^^?__I3``3aa"3bbM3cc3dd'3ee3ff63ggQ3hhW3ii 3jj&3kk#3ll+3mmJ3nn;3oo3pp3qq3rr3ss3tt3uu3vv?ww?xx?yy?zz?{{?||?}}?~~{300!3!!22222122292~3}3|3R"a"+"."""" """5")"*"?????????????????????????????????????‡‡?ÇÇ?ćć?ŇŇ?ƇƇ?LJLJ?ȇȇ?ɇɇ?ʇʇ?ˇˇ?̇̇?͇͇?··?χχ?ЇЇ?чч?҇҇?ӇӇ?ԇԇ?ՇՇ?ևև?ׇׇ?؇؇?هه?ڇڇ?ۇۇ?܇܇?݇݇?އއ?߇߇??????????????????????????????@pAqBrCsDtEuFvGwHxIyJzK{L|M}N~OPQ R!S"T#U$V%W&X'Y(Z)[*\+],^-_.`/aa?bb?cc?dd?ee?ff?gg?hh?ii?jj?kk?ll?mm?nn?oo?@p0Aq1Br2Cs3Dt4Eu5FvQGw6Hx7Iy8Jz9K{:L|;M}<N~=O>P?Q@RASBTCUDVEWFXGYHZI[J\K]L^M_N`O?????????????%% %%%%%,%$%4%<%%%%%%%#%3%+%;%K% %/%(%7%?%%0%%%8%B%???„„?ÄÄ?ĄĄ?ńń?ƄƄ?DŽDŽ?ȄȄ?ɄɄ?ʄʄ?˄˄?̄̄?̈́̈́?΄΄?ττ?ЄЄ?фф?҄҄?ӄӄ?ԄԄ?ՄՄ?քք?ׄׄ?؄؄?لل?ڄڄ?ۄۄ?܄܄?݄݄?ބބ?߄߄??????????????????????????????@@0AA0BB0CC0DD0EE0FF0GG0HH0II0JJ0KK0LL0MM0NN0OO0PP0QQ0RR0SS0TT0UU0VV0WW0XX0YY0ZZ0[[0\\0]]0^^0__0``0aa0bb0cc0dd0ee0ff0gg0hh0ii0jj0kk0ll0mm0nn0oo0pp0qq0rr0ss0tt0uu0vv0ww0xx0yy0zz0{{0||0}}0~~000000000000000000000000????????ƒÃăŃƃǃȃɃʃ˃̃̓΃σЃу҃ӃԃՃփ????????ƒÃăŃƃǃȃɃʃ˃̃̓΃σЃу҃ӃԃՃփ׃׃?؃؃?كك?ڃڃ?ۃۃ?܃܃?݃݃?ރރ?߃߃??????????????????????????????@@?AA?BB?CC?DD?EE?FF?GG?HH?II?JJ?KK?LL?MM?NN?OOPPQQRRSSTTUUVVWWXXYY?ZZ?[[?\\?]]?^^?__?`!a"b#c$d%e&f'g(h)i*j+k,l-m.n/o0p1q2r3s4t5u6v7w8x9y:zz?{{?||?}}?~~??`AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZ????A0B0C0D0E0F0G0H0I0J0K0L0M0N0O0P0Q0R0S0T0U0V0W0X0Y0Z0[0\0]0^0_0`0a0b0c0‚‚d0ÂÂe0ĂĂf0łłg0ƂƂh0ǂǂi0ȂȂj0ɂɂk0ʂʂl0˂˂m0̂̂n0͂͂o0΂΂p0ςςq0ЂЂr0ттs0҂҂t0ӂӂu0ԂԂv0ՂՂw0ււx0ׂׂy0؂؂z0قق{0ڂڂ|0ۂۂ}0܂܂~0݂݂0ނނ0߂߂0000000000000000000???????????@@0AA0BB0CC DDEE0FFGGHHIIJJ0KK0LLMM@NNOO>PPQQ?RR0SS0TT0UU0VV0WWNXX0YY0ZZ0[[0\\ ]] ^^__<``^aa%"bb\cc& dd% ee ff gg hh iijj kk0ll0mm;nn=oo[pp]qq0rr 0ss 0tt 0uu 0vv 0ww0xx0yy0zz0{{ || }}~~`"f"g""4"B&@&2 3 ! &&%%%%%%%%%%%; 0!!!!0???????????" """""*")"???ÁÁ?āā?ŁŁ?ƁƁ?ǁǁ?ȁȁ'"ɁɁ("ʁʁˁˁ!́́!́́"΁΁"ρρ?ЁЁ?сс?ҁҁ?ӁӁ?ԁԁ?ՁՁ?ցց?ׁׁ?؁؁?فف?ځځ "ہہ"܁܁#݁݁"ށށ"߁߁a"R"j"k""=""5"+","???????+!0 o&m&j& ! ????%`a|```~[ `4\`5\_Aa|```~`}[ `4\5\`a |```~[ `4\`6\_aa|```~`}[ `4\6\` ^`^`]`]`]`]`]AH9ػ|````` [s\ `F\`7\@@?AABBCCDDEEFFGGHHIIJJ KK LL MMNNOOPPQQRRSSTTUUVVWWXXYYZZ [[?\\?]]?^^?__?``?aa!bb"cc#dd%ee&ff'gg)hh*ii+jj-kk.ll/mm0nn1oo2pp3qq4rr5ss6tt7uu8vv:ww;xx<yy=zz>{{?||?}}?~~????@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_ѬҬӬԬլ֬׬ج٬ڬ۬ܬݬެ߬ !"#$%&'()*+,-./¬¬?ìì?ĬĬ?ŬŬ?ƬƬ?ǬǬ?ȬȬ?ɬɬ?ʬʬ?ˬˬ?̬̬?ͬͬ?άά?ϬϬ?ЬЬ?Ѭ0Ҭ1Ӭ2Ԭ3լ4֬5׬Qج6٬7ڬ8۬9ܬ:ݬ;ެ<߬=>?@ABCDEFGHIJKLMNO??????????????@@?AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[?\\?]]?^^?__?``?aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{?||?}}?~~???  #$'I138@BSgKI222222222 2 2 2 2 2222©©2éé2ĩĩ2ũũ2ƩƩ2ǩǩ2ȩȩ2ɩɩ2ʩʩ2˩˩2̩̩2ͩͩ$ΩΩ$ϩϩ$ЩЩ$ѩѩ$ҩҩ$өө$ԩԩ$թթ$֩֩$שש$ةة$٩٩$کک$۩۩$ܩܩ$ݩݩ$ީީ$ߩߩ$$$$$$$$t$u$v$w$x$y$z${$|$}$~$$$$$t  ?@@?AAmBBnCCoDDpEEqFFrGGsHHtIIuJJvKKwLLzMM{NN|OO}PP~QQRRSSTTUUVVWWXXYYZZ[[?\\?]]?^^?__?``?aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{?||?}}?~~???&?2??ARfJ?`2a2b2c2d2e2f2g2h2i2j2k2l2m2n2o2p2¨¨q2èèr2ĨĨs2ŨŨt2ƨƨu2ǨǨv2ȨȨw2ɨɨx2ʨʨy2˨˨z2̨̨{2ͨͨ$ΨΨ$ϨϨ$ШШ$ѨѨ$ҨҨ$ӨӨ$ԨԨ$ըը$֨֨$רר$بب$٨٨$ڨڨ$ۨۨ$ܨܨ$ݨݨ$ިި$ߨߨ$$$$$$$$`$a$b$c$d$e$f$g$h$i$j$k$l$m$n$S!T![!\!]!^!?@@?AA BB CC DDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSS"TT#UU$VV%WW&XX'YY(ZZ)[[?\\?]]?^^?__?``?aa*bb+cc,dd-ee.ff/gg0hh1ii2jj3kk4ll5mm6nn7oo8pp9qq:rr;ss<tt=uu>vv?ww@xxByyCzzD{{?||?}}?~~???EFGJKMNOQRSTUVWZ[\^_`abcefghijkl333!33333333333333333333333333333§§3çç3ħħ3ŧŧ3ƧƧ3ǧǧ3ȧȧ3ɧɧ3ʧʧ3˧˧3̧̧3ͧͧ3ΧΧ3ϧϧ3ЧЧ3ѧѧ3ҧҧ3ӧӧ3ԧԧ3էէ3֧֧3קק3اا3٧&!ڧڧ3ۧۧ3ܧܧ3ݧݧ3ާާ3ߧߧ33333333333333333????????????????@@?AAGBBHCCIDDJEEKFFNGGOHHQIIRJJSKKULLVMMWNNXOOYPPZQQ[RR^SSbTTcUUdVVeWWfXXgYYiZZj[[?\\?]]?^^?__?``?aakbblccmddneeoffpggqhhriisjjtkkullvmmwnnxooyppzqq{rr|ss~ttuuvvwwxxyyzz{{?||?}}?~~???p!q!r!s!t!u!v!w!x!y!?????`!a!b!c!d!e!f!g!h!i!???????¥åĥťƥǥȥɥʥ˥̥ͥΥϥХѥҥӥԥե֥ץإ٥٥?ڥڥ?ۥۥ?ܥܥ?ݥݥ?ޥޥ?ߥߥ??¥åĥťƥǥȥɥʥ˥̥ͥΥϥХѥҥӥԥե֥ץإ???????@@?AAqBBrCCsDDuEEvFFwGGxHHyIIzJJ{KK}LL~MMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[?\\?]]?^^?__?``?aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{?||?}}?~~???  !£"ã#ģ$ţ%ƣ&ǣ'ȣ(ɣ)ʣ*ˣ+̣,ͣ-Σ.ϣ/У0ѣ1ң2ӣ3ԣ4գ5֣6ף7أ8٣9ڣ:ۣۣ;ܣܣݣݣ=ޣޣ>ߣߣ?@A£BãCģDţEƣFǣGȣHɣIʣJˣḲLͣMΣNϣOУPѣQңRӣSԣTգU֣VףWأX٣YڣZ[\]?UAW|@@@[ 7\8\AK|@@@@[ 7\`9\UA |@@@[ 7\9\!A|@@@@[ 7\`:\`^T^H^<^0^$^?b!c!d!e!f!g!h!i!12!!!pNPQS$STYWX[\S]_` aNe;fef)hkjjmm(puvv0yz}}b !"v#$%ސ&'();MQ*+,ٚr-ў????????????????????????????????????????????????????????????????????????????????????p!q!r!s!t!u!v!w!x!y!`!a!??   ?!%ª«êëīī?Ūū+ƪƫ/Ǫǫ)Ȫȫ5ɪɫ7ʪʫ:˪˫>̪̫<ͪͫDΪΫHϪϫFЪЫѪѫҪҫӪӫԪԫժի֪֫Qת׫Mتث٪٫UڪګY۪۫Wܪܫ[ݪݫ]ުޫaߪ߫_એ૏e᪏᫏c⪏⫏㪏㫏䪏䫏媏嫏檏櫏m窏竏誏諏q骏髏kꪏ꫏s몏뫏o쪏쫏i摒𢡊uwz~|?????????  ?" $ª«êëĪi0Ūū*ƪƫ.Ǫǫ(Ȫȫ4ɪɫ6ʪʫ9˪˫=̪̫;ͪͫCΪΫGϪϫEЪЫѪѫҪҫӪӫԪԫժի֪֫Pת׫Lتث٪٫TڪګX۪۫VܪܫZݪݫ\ުޫ`ߪ߫^એ૏d᪏᫏b⪏⫏㪏㫏䪏䫏媏嫏檏櫏l窏竏誏諏p骏髏jꪏ꫏r몏뫏n쪏쫏h摒𢡊txvy}{?????????©?ĩ&?Ʃ2?ȩAɩ??˩J̩ͩR?ϩfЩ????????????????©ééĩ'Iũ1Ʃ3ǩǩ8ȩBɩ@ʩʩI˩K̩ͩSΩΩϩgЩѩѩ?ҩҩ?өө?ԩԩ?թթ?֩֩?שש?ةة?٩٩?کک?۩۩?ܩܩ?ݩݩ?ީީ?ߩߩ?੏੏?ᩏᩏ?⩏⩏?㩏㩏?䩏䩏?婏婏?橏橏?穏穏?詏詏?驏驏?꩏꩏?멏멏?쩏쩏???祐祐???????????????????????????????????????????????????§çħŧƧǧȧɧ ʧ ˧ ̧ ͧΧϧϧ?ЧЧ?ѧѧ?ҧҧ?ӧӧ?ԧԧ?էէ?֧֧?קק?اا?٧٧?ڧڧ?ۧۧ?ܧܧ?ݧݧ?ާާ?ߧߧ?৏৏?᧏᧏?⧏⧏?㧏㧏?䧏䧏?姏姏?槏槏?秏秏?觏觏?駏駏?ꧏꧏ?맏맏?짏짏???紐紐???§RçSħTŧUƧVǧWȧXɧYʧZ˧[̧\ͧ^Χ_???????????????????????????????????¦¦?ææ?ĦĦ?ŦŦ?ƦƦ?ǦǦ?ȦȦ?ɦɦ?ʦʦ?˦˦?̦̦?ͦͦ?ΦΦ?ϦϦ?ЦЦ?ѦѦ?ҦҦ?ӦӦ?ԦԦ?զզ?֦֦?צצ?ئئ?٦٦?ڦڦ?ۦۦ?ܦܦ?ݦݦ?ަަ?ߦߦ?এএ?ᦏ⦏㦏䦏妏榏榏?福規規?馏ꦏ릏릏?즏??憐憐??ᦏ⦏㦏䦏妏福馏ꦏ즏????`$a$b$c$d$e$f$g$h$i$j$k$l$m$n$o$p$q$r$s$`!a!b!c!d!e!f!g!h!i!?I33­­"3ííM3ĭĭ3ŭŭ'3ƭƭ3ǭǭ63ȭȭQ3ɭɭW3ʭʭ 3˭˭&3̭̭#3ͭͭ+3έέJ3ϭϭ;3ЭЭ3ѭѭ3ҭҭ3ӭӭ3ԭԭ3խխ3֭֭3׭׭?حح?٭٭?ڭڭ?ۭۭ?ܭܭ?ݭݭ?ޭޭ?߭߭{300!3!!22222122292~3}3|3R"a"+"."""" """5")"*"????ѧҧӧԧէ֧קا٧ڧۧܧݧާߧ !"#$%&'()*+,-./§§?çç?ħħ?ŧŧ?ƧƧ?ǧǧ?ȧȧ?ɧɧ?ʧʧ?˧˧?̧̧?ͧͧ?ΧΧ?ϧϧ?ЧЧ?ѧ0ҧ1ӧ2ԧ3է4֧5קQا6٧7ڧ8ۧ9ܧ:ݧ;ާ<ߧ=>?@ABCDEFGHIJKLMNO???????????????¦æĦŦƦǦȦɦʦ˦̦ͦΦϦЦѦҦӦԦզ֦צئ????????¦æĦŦƦǦȦɦʦ˦̦ͦΦϦЦѦҦӦԦզ֦צئ٦٦?ڦڦ?ۦۦ?ܦܦ?ݦݦ?ަަ?ߦߦ????????????????????????????????????????????????????????!£"ã#ģ$ţ%ƣ&ǣ'ȣ(ɣ)ʣ*ˣ+̣,ͣ-Σ.ϣ/У0ѣ1ң2ӣ3ԣ4գ5֣6ף7أ8٣9ڣ:ۣۣ?ܣܣ?ݣݣ?ޣޣ?ߣߣ??A£BãCģDţEƣFǣGȣHɣIʣJˣḲLͣMΣNϣOУPѣQңRӣSԣTգU֣VףWأX٣YڣZ??????%%%%%%%; 0!!!!0???????????" """""*")"¢¢?ââ?ĢĢ?ŢŢ?ƢƢ?ǢǢ?ȢȢ?ɢɢ?ʢʢ'"ˢˢ("̢̢͢͢!΢΢!ϢϢ"ТТ"ѢѢ?ҢҢ?ӢӢ?ԢԢ?բբ?֢֢?עע?آآ?٢٢?ڢڢ?ۢۢ?ܢܢ "ݢݢ"ޢޢ#ߢߢ""a"R"j"k""=""5"+","???????+!0 o&m&j& ! ????%?bh!1|`!`!`![ :\;\ah!|`!`!`!`![ :\`<\bh! |`!`!`![ :\<\a!h!|`!`!`!`![ :\`=\@^@^@^@^@^@^@^@^@^@^@^@x^!|`T"`S"`R"`Q"`O"s\ `F\E\!|@N"@M"@L"@K"@I"s\ `F\E\0| H" G" F" E" C"s\ `F\E\!|B"A"@"?"="s\ `F\E\!TӸ|;":"9"8"6"s\ `F\E\ !G|5"4"3"2"0"s\ `F\E\ ! |/"."-","*"s\ `F\E\ !M+|)"("'"&"$"s\ `F\E\|!!!#"!s\ `F\E\0|`""`!"` "`"`"s\ `F\E\!^|@"@"@"@"@"s\ `F\E\(|!!!@"!s\ `F\E\G;|5"4"3"@"0"s\ `F\E\!g| " " " " "s\ `F\E\O|!!! "!s\ `F\E\!wǹ| " " " ""s\ `F\E\!޹|"""""s\ `F\E\Gc|5"4"3""0"s\ `F\E\Mv|@!@!@!!@!s\ `F\E\!ֵ |!!!!!s\ `F\E\ !&|!!!!!s\ `F\E\$!pt|!!!!!s\ `F\E\%!|`!`!`!`!`!s\ `F\E\&!|@!@!@!@!@!s\ `F\E\'!Ǻ| ! ! ! ! !s\ `F\E\(!|!!!!!s\ `F\E\)!|!!!!!s\ `F\E\*|!!!!!s\ `F\E\+ |@!@!@!@!s\ `F\3\,޹ɼ|"""!"s\ `F\E\00|!!!!!s\ `F\E\10|!!!!!s\ `F\E\2* |!!!!s\ `F\3\3!|!!!!!s\ `F\E\45|!!!!!s\ `F\E\5G | ! ! ! !s\ `F\3\9!-4|`!`!`!`!`!s\ `F\E\:M |@!@!@!@!s\ `F\3\;!MT|@!@!@!@!@!s\ `F\E\@t |!!!!s\ `F\3\AM |)"("'"$"s\ `F\3\B޹ǽ |""""s\ `F\3\C-ҽ |`!`!`!`!s\ `F\3\Dpݽ |!!!!s\ `F\3\E|`T"`S"`R"`O"s\ `F\3\Fw | " " ""s\ `F\3\G |@"@"@"@"s\ `F\3\H|B"A"@"="s\ `F\3\I |`!`!`!`!s\ `F\3\JT# |;":"9"6"s\ `F\3\Kg- | " " " "s\ `F\3\MGJ |5"4"3"0"s\ `F\3\NֵU |!!!!s\ `F\3\O` |!!!!s\ `F\3\Pk |@N"@M"@L"@I"s\ `F\3\Qu |!!!!s\ `F\3\R |/"."-"*"s\ `F\3\\!| ! ! ! ! !s\ `F\E\] | ! ! ! !s\ `F\3\^0|!!!!!s\ `F\E\c޹|"""!"s\ `F\E\p!|!`T"`S"`R"`O"s\ `F\`E\P|!@N"@M"@L"@I"s\ `F\`E\g|!B"A"@"="s\ `F\`E\T||ѝ!;":"9"6"s\ `F\`E\ G|!5"4"3"0"s\ `F\`E\  |!/"."-"*"s\ `F\`E\ M|!)"("'"$"s\ `F\`E\|9!@"@"@"@"s\ `F\`E\ga|T! " " " "s\ `F\`E\w|n! " " ""s\ `F\`E\޹|!""""s\ `F\`E\ֵ|!!!!!s\ `F\`E\ |!!!!!s\ `F\`E\$p5|۞!!!!!s\ `F\`E\%L|!`!`!`!`!s\ `F\`E\&e|!@!@!@!@!s\ `F\`E\'||+! ! ! ! !s\ `F\`E\(|H!!!!!s\ `F\`E\)|b!!!!!s\ `F\`E\+|@!@!@!@!s\ `F\`3\2|!!!!s\ `F\`3\3*|}!!!!!s\ `F\`E\5B| ! ! ! !s\ `F\`3\9-|!`!`!`!`!s\ `F\`E\:M|@!@!@!@!s\ `F\`3\;M|!@!@!@!@!s\ `F\`E\@|!!!!s\ `F\`3\AM"|)"("'"$"s\ `F\`3\B޹2|""""s\ `F\`3\C-C|`!`!`!`!s\ `F\`3\DpT|!!!!s\ `F\`3\Ed|`T"`S"`R"`O"s\ `F\`3\Fws| " " ""s\ `F\`3\G|@"@"@"@"s\ `F\`3\H |B"A"@"="s\ `F\`3\I|`!`!`!`!s\ `F\`3\JT|;":"9"6"s\ `F\`3\Kg| " " " "s\ `F\`3\MG|5"4"3"0"s\ `F\`3\Nֵ|!!!!s\ `F\`3\O|!!!!s\ `F\`3\P|@N"@M"@L"@I"s\ `F\`3\Q|!!!!s\ `F\`3\R '|/"."-"*"s\ `F\`3\\|Ο! ! ! ! !s\ `F\`E\]| ! ! ! !s\ `F\`3\s\ `F\E\+Mk???????¨¨?èè?ĨĨ?ŨŨ1ƨƨ1ǨǨ1ȨȨ1ɨɨ 1ʨʨ 1˨˨ 1̨̨ 1ͨͨ 1ΨΨ1ϨϨ1ШШ1ѨѨ1ҨҨ1ӨӨ1ԨԨ1ըը1֨֨1רר1بب1٨٨1ڨڨ1ۨۨ1ܨܨ1ݨݨ1ިި1ߨߨ1 1!1"1#1$1%1&1'1(1)1?????????????????????ѧҧӧԧէ֧קا٧ڧۧܧݧާߧ !"#$%&'()*+,-./§§?çç?ħħ?ŧŧ?ƧƧ?ǧǧ?ȧȧ?ɧɧ?ʧʧ?˧˧?̧̧?ͧͧ?ΧΧ?ϧϧ?ЧЧ?ѧ0ҧ1ӧ2ԧ3է4֧5קQا6٧7ڧ8ۧ9ܧ:ݧ;ާ<ߧ=>?@ABCDEFGHIJKLMNO?????????????¦æĦŦƦǦȦɦʦ˦̦ͦΦϦЦѦҦӦԦզ֦צئ????????¦æĦŦƦǦȦɦʦ˦̦ͦΦϦЦѦҦӦԦզ֦צئ٦٦?ڦڦ?ۦۦ?ܦܦ?ݦݦ?ަަ?ߦߦ????????????????????????????????  !£"ã#ģ$ţ%ƣ&ǣ'ȣ(ɣ)ʣ*ˣ+̣,ͣ-Σ.ϣ/У0ѣ1ң2ӣ3ԣ4գ5֣6ף7أ8٣9ڣ:ۣۣ;ܣܣ<ݣݣ=ޣޣ>ߣߣ?@A£BãCģDţEƣFǣGȣHɣIʣJˣḲLͣMΣNϣOУPѣQңRӣSԣTգU֣VףWأX٣YڣZ[\]????????????????$$$$$$$$$$$$$$$$$¢¢$ââ$ĢĢ$ŢŢt$ƢƢu$ǢǢv$ȢȢw$ɢɢx$ʢʢy$ˢˢz$̢̢{$͢͢|$΢΢}$ϢϢ~$ТТ$ѢѢ$ҢҢ$ӢӢ$ԢԢ$բբ$֢֢$עע$آآ$٢٢`$ڢڢa$ۢۢb$ܢܢc$ݢݢd$ޢޢe$ߢߢf$g$h$i$?? 2!2"2#2$2%2&2'2(2)2??`!a!b!c!d!e!f!g!h!i!j!k!??V#g|###[ =\>\#x|####[ =\`?\V# |###[ =\?\!#|####[ =\`@\ _ _ _ |_ p_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\][^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}Y@@?AA?BB?CC?DD?EE?FF?GG?HH?II?JJ?KK?LL?MM?NN?OO?PP?QQ?RR?SS?TT?UU?VV?WW?XX?YY?ZZ?[[?\\?]]?^^?__?``?aa?bb?cc?dd?ee?ff?gg?hh?ii?jj?kk?ll?mm?nn?oo?pp?qq?rr?ss?tt?uu?vv?ww?xx?yy?zz?{{?||?}}?~~??????????????????????????????????ѧҧӧԧէ֧קا٧ڧۧܧݧާߧ !"#$%&'()*+,-./§§?çç?ħħ?ŧŧ?ƧƧ?ǧǧ?ȧȧ?ɧɧ?ʧʧ?˧˧?̧̧?ͧͧ?ΧΧ?ϧϧ?ЧЧ?ѧ0ҧ1ӧ2ԧ3է4֧5קQا6٧7ڧ8ۧ9ܧ:ݧ;ާ<ߧ=>?@ABCDEFGHIJKLMNO?????????????@@?AA?BB?CC?DD?EE?FF?GG?HH?II?JJ?KK?LL?MM?NN?OO?PP?QQ?RR?SS?TT?UU?VV?WW?XX?YY?ZZ?[[?\\?]]?^^?__?``?aa?bb?cc?dd?ee?ff?gg?hh?ii?jj?kk?ll?mm?nn?oo?pp?qq?rr?ss?tt?uu?vv?ww?xx?yy?zz?{{?||?}}?~~??????????????????????????????????¦æĦŦƦǦȦɦʦ˦̦ͦΦϦЦѦҦӦԦզ֦צئ????????¦æĦŦƦǦȦɦʦ˦̦ͦΦϦЦѦҦӦԦզ֦צئ٦٦?ڦڦ?ۦۦ?ܦܦ?ݦݦ?ަަ?ߦߦ?569:?@=>ABCD??;<781?34?????????@@?AA?BB?CC?DD?EE?FF?GG?HH?II?JJ?KK?LL?MM?NN?OO?PP?QQ?RR?SS?TT?UU?VV?WW?XX?YY?ZZ?[[?\\?]]?^^?__?``?aa?bb?cc?dd?ee?ff?gg?hh?ii?jj?kk?ll?mm?nn?oo?pp?qq?rr?ss?tt?uu?vv?ww?xx?yy?zz?{{?||?}}?~~??????????????????????????????????  !£"ã#ģ$ţ%ƣ&ǣ'ȣ(ɣ)ʣ*ˣ+̣,ͣ-Σ.ϣ/У0ѣ1ң2ӣ3ԣ4գ5֣6ף7أ8٣9ڣ:ۣۣ;ܣܣ<ݣݣ=ޣޣ>ߣߣ?@A£BãCģDţEƣFǣGȣHɣIʣJˣḲLͣMΣNϣOУPѣQңRӣSԣTգU֣VףWأX٣YڣZ[\]@@?AA?BB?CC?DD?EE?FF?GG?HH?II?JJ?KK?LL?MM?NN?OO?PP?QQ?RR?SS?TT?UU?VV?WW?XX?YY?ZZ?[[?\\?]]?^^?__?``?aa?bb?cc?dd?ee?ff?gg?hh?ii?jj?kk?ll?mm?nn?oo?pp?qq?rr?ss?tt?uu?vv?ww?xx?yy?zz?{{?||?}}?~~??????????????????????????????????p!q!r!s!t!u!v!w!x!y!??????$$$$$$$$$$$$$$$$$¢¢$ââ$ĢĢ$ŢŢt$ƢƢu$ǢǢv$ȢȢw$ɢɢx$ʢʢy$ˢˢz$̢̢{$͢͢|$΢΢}$ϢϢ~$ТТ$ѢѢ$ҢҢ$ӢӢ$ԢԢ$բբ$֢֢$עע$آآ$٢٢`$ڢڢa$ۢۢb$ܢܢc$ݢݢd$ޢޢe$ߢߢf$g$h$i$?? 2!2"2#2$2%2&2'2(2)2??`!a!b!c!d!e!f!g!h!i!j!k!??W &x |&&&[ @\A\A &|&&&_[g @\`B\W &|&&&[ @\B\a &|&&&_[g @\`C\____//&|.&-&,&)&s\ `D\`3\//& |.&-&,&)&s\ `D\3\A/&|.&-&,&#&)&s\ `D\C\/&|.&-&,&+&)&s\ `D\`E\!/&|.&-&,&+&)&s\ `D\E\@pAqBrCsDtEuFvGwHxIyJzK{L|M}N~OPQ R!S"T#U$V%W&X'Y(Z)[*\+],^-_.`/aa?bb?cc?dd?ee?ff?gg?hh?ii?jj?kk?ll?mm?nn?oo?@p0Aq1Br2Cs3Dt4Eu5FvQGw6Hx7Iy8Jz9K{:L|;M}<N~=O>P?Q@RASBTCUDVEWFXGYHZI[J\K]L^M_N`O?????????????%% %%%%%,%$%4%<%%%%%%%#%3%+%;%K% %/%(%7%?%%0%%%8%B%???„„?ÄÄ?ĄĄ?ńń?ƄƄ?DŽDŽ?ȄȄ?ɄɄ?ʄʄ?˄˄?̄̄?̈́̈́?΄΄?ττ?ЄЄ?фф?҄҄?ӄӄ?ԄԄ?ՄՄ?քք?ׄׄ?؄؄?لل?ڄڄ?ۄۄ?܄܄?݄݄?ބބ?߄߄??????????????????????????????@@0AA0BB0CC0DD0EE0FF0GG0HH0II0JJ0KK0LL0MM0NN0OO0PP0QQ0RR0SS0TT0UU0VV0WW0XX0YY0ZZ0[[0\\0]]0^^0__0``0aa0bb0cc0dd0ee0ff0gg0hh0ii0jj0kk0ll0mm0nn0oo0pp0qq0rr0ss0tt0uu0vv0ww0xx0yy0zz0{{0||0}}0~~000000000000000000000000????????ƒÃăŃƃǃȃɃʃ˃̃̓΃σЃу҃ӃԃՃփ????????ƒÃăŃƃǃȃɃʃ˃̃̓΃σЃу҃ӃԃՃփ׃׃?؃؃?كك?ڃڃ?ۃۃ?܃܃?݃݃?ރރ?߃߃??????????????????????????????@@?AA?BB?CC?DD?EE?FF?GG?HH?II?JJ?KK?LL?MM?NN?OOPPQQRRSSTTUUVVWWXXYY?ZZ?[[?\\?]]?^^?__?`!a"b#c$d%e&f'g(h)i*j+k,l-m.n/o0p1q2r3s4t5u6v7w8x9y:zz?{{?||?}}?~~??`AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZ????A0B0C0D0E0F0G0H0I0J0K0L0M0N0O0P0Q0R0S0T0U0V0W0X0Y0Z0[0\0]0^0_0`0a0b0c0‚‚d0ÂÂe0ĂĂf0łłg0ƂƂh0ǂǂi0ȂȂj0ɂɂk0ʂʂl0˂˂m0̂̂n0͂͂o0΂΂p0ςςq0ЂЂr0ттs0҂҂t0ӂӂu0ԂԂv0ՂՂw0ււx0ׂׂy0؂؂z0قق{0ڂڂ|0ۂۂ}0܂܂~0݂݂0ނނ0߂߂0000000000000000000???????????@@0AA0BB0CC DDEE0FFGGHHIIJJ0KK0LLMM@NNOO>PPQQ?RR0SS0TT0UU0VV0WWNXX0YY0ZZ0[[0\\ ]] ^^__<``^aa%"bb\cc& dd% ee ff gg hh iijj kk0ll0mm;nn=oo[pp]qq0rr 0ss 0tt 0uu 0vv 0ww0xx0yy0zz0{{ || }}~~`"f"g""4"B&@&2 3 ! &&%%%%%%%%%%%; 0!!!!0???????????" """""*")"???ÁÁ?āā?ŁŁ?ƁƁ?ǁǁ?ȁȁ'"ɁɁ("ʁʁˁˁ!́́!́́"΁΁"ρρ?ЁЁ?сс?ҁҁ?ӁӁ?ԁԁ?ՁՁ?ցց?ׁׁ?؁؁?فف?ځځ "ہہ"܁܁#݁݁"ށށ"߁߁a"R"j"k""=""5"+","???????+!0 o&m&j& ! ????%X A*|@*?*>* [ `G\`H\ A A*|@*?*>*=* [ `G\H\X A*ƾ|@*?*>* [ `G\`I\ a A*M|@*?*>*=* [ `G\I\```_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~  !"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ((((( H Y\*|6`5`4`s\ `J\`3\A\*6|6`5`4`G*s\ `J\`K\Y\*Ͼ |6`5`4`s\ `J\3\a\*~|6`5`4`G*s\ `J\K\ ((((( H M2 @pApBpCpDp@qAqBqCqDq@rArBrCrDr@sAsBsCsDs@tAtBtCtDt@uAuBuCuDu@vAvBvCvDv@wAwBwCwDw@ xA xB xC xD x@ yA yB yC yD y@ zA zB zC zD z@ {A {B {C {D {@ |A |B |C |D |@}A}B}C}D}@~A~B~C~D~@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ABCD@ A B C D @!A!B!C!D!@"A"B"C"D"@#A#B#C#D#@$A$B$C$D$@%A%B%C%D%@&A&B&C&D&@'A'B'C'D'@(A(B(C(D(@)A)B)C)D)@*A*B*C*D*@+A+B+C+D+@,A,B,C,D,@-A-B-C-D-@.A.B.C.D.M2{ 39Z|| as\  e\`M\e 39C||s\ e\`M\| 39| *s\ e\M\{ 39|| as\  e\M\ 39|\*` as\ e\L\ 39|`*s\ e\M\ 39|*s\ e\M\z 39|@*s\ e\M\y 39u|*s\ e\M\x 39d|*s\ e\M\w 39^*|*s\ e\M\v 39Q|*s\ e\M\u 39@|*s\ e\M\t 391|*s\ e\M\s 39|*s\ e\M\r 39|`*s\ e\M\q 39^*|*s\ e\M\p 39|*s\ e\M\o 39ݿ|*s\ e\M\n 39̿|*` \ e\M\m 39|*s\ e\M\l 39|0*s\ e\M\k 39|`*s\ e\M\j 39|*s\ e\M\i 39u|*s\ e\M\h 39c|@*s\ e\M\g 39R|*s\ e\M\f 39?|*s\ e\M\e 39.||s\ e\M\M\`M\L\`L\ -9|| as\  _\`O\ -9||s\ _\`O\ -9| *s\ _\O\ -9|| as\  _\O\ -9|\*` as\ _\N\ -9|`*s\ _\O\ -9|*s\ _\O\ -9|@*s\ _\O\ -9|*s\ _\O\ -9|*s\ _\O\ -9|*s\ _\O\ -9|*s\ _\O\ -9{|*s\ _\O\ -9l|*s\ _\O\ -9^*|*s\ _\O\ -9\|`*s\ _\O\ -9H|*s\ _\O\ -98|*s\ _\O\ -9)|*s\ _\O\ -9|*` \ _\O\ -9|*s\ _\O\ -9|0*s\ _\O\ -9|`*s\ _\O\ -9|*s\ _\O\ -9|*s\ _\O\ -9|@*s\ _\O\ -9|*s\ _\O\ -9|*s\ _\O\ -9z||s\ _\O\O\`O\N\`N\@ 9&||:` as\  k\`S\@ 9 ||:`s\ k\`S\@ 9| *:`s\ k\S\@ 9||:` as\  k\S\b@ 9|\*:`` as\ k\R\a@ 9q|`*:`s\ k\S\`@ 9]|*:`s\ k\S\@ 9|@*:`s\ k\S\@ 9{|*:`s\ k\S\@ 9h|*:`s\ k\S\@ 9S|*:`s\ k\S\@ 9>|*:`s\ k\S\@ 9+|*:`s\ k\S\@ 9|*:`s\ k\S\@ 9|*:`s\ k\S\@ 9|`*:`s\ k\S\@ 9|*:`s\ k\S\@ 9|*:`s\ k\S\@ 9|*:`s\ k\S\@ 9|*:`` \ k\S\@ 9|*:`s\ k\S\@ 9|0*:`s\ k\S\@ 9n|`*:`s\ k\S\@ 9\|*:`s\ k\S\@ 9G|*:`s\ k\S\@ 93|@*:`s\ k\S\@ 9 |*:`s\ k\S\@ 9 |*:`s\ k\S\@ 9||:`s\ k\S\Q\`Q\P\`P\S\`S\R\`R\@9||:` as\ `p\`W\@9||:`s\ `p\`W\@9| *:`s\ `p\W\B@9I|\*:`` as\ `p\V\@9||:` as\ `p\W\A@96|`*:`s\ `p\W\@@9|*:`s\ `p\W\@9^*|@*:`s\ `p\W\@9|*:`s\ `p\W\@9u|*:`s\ `p\W\@9`|*:`s\ `p\W\@9K|*:`s\ `p\W\@98|*:`s\ `p\W\@9'|*:`s\ `p\W\@9|*:`s\ `p\W\@9|`*:`s\ `p\W\@9|*:`s\ `p\W\@9|*:`s\ `p\W\@9|*:`s\ `p\W\@9|*:`` \ `p\W\@9|*:`s\ `p\W\@9|0*:`s\ `p\W\@9{|`*:`s\ `p\W\@9i|*:`s\ `p\W\@9T|*:`s\ `p\W\@9@|@*:`s\ `p\W\@9-|*:`s\ `p\W\@9|*:`s\ `p\W\@9^*||:`s\ `p\W\U\`U\T\`T\W\`W\V\`V\ (9|| as\ `\\`Y\ (9u||s\ `\\`Y\ (9N| *s\ `\\Y\ (9:|| as\ `\\Y\ (9|\*` as\ `\\X\ (9|`*s\ `\\Y\ (9)|*s\ `\\Y\ (9^*|@*s\ `\\Y\ (9|*s\ `\\Y\ (9 |*s\ `\\Y\ (9|*s\ `\\Y\ (9|*s\ `\\Y\ (9|*s\ `\\Y\ (9 |*s\ `\\Y\ (9|*s\ `\\Y\ (9|`*s\ `\\Y\ (9|*s\ `\\Y\ (9|*s\ `\\Y\ (9w |*s\ `\\Y\ (9g|*` \ `\\Y\ (9W|*s\ `\\Y\ (9G|0*s\ `\\Y\ (96|`*s\ `\\Y\ (9'|*s\ `\\Y\ (9|*s\ `\\Y\ (9|@*s\ `\\Y\ (9|*s\ `\\Y\ (9|*s\ `\\Y\ (9||s\ `\\Y\Y\`Y\X\`X\[\`[\Z\`Z\,@a*@ a .42ss q,@a <`*@ a;` .42ss q,,,,,,,,,,,,,,,,z,t,j,d,^,V,N,H,B,:,2,(,,, ,,+++++++++++++++++n+f+b+\+V+P+J+D+>+8+2+,+&+ ++++ ++**/////////}/w/q/k/e/_/Y/Q/M/G/A/=/9/3/-/'//// //....................o.].W.S.O.K.G.A.=.7.1.+.%.... ..---------------------y-u-q-m-i-c-]-W-Q-K-E-?-9-3---%---- --,/@\ 2 ss !Z (9|J1I1H1s\ `\\`]\# (9|J1I1H1H1s\ `\\]\Z (9ھ|J1I1H1s\ `\\`^\ (9a|J1I1H1H1s\ `\\^\# (9\|J1I1H1H1s\ `\\`_\= -9H1s\ _\`\< -9H1s\ _\`a\= -9 H1s\ _\a\< -9H1s\ _\`b\> K1H1s\ b\c\8 K1|H1s\ b\`d\> K1H1 H1s\ b\d\8 K1H1H1s\ b\`e\7 39lH1s\ e\f\6 39UH1s\ e\`g\7 39q H1s\ e\g\6 39ZH1s\ e\`h\?   ?!%ª«êëīī?Ūū+ƪƫ/Ǫǫ)Ȫȫ5ɪɫ7ʪʫ:˪˫>̪̫<ͪͫDΪΫHϪϫFЪЫѪѫҪҫӪӫԪԫժի֪֫Qת׫Mتث٪٫UڪګY۪۫Wܪܫ[ݪݫ]ުޫaߪ߫_એ૏e᪏᫏c⪏⫏㪏㫏䪏䫏媏嫏檏櫏m窏竏誏諏q骏髏kꪏ꫏s몏뫏o쪏쫏i摒𢡊uwz~|?????????  ?" $ª«êëĪi0Ūū*ƪƫ.Ǫǫ(Ȫȫ4ɪɫ6ʪʫ9˪˫=̪̫;ͪͫCΪΫGϪϫEЪЫѪѫҪҫӪӫԪԫժի֪֫Pת׫Lتث٪٫TڪګX۪۫VܪܫZݪݫ\ުޫ`ߪ߫^એ૏d᪏᫏b⪏⫏㪏㫏䪏䫏媏嫏檏櫏l窏竏誏諏p骏髏jꪏ꫏r몏뫏n쪏쫏h摒𢡊txvy}{?????????©?ĩ&?Ʃ2?ȩAɩ??˩J̩ͩR?ϩfЩ????????????????©ééĩ'Iũ1Ʃ3ǩǩ8ȩBɩ@ʩʩI˩K̩ͩSΩΩϩgЩѩѩ?ҩҩ?өө?ԩԩ?թթ?֩֩?שש?ةة?٩٩?کک?۩۩?ܩܩ?ݩݩ?ީީ?ߩߩ?੏੏?ᩏᩏ?⩏⩏?㩏㩏?䩏䩏?婏婏?橏橏?穏穏?詏詏?驏驏?꩏꩏?멏멏?쩏쩏???祐祐???????????????????????????????????????????????????§çħŧƧǧȧɧ ʧ ˧ ̧ ͧΧϧϧ?ЧЧ?ѧѧ?ҧҧ?ӧӧ?ԧԧ?էէ?֧֧?קק?اا?٧٧?ڧڧ?ۧۧ?ܧܧ?ݧݧ?ާާ?ߧߧ?৏৏?᧏᧏?⧏⧏?㧏㧏?䧏䧏?姏姏?槏槏?秏秏?觏觏?駏駏?ꧏꧏ?맏맏?짏짏???紐紐???§RçSħTŧUƧVǧWȧXɧYʧZ˧[̧\ͧ^Χ_???????????????????????????????????¦¦?ææ?ĦĦ?ŦŦ?ƦƦ?ǦǦ?ȦȦ?ɦɦ?ʦʦ?˦˦?̦̦?ͦͦ?ΦΦ?ϦϦ?ЦЦ?ѦѦ?ҦҦ?ӦӦ?ԦԦ?զզ?֦֦?צצ?ئئ?٦٦?ڦڦ?ۦۦ?ܦܦ?ݦݦ?ަަ?ߦߦ?এএ?ᦏ⦏㦏䦏妏榏榏?福規規?馏ꦏ릏릏?즏??憐憐??ᦏ⦏㦏䦏妏福馏ꦏ즏????ѧҧӧԧէ֧קا٧ڧۧܧݧާߧ !"#$%&'()*+,-./§§?çç?ħħ?ŧŧ?ƧƧ?ǧǧ?ȧȧ?ɧɧ?ʧʧ?˧˧?̧̧?ͧͧ?ΧΧ?ϧϧ?ЧЧ?ѧ0ҧ1ӧ2ԧ3է4֧5קQا6٧7ڧ8ۧ9ܧ:ݧ;ާ<ߧ=>?@ABCDEFGHIJKLMNO???????????????¦æĦŦƦǦȦɦʦ˦̦ͦΦϦЦѦҦӦԦզ֦צئ????????¦æĦŦƦǦȦɦʦ˦̦ͦΦϦЦѦҦӦԦզ֦צئ٦٦?ڦڦ?ۦۦ?ܦܦ?ݦݦ?ަަ?ߦߦ????????????????????????????????????????????????????????!£"ã#ģ$ţ%ƣ&ǣ'ȣ(ɣ)ʣ*ˣ+̣,ͣ-Σ.ϣ/У0ѣ1ң2ӣ3ԣ4գ5֣6ף7أ8٣9ڣ:ۣۣ?ܣܣ?ݣݣ?ޣޣ?ߣߣ??A£BãCģDţEƣFǣGȣHɣIʣJˣḲLͣMΣNϣOУPѣQңRӣSԣTգU֣VףWأX٣YڣZ??????%%%%%%%; 0!!!!0???????????" """""*")"¢¢?ââ?ĢĢ?ŢŢ?ƢƢ?ǢǢ?ȢȢ?ɢɢ?ʢʢ'"ˢˢ("̢̢͢͢!΢΢!ϢϢ"ТТ"ѢѢ?ҢҢ?ӢӢ?ԢԢ?բբ?֢֢?עע?آآ?٢٢?ڢڢ?ۢۢ?ܢܢ "ݢݢ"ޢޢ#ߢߢ""a"R"j"k""=""5"+","???????+!0 o&m&j& ! ????%?[aP9|`O9`N9`M9@ \ h\i\ aP9|`O9`N9`M9`L9@ \ h\`j\[aP9|`O9`N9`M9@ \ h\j\ !aP9<|`O9`N9`M9`L9@ \ h\`k\bbubib]bQbEb9b-b  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~  !"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ((((( H ()*+,-./0 1  2  3  4  5 6789:;<=>?@ABCDEFG H !I!"J"#K#$L$%M%&N&'O'()*+,-./0 1  2  3  4  5 6789:;<=>?@ABCDEFG H !I!"J"#K#$L$%M%&N&'O'PPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~  !A!"B"#C#$D$%E%&F&'G'(H()I)*J*+K+,L,-M-.N./O/0P01Q12R23S34T45U56V67W78X89Y9:Z:;;;<<<===>>>???@@@!A!"B"#C#$D$%E%&F&'G'(H()I)*J*+K+,L,-M-.N./O/0P01Q12R23S34T45U56V67W78X89Y9:Z:[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~  !!!"#""#"$%$$%$&'&&'&()(()(*+**+*,-,,-,./../.000111232232454454676676898898:;::;:<=<<=<>?>>?>@A@@A@BCBBCBDEDDEDFGFFGFHIHHIHJKJJKJLMLLMLNONNONPQPPQPRSRRSRTUTTUTVWVVWVXYXXYXZ[ZZ[Z\]\\]\^_^^_^`a``a`bcbbcbdeddedfgffgfhihhihjkjjkjlmllmlnonnonpppqqqrrrssstttuuuvvvwwwxxxyzyyzy{|{{|{}y}~~~~§§§çççħħħŧŧŧƧƧƧǧǧǧȧȧȧɧɧɧʧʧʧ˧˧˧̧̧̧ͧͧͧΧΧΧϧϧϧЧЧЧѧѧѧҧҧҧӧӧӧԧԧԧէէէ֧֧֧קקקااا٧٧٧ڧڧڧۧۧۧܧܧܧݧݧݧާާާߧߧߧ  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@A@@A@BCBBCBDEDDEDFGFFGFHIHHIHJKJJKJLMLLMLNONNONPQPPQPRSRRSRTUTTUTVWVVWVXYXXYXZ[ZZ[Z\]\\]\^_^^_^```aaabcbbcbdeddedfgffgfhihhihjkjjkjlmllmlnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~¦¦¦æææĦĦĦŦŦŦƦƦƦǦǦǦȦȦȦɦɦɦʦʦʦ˦˦˦̦̦̦ͦͦͦΦΦΦϦϦϦЦЦЦѦѦѦҦҦҦӦӦӦԦԦԦզզզ֦֦֦צצצئئئ٦٦٦ڦڦڦۦۦۦܦܦܦݦݦݦަަަߦߦߦ--------- - - - - ------------------- -!-"-#-$-%-&-&-&-'-'-'-(-(-(-)-)-)-*-*-*-+-+-+-,-,-,-------.-.-.-/-/-/-0-0-0-1-1-1-2-2-2-3-3-3-4-4-4-5-5-5-6-6-6-7-7-7-8-8-8-9-9-9-:-:-:-;-;-;-<-<-<-=-=-=->->->-?-?-?-@-@-@-A-A-A-B-B-B-C-C-C-D-D-D-E-E-E-F-F-F-G-G-G-H-H-H-I-I-I-J-J-J-K-K-K-L-L-L-M-M-M-N-N-N-O-O-O-P-P-P-Q-Q-Q-R-R-R-S-S-S-T-T-T-U-U-U-V-V-V-W-W-W-X-X-X-Y-Y-Y-Z-Z-Z-[-[-[-\-\-\-]-]-]-^-^-^-_-_-_-`-`-`-a-a-a-b-b-b-c-c-c-d-d-d-e-e-e-f-f-f-g-g-g-h-h-h-i-i-i-j-j-j-k-k-k-l-l-l-m-m-m-n-n-n-o-o-o-p-p-p-q-q-q-r-r-r-s-s-s-t-t-t-u-u-u-v-v-v-w-w-w-x-x-x-y-y-y-z-z-z-{-{-{-|-|-|-}-}-}-~-~-~----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------,0,,,1,,,2,,,3,,,4,,,5,,,6,,,7,,,8,, ,9, , ,:, , ,;, , ,<, , ,=, ,,>,,,?,,,@,,,A,,,B,,,C,,,D,,,E,,,F,,,G,,,H,,,I,,,J,,,K,,,L,,,M,,,N,,,O,, ,P, ,!,Q,!,",R,",#,S,#,$,T,$,%,U,%,&,V,&,',W,',(,X,(,),Y,),*,Z,*,+,[,+,,,\,,,-,],-,.,^,.,/,/,/,,0,,,1,,,2,,,3,,,4,,,5,,,6,,,7,,,8,, ,9, , ,:, , ,;, , ,<, , ,=, ,,>,,,?,,,@,,,A,,,B,,,C,,,D,,,E,,,F,,,G,,,H,,,I,,,J,,,K,,,L,,,M,,,N,,,O,, ,P, ,!,Q,!,",R,",#,S,#,$,T,$,%,U,%,&,V,&,',W,',(,X,(,),Y,),*,Z,*,+,[,+,,,\,,,-,],-,.,^,.,_,_,_,`,a,`,`,a,`,b,kb,c,}c,d,}d,:e,:>f,>g,h,g,g,h,g,i,j,i,i,j,i,k,l,k,k,l,k,m,Qm,n,qn,o,Po,p,Rp,q,q,q,r,s,r,r,s,r,t,t,t,u,v,u,u,v,u,w,w,w,x,x,x,y,y,y,z,z,z,{,{,{,|,|,|,},},},~,?~,,@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,$$$$$$$$$$$$$$$$$$$$$$$$$$$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $ $ $!$!$!$"$"$"$#$#$#$$$$$$$%$%$%$&$&$&$'$'$'$($($($)$)$)$*$*$*$+$+$+$,$,$,$-$-$-$.$.$.$/$/$/$0$0$0$1$1$1$2$2$2$3$3$3$4$4$4$5$5$5$6$6$6$7$7$7$8$8$8$9$9$9$:$:$:$;$;$;$<$<$<$=$=$=$>$>$>$?$?$?$@$@$@$A$A$A$B$B$B$C$C$C$D$D$D$E$E$E$F$F$F$G$G$G$H$H$H$I$I$I$J$J$J$K$K$K$L$L$L$M$M$M$N$N$N$O$O$O$P$P$P$Q$Q$Q$R$R$R$S$S$S$T$T$T$U$U$U$V$V$V$W$W$W$X$X$X$Y$Y$Y$Z$Z$Z$[$[$[$\$\$\$]$]$]$^$^$^$_$_$_$`$`$`$a$a$a$b$b$b$c$c$c$d$d$d$e$e$e$f$f$f$g$g$g$h$h$h$i$i$i$j$j$j$k$k$k$l$l$l$m$m$m$n$n$n$o$o$o$p$p$p$q$q$q$r$r$r$s$s$s$t$t$t$u$u$u$v$v$v$w$w$w$x$x$x$y$y$y$z$z$z${${${$|$|$|$}$}$}$~$~$~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! !!!!!!!"!"!"!#!#!#!$!$!$!%!%!%!&!&!'!'!'!(!(!(!)!)!)!*!k*!+!+!,!,!,!-!-!-!.!.!.!/!/!/!0!0!0!1!1!1!2!N!2!3!3!3!4!4!4!5!5!5!6!6!6!7!7!7!8!8!8!9!9!9!:!:!:!;!;!;!!>!>!?!?!?!@!@!@!A!A!A!B!B!B!C!C!C!D!D!D!E!E!E!F!F!F!G!G!G!H!H!H!I!I!I!J!J!J!K!K!K!L!L!L!M!M!M!2!N!2!O!O!O!P!P!P!Q!Q!Q!R!R!R!S!S!S!T!T!T!U!U!U!V!V!V!W!W!W!X!X!X!Y!Y!Y!Z!Z!Z![![![!\!\!\!]!]!]!^!^!^!_!_!_!`!p!`!a!q!a!b!r!b!c!s!c!d!t!d!e!u!e!f!v!f!g!w!g!h!x!h!i!y!i!j!z!j!k!{!k!l!|!l!m!}!m!n!~!n!o!!o!`!p!`!a!q!a!b!r!b!c!s!c!d!t!d!e!u!e!f!v!f!g!w!g!h!x!h!i!y!i!j!z!j!k!{!k!l!|!l!m!}!m!n!~!n!o!!o!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!          ( )!*"+#,$-%.&/'( )!*"+#,$-%.&/'8091:2;3<4=5>6?78091:2;3<4=5>6?7H@IAJBKCLDMEFFFGGGH@IAJBKCLDMENNNOOOPPYQRR[STT]UVV_WXXXYQZZZ[S\\\]U^^^_Wh`iajbkcldmenfogh`iajbkcldmenfogpqrstuvwxyz{|}~~~pqrstuvwz{xy|}AABBBBBB C C  D  D  D  DDDDDDDEEEEEEEEEEFF !G !G"#H"#H$%H$%H&'H&'H()H()H*+H*+H,-I,-I./I./I01K01K23K23K45K45K67L67L89L89L:;L:;L<=L<=L>?M>?M@AM@AMBCMBCMDENDENFGNFGNHINHINJKNJKNLMOLMONOONOOPQOPQORSORSOTUPTUPVWPVWPXYRXYRZ[RZ[R\]R\]R^_R^_R`aS`aSbcSbcSdeSdeSfgSfgShiShiSjkTjkTlmTlmTnoTnoTpqTpqTrsUrsUtuUtuUvwUvwUxyUxyUz{Uz{U|}V|}V~V~VWWWWWWWWWWXXXXYYZZZZZZHTWY`SAAAAAAAAAAAAAAAAAAAAAAAAEEEEEEEEEEEEEEEEIIIIOOOOOOOOOOOOOOOOOOOOOOOOUUUUUUUUUUUUUUYYYYYYYY                  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxx}y}zzz{{{|||c,}c,~~~                  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~--------- - - - - ------------------- -!-"-#-$-%-               !  ! "#""#"$%$$%$&&&'''((()))***+++,,,---...///0001a12b23c34d45e56f67g78h89i9:j:;k;<l<=m=>n>?o?@p@AqABrBCsCDtDEuEFvFGwGHxHIyIJzJK{KL|LM}MN~NOOPPQQRRSSTTUUVVWWWXXXYYYZZZ[[[\\\]]]^^^___```1a12b23c34d45e56f67g78h89i9:j:;k;<l<=m=>n>?o?@p@AqABrBCsCDtDEuEFvFGwGHxHIyIJzJK{KL|LM}MN~NOOPPQQRRSSTTUUVVPQRSTUVWX Y  Z  [  \ ]^#_0123456789:;<=>? @ !A!"B"#C#$D$%E%&F&'G'(H()I)*J*+K+,L,-M-.N./O/0123456789:;<=>? @ !A!"B"#C#$D$%E%&F&'G'(H()I)*J*+K+,L,-M-.N./O/PQRSTUVWX Y  Z  [  \ ]^#_`a``a`bcbbcbdeddedfgffgfhihhihjkjjkjlmllmlnonnonpqppqprsrrsrtuttutvwtvwtxyxxyxz{zz{z|}||}|~~~~--######''++                  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopqppqprsrrsrtttuuuvwvvwvxxxyyyzzz{|}~~~{|}AAAAEEEE I I  I  I  O  OOORRRRUUUUSSTTHH  !!!"#""#"$%$$%$&'A&'A()E()E*+O*+O,-O,-O./O./O01O01O23Y23Y444555666777888999:e,:;<;;<;==>f,>~,?~,,@,ABAABACCDDEEFGFFGFHIHHIHJKJJKJLMLLMLNONNONo,Po,m,Qm,p,Rp,STUUUVWXXXYZZZ[\\\]]]^^^___`aaabbbcdddeeefffggghijjjb,kb,lllmmmnnnopppn,qn,rssstttuvvvwwwxxxyyyzzz{{{|||d,}d,~~~DDEEAAAAAACC C C  C  C  C  CDDEEEEEEEEEEGGGG !G !G"#G"#G$%H$%H&'&&'&()I()I*+I*+I,-I,-I./I./I0iII1I23223245J45J67K67K8889:L9:L;<L;<L=>L=>L?@??@?ABAABACDNCDNEFNEFNGHNGHNIIIJKJJKJLMOLMONOONOOPQOPQORSRRSRTURTURVWRVWRXYRXYRZ[SZ[S\]S\]S^_S^_S`aS`aSbcTbcTdeTdeTfgffgfhiUhiUjkUjkUlmUlmUnoUnoUpqUpqUrsUrsUtuWtuWvwYvwYxYyzZyzZ{|Z{|Z}~Z}~ZSSCCSTVWY[`cih==or  uOOUUAAIIOOUUUUUUUUUUAAAAGGKKOOOOJGGNNAA  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AaABbBCcCDdDEeEFfFGgGHhHIiIJjJKkKLlLMmMNnNOoOPpPQqQRrRSsSTtTUuUVvVWwWXxXYyYZzZ[[[\\\]]]^^^___```AaABbBCcCDdDEeEFfFGgGHhHIiIJjJKkKLlLMmMNnNOoOPpPQqQRrRSsSTtTUuUVvVWwWXxXYyYZzZ{{{|||}}}~~~AAAAAACEEEEIIIINOOOOOUUUUYSAAAAAACEEEEIIIINOOOOOUUUUYxY  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AaABbBCcCDdDEeEFfFGgGHhHI1IJjJKkKLlLMmMNnNOoOPpPQqQRrRSsSTtTUuUVvVWwWXxXYyYZzZ[[[\\\]]]^^^___```AaABbBCcCDdDEeEFfFGgGHhH0iIJjJKkKLlLMmMNnNOoOPpPQqQRrRSsSTtTUuUVvVWwWXxXYyYZzZ{{{|||}}}~~~AAAAAACEEEEIIIINOOOOOUUUUYAAAAAACEEEEIIIINOOOOOUUUUYxY  !A!"B"#C#$D$%E%&F&'G'(H()I)*J*+K+,L,-M-.N./O/0P01Q12R23S34T45U56V67W78X89Y9:Z:;;;<<<===>>>???@@@!A!"B"#C#$D$%E%&F&'G'(H()I)*J*+K+,L,-M-.N./O/0P01Q12R23S34T45U56V67W78X89Y9:Z:[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~$$$$$$$$$$$$$$$$$$$$$$$$$$$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $ $ $!$!$!$"$"$"$#$#$#$$$$$$$%$%$%$&$&$&$'$'$'$($($($)$)$)$*$*$*$+$+$+$,$,$,$-$-$-$.$.$.$/$/$/$0$0$0$1$1$1$2$2$2$3$3$3$4$4$4$5$5$5$6$6$6$7$7$7$8$8$8$9$9$9$:$:$:$;$;$;$<$<$<$=$=$=$>$>$>$?$?$?$@$@$@$A$A$A$B$B$B$C$C$C$D$D$D$E$E$E$F$F$F$G$G$G$H$H$H$I$I$I$J$J$J$K$K$K$L$L$L$M$M$M$N$N$N$O$O$O$P$P$P$Q$Q$Q$R$R$R$S$S$S$T$T$T$U$U$U$V$V$V$W$W$W$X$X$X$Y$Y$Y$Z$Z$Z$[$[$[$\$\$\$]$]$]$^$^$^$_$_$_$`$`$`$a$a$a$b$b$b$c$c$c$d$d$d$e$e$e$f$f$f$g$g$g$h$h$h$i$i$i$j$j$j$k$k$k$l$l$l$m$m$m$n$n$n$o$o$o$p$p$p$q$q$q$r$r$r$s$s$s$t$t$t$u$u$u$v$v$v$w$w$w$x$x$x$y$y$y$z$z$z${${${$|$|$|$}$}$}$~$~$~$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! !!!!!!!"!"!"!#!#!#!$!$!$!%!%!%!&!&!'!'!'!(!(!(!)!)!)!*!k*!+!+!,!,!,!-!-!-!.!.!.!/!/!/!0!0!0!1!1!1!2!2!2!3!3!3!4!4!4!5!5!5!6!6!6!7!7!7!8!8!8!9!9!9!:!:!:!;!;!;!!>!>!?!?!?!@!@!@!A!A!A!B!B!B!C!C!C!D!D!D!E!E!E!F!F!F!G!G!G!H!H!H!I!I!I!J!J!J!K!K!K!L!L!L!M!M!M!N!N!N!O!O!O!P!P!P!Q!Q!Q!R!R!R!S!S!S!T!T!T!U!U!U!V!V!V!W!W!W!X!X!X!Y!Y!Y!Z!Z!Z![![![!\!\!\!]!]!]!^!^!^!_!_!_!`!p!`!a!q!a!b!r!b!c!s!c!d!t!d!e!u!e!f!v!f!g!w!g!h!x!h!i!y!i!j!z!j!k!{!k!l!|!l!m!}!m!n!~!n!o!!o!`!p!`!a!q!a!b!r!b!c!s!c!d!t!d!e!u!e!f!v!f!g!w!g!h!x!h!i!y!i!j!z!j!k!{!k!l!|!l!m!}!m!n!~!n!o!!o!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!          ( )!*"+#,$-%.&/'( )!*"+#,$-%.&/'8091:2;3<4=5>6?78091:2;3<4=5>6?7H@IAJBKCLDMEFFFGGGH@IAJBKCLDMENNNOOOPPYQRR[STT]UVV_WXXXYQZZZ[S\\\]U^^^_Wh`iajbkcldmenfogh`iajbkcldmenfogpqrstuvwxyz{|}~~~pqrstuvwz{xy|}AABBBBBB C C  D  D  D  DDDDDDDEEEEEEEEEEFF !G !G"#H"#H$%H$%H&'H&'H()H()H*+H*+H,-I,-I./I./I01K01K23K23K45K45K67L67L89L89L:;L:;L<=L<=L>?M>?M@AM@AMBCMBCMDENDENFGNFGNHINHINJKNJKNLMOLMONOONOOPQOPQORSORSOTUPTUPVWPVWPXYRXYRZ[RZ[R\]R\]R^_R^_R`aS`aSbcSbcSdeSdeSfgSfgShiShiSjkTjkTlmTlmTnoTnoTpqTpqTrsUrsUtuUtuUvwUvwUxyUxyUz{Uz{U|}V|}V~V~VWWWWWWWWWWXXXXYYZZZZZZHTWY`SAAAAAAAAAAAAAAAAAAAAAAAAEEEEEEEEEEEEEEEEIIIIOOOOOOOOOOOOOOOOOOOOOOOOUUUUUUUUUUUUUUYYYYYYYY                  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///0001a12b23c34d45e56f67g78h89i9:j:;k;<l<=m=>n>?o?@p@AqABrBCsCDtDEuEFvFGwGHxHIyIJzJK{KL|LM}MN~NOOPPQQRRSSTTUUVVWWWXXXYYYZZZ[[[\\\]]]^^^___```1a12b23c34d45e56f67g78h89i9:j:;k;<l<=m=>n>?o?@p@AqABrBCsCDtDEuEFvFGwGHxHIyIJzJK{KL|LM}MN~NOOPPQQRRSSTTUUVVPQRSTUVWX Y  Z  [  \ ]^#_0123456789:;<=>? @ !A!"B"#C#$D$%E%&F&'G'(H()I)*J*+K+,L,-M-.N./O/0123456789:;<=>? @ !A!"B"#C#$D$%E%&F&'G'(H()I)*J*+K+,L,-M-.N./O/PQRSTUVWX Y  Z  [  \ ]^#_`a``a`bcbbcbdeddedfgffgfhihhihjkjjkjlmllmlnonnonpqppqprsrrsrtuttutvwtvwtxyxxyxz{zz{z|}||}|~~~~--######''++                  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~AAAAEEEE I I  I  I  O  OOORRRRUUUUSSTTHH   !!!"#""#"$%$$%$&'A&'A()E()E*+O*+O,-O,-O./O./O01O01O23Y23Y444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSTUUUVWXXXYZZZ[\\\]]]^^^___`aaabbbcdddeeefffggghijjjkkklllmmmnnnopppqqqrssstttuvvvwwwxxxyyyzzz{{{|||}}}~~~AAAAAACC C C  C  C  C  CDDEEEEEEEEEEGGGG !G !G"#G"#G$%H$%H&'&&'&()I()I*+I*+I,-I,-I./I./I0iII1I23223245J45J67K67K8889:L9:L;<L;<L=>L=>L?@??@?ABAABACDNCDNEFNEFNGHNGHNIIIJKJJKJLMOLMONOONOOPQOPQORSRRSRTURTURVWRVWRXYRXYRZ[SZ[S\]S\]S^_S^_S`aS`aSbcTbcTdeTdeTfgffgfhiUhiUjkUjkUlmUlmUnoUnoUpqUpqUrsUrsUtuWtuWvwYvwYxYyzZyzZ{|Z{|Z}~Z}~ZSSSTVWY[`cihoruOOUUAAIIOOUUUUUUUUUUAAAAGGKKOOOOJGGNNAA  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AaABbBCcCDdDEeEFfFGgGHhHIiIJjJKkKLlLMmMNnNOoOPpPQqQRrRSsSTtTUuUVvVWwWXxXYyYZzZ[[[\\\]]]^^^___```AaABbBCcCDdDEeEFfFGgGHhHIiIJjJKkKLlLMmMNnNOoOPpPQqQRrRSsSTtTUuUVvVWwWXxXYyYZzZ{{{|||}}}~~~AAAAAACEEEEIIIINOOOOOUUUUYAAAAAACEEEEIIIINOOOOOUUUUYxY  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AaABbBCcCDdDEeEFfFGgGHhHIiIJjJKkKLlLMmMNnNOoOPpPQqQRrRSsSTtTUuUVvVWwWXxXYyYZzZ[[[\\\]]]^^^___```AaABbBCcCDdDEeEFfFGgGHhHIiIJjJKkKLlLMmMNnNOoOPpPQqQRrRSsSTtTUuUVvVWwWXxXYyYZzZ{{{|||}}}~~~AAAAAACEEEEIIIINOOOOOUUUUYSAAAAAACEEEEIIIINOOOOOUUUUYxY             .@ 99ӓ9bbbs\ k\l\-@ 9ӓ9bbbbs\ k\`m\.@ 9 ӓ9bbbs\ k\m\-@ 9ܼӓ9bbbbs\ k\`n\(|9999s\ n\o\S@96|999s\ `p\`q\!@9|9999s\ `p\q\S@9 |999s\ `p\`r\@9|9999s\ `p\r\!@9D|9999s\ `p\`s\ dccccccccccdcccccccccc{cocccWcKc?c3c'ccccbbbbbbbccccccccccc"A`9|9999`9\s\ `F\t\qo#ſt[Am-jd8n헧?O>. 8/t#ڰͼ3&N|.[Ӿr؇/PkpnJؕnq&fƭ$6ZB<TcsUe(U܀n_S@ eD eH eP e\ ep e eGA$3a14GA$3a14O GA$3p1113`OOGA*GA$annobin gcc 8.5.0 20210514GA$plugin name: gcc-annobinGA$running gcc 8.5.0 20210514GA*GA*GA! GA*FORTIFYGA+GLIBCXX_ASSERTIONS GA*GOW*GA*cf_protectionGA+omit_frame_pointerGA+stack_clashGA!stack_realign GA*FORTIFY`OOGA+GLIBCXX_ASSERTIONSmariadb-10.6.23-1.el8.x86_64.debugU7zXZִF!t/EF]?Eh=(aK"a 9Om}$[:<)ނPG`_g_@[eSmޡR }ny3Xd(""oٺ윛Chl"¸ ~EC~ 6#5P&T1]ĕ\#Ƭ;;g7U_aXqI9Fn?;Wu6g[igM۽&@e2>0ZӞ%x"*u-sO5JM-r2Mץ4@}csd6_BNjli$~.fCۜxổ?;eucz-Bpn@dZNչZ(E4iaZңrZXZo1bnmQfkQK9>`i^!J8bfdJEy@P`lFzlU;< wNIQ\\Zݨru 04x+huBxdϔ|u`tU5ITۮ}ZNIua}G:?J N-Ty=6&V2HOUHl-F>@Ao_G*o8|UPuUui'd紦/r%G ! m6=BTL!Jht8vQxͧݞWR짙kK"RlFX CFM9%Bqd~ܚ5l}-BF7xۥԩ)TA.oQb@l ;EkY-$2$N/B5XތRRˆT -Xr. ͏ḁ K2=7ϝՒwɏ!:@,}3{>4v$/ 5ޫX+X9G2Jn^KUV5ˈ.G}nsLLQvTŎqЩ% ?ymT@1vvHMLF=oqR3Xv-M1k[,T=oqt$򖁋( WCA|!^j) r/VTL4<W; @k;q:gBCL㠓<۵v\>8Z:((;/ *p=mԒ()}(4v$K%fzx6/5zeWl™Ka`G*ӞtN'P!#dxuyLwؗiLQ7s}T뢲4W_LSBqJ/{ձm>܄E6mY/߻KrF k|lÅxO<n q=rs8Ȱ=Fѷ?%^Ck ~-$2ҁXT]ma$PĴ KjdC^L->ZlS &XÉ_VZBӯJiyiA^7ME} &t95C//. uYXmd+NlUW|Pl2-lnzLKE=nj!N5ނm֫5l޵ic)K/3 FXI@TkBw kZ0=@J*Y/R+~|K 0@D2~uvϗ%eX'p1LQ)3UVzt5bE1Ә^?;ٶ#sMyqHKH] #_ϒx.IԤn!\K̇_ntb#{4Ƹ.\0Ε2+n0r-wc,o 7lIFCX.; anBP??,2 `_7W#Ćh۝D O [[Q *.)l{FCS-~́H81̫.874',zgDflwR/įW::ՙN"A0LP >]Ru5p] `-=]n\HKC~[S"#]#Œ,Yt0qt> ^'g>g.('6b]g#9B oxRHFYft;UodVv):¼2[S\;FA&z;H}_1M%sj}bg!@f=.􍞧IߋBA4ɞw@WWkJ)m h?Khqlud4G>"${պS@ Ec8xr(^km?RkVwFJ 21X=AJ նW[$j]Rq oK0 BJ P?%&O{01%0FŐԝ12$%@@+=KNO&#oq^Gzouu iص8sۥ{TjPO\f8*Va+7i5GD'R?GI_QmCwc􋷎CF@+vI$^C (h{8\c鞫 2E8 P0WF5z.rDp&,DswA 0i8ϝo"Y~X3c;(`3sNn`EDK{nmxبiO6 _`Ah/vœa_SץٯYmT餧G.{f@ZDp3a0E[Myӷ xVl:b1D<& c} T[@_\G]OW~ Ɯ}Gii)9ߡ| nVw"Y#}c[vWO/}q-&s+DϗSj~8Lװ+?dj9o1u N+sdHJ@7ax,^ԇb∏bۋ+x? }WN {"P': M r|sW gƺqu=xi[tDbƬ΃4q[ީb)!&p*Hn/}/ (D4T|uZ@W[؇cw"[nq219Cj Nt=Y::U>ȴB6,^{~;"7ft7’G5^vdJ@@;hx/t#:!lŭ3 Z9mE@EbY?{/BƌlR 1/ˏ35мG]| &;Ldr!2:-і:L=b{XG$a܌=>I4 $L.jTW= 0+?8wZExmW$#6DMd[C75@d2u/tb| }9D; H&}a\)xuڑeFDmMgĉbJ0=eКeiwe.:3p6ȍCj[@@~CTe fӺ .ч{dX<\$FbYvp阨ͯDka5dusT\~>6WB'Jր{U=ǥ_)z+cSpFKus#Ș (: IO {Ψ+Kq՜{|Ӥ6X'NaSGc]Z4Zy <y'0B]Fe3^<'H%RU}s>!bQ$,x ujT_0/MK ,m8S8e.6юLM=W_yM9hdIS/ѶgCAG)b#An:רTmFP_M@qb96X~}_"UR0 {!'IZ{;iȇ7F,,6y1 ;x|Օ8߆Kڹe QGH'4 f'k壘e|I;?Tj5t 6C.^`xXTqŏ=}39b<W#h 1p-NDk7uWRYh;ԷJcA*7ۄZ7|d5Ǎ-O`5/BHy~X]&C zsB:T6q\iCQʱzxcKumLNK Ӷ%f HqEYKߘAv[H~x[]UcEXjH&zhVҳFv*Oih%ʘt8ɽb3\Nq7,gszQ Qt؄6] esJW<1&33ǥ;1i: kє[/Y!-[:h/TVWLy5簪C|5%=o@ェ]$}JP/ǻ8*\J}nmŕP% ksLx1XFTEg0ƿ]>8z*6Px"FF1~0~I=` fewp0wts!bj*/xTAGjSũJġdDXv #Ē'I4c4xpoH־%n <;)=6 ٧K:$ (hEO9IhԖ8A͸7mh%i'seMq'WTm "7G45¼`/hV<28"ieQ nMsUE81 0kp*'1b!1xo_i@O;Ղ7'QI..7HkQ^u_4̛O]SqF9+l;SO˙N1kNx+;#bB3}Fֶ@DՌAd}|ٲx{Q/nmqUr0#=Te%`EH>X[ b:ŮDA෉1^RdJE`(IwzTG)U lQ'`y{O0 ǂ>~.#~qf) 0c4Ha@d@{p-%fdX# >6sl@Jwa[j0o $2Q+H4j&ʨЌQ$*qFKnOztlVEG'F'QM5[19 ԼCܮj]jŜ>ZvJ&MGH2 0$hzpޕNI!$6^˄a/MQiN`9wųAmYf9K?)ͿqIŻƃ2N`{t5Ty$ "`Jjx=G_cpϭޥ"֛DCAֳ˅ѓ:xbd3axQ;2s[*bDOӍYnܧt R]$:U 6IRQd##h qǹ%zL W }t,eNu::[ϘC{3Y37#{ L+ #?f_~୭拵)qcvľĜ0Ja Gl%T7ӔlU ܚ_ d{g>3ܒlu4dR T5]ovm]uF=plose):ӭEl{9:qw\1gr屰s.g+[,]LFc'r>(~U= ^:TDDxav\!Kky叻Ģzm".E :}7O!Qo-$A9#7BL&tzjPݺffY`S3&s4Ň|~Eūmkdu9ޯWKN9<@avbG@?W[_>rYX>Zz lup-x*mk=mΈ.16RMpxjAYPqJ4Ús'}fϯ2,$pI̵6i/4FѼx ycj=k\5zZу:rN7P -Qš%V/%^ƍEJ:MT!7YP?X!}~su6OCW N@UFv6E3BY ư39z3Ѫ1t_Ŕ\9±&pƣ/q #\5˔׫a& GV+`(&ӵ3JtRzܛμm[oh} ӫP໠8)ǎ,iZB!$<*() en:4,;m1Ry߶+DqoyF$ɷQ!ੰYV'T븩!Ry͍ke GÜ<F9,#ZYHckf}PrH! D]Q*7H΃6xB~+G@Khji1!Ϟx"dVKiz+R쭢Rt$AGJ-Lj]J˦?!Q|f^4 SX#0teR&D՗o,~r% hr`x^(޸D|/W 1V^8֓Nw&%ց^ œ^`mr&{q>עM&@a#l>ߩ_mx,ucWrnumbʴ8)ݪ2[ @)eq%wAe⎞!/.3NHx[3x$VQE{DOKdf4pYfj ۀrO A0P\QX<n'87<ƮzbKì`_9B:2F۹1Lf!2h3~,5}d+)Nu{<!׋W9lmW@/`Us7 /f6CK<μAI='`$ՍU$52tE\_ Pv vnŵ;}tzVs~?s3ItDž!Af9O{n⏿$`4Խy)Cs+ lp.$X2{ZqZr#-~(=AXDV3 ʖs=_.}ۦ)W>[%%-U.61un/\`cTHQ$aֵj(y vJ-B)"лmdk݄!ۢo7ogEA^V#zDfV k:4ڔA@M0LΧy}|f8 4KBË|W'Ie:di^܊ ǤM㿺cLZ3kj' 7_zb笰8QBe ?j9˜u śb9lB{ז ns')KXhYixTنs:3SZ zuӊY,.Ǩ`.Ӣ3fٍ`,&ḭTF8_rxzΗA(F`OEE-qmK\M2S+Q3Kqt:ezIb`aU]녙\LH@=Mj(A6ֲDkSAdKy,h>\c4Lq|S,7SpLpwql_ow[IdX9L LXsQ<"M\l%= p')I Π:3I ֢Hd]%jWDN a\oKbБ2Ț7;$q|]9:deY O5F#5 A.(A=d3ॗPfP'p(j ?^%JLU hb A9Il($-A CK"dW^]Hl#AۑElTat=l% ՛_)7h4_dMn~n7KS nA<1DyMMжݎ=u$;e3zHZu<Æ]hrm}|]P$KGVr0Q~3Zj8dJ*8d`눿XV\FQ6wo0oV,⾡5a!-~ "@ C }᡹jX=*Ouy5`%ڊם6 !tڠJ|,o Aj x|Qӿ}5_3م瓪/.J>\r< ̴8+2G*O2_Ȧ2 >ͩ4"-262W$5KAo _5naR \(nV~_Ȍ@ w, FxʾMY.-,zp)YF z5TMu'>KVљS*n^te yt>P_G Ϲ7).p[(}5;⿻P4?RWHQ4ae3'bi%⣓SF|YEI 1&y@wr(7g'Jv>IV:/UD~T vSR!G )zX?CeۂK&hU>IBUpY|QQεM)-kLs%OHHt*Ł&{Jm㎂emNqdЌ[CA'a4=p޷ny rJ B{5u֍ _)~{V]3Ei NY7L9acg(۽6>\턷a杴&0K 58&M"Et:&ns`U& G@( }'M~9ͷ3Rt04/5=@LJl*(É}9tāx9ZY?D#9S0'"_TۣQRc~yy(go=Dƥ紾]IR4డ+k_ \0V8Haz~ƀQUR"v^pFl*NpGǾ5+ؚǶ"x,DdA^9w(MʻNũLduE4}/v IģL'`bڛw!7a\y8,9L{́QWcR=|k&CIb8f/V|x0A&UjRNČRrHWFE hb?8!D')}tH^-v,~ | )+d-KB!szd!z,vjNe? No&A.5>a'ͅvЀ;{!wW8d&U+;4u'Þy,8:W`nt2yHIl΃x`N=ƅ RٕPc\w&f}<+v'͖ǡSxJ4+ַ27y,_ i:!m~A_ޚZ`N#AJyu\5Rc+nI=EPN3rsIIKU> a`v3&Q$K)nD+eK᪙H/DzRm"0ƃF<("s2a; !z@4GNEhB]|xR<"*L Y/~(郘~p䎮wmod]`:%X'@BhtE#l]~wEO0:q&=ur >9+ W{$30 )v20[F3 CQ҂wP{Ow|,dAa9F9\-g(?Zז.9nE1[+* ې=E J.[(e_UV aҴK>Vb$J/jQ]>`Y' Ȝ%Ҷ/ӈBΦ OS4Uom\SP39h`e:'=<&ɥ2 $V[dJ6!Ly繜V`oہgN$j[2zI0ܶtS~"!4ɔp?%=oAhY h52un$Khף P|GN[IKG"!%7NC' DYL^ne;0@mJ3M}Yg+3@ũQFmx^8m j;Q<{y1Wj[ﮬvMDn䛃{m)\E\<$FŻ:MpKb-{.:2/~SB()9J`F%`Ri+]M| RarČt dbkj[h&ak=z;:b9/q>GnNwsI?|kT2~TRR*ڭII'lSu5aӳ=r3悍luஂ˝})ߞJRI~:A<#-c<Uk)Ez3 ~1[F ]c*TtؑdpmQ:>{UUƐz vd#ZVt-Td~{  ĵ\t2cAɇWc5&[>W˨~u^U%ᑡ;["$GzZ>=!uIvnQ˿xl QƝn\xe˵4؎#+)wx&{sⳓ2hwpOuI9-c`@B0w"U;2΋l9 E'En.\U1 ޣzG`*I7b\|G 17x aeW6ڈ`%d5n%)3Ir h]ttkK@C]h2 l!3ٌn㐡?jjJ#TE:v:qǝCv9B0;)idG10~M?_b"݃ UX>XVr#]H2rߑ4iJ R 2w>%gx`_~6Z+=4f4 :̎qQ't`"GjG!JL>5.f.;IRl[WtZ%lEh7cd:TF+}̻:x U4U@QuS:P. 6P)k|]Y)2v/d]ԥtGw31 #n}52Fb\]FZ])G=;yKUwMaA5S#a\䬽V퐲19j2tص XaD&љj31)#0 n@X·gOIl/sf-ln`"~ݙjoopXwe/aݛb}Tͧ6[ :iNUD\^2ySҋy4" Zds|w:; ( xqws,%$O۰'#.s>R⧩3*sT,BARxxfk 7ͣk7UΟJOryWa⭈5Z7k |(Ś*OStnz/C =\P4 7s Py!;u5^h V l%Je"zϢV y1NC}%ĭ?4N\0;%}OMvg!Y$DRh2Gf6!b`n/(gݍ1ɱgYZ.shstrtab.interp.note.ABI-tag.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.gcc_except_table.init_array.fini_array.data.rel.ro.dynamic.got.data.bss.gnu.build.attributes.gnu_debuglink.gnu_debugdata 88TT !tt$4o6> @9@9FNoL[o88j1tBhh~y00##, OO PP|( 99F::Pc;c;hj[hj;xj[xj;j[j;  pt\pt<w\w<\<  e E@  El E(%< EG@TE4service_kill_statement.h000064400000004026151030241300011443 0ustar00/* Copyright (c) 2013, 2018, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SERVICE_KILL_STATEMENT_INCLUDED #define MYSQL_SERVICE_KILL_STATEMENT_INCLUDED /** @file This service provides functions that allow plugins to support the KILL statement. In MySQL support for the KILL statement is cooperative. The KILL statement only sets a "killed" flag. This function returns the value of that flag. A thread should check it often, especially inside time-consuming loops, and gracefully abort the operation if it is non-zero. thd_killed(thd) @return 0 - no KILL statement was issued, continue normally @return 1 - there was a KILL statement, abort the execution. thd_kill_level(thd) @return thd_kill_levels_enum values */ #ifdef __cplusplus extern "C" { #endif enum thd_kill_levels { THD_IS_NOT_KILLED=0, THD_ABORT_SOFTLY=50, /**< abort when possible, don't leave tables corrupted */ THD_ABORT_ASAP=100, /**< abort asap */ }; extern struct kill_statement_service_st { enum thd_kill_levels (*thd_kill_level_func)(const MYSQL_THD); } *thd_kill_statement_service; /* backward compatibility helper */ #define thd_killed(THD) (thd_kill_level(THD) == THD_ABORT_ASAP) #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_kill_level(THD) \ thd_kill_statement_service->thd_kill_level_func(THD) #else enum thd_kill_levels thd_kill_level(const MYSQL_THD); #endif #ifdef __cplusplus } #endif #endif service_sha2.h000064400000012263151030241300007263 0ustar00#ifndef MYSQL_SERVICE_SHA2_INCLUDED /* Copyright (c) 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my sha2 service Functions to calculate SHA2 hash from a memory buffer */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #endif extern struct my_sha2_service_st { void (*my_sha224_type)(unsigned char*, const char*, size_t); void (*my_sha224_multi_type)(unsigned char*, ...); size_t (*my_sha224_context_size_type)(); void (*my_sha224_init_type)(void *); void (*my_sha224_input_type)(void *, const unsigned char *, size_t); void (*my_sha224_result_type)(void *, unsigned char *); void (*my_sha256_type)(unsigned char*, const char*, size_t); void (*my_sha256_multi_type)(unsigned char*, ...); size_t (*my_sha256_context_size_type)(); void (*my_sha256_init_type)(void *); void (*my_sha256_input_type)(void *, const unsigned char *, size_t); void (*my_sha256_result_type)(void *, unsigned char *); void (*my_sha384_type)(unsigned char*, const char*, size_t); void (*my_sha384_multi_type)(unsigned char*, ...); size_t (*my_sha384_context_size_type)(); void (*my_sha384_init_type)(void *); void (*my_sha384_input_type)(void *, const unsigned char *, size_t); void (*my_sha384_result_type)(void *, unsigned char *); void (*my_sha512_type)(unsigned char*, const char*, size_t); void (*my_sha512_multi_type)(unsigned char*, ...); size_t (*my_sha512_context_size_type)(); void (*my_sha512_init_type)(void *); void (*my_sha512_input_type)(void *, const unsigned char *, size_t); void (*my_sha512_result_type)(void *, unsigned char *); } *my_sha2_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_sha224(A,B,C) my_sha2_service->my_sha224_type(A,B,C) #define my_sha224_multi my_sha2_service->my_sha224_multi_type #define my_sha224_context_size() my_sha2_service->my_sha224_context_size_type() #define my_sha224_init(A) my_sha2_service->my_sha224_init_type(A) #define my_sha224_input(A,B,C) my_sha2_service->my_sha224_input_type(A,B,C) #define my_sha224_result(A,B) my_sha2_service->my_sha224_result_type(A,B) #define my_sha256(A,B,C) my_sha2_service->my_sha256_type(A,B,C) #define my_sha256_multi my_sha2_service->my_sha256_multi_type #define my_sha256_context_size() my_sha2_service->my_sha256_context_size_type() #define my_sha256_init(A) my_sha2_service->my_sha256_init_type(A) #define my_sha256_input(A,B,C) my_sha2_service->my_sha256_input_type(A,B,C) #define my_sha256_result(A,B) my_sha2_service->my_sha256_result_type(A,B) #define my_sha384(A,B,C) my_sha2_service->my_sha384_type(A,B,C) #define my_sha384_multi my_sha2_service->my_sha384_multi_type #define my_sha384_context_size() my_sha2_service->my_sha384_context_size_type() #define my_sha384_init(A) my_sha2_service->my_sha384_init_type(A) #define my_sha384_input(A,B,C) my_sha2_service->my_sha384_input_type(A,B,C) #define my_sha384_result(A,B) my_sha2_service->my_sha384_result_type(A,B) #define my_sha512(A,B,C) my_sha2_service->my_sha512_type(A,B,C) #define my_sha512_multi my_sha2_service->my_sha512_multi_type #define my_sha512_context_size() my_sha2_service->my_sha512_context_size_type() #define my_sha512_init(A) my_sha2_service->my_sha512_init_type(A) #define my_sha512_input(A,B,C) my_sha2_service->my_sha512_input_type(A,B,C) #define my_sha512_result(A,B) my_sha2_service->my_sha512_result_type(A,B) #else void my_sha224(unsigned char*, const char*, size_t); void my_sha224_multi(unsigned char*, ...); size_t my_sha224_context_size(); void my_sha224_init(void *context); void my_sha224_input(void *context, const unsigned char *buf, size_t len); void my_sha224_result(void *context, unsigned char *digest); void my_sha256(unsigned char*, const char*, size_t); void my_sha256_multi(unsigned char*, ...); size_t my_sha256_context_size(); void my_sha256_init(void *context); void my_sha256_input(void *context, const unsigned char *buf, size_t len); void my_sha256_result(void *context, unsigned char *digest); void my_sha384(unsigned char*, const char*, size_t); void my_sha384_multi(unsigned char*, ...); size_t my_sha384_context_size(); void my_sha384_init(void *context); void my_sha384_input(void *context, const unsigned char *buf, size_t len); void my_sha384_result(void *context, unsigned char *digest); void my_sha512(unsigned char*, const char*, size_t); void my_sha512_multi(unsigned char*, ...); size_t my_sha512_context_size(); void my_sha512_init(void *context); void my_sha512_input(void *context, const unsigned char *buf, size_t len); void my_sha512_result(void *context, unsigned char *digest); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_SHA2_INCLUDED #endif plugin_password_validation.h000064400000003021151030241300012330 0ustar00#ifndef MYSQL_PLUGIN_PASSWORD_VALIDATION_INCLUDED /* Copyright (C) 2014 Sergei Golubchik and MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Password Validation Plugin API. This file defines the API for server password validation plugins. */ #define MYSQL_PLUGIN_PASSWORD_VALIDATION_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #define MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION 0x0100 /** Password validation plugin descriptor */ struct st_mariadb_password_validation { int interface_version; /**< version plugin uses */ /** Function provided by the plugin which should perform password validation and return 0 if the password has passed the validation. */ int (*validate_password)(const MYSQL_CONST_LEX_STRING *username, const MYSQL_CONST_LEX_STRING *password); }; #ifdef __cplusplus } #endif #endif plugin_data_type.h000064400000002424151030241300010234 0ustar00#ifndef MARIADB_PLUGIN_DATA_TYPE_INCLUDED #define MARIADB_PLUGIN_DATA_TYPE_INCLUDED /* Copyright (C) 2019, Alexander Barkov and MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Data Type Plugin API. This file defines the API for server plugins that manage data types. */ #ifdef __cplusplus #include /* API for data type plugins. (MariaDB_DATA_TYPE_PLUGIN) */ #define MariaDB_DATA_TYPE_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) struct st_mariadb_data_type { int interface_version; class Type_handler *type_handler; }; /** Data type plugin descriptor */ #endif /* __cplusplus */ #endif /* MARIADB_PLUGIN_DATA_TYPE_INCLUDED */ service_thd_error_context.h000064400000006540151030241300012163 0ustar00#ifndef MYSQL_SERVICE_THD_STMT_DA_INCLUDED /* Copyright (C) 2013 MariaDB Foundation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service provides access to the statement diagnostics area: - error message - error number - row for warning (e.g. for multi-row INSERT statements) */ #ifdef __cplusplus extern "C" { #endif extern struct thd_error_context_service_st { const char *(*thd_get_error_message_func)(const MYSQL_THD thd); unsigned int (*thd_get_error_number_func)(const MYSQL_THD thd); unsigned long (*thd_get_error_row_func)(const MYSQL_THD thd); void (*thd_inc_error_row_func)(MYSQL_THD thd); char *(*thd_get_error_context_description_func)(MYSQL_THD thd, char *buffer, unsigned int length, unsigned int max_query_length); } *thd_error_context_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_get_error_message(thd) \ (thd_error_context_service->thd_get_error_message_func((thd))) #define thd_get_error_number(thd) \ (thd_error_context_service->thd_get_error_number_func((thd))) #define thd_get_error_row(thd) \ (thd_error_context_service->thd_get_error_row_func((thd))) #define thd_inc_error_row(thd) \ (thd_error_context_service->thd_inc_error_row_func((thd))) #define thd_get_error_context_description(thd, buffer, length, max_query_len) \ (thd_error_context_service->thd_get_error_context_description_func((thd), \ (buffer), \ (length), \ (max_query_len))) #else /** Return error message @param thd user thread connection handle @return error text */ const char *thd_get_error_message(const MYSQL_THD thd); /** Return error number @param thd user thread connection handle @return error number */ unsigned int thd_get_error_number(const MYSQL_THD thd); /** Return the current row number (i.e. in a multiple INSERT statement) @param thd user thread connection handle @return row number */ unsigned long thd_get_error_row(const MYSQL_THD thd); /** Increment the current row number @param thd user thread connection handle */ void thd_inc_error_row(MYSQL_THD thd); /** Return a text description of a thread, its security context (user,host) and the current query. */ char *thd_get_error_context_description(MYSQL_THD thd, char *buffer, unsigned int length, unsigned int max_query_length); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_STMT_DA_INCLUDED #endif service_thd_wait.h000064400000007157151030241300010237 0ustar00/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SERVICE_THD_WAIT_INCLUDED #define MYSQL_SERVICE_THD_WAIT_INCLUDED /** @file include/mysql/service_thd_wait.h This service provides functions for plugins and storage engines to report when they are going to sleep/stall. SYNOPSIS thd_wait_begin() - call just before a wait begins thd Thread object Use NULL if the thd is NOT known. wait_type Type of wait 1 -- short wait (e.g. for mutex) 2 -- medium wait (e.g. for disk io) 3 -- large wait (e.g. for locked row/table) NOTES This is used by the threadpool to have better knowledge of which threads that currently are actively running on CPUs. When a thread reports that it's going to sleep/stall, the threadpool scheduler is free to start another thread in the pool most likely. The expected wait time is simply an indication of how long the wait is expected to become, the real wait time could be very different. thd_wait_end() called immediately after the wait is complete thd_wait_end() MUST be called if thd_wait_begin() was called. Using thd_wait_...() service is optional but recommended. Using it will improve performance as the thread pool will be more active at managing the thread workload. */ #ifdef __cplusplus extern "C" { #endif /* One should only report wait events that could potentially block for a long time. A mutex wait is too short of an event to report. The reason is that an event which is reported leads to a new thread starts executing a query and this has a negative impact of usage of CPU caches and thus the expected gain of starting a new thread must be higher than the expected cost of lost performance due to starting a new thread. Good examples of events that should be reported are waiting for row locks that could easily be for many milliseconds or even seconds and the same holds true for global read locks, table locks and other meta data locks. Another event of interest is going to sleep for an extended time. */ typedef enum _thd_wait_type_e { THD_WAIT_SLEEP= 1, THD_WAIT_DISKIO= 2, THD_WAIT_ROW_LOCK= 3, THD_WAIT_GLOBAL_LOCK= 4, THD_WAIT_META_DATA_LOCK= 5, THD_WAIT_TABLE_LOCK= 6, THD_WAIT_USER_LOCK= 7, THD_WAIT_BINLOG= 8, THD_WAIT_GROUP_COMMIT= 9, THD_WAIT_SYNC= 10, THD_WAIT_NET= 11, THD_WAIT_LAST= 12 } thd_wait_type; extern struct thd_wait_service_st { void (*thd_wait_begin_func)(MYSQL_THD, int); void (*thd_wait_end_func)(MYSQL_THD); } *thd_wait_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_wait_begin(_THD, _WAIT_TYPE) \ thd_wait_service->thd_wait_begin_func(_THD, _WAIT_TYPE) #define thd_wait_end(_THD) thd_wait_service->thd_wait_end_func(_THD) #else void thd_wait_begin(MYSQL_THD thd, int wait_type); void thd_wait_end(MYSQL_THD thd); #endif #ifdef __cplusplus } #endif #endif service_debug_sync.h000064400000032414151030241300010550 0ustar00#ifndef MYSQL_SERVICE_DEBUG_SYNC_INCLUDED /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. Copyright (c) 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file == Debug Sync Facility == The Debug Sync Facility allows placement of synchronization points in the server code by using the DEBUG_SYNC macro: open_tables(...) DEBUG_SYNC(thd, "after_open_tables"); lock_tables(...) When activated, a sync point can - Emit a signal and/or - Wait for a signal Nomenclature: - signal: A value of a global variable that persists until overwritten by a new signal. The global variable can also be seen as a "signal post" or "flag mast". Then the signal is what is attached to the "signal post" or "flag mast". - emit a signal: Assign the value (the signal) to the global variable ("set a flag") and broadcast a global condition to wake those waiting for a signal. - wait for a signal: Loop over waiting for the global condition until the global value matches the wait-for signal. By default, all sync points are inactive. They do nothing (except to burn a couple of CPU cycles for checking if they are active). A sync point becomes active when an action is requested for it. To do so, put a line like this in the test case file: SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed'; This activates the sync point 'after_open_tables'. It requests it to emit the signal 'opened' and wait for another thread to emit the signal 'flushed' when the thread's execution runs through the sync point. For every sync point there can be one action per thread only. Every thread can request multiple actions, but only one per sync point. In other words, a thread can activate multiple sync points. Here is an example how to activate and use the sync points: --connection conn1 SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed'; send INSERT INTO t1 VALUES(1); --connection conn2 SET DEBUG_SYNC= 'now WAIT_FOR opened'; SET DEBUG_SYNC= 'after_abort_locks SIGNAL flushed'; FLUSH TABLE t1; When conn1 runs through the INSERT statement, it hits the sync point 'after_open_tables'. It notices that it is active and executes its action. It emits the signal 'opened' and waits for another thread to emit the signal 'flushed'. conn2 waits immediately at the special sync point 'now' for another thread to emit the 'opened' signal. A signal remains in effect until it is overwritten. If conn1 signals 'opened' before conn2 reaches 'now', conn2 will still find the 'opened' signal. It does not wait in this case. When conn2 reaches 'after_abort_locks', it signals 'flushed', which lets conn1 awake. Normally the activation of a sync point is cleared when it has been executed. Sometimes it is necessary to keep the sync point active for another execution. You can add an execute count to the action: SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 3'; This sets the signal point's activation counter to 3. Each execution decrements the counter. After the third execution the sync point becomes inactive. One of the primary goals of this facility is to eliminate sleeps from the test suite. In most cases it should be possible to rewrite test cases so that they do not need to sleep. (But this facility cannot synchronize multiple processes.) However, to support test development, and as a last resort, sync point waiting times out. There is a default timeout, but it can be overridden: SET DEBUG_SYNC= 'name WAIT_FOR sig TIMEOUT 10 EXECUTE 2'; TIMEOUT 0 is special: If the signal is not present, the wait times out immediately. When a wait timed out (even on TIMEOUT 0), a warning is generated so that it shows up in the test result. You can throw an error message and kill the query when a synchronization point is hit a certain number of times: SET DEBUG_SYNC= 'name HIT_LIMIT 3'; Or combine it with signal and/or wait: SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 2 HIT_LIMIT 3'; Here the first two hits emit the signal, the third hit returns the error message and kills the query. For cases where you are not sure that an action is taken and thus cleared in any case, you can force to clear (deactivate) a sync point: SET DEBUG_SYNC= 'name CLEAR'; If you want to clear all actions and clear the global signal, use: SET DEBUG_SYNC= 'RESET'; This is the only way to reset the global signal to an empty string. For testing of the facility itself you can execute a sync point just as if it had been hit: SET DEBUG_SYNC= 'name TEST'; === Formal Syntax === The string to "assign" to the DEBUG_SYNC variable can contain: {RESET | TEST | CLEAR | {{SIGNAL | WAIT_FOR [TIMEOUT ]} [EXECUTE ] &| HIT_LIMIT } Here '&|' means 'and/or'. This means that one of the sections separated by '&|' must be present or both of them. === Activation/Deactivation === The facility is an optional part of the MySQL server. It is enabled in a debug server by default. ./configure --enable-debug-sync The Debug Sync Facility, when compiled in, is disabled by default. It can be enabled by a mysqld command line option: --debug-sync-timeout[=default_wait_timeout_value_in_seconds] 'default_wait_timeout_value_in_seconds' is the default timeout for the WAIT_FOR action. If set to zero, the facility stays disabled. The facility is enabled by default in the test suite, but can be disabled with: mysql-test-run.pl ... --debug-sync-timeout=0 ... Likewise the default wait timeout can be set: mysql-test-run.pl ... --debug-sync-timeout=10 ... The command line option influences the readable value of the system variable 'debug_sync'. * If the facility is not compiled in, the system variable does not exist. * If --debug-sync-timeout=0 the value of the variable reads as "OFF". * Otherwise the value reads as "ON - current signal: " followed by the current signal string, which can be empty. The readable variable value is the same, regardless if read as global or session value. Setting the 'debug-sync' system variable requires 'SUPER' privilege. You can never read back the string that you assigned to the variable, unless you assign the value that the variable does already have. But that would give a parse error. A syntactically correct string is parsed into a debug sync action and stored apart from the variable value. === Implementation === Pseudo code for a sync point: #define DEBUG_SYNC(thd, sync_point_name) if (unlikely(opt_debug_sync_timeout)) debug_sync(thd, STRING_WITH_LEN(sync_point_name)) The sync point performs a binary search in a sorted array of actions for this thread. The SET DEBUG_SYNC statement adds a requested action to the array or overwrites an existing action for the same sync point. When it adds a new action, the array is sorted again. === A typical synchronization pattern === There are quite a few places in MySQL, where we use a synchronization pattern like this: mysql_mutex_lock(&mutex); thd->enter_cond(&condition_variable, &mutex, new_message); #if defined(ENABLE_DEBUG_SYNC) if (!thd->killed && !end_of_wait_condition) DEBUG_SYNC(thd, "sync_point_name"); #endif while (!thd->killed && !end_of_wait_condition) mysql_cond_wait(&condition_variable, &mutex); thd->exit_cond(old_message); Here some explanations: thd->enter_cond() is used to register the condition variable and the mutex in thd->mysys_var. This is done to allow the thread to be interrupted (killed) from its sleep. Another thread can find the condition variable to signal and mutex to use for synchronization in this thread's THD::mysys_var. thd->enter_cond() requires the mutex to be acquired in advance. thd->exit_cond() unregisters the condition variable and mutex and releases the mutex. If you want to have a Debug Sync point with the wait, please place it behind enter_cond(). Only then you can safely decide, if the wait will be taken. Also you will have THD::proc_info correct when the sync point emits a signal. DEBUG_SYNC sets its own proc_info, but restores the previous one before releasing its internal mutex. As soon as another thread sees the signal, it does also see the proc_info from before entering the sync point. In this case it will be "new_message", which is associated with the wait that is to be synchronized. In the example above, the wait condition is repeated before the sync point. This is done to skip the sync point, if no wait takes place. The sync point is before the loop (not inside the loop) to have it hit once only. It is possible that the condition variable is signaled multiple times without the wait condition to be true. A bit off-topic: At some places, the loop is taken around the whole synchronization pattern: while (!thd->killed && !end_of_wait_condition) { mysql_mutex_lock(&mutex); thd->enter_cond(&condition_variable, &mutex, new_message); if (!thd->killed [&& !end_of_wait_condition]) { [DEBUG_SYNC(thd, "sync_point_name");] mysql_cond_wait(&condition_variable, &mutex); } thd->exit_cond(old_message); } Note that it is important to repeat the test for thd->killed after enter_cond(). Otherwise the killing thread may kill this thread after it tested thd->killed in the loop condition and before it registered the condition variable and mutex in enter_cond(). In this case, the killing thread does not know that this thread is going to wait on a condition variable. It would just set THD::killed. But if we would not test it again, we would go asleep though we are killed. If the killing thread would kill us when we are after the second test, but still before sleeping, we hold the mutex, which is registered in mysys_var. The killing thread would try to acquire the mutex before signaling the condition variable. Since the mutex is only released implicitly in mysql_cond_wait(), the signaling happens at the right place. We have a safe synchronization. === Co-work with the DBUG facility === When running the MySQL test suite with the --debug-dbug command line option, the Debug Sync Facility writes trace messages to the DBUG trace. The following shell commands proved very useful in extracting relevant information: egrep 'query:|debug_sync_exec:' mysql-test/var/log/mysqld.1.trace It shows all executed SQL statements and all actions executed by synchronization points. Sometimes it is also useful to see, which synchronization points have been run through (hit) with or without executing actions. Then add "|debug_sync_point:" to the egrep pattern. === Further reading === For a discussion of other methods to synchronize threads see http://forge.mysql.com/wiki/MySQL_Internals_Test_Synchronization For complete syntax tests, functional tests, and examples see the test case debug_sync.test. See also http://forge.mysql.com/worklog/task.php?id=4259 */ #ifndef MYSQL_ABI_CHECK #include #endif #ifdef __cplusplus extern "C" { #endif #ifdef MYSQL_DYNAMIC_PLUGIN extern void (*debug_sync_service)(MYSQL_THD, const char *, size_t); #else #define debug_sync_service debug_sync_C_callback_ptr extern void (*debug_sync_C_callback_ptr)(MYSQL_THD, const char *, size_t); #endif #ifdef ENABLED_DEBUG_SYNC #define DEBUG_SYNC(thd, name) \ do { \ if (debug_sync_service) \ debug_sync_service(thd, STRING_WITH_LEN(name)); \ } while(0) #define DEBUG_SYNC_C_IF_THD(thd, name) \ do { \ if (debug_sync_service && thd) \ debug_sync_service((MYSQL_THD) thd, STRING_WITH_LEN(name)); \ } while(0) #else #define DEBUG_SYNC(thd,name) do { } while(0) #define DEBUG_SYNC_C_IF_THD(thd, _sync_point_name_) do { } while(0) #endif /* defined(ENABLED_DEBUG_SYNC) */ /* compatibility macro */ #ifdef __cplusplus #define DEBUG_SYNC_C(name) DEBUG_SYNC(nullptr, name) #else #define DEBUG_SYNC_C(name) DEBUG_SYNC(NULL, name) #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_DEBUG_SYNC_INCLUDED #endif service_my_crypt.h000064400000010107151030241300010267 0ustar00#ifndef MYSQL_SERVICE_MY_CRYPT_INCLUDED #define MYSQL_SERVICE_MY_CRYPT_INCLUDED /* Copyright (c) 2014 Google Inc. Copyright (c) 2014, 2015 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my crypt service AES encryption functions, and a function to generate random bytes. Include my_config.h before this file to use CTR and GCM modes (they only work if server was compiled with openssl). */ #ifdef __cplusplus extern "C" { #endif /* return values from my_aes_encrypt/my_aes_decrypt functions */ #define MY_AES_OK 0 #define MY_AES_BAD_DATA -100 #define MY_AES_OPENSSL_ERROR -101 #define MY_AES_BAD_KEYSIZE -102 /* The block size for all supported algorithms */ #define MY_AES_BLOCK_SIZE 16 /* The max key length of all supported algorithms */ #define MY_AES_MAX_KEY_LENGTH 32 #define MY_AES_CTX_SIZE 1040 enum my_aes_mode { MY_AES_ECB, MY_AES_CBC #ifdef HAVE_EncryptAes128Ctr , MY_AES_CTR #endif #ifdef HAVE_EncryptAes128Gcm , MY_AES_GCM #endif }; extern struct my_crypt_service_st { int (*my_aes_crypt_init)(void *ctx, enum my_aes_mode mode, int flags, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen); int (*my_aes_crypt_update)(void *ctx, const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen); int (*my_aes_crypt_finish)(void *ctx, unsigned char *dst, unsigned int *dlen); int (*my_aes_crypt)(enum my_aes_mode mode, int flags, const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen, const unsigned char *key, unsigned int klen, const unsigned char *iv, unsigned int ivlen); unsigned int (*my_aes_get_size)(enum my_aes_mode mode, unsigned int source_length); unsigned int (*my_aes_ctx_size)(enum my_aes_mode mode); int (*my_random_bytes)(unsigned char* buf, int num); } *my_crypt_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_aes_crypt_init(A,B,C,D,E,F,G) \ my_crypt_service->my_aes_crypt_init(A,B,C,D,E,F,G) #define my_aes_crypt_update(A,B,C,D,E) \ my_crypt_service->my_aes_crypt_update(A,B,C,D,E) #define my_aes_crypt_finish(A,B,C) \ my_crypt_service->my_aes_crypt_finish(A,B,C) #define my_aes_crypt(A,B,C,D,E,F,G,H,I,J) \ my_crypt_service->my_aes_crypt(A,B,C,D,E,F,G,H,I,J) #define my_aes_get_size(A,B)\ my_crypt_service->my_aes_get_size(A,B) #define my_aes_ctx_size(A)\ my_crypt_service->my_aes_ctx_size(A) #define my_random_bytes(A,B)\ my_crypt_service->my_random_bytes(A,B) #else int my_aes_crypt_init(void *ctx, enum my_aes_mode mode, int flags, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen); int my_aes_crypt_update(void *ctx, const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen); int my_aes_crypt_finish(void *ctx, unsigned char *dst, unsigned int *dlen); int my_aes_crypt(enum my_aes_mode mode, int flags, const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen, const unsigned char *key, unsigned int klen, const unsigned char *iv, unsigned int ivlen); int my_random_bytes(unsigned char* buf, int num); unsigned int my_aes_get_size(enum my_aes_mode mode, unsigned int source_length); unsigned int my_aes_ctx_size(enum my_aes_mode mode); #endif #ifdef __cplusplus } #endif #endif /* MYSQL_SERVICE_MY_CRYPT_INCLUDED */ plugin_function.h000064400000002635151030241300010113 0ustar00#ifndef MARIADB_PLUGIN_FUNCTION_INCLUDED #define MARIADB_PLUGIN_FUNCTION_INCLUDED /* Copyright (C) 2019, Alexander Barkov and MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Function Plugin API. This file defines the API for server plugins that manage functions. */ #ifdef __cplusplus #include /* API for function plugins. (MariaDB_FUNCTION_PLUGIN) */ #define MariaDB_FUNCTION_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) class Plugin_function { int m_interface_version; Create_func *m_builder; public: Plugin_function(Create_func *builder) :m_interface_version(MariaDB_FUNCTION_INTERFACE_VERSION), m_builder(builder) { } Create_func *create_func() { return m_builder; } }; #endif /* __cplusplus */ #endif /* MARIADB_PLUGIN_FUNCTION_INCLUDED */ client_plugin.h000064400000014267151030241300007550 0ustar00#ifndef MYSQL_CLIENT_PLUGIN_INCLUDED /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab Copyright (c) 2010, 2011, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file MySQL Client Plugin API This file defines the API for plugins that work on the client side */ #define MYSQL_CLIENT_PLUGIN_INCLUDED /* On Windows, exports from DLL need to be declared Also, plugin needs to be declared as extern "C" because MSVC unlike other compilers, uses C++ mangling for variables not only for functions. */ #undef MYSQL_PLUGIN_EXPORT #if defined(_MSC_VER) #define MYSQL_PLUGIN_EXPORT_C __declspec(dllexport) #else /*_MSC_VER */ #define MYSQL_PLUGIN_EXPORT_C #endif #ifdef __cplusplus #define MYSQL_PLUGIN_EXPORT extern "C" MYSQL_PLUGIN_EXPORT_C #define C_MODE_START extern "C" { #define C_MODE_END } #else #define MYSQL_PLUGIN_EXPORT MYSQL_PLUGIN_EXPORT_C #define C_MODE_START #define C_MODE_END #endif #ifndef MYSQL_ABI_CHECK #include #include #endif /* known plugin types */ #define MYSQL_CLIENT_reserved1 0 #define MYSQL_CLIENT_reserved2 1 #define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2 #define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0100 #define MYSQL_CLIENT_MAX_PLUGINS 3 #define mysql_declare_client_plugin(X) \ C_MODE_START MYSQL_PLUGIN_EXPORT_C \ struct st_mysql_client_plugin_ ## X \ _mysql_client_plugin_declaration_ = { \ MYSQL_CLIENT_ ## X ## _PLUGIN, \ MYSQL_CLIENT_ ## X ## _PLUGIN_INTERFACE_VERSION, #define mysql_end_client_plugin }; C_MODE_END /* generic plugin header structure */ #define MYSQL_CLIENT_PLUGIN_HEADER \ int type; \ unsigned int interface_version; \ const char *name; \ const char *author; \ const char *desc; \ unsigned int version[3]; \ const char *license; \ void *mysql_api; \ int (*init)(char *, size_t, int, va_list); \ int (*deinit)(); \ int (*options)(const char *option, const void *); struct st_mysql_client_plugin { MYSQL_CLIENT_PLUGIN_HEADER }; struct st_mysql; /******** authentication plugin specific declarations *********/ #include struct st_mysql_client_plugin_AUTHENTICATION { MYSQL_CLIENT_PLUGIN_HEADER int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql); }; #include /******** using plugins ************/ /** loads a plugin and initializes it @param mysql MYSQL structure. @param name a name of the plugin to load @param type type of plugin that should be loaded, -1 to disable type check @param argc number of arguments to pass to the plugin initialization function @param ... arguments for the plugin initialization function @retval a pointer to the loaded plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, int argc, ...); /** loads a plugin and initializes it, taking va_list as an argument This is the same as mysql_load_plugin, but take va_list instead of a list of arguments. @param mysql MYSQL structure. @param name a name of the plugin to load @param type type of plugin that should be loaded, -1 to disable type check @param argc number of arguments to pass to the plugin initialization function @param args arguments for the plugin initialization function @retval a pointer to the loaded plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type, int argc, va_list args); /** finds an already loaded plugin by name, or loads it, if necessary @param mysql MYSQL structure. @param name a name of the plugin to load @param type type of plugin that should be loaded @retval a pointer to the plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type); /** adds a plugin structure to the list of loaded plugins This is useful if an application has the necessary functionality (for example, a special load data handler) statically linked into the application binary. It can use this function to register the plugin directly, avoiding the need to factor it out into a shared object. @param mysql MYSQL structure. It is only used for error reporting @param plugin an st_mysql_client_plugin structure to register @retval a pointer to the plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * mysql_client_register_plugin(struct st_mysql *mysql, struct st_mysql_client_plugin *plugin); /** set plugin options Can be used to set extra options and affect behavior for a plugin. This function may be called multiple times to set several options @param plugin an st_mysql_client_plugin structure @param option a string which specifies the option to set @param value value for the option. @retval 0 on success, 1 in case of failure **/ int mysql_plugin_options(struct st_mysql_client_plugin *plugin, const char *option, const void *value); #endif plugin_auth.h000064400000012430151030241300007221 0ustar00#ifndef MYSQL_PLUGIN_AUTH_INCLUDED /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab Copyright (c) 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Authentication Plugin API. This file defines the API for server authentication plugins. */ #define MYSQL_PLUGIN_AUTH_INCLUDED #include #define MYSQL_AUTHENTICATION_INTERFACE_VERSION 0x0202 #include #ifdef __cplusplus extern "C" { #endif /* defines for MYSQL_SERVER_AUTH_INFO.password_used */ #define PASSWORD_USED_NO 0 #define PASSWORD_USED_YES 1 #define PASSWORD_USED_NO_MENTION 2 /** Provides server plugin access to authentication information */ typedef struct st_mysql_server_auth_info { /** User name as sent by the client and shown in USER(). NULL if the client packet with the user name was not received yet. */ const char *user_name; /** Length of user_name */ unsigned int user_name_length; /** A corresponding column value from the mysql.user table for the matching account name or the preprocessed value, if preprocess_hash method is not NULL */ const char *auth_string; /** Length of auth_string */ unsigned long auth_string_length; /** Matching account name as found in the mysql.user table. A plugin can override it with another name that will be used by MySQL for authorization, and shown in CURRENT_USER() */ char authenticated_as[MYSQL_USERNAME_LENGTH+1]; /** The unique user name that was used by the plugin to authenticate. Not used by the server. Available through the @@EXTERNAL_USER variable. */ char external_user[MYSQL_USERNAME_LENGTH+1]; /** This only affects the "Authentication failed. Password used: %s" error message. has the following values : 0 : %s will be NO. 1 : %s will be YES. 2 : there will be no %s. Set it as appropriate or ignore at will. */ int password_used; /** Set to the name of the connected client host, if it can be resolved, or to its IP address otherwise. */ const char *host_or_ip; /** Length of host_or_ip */ unsigned int host_or_ip_length; /** Current THD pointer (to use with various services) */ MYSQL_THD thd; } MYSQL_SERVER_AUTH_INFO; /** Server authentication plugin descriptor */ struct st_mysql_auth { int interface_version; /**< version plugin uses */ /** A plugin that a client must use for authentication with this server plugin. Can be NULL to mean "any plugin". */ const char *client_auth_plugin; /** Function provided by the plugin which should perform authentication (using the vio functions if necessary) and return 0 if successful. The plugin can also fill the info.authenticated_as field if a different username should be used for authorization. */ int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info); /** Create a password hash (or digest) out of a plain-text password Used in SET PASSWORD, GRANT, and CREATE USER to convert user specified plain-text password into a value that will be stored in mysql.user table. @see preprocess_hash @param password plain-text password @param password_length plain-text password length @param hash the digest will be stored there @param hash_length in: hash buffer size out: the actual length of the hash @return 0 for ok, 1 for error Can be NULL, in this case one will not be able to use SET PASSWORD or PASSWORD('...') in GRANT, CREATE USER, ALTER USER. */ int (*hash_password)(const char *password, size_t password_length, char *hash, size_t *hash_length); /** Prepare the password hash for authentication. Password hash is stored in the authentication_string column of the mysql.user table in a text form. If a plugin needs to preprocess the value somehow before the authentication (e.g. convert from hex or base64 to binary), it can do it in this method. This way the conversion will happen only once, not for every authentication attempt. The value written to the out buffer will be cached and later made available to the authenticate_user() method in the MYSQL_SERVER_AUTH_INFO::auth_string[] buffer. @return 0 for ok, 1 for error Can be NULL, in this case the mysql.user.authentication_string value will be given to the authenticate_user() method as is, unconverted. */ int (*preprocess_hash)(const char *hash, size_t hash_length, unsigned char *out, size_t *out_length); }; #ifdef __cplusplus } #endif #endif plugin.h000064400000072306151030241300006210 0ustar00/* Copyright (c) 2005, 2013, Oracle and/or its affiliates Copyright (C) 2009, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_PLUGIN_INCLUDED #define MYSQL_PLUGIN_INCLUDED /* On Windows, exports from DLL need to be declared Also, plugin needs to be declared as extern "C" because MSVC unlike other compilers, uses C++ mangling for variables not only for functions. */ #ifdef MYSQL_DYNAMIC_PLUGIN #ifdef _MSC_VER #define MYSQL_DLLEXPORT _declspec(dllexport) #else #define MYSQL_DLLEXPORT #endif #else #define MYSQL_DLLEXPORT #endif #ifdef __cplusplus #define MYSQL_PLUGIN_EXPORT extern "C" MYSQL_DLLEXPORT #else #define MYSQL_PLUGIN_EXPORT MYSQL_DLLEXPORT #endif #ifdef __cplusplus class THD; class Item; #define MYSQL_THD THD* #else struct THD; typedef struct THD* MYSQL_THD; #endif typedef char my_bool; typedef void * MYSQL_PLUGIN; #include #define MYSQL_XIDDATASIZE 128 /** struct st_mysql_xid is binary compatible with the XID structure as in the X/Open CAE Specification, Distributed Transaction Processing: The XA Specification, X/Open Company Ltd., 1991. http://www.opengroup.org/bookstore/catalog/c193.htm @see XID in sql/handler.h */ struct st_mysql_xid { long formatID; long gtrid_length; long bqual_length; char data[MYSQL_XIDDATASIZE]; /* Not \0-terminated */ }; typedef struct st_mysql_xid MYSQL_XID; /************************************************************************* Plugin API. Common for all plugin types. */ /* MySQL plugin interface version */ #define MYSQL_PLUGIN_INTERFACE_VERSION 0x0104 /* MariaDB plugin interface version */ #define MARIA_PLUGIN_INTERFACE_VERSION 0x010e /* The allowable types of plugins */ #define MYSQL_UDF_PLUGIN 0 /* not implemented */ #define MYSQL_STORAGE_ENGINE_PLUGIN 1 #define MYSQL_FTPARSER_PLUGIN 2 /* Full-text parser plugin */ #define MYSQL_DAEMON_PLUGIN 3 #define MYSQL_INFORMATION_SCHEMA_PLUGIN 4 #define MYSQL_AUDIT_PLUGIN 5 #define MYSQL_REPLICATION_PLUGIN 6 #define MYSQL_AUTHENTICATION_PLUGIN 7 #define MYSQL_MAX_PLUGIN_TYPE_NUM 12 /* The number of plugin types */ /* MariaDB plugin types */ #define MariaDB_PASSWORD_VALIDATION_PLUGIN 8 #define MariaDB_ENCRYPTION_PLUGIN 9 #define MariaDB_DATA_TYPE_PLUGIN 10 #define MariaDB_FUNCTION_PLUGIN 11 /* We use the following strings to define licenses for plugins */ #define PLUGIN_LICENSE_PROPRIETARY 0 #define PLUGIN_LICENSE_GPL 1 #define PLUGIN_LICENSE_BSD 2 #define PLUGIN_LICENSE_PROPRIETARY_STRING "PROPRIETARY" #define PLUGIN_LICENSE_GPL_STRING "GPL" #define PLUGIN_LICENSE_BSD_STRING "BSD" /* definitions of code maturity for plugins */ #define MariaDB_PLUGIN_MATURITY_UNKNOWN 0 #define MariaDB_PLUGIN_MATURITY_EXPERIMENTAL 1 #define MariaDB_PLUGIN_MATURITY_ALPHA 2 #define MariaDB_PLUGIN_MATURITY_BETA 3 #define MariaDB_PLUGIN_MATURITY_GAMMA 4 #define MariaDB_PLUGIN_MATURITY_STABLE 5 /* Macros for beginning and ending plugin declarations. Between mysql_declare_plugin and mysql_declare_plugin_end there should be a st_mysql_plugin struct for each plugin to be declared. */ #ifndef MYSQL_DYNAMIC_PLUGIN #define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ int VERSION= MYSQL_PLUGIN_INTERFACE_VERSION; \ int PSIZE= sizeof(struct st_mysql_plugin); \ struct st_mysql_plugin DECLS[]= { #define MARIA_DECLARE_PLUGIN__(NAME, VERSION, PSIZE, DECLS) \ MYSQL_PLUGIN_EXPORT int VERSION; \ int VERSION= MARIA_PLUGIN_INTERFACE_VERSION; \ MYSQL_PLUGIN_EXPORT int PSIZE; \ int PSIZE= sizeof(struct st_maria_plugin); \ MYSQL_PLUGIN_EXPORT struct st_maria_plugin DECLS[]; \ struct st_maria_plugin DECLS[]= { #else #define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ MYSQL_PLUGIN_EXPORT int _mysql_plugin_interface_version_; \ int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \ MYSQL_PLUGIN_EXPORT int _mysql_sizeof_struct_st_plugin_; \ int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin); \ MYSQL_PLUGIN_EXPORT struct st_mysql_plugin _mysql_plugin_declarations_[]; \ struct st_mysql_plugin _mysql_plugin_declarations_[]= { #define MARIA_DECLARE_PLUGIN__(NAME, VERSION, PSIZE, DECLS) \ MYSQL_PLUGIN_EXPORT int _maria_plugin_interface_version_; \ int _maria_plugin_interface_version_= MARIA_PLUGIN_INTERFACE_VERSION; \ MYSQL_PLUGIN_EXPORT int _maria_sizeof_struct_st_plugin_; \ int _maria_sizeof_struct_st_plugin_= sizeof(struct st_maria_plugin); \ MYSQL_PLUGIN_EXPORT struct st_maria_plugin _maria_plugin_declarations_[]; \ struct st_maria_plugin _maria_plugin_declarations_[]= { #endif #define mysql_declare_plugin(NAME) \ __MYSQL_DECLARE_PLUGIN(NAME, \ builtin_ ## NAME ## _plugin_interface_version, \ builtin_ ## NAME ## _sizeof_struct_st_plugin, \ builtin_ ## NAME ## _plugin) #define maria_declare_plugin(NAME) \ MARIA_DECLARE_PLUGIN__(NAME, \ builtin_maria_ ## NAME ## _plugin_interface_version, \ builtin_maria_ ## NAME ## _sizeof_struct_st_plugin, \ builtin_maria_ ## NAME ## _plugin) #define mysql_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0,0}} #define maria_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0,0}} /* declarations for SHOW STATUS support in plugins */ enum enum_mysql_show_type { SHOW_UNDEF, SHOW_BOOL, SHOW_UINT, SHOW_ULONG, SHOW_ULONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE, SHOW_SINT, SHOW_SLONG, SHOW_SLONGLONG, SHOW_SIMPLE_FUNC, SHOW_SIZE_T, SHOW_always_last }; /* backward compatibility mapping. */ #define SHOW_INT SHOW_UINT #define SHOW_LONG SHOW_ULONG #define SHOW_LONGLONG SHOW_ULONGLONG enum enum_var_type { SHOW_OPT_DEFAULT= 0, SHOW_OPT_SESSION, SHOW_OPT_GLOBAL }; struct st_mysql_show_var { const char *name; void *value; enum enum_mysql_show_type type; }; struct system_status_var; #define SHOW_VAR_FUNC_BUFF_SIZE (256 * sizeof(void*)) typedef int (*mysql_show_var_func)(MYSQL_THD, struct st_mysql_show_var*, void *, struct system_status_var *status_var, enum enum_var_type); static inline struct st_mysql_show_var SHOW_FUNC_ENTRY(const char *name, mysql_show_var_func func_arg) { struct st_mysql_show_var tmp; tmp.name= name; tmp.value= (void*) func_arg; tmp.type= SHOW_FUNC; return tmp; }; /* Constants for plugin flags. */ #define PLUGIN_OPT_NO_INSTALL 1UL /* Not dynamically loadable */ #define PLUGIN_OPT_NO_UNINSTALL 2UL /* Not dynamically unloadable */ /* declarations for server variables and command line options */ #define PLUGIN_VAR_BOOL 0x0001 #define PLUGIN_VAR_INT 0x0002 #define PLUGIN_VAR_LONG 0x0003 #define PLUGIN_VAR_LONGLONG 0x0004 #define PLUGIN_VAR_STR 0x0005 #define PLUGIN_VAR_ENUM 0x0006 #define PLUGIN_VAR_SET 0x0007 #define PLUGIN_VAR_DOUBLE 0x0008 #define PLUGIN_VAR_UNSIGNED 0x0080 #define PLUGIN_VAR_THDLOCAL 0x0100 /* Variable is per-connection */ #define PLUGIN_VAR_READONLY 0x0200 /* Server variable is read only */ #define PLUGIN_VAR_NOSYSVAR 0x0400 /* Not a server variable */ #define PLUGIN_VAR_NOCMDOPT 0x0800 /* Not a command line option */ #define PLUGIN_VAR_NOCMDARG 0x1000 /* No argument for cmd line */ #define PLUGIN_VAR_RQCMDARG 0x0000 /* Argument required for cmd line */ #define PLUGIN_VAR_OPCMDARG 0x2000 /* Argument optional for cmd line */ #define PLUGIN_VAR_DEPRECATED 0x4000 /* Server variable is deprecated */ #define PLUGIN_VAR_MEMALLOC 0x8000 /* String needs memory allocated */ struct st_mysql_sys_var; struct st_mysql_value; /* SYNOPSIS (*mysql_var_check_func)() thd thread handle var dynamic variable being altered save pointer to temporary storage value user provided value RETURN 0 user provided value is OK and the update func may be called. any other value indicates error. This function should parse the user provided value and store in the provided temporary storage any data as required by the update func. There is sufficient space in the temporary storage to store a double. Note that the update func may not be called if any other error occurs so any memory allocated should be thread-local so that it may be freed automatically at the end of the statement. */ typedef int (*mysql_var_check_func)(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save, struct st_mysql_value *value); /* SYNOPSIS (*mysql_var_update_func)() thd thread handle var dynamic variable being altered var_ptr pointer to dynamic variable save pointer to temporary storage RETURN NONE This function should use the validated value stored in the temporary store and persist it in the provided pointer to the dynamic variable. For example, strings may require memory to be allocated. */ typedef void (*mysql_var_update_func)(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save); /* the following declarations are for internal use only */ #define PLUGIN_VAR_MASK \ (PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR | \ PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_NOCMDARG | \ PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_RQCMDARG | \ PLUGIN_VAR_DEPRECATED | PLUGIN_VAR_MEMALLOC) #define MYSQL_PLUGIN_VAR_HEADER \ int flags; \ const char *name; \ const char *comment; \ mysql_var_check_func check; \ mysql_var_update_func update #define MYSQL_SYSVAR_NAME(name) mysql_sysvar_ ## name #define MYSQL_SYSVAR(name) \ ((struct st_mysql_sys_var *)&(MYSQL_SYSVAR_NAME(name))) /* for global variables, the value pointer is the first element after the header, the default value is the second. for thread variables, the value offset is the first element after the header, the default value is the second. */ #define DECLARE_MYSQL_SYSVAR_BASIC(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ type *value; \ const type def_val; \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_MYSQL_SYSVAR_CONST_BASIC(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ const type *value; \ const type def_val; \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_MYSQL_SYSVAR_SIMPLE(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ type *value; type def_val; \ type min_val; type max_val; \ type blk_sz; \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_MYSQL_SYSVAR_TYPELIB(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ type *value; type def_val; \ TYPELIB *typelib; \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_THDVAR_FUNC(type) \ type *(*resolve)(MYSQL_THD thd, int offset) #define DECLARE_MYSQL_THDVAR_BASIC(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ int offset; \ const type def_val; \ DECLARE_THDVAR_FUNC(type); \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_MYSQL_THDVAR_SIMPLE(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ int offset; \ type def_val; type min_val; \ type max_val; type blk_sz; \ DECLARE_THDVAR_FUNC(type); \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_MYSQL_THDVAR_TYPELIB(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ int offset; \ const type def_val; \ DECLARE_THDVAR_FUNC(type); \ TYPELIB *typelib; \ } MYSQL_SYSVAR_NAME(name) /* the following declarations are for use by plugin implementors */ #define MYSQL_SYSVAR_BOOL(name, varname, opt, comment, check, update, def) \ DECLARE_MYSQL_SYSVAR_BASIC(name, char) = { \ PLUGIN_VAR_BOOL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def} #define MYSQL_SYSVAR_STR(name, varname, opt, comment, check, update, def) \ DECLARE_MYSQL_SYSVAR_BASIC(name, char *) = { \ PLUGIN_VAR_STR | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def} #define MYSQL_SYSVAR_CONST_STR(name, varname, opt, comment, check, update, def) \ DECLARE_MYSQL_SYSVAR_CONST_BASIC(name, char *) = { \ PLUGIN_VAR_STR | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def} #define MYSQL_SYSVAR_INT(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, int) = { \ PLUGIN_VAR_INT | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_UINT(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned int) = { \ PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_LONG(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, long) = { \ PLUGIN_VAR_LONG | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_ULONG(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned long) = { \ PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_LONGLONG(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, long long) = { \ PLUGIN_VAR_LONGLONG | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_ULONGLONG(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned long long) = { \ PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_UINT64_T(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, uint64_t) = { \ PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #ifdef _WIN64 #define MYSQL_SYSVAR_SIZE_T(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, size_t) = { \ PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #else #define MYSQL_SYSVAR_SIZE_T(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, size_t) = { \ PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #endif #define MYSQL_SYSVAR_ENUM(name, varname, opt, comment, check, update, def, typelib) \ DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long) = { \ PLUGIN_VAR_ENUM | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, typelib } #define MYSQL_SYSVAR_SET(name, varname, opt, comment, check, update, def, typelib) \ DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long long) = { \ PLUGIN_VAR_SET | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, typelib } #define MYSQL_SYSVAR_DOUBLE(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, double) = { \ PLUGIN_VAR_DOUBLE | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_THDVAR_BOOL(name, opt, comment, check, update, def) \ DECLARE_MYSQL_THDVAR_BASIC(name, char) = { \ PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, NULL} #define MYSQL_THDVAR_STR(name, opt, comment, check, update, def) \ DECLARE_MYSQL_THDVAR_BASIC(name, char *) = { \ PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, NULL} #define MYSQL_THDVAR_INT(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, int) = { \ PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_UINT(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned int) = { \ PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_LONG(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, long) = { \ PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_ULONG(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned long) = { \ PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_LONGLONG(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, long long) = { \ PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_ULONGLONG(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned long long) = { \ PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_ENUM(name, opt, comment, check, update, def, typelib) \ DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long) = { \ PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, NULL, typelib } #define MYSQL_THDVAR_SET(name, opt, comment, check, update, def, typelib) \ DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long long) = { \ PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, NULL, typelib } #define MYSQL_THDVAR_DOUBLE(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, double) = { \ PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } /* accessor macros */ #define SYSVAR(name) \ (*(MYSQL_SYSVAR_NAME(name).value)) /* when thd == null, result points to global value */ #define THDVAR(thd, name) \ (*(MYSQL_SYSVAR_NAME(name).resolve(thd, MYSQL_SYSVAR_NAME(name).offset))) /* Plugin description structure. */ struct st_mysql_plugin { int type; /* the plugin type (a MYSQL_XXX_PLUGIN value) */ void *info; /* pointer to type-specific plugin descriptor */ const char *name; /* plugin name */ const char *author; /* plugin author (for I_S.PLUGINS) */ const char *descr; /* general descriptive text (for I_S.PLUGINS) */ int license; /* the plugin license (PLUGIN_LICENSE_XXX) */ /* The function to invoke when plugin is loaded. Plugin initialisation done here should defer any ALTER TABLE queries to after the ddl recovery is done, in the signal_ddl_recovery_done() callback called by ha_signal_ddl_recovery_done(). */ int (*init)(void *); int (*deinit)(void *);/* the function to invoke when plugin is unloaded */ unsigned int version; /* plugin version (for I_S.PLUGINS) */ struct st_mysql_show_var *status_vars; struct st_mysql_sys_var **system_vars; void * __reserved1; /* reserved for dependency checking */ unsigned long flags; /* flags for plugin */ }; /* MariaDB extension for plugins declaration structure. It also copy current MySQL plugin fields to have more independency in plugins extension */ struct st_maria_plugin { int type; /* the plugin type (a MYSQL_XXX_PLUGIN value) */ void *info; /* pointer to type-specific plugin descriptor */ const char *name; /* plugin name */ const char *author; /* plugin author (for SHOW PLUGINS) */ const char *descr; /* general descriptive text (for SHOW PLUGINS ) */ int license; /* the plugin license (PLUGIN_LICENSE_XXX) */ /* The function to invoke when plugin is loaded. Plugin initialisation done here should defer any ALTER TABLE queries to after the ddl recovery is done, in the signal_ddl_recovery_done() callback called by ha_signal_ddl_recovery_done(). */ int (*init)(void *); int (*deinit)(void *);/* the function to invoke when plugin is unloaded */ unsigned int version; /* plugin version (for SHOW PLUGINS) */ struct st_mysql_show_var *status_vars; struct st_mysql_sys_var **system_vars; const char *version_info; /* plugin version string */ unsigned int maturity; /* MariaDB_PLUGIN_MATURITY_XXX */ }; /************************************************************************* API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) */ #include "plugin_ftparser.h" /************************************************************************* API for Storage Engine plugin. (MYSQL_DAEMON_PLUGIN) */ /* handlertons of different MySQL releases are incompatible */ #define MYSQL_DAEMON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) /* Here we define only the descriptor structure, that is referred from st_mysql_plugin. */ struct st_mysql_daemon { int interface_version; }; /************************************************************************* API for I_S plugin. (MYSQL_INFORMATION_SCHEMA_PLUGIN) */ /* handlertons of different MySQL releases are incompatible */ #define MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) /* Here we define only the descriptor structure, that is referred from st_mysql_plugin. */ struct st_mysql_information_schema { int interface_version; }; /************************************************************************* API for Storage Engine plugin. (MYSQL_STORAGE_ENGINE_PLUGIN) */ /* handlertons of different MySQL releases are incompatible */ #define MYSQL_HANDLERTON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) /* The real API is in the sql/handler.h Here we define only the descriptor structure, that is referred from st_mysql_plugin. */ struct st_mysql_storage_engine { int interface_version; }; struct handlerton; /* API for Replication plugin. (MYSQL_REPLICATION_PLUGIN) */ #define MYSQL_REPLICATION_INTERFACE_VERSION 0x0200 /** Replication plugin descriptor */ struct Mysql_replication { int interface_version; }; /************************************************************************* st_mysql_value struct for reading values from mysqld. Used by server variables framework to parse user-provided values. Will be used for arguments when implementing UDFs. Note that val_str() returns a string in temporary memory that will be freed at the end of statement. Copy the string if you need it to persist. */ #define MYSQL_VALUE_TYPE_STRING 0 #define MYSQL_VALUE_TYPE_REAL 1 #define MYSQL_VALUE_TYPE_INT 2 struct st_mysql_value { int (*value_type)(struct st_mysql_value *); const char *(*val_str)(struct st_mysql_value *, char *buffer, int *length); int (*val_real)(struct st_mysql_value *, double *realbuf); int (*val_int)(struct st_mysql_value *, long long *intbuf); int (*is_unsigned)(struct st_mysql_value *); }; /************************************************************************* Miscellaneous functions for plugin implementors */ #ifdef __cplusplus extern "C" { #endif int thd_in_lock_tables(const MYSQL_THD thd); int thd_tablespace_op(const MYSQL_THD thd); long long thd_test_options(const MYSQL_THD thd, long long test_options); int thd_sql_command(const MYSQL_THD thd); struct DDL_options_st; struct DDL_options_st *thd_ddl_options(const MYSQL_THD thd); void thd_storage_lock_wait(MYSQL_THD thd, long long value); int thd_tx_isolation(const MYSQL_THD thd); int thd_tx_is_read_only(const MYSQL_THD thd); /** Create a temporary file. @details The temporary file is created in a location specified by the mysql server configuration (--tmpdir option). The caller does not need to delete the file, it will be deleted automatically. @param prefix prefix for temporary file name @retval -1 error @retval >= 0 a file handle that can be passed to dup or my_close */ int mysql_tmpfile(const char *prefix); /** Return the thread id of a user thread @param thd user thread connection handle @return thread id */ unsigned long thd_get_thread_id(const MYSQL_THD thd); /** Get the XID for this connection's transaction @param thd user thread connection handle @param xid location where identifier is stored */ void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid); /** Invalidate the query cache for a given table. @param thd user thread connection handle @param key databasename\\0tablename\\0 @param key_length length of key in bytes, including the NUL bytes @param using_trx flag: TRUE if using transactions, FALSE otherwise */ void mysql_query_cache_invalidate4(MYSQL_THD thd, const char *key, unsigned int key_length, int using_trx); /** Provide a handler data getter to simplify coding */ void *thd_get_ha_data(const MYSQL_THD thd, const struct handlerton *hton); /** Provide a handler data setter to simplify coding @details Set ha_data pointer (storage engine per-connection information). To avoid unclean deactivation (uninstall) of storage engine plugin in the middle of transaction, additional storage engine plugin lock is acquired. If ha_data is not null and storage engine plugin was not locked by thd_set_ha_data() in this connection before, storage engine plugin gets locked. If ha_data is null and storage engine plugin was locked by thd_set_ha_data() in this connection before, storage engine plugin lock gets released. If handlerton::close_connection() didn't reset ha_data, server does it immediately after calling handlerton::close_connection(). */ void thd_set_ha_data(MYSQL_THD thd, const struct handlerton *hton, const void *ha_data); /** Signal that the first part of handler commit is finished, and that the committed transaction is now visible and has fixed commit ordering with respect to other transactions. The commit need _not_ be durable yet, and typically will not be when this call makes sense. This call is optional, if the storage engine does not call it the upper layer will after the handler commit() method is done. However, the storage engine may choose to call it itself to increase the possibility for group commit. In-order parallel replication uses this to apply different transaction in parallel, but delay the commits of later transactions until earlier transactions have committed first, thus achieving increased performance on multi-core systems while still preserving full transaction consistency. The storage engine can call this from within the commit() method, typically after the commit record has been written to the transaction log, but before the log has been fsync()'ed. This will allow the next replicated transaction to proceed to commit before the first one has done fsync() or similar. Thus, it becomes possible for multiple sequential replicated transactions to share a single fsync() inside the engine in group commit. Note that this method should _not_ be called from within the commit_ordered() method, or any other place in the storage engine. When commit_ordered() is used (typically when binlog is enabled), the transaction coordinator takes care of this and makes group commit in the storage engine possible without any other action needed on the part of the storage engine. This function thd_wakeup_subsequent_commits() is only needed when no transaction coordinator is used, meaning a single storage engine and no binary log. */ void thd_wakeup_subsequent_commits(MYSQL_THD thd, int wakeup_error); #ifdef __cplusplus } #endif #endif service_log_warnings.h000064400000002541151030241300011115 0ustar00/* Copyright (c) 2013, 2018, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SERVICE_LOG_WARNINGS #define MYSQL_SERVICE_LOG_WARNINGS /** @file This service provides access to the log warning level for the current session. thd_log_warnings(thd) @return thd->log_warnings */ #ifdef __cplusplus extern "C" { #endif extern struct thd_log_warnings_service_st { void *(*thd_log_warnings)(MYSQL_THD); } *thd_log_warnings_service; #ifdef MYSQL_DYNAMIC_PLUGIN # define thd_log_warnings(THD) thd_log_warnings_service->thd_log_warnings(THD) #else /** MDL_context accessor @param thd the current session @return pointer to thd->mdl_context */ int thd_log_warnings(MYSQL_THD thd); #endif #ifdef __cplusplus } #endif #endif service_thd_timezone.h000064400000004363151030241300011121 0ustar00#ifndef MYSQL_SERVICE_THD_TIMEZONE_INCLUDED /* Copyright (C) 2013 MariaDB Foundation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service provides functions to convert between my_time_t and MYSQL_TIME taking into account the current value of the time_zone session variable. The values of the my_time_t type are in Unix timestamp format, i.e. the number of seconds since "1970-01-01 00:00:00 UTC". The values of the MYSQL_TIME type are in the current time zone, according to thd->variables.time_zone. If the MYSQL_THD parameter is NULL, then global_system_variables.time_zone is used for conversion. */ #ifndef MYSQL_ABI_CHECK /* This service currently does not depend on any system headers. If it needs system headers in the future, make sure to put them inside this ifndef. */ #endif #include "mysql_time.h" #ifdef __cplusplus extern "C" { #endif extern struct thd_timezone_service_st { my_time_t (*thd_TIME_to_gmt_sec)(MYSQL_THD thd, const MYSQL_TIME *ltime, unsigned int *errcode); void (*thd_gmt_sec_to_TIME)(MYSQL_THD thd, MYSQL_TIME *ltime, my_time_t t); } *thd_timezone_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_TIME_to_gmt_sec(thd, ltime, errcode) \ (thd_timezone_service->thd_TIME_to_gmt_sec((thd), (ltime), (errcode))) #define thd_gmt_sec_to_TIME(thd, ltime, t) \ (thd_timezone_service->thd_gmt_sec_to_TIME((thd), (ltime), (t))) #else my_time_t thd_TIME_to_gmt_sec(MYSQL_THD thd, const MYSQL_TIME *ltime, unsigned int *errcode); void thd_gmt_sec_to_TIME(MYSQL_THD thd, MYSQL_TIME *ltime, my_time_t t); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_TIMEZONE_INCLUDED #endif service_md5.h000064400000004107151030241300007111 0ustar00#ifndef MYSQL_SERVICE_MD5_INCLUDED /* Copyright (c) 2014, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my md5 service Functions to calculate MD5 hash from a memory buffer */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #endif #define MY_MD5_HASH_SIZE 16 /* Hash size in bytes */ extern struct my_md5_service_st { void (*my_md5_type)(unsigned char*, const char*, size_t); void (*my_md5_multi_type)(unsigned char*, ...); size_t (*my_md5_context_size_type)(); void (*my_md5_init_type)(void *); void (*my_md5_input_type)(void *, const unsigned char *, size_t); void (*my_md5_result_type)(void *, unsigned char *); } *my_md5_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_md5(A,B,C) my_md5_service->my_md5_type(A,B,C) #define my_md5_multi my_md5_service->my_md5_multi_type #define my_md5_context_size() my_md5_service->my_md5_context_size_type() #define my_md5_init(A) my_md5_service->my_md5_init_type(A) #define my_md5_input(A,B,C) my_md5_service->my_md5_input_type(A,B,C) #define my_md5_result(A,B) my_md5_service->my_md5_result_type(A,B) #else void my_md5(unsigned char*, const char*, size_t); void my_md5_multi(unsigned char*, ...); size_t my_md5_context_size(); void my_md5_init(void *context); void my_md5_input(void *context, const unsigned char *buf, size_t len); void my_md5_result(void *context, unsigned char *digest); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_MD5_INCLUDED #endif service_wsrep.h000064400000033516151030241300007572 0ustar00#ifndef MYSQL_SERVICE_WSREP_INCLUDED #define MYSQL_SERVICE_WSREP_INCLUDED enum Wsrep_service_key_type { WSREP_SERVICE_KEY_SHARED, WSREP_SERVICE_KEY_REFERENCE, WSREP_SERVICE_KEY_UPDATE, WSREP_SERVICE_KEY_EXCLUSIVE }; #if (defined (MYSQL_DYNAMIC_PLUGIN) && defined(MYSQL_SERVICE_WSREP_DYNAMIC_INCLUDED)) || (!defined(MYSQL_DYNAMIC_PLUGIN) && defined(MYSQL_SERVICE_WSREP_STATIC_INCLUDED)) #else /* Copyright (c) 2015, 2020, MariaDB Corporation Ab 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file wsrep service Interface to WSREP functionality in the server. For engines that want to support galera. */ #include #ifdef __cplusplus #endif struct xid_t; struct wsrep_ws_handle; struct wsrep_buf; /* Must match to definition in sql/mysqld.h */ typedef int64 query_id_t; extern struct wsrep_service_st { my_bool (*get_wsrep_recovery_func)(); bool (*wsrep_consistency_check_func)(MYSQL_THD thd); int (*wsrep_is_wsrep_xid_func)(const void *xid); long long (*wsrep_xid_seqno_func)(const struct xid_t *xid); const unsigned char* (*wsrep_xid_uuid_func)(const struct xid_t *xid); my_bool (*wsrep_on_func)(const MYSQL_THD thd); bool (*wsrep_prepare_key_for_innodb_func)(MYSQL_THD thd, const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*); void (*wsrep_thd_LOCK_func)(const MYSQL_THD thd); int (*wsrep_thd_TRYLOCK_func)(const MYSQL_THD thd); void (*wsrep_thd_UNLOCK_func)(const MYSQL_THD thd); const char * (*wsrep_thd_query_func)(const MYSQL_THD thd); int (*wsrep_thd_retry_counter_func)(const MYSQL_THD thd); bool (*wsrep_thd_ignore_table_func)(MYSQL_THD thd); long long (*wsrep_thd_trx_seqno_func)(const MYSQL_THD thd); my_bool (*wsrep_thd_is_aborting_func)(const MYSQL_THD thd); void (*wsrep_set_data_home_dir_func)(const char *data_dir); my_bool (*wsrep_thd_is_BF_func)(const MYSQL_THD thd, my_bool sync); my_bool (*wsrep_thd_is_local_func)(const MYSQL_THD thd); void (*wsrep_thd_self_abort_func)(MYSQL_THD thd); int (*wsrep_thd_append_key_func)(MYSQL_THD thd, const struct wsrep_key* key, int n_keys, enum Wsrep_service_key_type); int (*wsrep_thd_append_table_key_func)(MYSQL_THD thd, const char* db, const char* table, enum Wsrep_service_key_type); my_bool (*wsrep_thd_is_local_transaction)(const MYSQL_THD thd); const char* (*wsrep_thd_client_state_str_func)(const MYSQL_THD thd); const char* (*wsrep_thd_client_mode_str_func)(const MYSQL_THD thd); const char* (*wsrep_thd_transaction_state_str_func)(const MYSQL_THD thd); query_id_t (*wsrep_thd_transaction_id_func)(const MYSQL_THD thd); my_bool (*wsrep_thd_bf_abort_func)(MYSQL_THD bf_thd, MYSQL_THD victim_thd, my_bool signal); my_bool (*wsrep_thd_order_before_func)(const MYSQL_THD left, const MYSQL_THD right); void (*wsrep_handle_SR_rollback_func)(MYSQL_THD BF_thd, MYSQL_THD victim_thd); my_bool (*wsrep_thd_skip_locking_func)(const MYSQL_THD thd); const char* (*wsrep_get_sr_table_name_func)(); my_bool (*wsrep_get_debug_func)(); void (*wsrep_commit_ordered_func)(MYSQL_THD thd); my_bool (*wsrep_thd_is_applying_func)(const MYSQL_THD thd); ulong (*wsrep_OSU_method_get_func)(const MYSQL_THD thd); my_bool (*wsrep_thd_has_ignored_error_func)(const MYSQL_THD thd); void (*wsrep_thd_set_ignored_error_func)(MYSQL_THD thd, my_bool val); void (*wsrep_report_bf_lock_wait_func)(const MYSQL_THD thd, unsigned long long trx_id); void (*wsrep_thd_kill_LOCK_func)(const MYSQL_THD thd); void (*wsrep_thd_kill_UNLOCK_func)(const MYSQL_THD thd); void (*wsrep_thd_set_wsrep_PA_unsafe_func)(MYSQL_THD thd); uint32 (*wsrep_get_domain_id_func)(); } *wsrep_service; #define MYSQL_SERVICE_WSREP_INCLUDED #endif #ifdef MYSQL_DYNAMIC_PLUGIN #define MYSQL_SERVICE_WSREP_DYNAMIC_INCLUDED #define get_wsrep_recovery() wsrep_service->get_wsrep_recovery_func() #define wsrep_consistency_check(T) wsrep_service->wsrep_consistency_check_func(T) #define wsrep_is_wsrep_xid(X) wsrep_service->wsrep_is_wsrep_xid_func(X) #define wsrep_xid_seqno(X) wsrep_service->wsrep_xid_seqno_func(X) #define wsrep_xid_uuid(X) wsrep_service->wsrep_xid_uuid_func(X) #define wsrep_on(thd) (thd) && WSREP_ON && wsrep_service->wsrep_on_func(thd) #define wsrep_prepare_key_for_innodb(A,B,C,D,E,F,G) wsrep_service->wsrep_prepare_key_for_innodb_func(A,B,C,D,E,F,G) #define wsrep_thd_LOCK(T) wsrep_service->wsrep_thd_LOCK_func(T) #define wsrep_thd_TRYLOCK(T) wsrep_service->wsrep_thd_TRYLOCK_func(T) #define wsrep_thd_UNLOCK(T) wsrep_service->wsrep_thd_UNLOCK_func(T) #define wsrep_thd_kill_LOCK(T) wsrep_service->wsrep_thd_kill_LOCK_func(T) #define wsrep_thd_kill_UNLOCK(T) wsrep_service->wsrep_thd_kill_UNLOCK_func(T) #define wsrep_thd_query(T) wsrep_service->wsrep_thd_query_func(T) #define wsrep_thd_retry_counter(T) wsrep_service->wsrep_thd_retry_counter_func(T) #define wsrep_thd_ignore_table(T) wsrep_service->wsrep_thd_ignore_table_func(T) #define wsrep_thd_trx_seqno(T) wsrep_service->wsrep_thd_trx_seqno_func(T) #define wsrep_set_data_home_dir(A) wsrep_service->wsrep_set_data_home_dir_func(A) #define wsrep_thd_is_BF(T,S) wsrep_service->wsrep_thd_is_BF_func(T,S) #define wsrep_thd_is_aborting(T) wsrep_service->wsrep_thd_is_aborting_func(T) #define wsrep_thd_is_local(T) wsrep_service->wsrep_thd_is_local_func(T) #define wsrep_thd_self_abort(T) wsrep_service->wsrep_thd_self_abort_func(T) #define wsrep_thd_append_key(T,W,N,K) wsrep_service->wsrep_thd_append_key_func(T,W,N,K) #define wsrep_thd_append_table_key(T,D,B,K) wsrep_service->wsrep_thd_append_table_key_func(T,D,B,K) #define wsrep_thd_is_local_transaction(T) wsrep_service->wsrep_thd_is_local_transaction_func(T) #define wsrep_thd_client_state_str(T) wsrep_service->wsrep_thd_client_state_str_func(T) #define wsrep_thd_client_mode_str(T) wsrep_service->wsrep_thd_client_mode_str_func(T) #define wsrep_thd_transaction_state_str(T) wsrep_service->wsrep_thd_transaction_state_str_func(T) #define wsrep_thd_transaction_id(T) wsrep_service->wsrep_thd_transaction_id_func(T) #define wsrep_thd_bf_abort(T,T2,S) wsrep_service->wsrep_thd_bf_abort_func(T,T2,S) #define wsrep_thd_order_before(L,R) wsrep_service->wsrep_thd_order_before_func(L,R) #define wsrep_handle_SR_rollback(B,V) wsrep_service->wsrep_handle_SR_rollback_func(B,V) #define wsrep_thd_skip_locking(T) wsrep_service->wsrep_thd_skip_locking_func(T) #define wsrep_get_sr_table_name() wsrep_service->wsrep_get_sr_table_name_func() #define wsrep_get_debug() wsrep_service->wsrep_get_debug_func() #define wsrep_commit_ordered(T) wsrep_service->wsrep_commit_ordered_func(T) #define wsrep_thd_is_applying(T) wsrep_service->wsrep_thd_is_applying_func(T) #define wsrep_OSU_method_get(T) wsrep_service->wsrep_OSU_method_get_func(T) #define wsrep_thd_has_ignored_error(T) wsrep_service->wsrep_thd_has_ignored_error_func(T) #define wsrep_thd_set_ignored_error(T,V) wsrep_service->wsrep_thd_set_ignored_error_func(T,V) #define wsrep_report_bf_lock_wait(T,I) wsrep_service->wsrep_report_bf_lock_wait(T,I) #define wsrep_thd_set_PA_unsafe(T) wsrep_service->wsrep_thd_set_PA_unsafe_func(T) #define wsrep_get_domain_id(T) wsrep_service->wsrep_get_domain_id_func(T) #else #define MYSQL_SERVICE_WSREP_STATIC_INCLUDED extern ulong wsrep_debug; extern my_bool wsrep_log_conflicts; extern my_bool wsrep_certify_nonPK; extern my_bool wsrep_load_data_splitting; extern my_bool wsrep_drupal_282555_workaround; extern my_bool wsrep_recovery; extern long wsrep_protocol_version; extern "C" bool wsrep_consistency_check(MYSQL_THD thd); bool wsrep_prepare_key_for_innodb(MYSQL_THD thd, const unsigned char* cache_key, size_t cache_key_len, const unsigned char* row_id, size_t row_id_len, struct wsrep_buf* key, size_t* key_len); extern "C" const char *wsrep_thd_query(const MYSQL_THD thd); extern "C" int wsrep_is_wsrep_xid(const void* xid); extern "C" long long wsrep_xid_seqno(const struct xid_t* xid); const unsigned char* wsrep_xid_uuid(const struct xid_t* xid); extern "C" long long wsrep_thd_trx_seqno(const MYSQL_THD thd); my_bool get_wsrep_recovery(); bool wsrep_thd_ignore_table(MYSQL_THD thd); void wsrep_set_data_home_dir(const char *data_dir); /* from mysql wsrep-lib */ #include "my_global.h" #include "my_pthread.h" /* Return true if wsrep is enabled for a thd. This means that wsrep is enabled globally and the thd has wsrep on */ extern "C" my_bool wsrep_on(const MYSQL_THD thd); /* Lock thd wsrep lock */ extern "C" void wsrep_thd_LOCK(const MYSQL_THD thd); /* Try thd wsrep lock. Return non-zero if lock could not be taken. */ extern "C" int wsrep_thd_TRYLOCK(const MYSQL_THD thd); /* Unlock thd wsrep lock */ extern "C" void wsrep_thd_UNLOCK(const MYSQL_THD thd); extern "C" void wsrep_thd_kill_LOCK(const MYSQL_THD thd); extern "C" void wsrep_thd_kill_UNLOCK(const MYSQL_THD thd); /* Return thd client state string */ extern "C" const char* wsrep_thd_client_state_str(const MYSQL_THD thd); /* Return thd client mode string */ extern "C" const char* wsrep_thd_client_mode_str(const MYSQL_THD thd); /* Return thd transaction state string */ extern "C" const char* wsrep_thd_transaction_state_str(const MYSQL_THD thd); /* Return current transaction id */ extern "C" query_id_t wsrep_thd_transaction_id(const MYSQL_THD thd); /* Mark thd own transaction as aborted */ extern "C" void wsrep_thd_self_abort(MYSQL_THD thd); /* Return true if thd is in replicating mode */ extern "C" my_bool wsrep_thd_is_local(const MYSQL_THD thd); /* Return true if thd is in high priority mode */ /* todo: rename to is_high_priority() */ extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd); /* Return true if thd is in TOI mode */ extern "C" my_bool wsrep_thd_is_toi(const MYSQL_THD thd); /* Return true if thd is in replicating TOI mode */ extern "C" my_bool wsrep_thd_is_local_toi(const MYSQL_THD thd); /* Return true if thd is in RSU mode */ extern "C" my_bool wsrep_thd_is_in_rsu(const MYSQL_THD thd); /* Return true if thd is in BF mode, either high_priority or TOI */ extern "C" my_bool wsrep_thd_is_BF(const MYSQL_THD thd, my_bool sync); /* Return true if thd is streaming in progress */ extern "C" my_bool wsrep_thd_is_SR(const MYSQL_THD thd); extern "C" void wsrep_handle_SR_rollback(MYSQL_THD BF_thd, MYSQL_THD victim_thd); /* Return thd retry counter */ extern "C" int wsrep_thd_retry_counter(const MYSQL_THD thd); /* BF abort victim_thd */ extern "C" my_bool wsrep_thd_bf_abort(MYSQL_THD bf_thd, MYSQL_THD victim_thd, my_bool signal); /* Return true if left thd is ordered before right thd */ extern "C" my_bool wsrep_thd_order_before(const MYSQL_THD left, const MYSQL_THD right); /* Return true if thd should skip locking. This means that the thd is operating on shared resource inside commit order critical section. */ extern "C" my_bool wsrep_thd_skip_locking(const MYSQL_THD thd); /* Return true if thd is aborting */ extern "C" my_bool wsrep_thd_is_aborting(const MYSQL_THD thd); struct wsrep_key; struct wsrep_key_array; extern "C" int wsrep_thd_append_key(MYSQL_THD thd, const struct wsrep_key* key, int n_keys, enum Wsrep_service_key_type); extern "C" int wsrep_thd_append_table_key(MYSQL_THD thd, const char* db, const char* table, enum Wsrep_service_key_type); extern "C" my_bool wsrep_thd_is_local_transaction(const MYSQL_THD thd); extern const char* wsrep_sr_table_name_full; extern "C" const char* wsrep_get_sr_table_name(); extern "C" my_bool wsrep_get_debug(); extern "C" void wsrep_commit_ordered(MYSQL_THD thd); extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd); extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd); extern "C" my_bool wsrep_thd_has_ignored_error(const MYSQL_THD thd); extern "C" void wsrep_thd_set_ignored_error(MYSQL_THD thd, my_bool val); extern "C" void wsrep_report_bf_lock_wait(const THD *thd, unsigned long long trx_id); /* declare parallel applying unsafety for the THD */ extern "C" void wsrep_thd_set_PA_unsafe(MYSQL_THD thd); extern "C" uint32 wsrep_get_domain_id(); #endif #endif /* MYSQL_SERVICE_WSREP_INCLUDED */ service_thd_rnd.h000064400000003556151030241300010055 0ustar00#ifndef MYSQL_SERVICE_THD_RND_INCLUDED /* Copyright (C) 2017 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service provides access to the thd-local random number generator. It's preferable over the global one, because concurrent threads can generate random numbers without fighting each other over the access to the shared rnd state. */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #endif extern struct thd_rnd_service_st { double (*thd_rnd_ptr)(MYSQL_THD thd); void (*thd_c_r_p_ptr)(MYSQL_THD thd, char *to, size_t length); } *thd_rnd_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_rnd(A) thd_rnd_service->thd_rnd_ptr(A) #define thd_create_random_password(A,B,C) thd_rnd_service->thd_c_r_p_ptr(A,B,C) #else double thd_rnd(MYSQL_THD thd); /** Generate string of printable random characters of requested length. @param to[out] Buffer for generation; must be at least length+1 bytes long; result string is always null-terminated @param length[in] How many random characters to put in buffer */ void thd_create_random_password(MYSQL_THD thd, char *to, size_t length); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_RND_INCLUDED #endif service_logger.h000064400000006737151030241300007716 0ustar00/* Copyright (C) 2012 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SERVICE_LOGGER_INCLUDED #define MYSQL_SERVICE_LOGGER_INCLUDED #ifndef MYSQL_ABI_CHECK #include #endif /** @file logger service Log file with rotation implementation. This service implements logging with possible rotation of the log files. Interface intentionally tries to be similar to FILE* related functions. So that one can open the log with logger_open(), specifying the limit on the logfile size and the rotations number. Then it's possible to write messages to the log with logger_printf or logger_vprintf functions. As the size of the logfile grows over the specified limit, it is renamed to 'logfile.1'. The former 'logfile.1' becomes 'logfile.2', etc. The file 'logfile.rotations' is removed. That's how the rotation works. The rotation can be forced with the logger_rotate() call. Finally the log should be closed with logger_close(). @notes: Implementation checks the size of the log file before it starts new printf into it. So the size of the file gets over the limit when it rotates. The access is secured with the mutex, so the log is threadsafe. */ #ifdef __cplusplus extern "C" { #endif typedef struct logger_handle_st LOGGER_HANDLE; extern struct logger_service_st { void (*logger_init_mutexes)(); LOGGER_HANDLE* (*open)(const char *path, unsigned long long size_limit, unsigned int rotations); int (*close)(LOGGER_HANDLE *log); int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr); int (*printf)(LOGGER_HANDLE *log, const char *fmt, ...); int (*write)(LOGGER_HANDLE *log, const char *buffer, size_t size); int (*rotate)(LOGGER_HANDLE *log); } *logger_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define logger_init_mutexes logger_service->logger_init_mutexes #define logger_open(path, size_limit, rotations) \ (logger_service->open(path, size_limit, rotations)) #define logger_close(log) (logger_service->close(log)) #define logger_rotate(log) (logger_service->rotate(log)) #define logger_vprintf(log, fmt, argptr) (logger_service->\ vprintf(log, fmt, argptr)) #define logger_printf (*logger_service->printf) #define logger_write(log, buffer, size) \ (logger_service->write(log, buffer, size)) #else void logger_init_mutexes(); LOGGER_HANDLE *logger_open(const char *path, unsigned long long size_limit, unsigned int rotations); int logger_close(LOGGER_HANDLE *log); int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list argptr); int logger_printf(LOGGER_HANDLE *log, const char *fmt, ...); int logger_write(LOGGER_HANDLE *log, const char *buffer, size_t size); int logger_rotate(LOGGER_HANDLE *log); #endif #ifdef __cplusplus } #endif #endif /*MYSQL_SERVICE_LOGGER_INCLUDED*/ plugin_ftparser.h000064400000017230151030241300010111 0ustar00/* Copyright (c) 2005 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_plugin_ftparser_h #define _my_plugin_ftparser_h #include "plugin.h" #ifdef __cplusplus extern "C" { #endif /************************************************************************* API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) */ #define MYSQL_FTPARSER_INTERFACE_VERSION 0x0100 /* Parsing modes. Set in MYSQL_FTPARSER_PARAM::mode */ enum enum_ftparser_mode { /* Fast and simple mode. This mode is used for indexing, and natural language queries. The parser is expected to return only those words that go into the index. Stopwords or too short/long words should not be returned. The 'boolean_info' argument of mysql_add_word() does not have to be set. */ MYSQL_FTPARSER_SIMPLE_MODE= 0, /* Parse with stopwords mode. This mode is used in boolean searches for "phrase matching." The parser is not allowed to ignore words in this mode. Every word should be returned, including stopwords and words that are too short or long. The 'boolean_info' argument of mysql_add_word() does not have to be set. */ MYSQL_FTPARSER_WITH_STOPWORDS= 1, /* Parse in boolean mode. This mode is used to parse a boolean query string. The parser should provide a valid MYSQL_FTPARSER_BOOLEAN_INFO structure in the 'boolean_info' argument to mysql_add_word(). Usually that means that the parser should recognize boolean operators in the parsing stream and set appropriate fields in MYSQL_FTPARSER_BOOLEAN_INFO structure accordingly. As for MYSQL_FTPARSER_WITH_STOPWORDS mode, no word should be ignored. Instead, use FT_TOKEN_STOPWORD for the token type of such a word. */ MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2 }; /* Token types for boolean mode searching (used for the type member of MYSQL_FTPARSER_BOOLEAN_INFO struct) FT_TOKEN_EOF: End of data. FT_TOKEN_WORD: Regular word. FT_TOKEN_LEFT_PAREN: Left parenthesis (start of group/sub-expression). FT_TOKEN_RIGHT_PAREN: Right parenthesis (end of group/sub-expression). FT_TOKEN_STOPWORD: Stopword. */ enum enum_ft_token_type { FT_TOKEN_EOF= 0, FT_TOKEN_WORD= 1, FT_TOKEN_LEFT_PAREN= 2, FT_TOKEN_RIGHT_PAREN= 3, FT_TOKEN_STOPWORD= 4 }; /* This structure is used in boolean search mode only. It conveys boolean-mode metadata to the MySQL search engine for every word in the search query. A valid instance of this structure must be filled in by the plugin parser and passed as an argument in the call to mysql_add_word (the callback function in the MYSQL_FTPARSER_PARAM structure) when a query is parsed in boolean mode. type: The token type. Should be one of the enum_ft_token_type values. yesno: Whether the word must be present for a match to occur: >0 Must be present <0 Must not be present 0 Neither; the word is optional but its presence increases the relevance With the default settings of the ft_boolean_syntax system variable, >0 corresponds to the '+' operator, <0 corresponds to the '-' operator, and 0 means neither operator was used. weight_adjust: A weighting factor that determines how much a match for the word counts. Positive values increase, negative - decrease the relative word's importance in the query. wasign: The sign of the word's weight in the query. If it's non-negative the match for the word will increase document relevance, if it's negative - decrease (the word becomes a "noise word", the less of it the better). trunc: Corresponds to the '*' operator in the default setting of the ft_boolean_syntax system variable. */ typedef struct st_mysql_ftparser_boolean_info { enum enum_ft_token_type type; int yesno; int weight_adjust; char wasign; char trunc; /* These are parser state and must be removed. */ char prev; char *quot; } MYSQL_FTPARSER_BOOLEAN_INFO; /* The following flag means that buffer with a string (document, word) may be overwritten by the caller before the end of the parsing (that is before st_mysql_ftparser::deinit() call). If one needs the string to survive between two successive calls of the parsing function, she needs to save a copy of it. The flag may be set by MySQL before calling st_mysql_ftparser::parse(), or it may be set by a plugin before calling st_mysql_ftparser_param::mysql_parse() or st_mysql_ftparser_param::mysql_add_word(). */ #define MYSQL_FTFLAGS_NEED_COPY 1 /* An argument of the full-text parser plugin. This structure is filled in by MySQL server and passed to the parsing function of the plugin as an in/out parameter. mysql_parse: A pointer to the built-in parser implementation of the server. It's set by the server and can be used by the parser plugin to invoke the MySQL default parser. If plugin's role is to extract textual data from .doc, .pdf or .xml content, it might extract plaintext from the content, and then pass the text to the default MySQL parser to be parsed. mysql_add_word: A server callback to add a new word. When parsing a document, the server sets this to point at a function that adds the word to MySQL full-text index. When parsing a search query, this function will add the new word to the list of words to search for. The boolean_info argument can be NULL for all cases except when mode is MYSQL_FTPARSER_FULL_BOOLEAN_INFO. A plugin can replace this callback to post-process every parsed word before passing it to the original mysql_add_word function. ftparser_state: A generic pointer. The plugin can set it to point to information to be used internally for its own purposes. mysql_ftparam: This is set by the server. It is used by MySQL functions called via mysql_parse() and mysql_add_word() callback. The plugin should not modify it. cs: Information about the character set of the document or query string. doc: A pointer to the document or query string to be parsed. length: Length of the document or query string, in bytes. flags: See MYSQL_FTFLAGS_* constants above. mode: The parsing mode. With boolean operators, with stopwords, or nothing. See enum_ftparser_mode above. */ typedef struct st_mysql_ftparser_param { int (*mysql_parse)(struct st_mysql_ftparser_param *, const char *doc, int doc_len); int (*mysql_add_word)(struct st_mysql_ftparser_param *, const char *word, int word_len, MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info); void *ftparser_state; void *mysql_ftparam; const struct charset_info_st *cs; const char *doc; int length; unsigned int flags; enum enum_ftparser_mode mode; } MYSQL_FTPARSER_PARAM; /* Full-text parser descriptor. interface_version is, e.g., MYSQL_FTPARSER_INTERFACE_VERSION. The parsing, initialization, and deinitialization functions are invoked per SQL statement for which the parser is used. */ struct st_mysql_ftparser { int interface_version; int (*parse)(MYSQL_FTPARSER_PARAM *param); int (*init)(MYSQL_FTPARSER_PARAM *param); int (*deinit)(MYSQL_FTPARSER_PARAM *param); }; #ifdef __cplusplus } #endif #endif service_sql.h000064400000012016151030241300007221 0ustar00/* Copyright (C) 2021 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #ifndef MYSQL_SERVICE_SQL #define MYSQL_SERVICE_SQL #ifndef MYSQL_ABI_CHECK #include #endif /** @file SQL service Interface for plugins to execute SQL queries on the local server. Functions of the service are the 'server-limited' client library: mysql_init mysql_real_connect_local mysql_real_connect mysql_errno mysql_error mysql_real_query mysql_affected_rows mysql_num_rows mysql_store_result mysql_free_result mysql_fetch_row mysql_close */ #ifdef __cplusplus extern "C" { #endif extern struct sql_service_st { MYSQL *(STDCALL *mysql_init_func)(MYSQL *mysql); MYSQL *(*mysql_real_connect_local_func)(MYSQL *mysql); MYSQL *(STDCALL *mysql_real_connect_func)(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); unsigned int(STDCALL *mysql_errno_func)(MYSQL *mysql); const char *(STDCALL *mysql_error_func)(MYSQL *mysql); int (STDCALL *mysql_real_query_func)(MYSQL *mysql, const char *q, unsigned long length); my_ulonglong (STDCALL *mysql_affected_rows_func)(MYSQL *mysql); my_ulonglong (STDCALL *mysql_num_rows_func)(MYSQL_RES *res); MYSQL_RES *(STDCALL *mysql_store_result_func)(MYSQL *mysql); void (STDCALL *mysql_free_result_func)(MYSQL_RES *result); MYSQL_ROW (STDCALL *mysql_fetch_row_func)(MYSQL_RES *result); void (STDCALL *mysql_close_func)(MYSQL *mysql); int (STDCALL *mysql_options_func)(MYSQL *mysql, enum mysql_option option, const void *arg); unsigned long *(STDCALL *mysql_fetch_lengths_func)(MYSQL_RES *res); int (STDCALL *mysql_set_character_set_func)(MYSQL *mysql, const char *cs_name); unsigned int (STDCALL *mysql_num_fields_func)(MYSQL_RES *res); int (STDCALL *mysql_select_db_func)(MYSQL *mysql, const char *db); MYSQL_RES *(STDCALL *mysql_use_result_func)(MYSQL *mysql); MYSQL_FIELD *(STDCALL *mysql_fetch_fields_func)(MYSQL_RES *res); unsigned long (STDCALL *mysql_real_escape_string_func)(MYSQL *mysql, char *to, const char *from, unsigned long length); my_bool (STDCALL *mysql_ssl_set_func)(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); } *sql_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define mysql_init(M) sql_service->mysql_init_func(M) #define mysql_real_connect_local(M) sql_service->mysql_real_connect_local_func(M) #define mysql_real_connect(M,H,U,PW,D,P,S,F) sql_service->mysql_real_connect_func(M,H,U,PW,D,P,S,F) #define mysql_errno(M) sql_service->mysql_errno_func(M) #define mysql_error(M) sql_service->mysql_error_func(M) #define mysql_real_query sql_service->mysql_real_query_func #define mysql_affected_rows(M) sql_service->mysql_affected_rows_func(M) #define mysql_num_rows(R) sql_service->mysql_num_rows_func(R) #define mysql_store_result(M) sql_service->mysql_store_result_func(M) #define mysql_free_result(R) sql_service->mysql_free_result_func(R) #define mysql_fetch_row(R) sql_service->mysql_fetch_row_func(R) #define mysql_close(M) sql_service->mysql_close_func(M) #define mysql_options(M,O,V) sql_service->mysql_options_func(M,O,V) #define mysql_fetch_lengths(R) sql_service->mysql_fetch_lengths_func(R) #define mysql_set_character_set(M,C) sql_service->mysql_set_character_set_func(M,C) #define mysql_num_fields(R) sql_service->mysql_num_fields_func(R) #define mysql_select_db(M,D) sql_service->mysql_select_db_func(M,D) #define mysql_use_result(M) sql_service->mysql_use_result_func(M) #define mysql_fetch_fields(R) sql_service->mysql_fetch_fields_func(R) #define mysql_real_escape_string(M,T,F,L) sql_service->mysql_real_escape_string_func(M,T,F,L) #define mysql_ssl_set(M,K,C1,C2,C3,C4) sql_service->mysql_ssl_set_func(M,K,C1,C2,C3,C4) #else /* Establishes the connection to the 'local' server that started the plugin. Like the mysql_real_connect() does for the remote server. The established connection has no user/host associated to it, neither it has the current db, so the queries should have database/table name specified. */ MYSQL *mysql_real_connect_local(MYSQL *mysql); /* The rest of the function declarations must be taken from the mysql.h */ #endif /*MYSQL_DYNAMIC_PLUGIN*/ #ifdef __cplusplus } #endif #endif /*MYSQL_SERVICE_SQL */ service_my_print_error.h000064400000004430151030241300011475 0ustar00/* Copyright (c) 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SERVICE_MY_PRINT_ERROR_INCLUDED #define MYSQL_SERVICE_MY_PRINT_ERROR_INCLUDED /** @file include/mysql/service_my_print_error.h This service provides functions for plugins to report errors to client (without client, the errors are written to the error log). */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #include #endif #define ME_ERROR_LOG 64 /* Write the message to the error log */ #define ME_ERROR_LOG_ONLY 128 /* Write the error message to error log only */ #define ME_NOTE 1024 /* Not an error, just a note */ #define ME_WARNING 2048 /* Not an error, just a warning */ #define ME_FATAL 4096 /* Fatal statement error */ extern struct my_print_error_service_st { void (*my_error_func)(unsigned int nr, unsigned long MyFlags, ...); void (*my_printf_error_func)(unsigned int nr, const char *fmt, unsigned long MyFlags,...); void (*my_printv_error_func)(unsigned int error, const char *format, unsigned long MyFlags, va_list ap); } *my_print_error_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_error my_print_error_service->my_error_func #define my_printf_error my_print_error_service->my_printf_error_func #define my_printv_error(A,B,C,D) my_print_error_service->my_printv_error_func(A,B,C,D) #else extern void my_error(unsigned int nr, unsigned long MyFlags, ...); extern void my_printf_error(unsigned int my_err, const char *format, unsigned long MyFlags, ...); extern void my_printv_error(unsigned int error, const char *format, unsigned long MyFlags,va_list ap); #endif /* MYSQL_DYNAMIC_PLUGIN */ #ifdef __cplusplus } #endif #endif services.h000064400000003342151030241300006527 0ustar00#ifndef MYSQL_SERVICES_INCLUDED /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. Copyright (c) 2012, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*#include */ #include #ifdef __cplusplus } #endif #define MYSQL_SERVICES_INCLUDED #endif service_thd_mdl.h000064400000002402151030241300010033 0ustar00/* Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #pragma once /** @file include/mysql/service_thd_mdl.h This service provides functions for plugins and storage engines to access metadata locks. */ #ifdef __cplusplus extern "C" { #endif extern struct thd_mdl_service_st { void *(*thd_mdl_context)(MYSQL_THD); } *thd_mdl_service; #ifdef MYSQL_DYNAMIC_PLUGIN # define thd_mdl_context(_THD) thd_mdl_service->thd_mdl_context(_THD) #else /** MDL_context accessor @param thd the current session @return pointer to thd->mdl_context */ void *thd_mdl_context(MYSQL_THD thd); #endif #ifdef __cplusplus } #endif psi/mysql_socket.h000064400000106615151030241300010223 0ustar00/* Copyright (c) 2010, 2023, Oracle and/or its affiliates. Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SOCKET_H #define MYSQL_SOCKET_H /* For MY_STAT */ #include /* For my_chsize */ #include /* For socket api */ #ifdef _WIN32 #include #include #include #define SOCKBUF_T char #else #include #define SOCKBUF_T void #endif /** @file mysql/psi/mysql_socket.h [...] */ #include "mysql/psi/psi.h" #ifndef PSI_SOCKET_CALL #define PSI_SOCKET_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Socket_instrumentation Socket Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_socket_register(P1, P2, P3) Socket registration. */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_register(P1, P2, P3) \ inline_mysql_socket_register(P1, P2, P3) #else #define mysql_socket_register(P1, P2, P3) \ do {} while (0) #endif /** An instrumented socket. */ struct st_mysql_socket { /** The real socket descriptor. */ my_socket fd; /** Is this a Unix-domain socket? */ char is_unix_domain_socket; /** Is this a socket opened for the extra port? */ char is_extra_port; /** Address family of the socket. (See sa_family from struct sockaddr). */ unsigned short address_family; /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c MYSQL_SOCKET interface. */ struct PSI_socket *m_psi; }; /** An instrumented socket. @c MYSQL_SOCKET is a replacement for @c my_socket. */ typedef struct st_mysql_socket MYSQL_SOCKET; /** @def MYSQL_INVALID_SOCKET MYSQL_SOCKET initial value. */ //MYSQL_SOCKET MYSQL_INVALID_SOCKET= {INVALID_SOCKET, NULL}; #define MYSQL_INVALID_SOCKET mysql_socket_invalid() /** MYSQL_SOCKET helper. Initialize instrumented socket. @sa mysql_socket_getfd @sa mysql_socket_setfd */ static inline MYSQL_SOCKET mysql_socket_invalid() { MYSQL_SOCKET mysql_socket= {INVALID_SOCKET, 0, 0, 0, NULL}; return mysql_socket; } /** Set socket descriptor and address. @param socket nstrumented socket @param addr unformatted socket address @param addr_len length of socket address */ static inline void mysql_socket_set_address( #ifdef HAVE_PSI_SOCKET_INTERFACE MYSQL_SOCKET socket, const struct sockaddr *addr, socklen_t addr_len #else MYSQL_SOCKET socket __attribute__ ((unused)), const struct sockaddr *addr __attribute__ ((unused)), socklen_t addr_len __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_SOCKET_INTERFACE if (socket.m_psi != NULL) PSI_SOCKET_CALL(set_socket_info)(socket.m_psi, NULL, addr, addr_len); #endif } /** Set socket descriptor and address. @param socket instrumented socket */ static inline void mysql_socket_set_thread_owner( #ifdef HAVE_PSI_SOCKET_INTERFACE MYSQL_SOCKET socket #else MYSQL_SOCKET socket __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_SOCKET_INTERFACE if (socket.m_psi != NULL) PSI_SOCKET_CALL(set_socket_thread_owner)(socket.m_psi); #endif } /** MYSQL_SOCKET helper. Get socket descriptor. @param mysql_socket Instrumented socket @sa mysql_socket_getfd */ static inline my_socket mysql_socket_getfd(MYSQL_SOCKET mysql_socket) { return mysql_socket.fd; } /** MYSQL_SOCKET helper. Set socket descriptor. @param mysql_socket Instrumented socket @param fd Socket descriptor @sa mysql_socket_setfd */ static inline void mysql_socket_setfd(MYSQL_SOCKET *mysql_socket, my_socket fd) { if (likely(mysql_socket != NULL)) mysql_socket->fd= fd; } /** @def MYSQL_SOCKET_WAIT_VARIABLES Instrumentation helper for socket waits. This instrumentation declares local variables. Do not use a ';' after this macro @param LOCKER locker @param STATE locker state @sa MYSQL_START_SOCKET_WAIT. @sa MYSQL_END_SOCKET_WAIT. */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define MYSQL_SOCKET_WAIT_VARIABLES(LOCKER, STATE) \ struct PSI_socket_locker* LOCKER; \ PSI_socket_locker_state STATE; #else #define MYSQL_SOCKET_WAIT_VARIABLES(LOCKER, STATE) #endif /** @def MYSQL_START_SOCKET_WAIT Instrumentation helper for socket waits. This instrumentation marks the start of a wait event. @param LOCKER locker @param STATE locker state @param SOCKET instrumented socket @param OP The socket operation to be performed @param COUNT bytes to be written/read @sa MYSQL_END_SOCKET_WAIT. */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define MYSQL_START_SOCKET_WAIT(LOCKER, STATE, SOCKET, OP, COUNT) \ LOCKER= inline_mysql_start_socket_wait(STATE, SOCKET, OP, COUNT,\ __FILE__, __LINE__) #else #define MYSQL_START_SOCKET_WAIT(LOCKER, STATE, SOCKET, OP, COUNT) \ do {} while (0) #endif /** @def MYSQL_END_SOCKET_WAIT Instrumentation helper for socket waits. This instrumentation marks the end of a wait event. @param LOCKER locker @param COUNT actual bytes written/read, or -1 @sa MYSQL_START_SOCKET_WAIT. */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define MYSQL_END_SOCKET_WAIT(LOCKER, COUNT) \ inline_mysql_end_socket_wait(LOCKER, COUNT) #else #define MYSQL_END_SOCKET_WAIT(LOCKER, COUNT) \ do {} while (0) #endif /** @def MYSQL_SOCKET_SET_STATE Set the state (IDLE, ACTIVE) of an instrumented socket. @param SOCKET the instrumented socket @param STATE the new state @sa PSI_socket_state */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define MYSQL_SOCKET_SET_STATE(SOCKET, STATE) \ inline_mysql_socket_set_state(SOCKET, STATE) #else #define MYSQL_SOCKET_SET_STATE(SOCKET, STATE) \ do {} while (0) #endif #ifdef HAVE_PSI_SOCKET_INTERFACE /** Instrumentation calls for MYSQL_START_SOCKET_WAIT. @sa MYSQL_START_SOCKET_WAIT. */ static inline struct PSI_socket_locker* inline_mysql_start_socket_wait(PSI_socket_locker_state *state, MYSQL_SOCKET mysql_socket, enum PSI_socket_operation op, size_t byte_count, const char *src_file, uint src_line) { struct PSI_socket_locker *locker; if (psi_likely(mysql_socket.m_psi != NULL)) { locker= PSI_SOCKET_CALL(start_socket_wait) (state, mysql_socket.m_psi, op, byte_count, src_file, src_line); } else locker= NULL; return locker; } /** Instrumentation calls for MYSQL_END_SOCKET_WAIT. @sa MYSQL_END_SOCKET_WAIT. */ static inline void inline_mysql_end_socket_wait(struct PSI_socket_locker *locker, size_t byte_count) { if (psi_likely(locker != NULL)) PSI_SOCKET_CALL(end_socket_wait)(locker, byte_count); } /** Set the state (IDLE, ACTIVE) of an instrumented socket. @param socket the instrumented socket @param state the new state @sa PSI_socket_state */ static inline void inline_mysql_socket_set_state(MYSQL_SOCKET socket, enum PSI_socket_state state) { if (socket.m_psi != NULL) PSI_SOCKET_CALL(set_socket_state)(socket.m_psi, state); } #endif /* HAVE_PSI_SOCKET_INTERFACE */ /** @def mysql_socket_fd(K, F) Create a socket. @c mysql_socket_fd is a replacement for @c socket. @param K PSI_socket_key for this instrumented socket @param F File descriptor */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_fd(K, F) \ inline_mysql_socket_fd(K, F) #else #define mysql_socket_fd(K, F) \ inline_mysql_socket_fd(F) #endif /** @def mysql_socket_socket(K, D, T, P) Create a socket. @c mysql_socket_socket is a replacement for @c socket. @param K PSI_socket_key for this instrumented socket @param D Socket domain @param T Protocol type @param P Transport protocol */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_socket(K, D, T, P) \ inline_mysql_socket_socket(K, D, T, P) #else #define mysql_socket_socket(K, D, T, P) \ inline_mysql_socket_socket(D, T, P) #endif /** @def mysql_socket_bind(FD, AP, L) Bind a socket to a local port number and IP address @c mysql_socket_bind is a replacement for @c bind. @param FD Instrumented socket descriptor returned by socket() @param AP Pointer to local port number and IP address in sockaddr structure @param L Length of sockaddr structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_bind(FD, AP, L) \ inline_mysql_socket_bind(__FILE__, __LINE__, FD, AP, L) #else #define mysql_socket_bind(FD, AP, L) \ inline_mysql_socket_bind(FD, AP, L) #endif /** @def mysql_socket_getsockname(FD, AP, LP) Return port number and IP address of the local host @c mysql_socket_getsockname is a replacement for @c getsockname. @param FD Instrumented socket descriptor returned by socket() @param AP Pointer to returned address of local host in @c sockaddr structure @param LP Pointer to length of @c sockaddr structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_getsockname(FD, AP, LP) \ inline_mysql_socket_getsockname(__FILE__, __LINE__, FD, AP, LP) #else #define mysql_socket_getsockname(FD, AP, LP) \ inline_mysql_socket_getsockname(FD, AP, LP) #endif /** @def mysql_socket_connect(FD, AP, L) Establish a connection to a remote host. @c mysql_socket_connect is a replacement for @c connect. @param FD Instrumented socket descriptor returned by socket() @param AP Pointer to target address in sockaddr structure @param L Length of sockaddr structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_connect(FD, AP, L) \ inline_mysql_socket_connect(__FILE__, __LINE__, FD, AP, L) #else #define mysql_socket_connect(FD, AP, L) \ inline_mysql_socket_connect(FD, AP, L) #endif /** @def mysql_socket_getpeername(FD, AP, LP) Get port number and IP address of remote host that a socket is connected to. @c mysql_socket_getpeername is a replacement for @c getpeername. @param FD Instrumented socket descriptor returned by socket() or accept() @param AP Pointer to returned address of remote host in sockaddr structure @param LP Pointer to length of sockaddr structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_getpeername(FD, AP, LP) \ inline_mysql_socket_getpeername(__FILE__, __LINE__, FD, AP, LP) #else #define mysql_socket_getpeername(FD, AP, LP) \ inline_mysql_socket_getpeername(FD, AP, LP) #endif /** @def mysql_socket_send(FD, B, N, FL) Send data from the buffer, B, to a connected socket. @c mysql_socket_send is a replacement for @c send. @param FD Instrumented socket descriptor returned by socket() or accept() @param B Buffer to send @param N Number of bytes to send @param FL Control flags */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_send(FD, B, N, FL) \ inline_mysql_socket_send(__FILE__, __LINE__, FD, B, N, FL) #else #define mysql_socket_send(FD, B, N, FL) \ inline_mysql_socket_send(FD, B, N, FL) #endif /** @def mysql_socket_recv(FD, B, N, FL) Receive data from a connected socket. @c mysql_socket_recv is a replacement for @c recv. @param FD Instrumented socket descriptor returned by socket() or accept() @param B Buffer to receive to @param N Maximum bytes to receive @param FL Control flags */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_recv(FD, B, N, FL) \ inline_mysql_socket_recv(__FILE__, __LINE__, FD, B, N, FL) #else #define mysql_socket_recv(FD, B, N, FL) \ inline_mysql_socket_recv(FD, B, N, FL) #endif /** @def mysql_socket_sendto(FD, B, N, FL, AP, L) Send data to a socket at the specified address. @c mysql_socket_sendto is a replacement for @c sendto. @param FD Instrumented socket descriptor returned by socket() @param B Buffer to send @param N Number of bytes to send @param FL Control flags @param AP Pointer to destination sockaddr structure @param L Size of sockaddr structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_sendto(FD, B, N, FL, AP, L) \ inline_mysql_socket_sendto(__FILE__, __LINE__, FD, B, N, FL, AP, L) #else #define mysql_socket_sendto(FD, B, N, FL, AP, L) \ inline_mysql_socket_sendto(FD, B, N, FL, AP, L) #endif /** @def mysql_socket_recvfrom(FD, B, N, FL, AP, L) Receive data from a socket and return source address information @c mysql_socket_recvfrom is a replacement for @c recvfrom. @param FD Instrumented socket descriptor returned by socket() @param B Buffer to receive to @param N Maximum bytes to receive @param FL Control flags @param AP Pointer to source address in sockaddr_storage structure @param LP Size of sockaddr_storage structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_recvfrom(FD, B, N, FL, AP, LP) \ inline_mysql_socket_recvfrom(__FILE__, __LINE__, FD, B, N, FL, AP, LP) #else #define mysql_socket_recvfrom(FD, B, N, FL, AP, LP) \ inline_mysql_socket_recvfrom(FD, B, N, FL, AP, LP) #endif /** @def mysql_socket_getsockopt(FD, LV, ON, OP, OL) Get a socket option for the specified socket. @c mysql_socket_getsockopt is a replacement for @c getsockopt. @param FD Instrumented socket descriptor returned by socket() @param LV Protocol level @param ON Option to query @param OP Buffer which will contain the value for the requested option @param OL Pointer to length of OP */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_getsockopt(FD, LV, ON, OP, OL) \ inline_mysql_socket_getsockopt(__FILE__, __LINE__, FD, LV, ON, OP, OL) #else #define mysql_socket_getsockopt(FD, LV, ON, OP, OL) \ inline_mysql_socket_getsockopt(FD, LV, ON, OP, OL) #endif /** @def mysql_socket_setsockopt(FD, LV, ON, OP, OL) Set a socket option for the specified socket. @c mysql_socket_setsockopt is a replacement for @c setsockopt. @param FD Instrumented socket descriptor returned by socket() @param LV Protocol level @param ON Option to modify @param OP Buffer containing the value for the specified option @param OL Pointer to length of OP */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_setsockopt(FD, LV, ON, OP, OL) \ inline_mysql_socket_setsockopt(__FILE__, __LINE__, FD, LV, ON, OP, OL) #else #define mysql_socket_setsockopt(FD, LV, ON, OP, OL) \ inline_mysql_socket_setsockopt(FD, LV, ON, OP, OL) #endif /** @def mysql_sock_set_nonblocking Set socket to non-blocking. @param FD instrumented socket descriptor */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_sock_set_nonblocking(FD) \ inline_mysql_sock_set_nonblocking(__FILE__, __LINE__, FD) #else #define mysql_sock_set_nonblocking(FD) \ inline_mysql_sock_set_nonblocking(FD) #endif /** @def mysql_socket_listen(FD, N) Set socket state to listen for an incoming connection. @c mysql_socket_listen is a replacement for @c listen. @param FD Instrumented socket descriptor, bound and connected @param N Maximum number of pending connections allowed. */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_listen(FD, N) \ inline_mysql_socket_listen(__FILE__, __LINE__, FD, N) #else #define mysql_socket_listen(FD, N) \ inline_mysql_socket_listen(FD, N) #endif /** @def mysql_socket_accept(K, FD, AP, LP) Accept a connection from any remote host; TCP only. @c mysql_socket_accept is a replacement for @c accept. @param K PSI_socket_key for this instrumented socket @param FD Instrumented socket descriptor, bound and placed in a listen state @param AP Pointer to sockaddr structure with returned IP address and port of connected host @param LP Pointer to length of valid information in AP */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_accept(K, FD, AP, LP) \ inline_mysql_socket_accept(__FILE__, __LINE__, K, FD, AP, LP) #else #define mysql_socket_accept(K, FD, AP, LP) \ inline_mysql_socket_accept(FD, AP, LP) #endif /** @def mysql_socket_close(FD) Close a socket and sever any connections. @c mysql_socket_close is a replacement for @c close. @param FD Instrumented socket descriptor returned by socket() or accept() */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_close(FD) \ inline_mysql_socket_close(__FILE__, __LINE__, FD) #else #define mysql_socket_close(FD) \ inline_mysql_socket_close(FD) #endif /** @def mysql_socket_shutdown(FD, H) Disable receives and/or sends on a socket. @c mysql_socket_shutdown is a replacement for @c shutdown. @param FD Instrumented socket descriptor returned by socket() or accept() @param H Specifies which operations to shutdown */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_shutdown(FD, H) \ inline_mysql_socket_shutdown(__FILE__, __LINE__, FD, H) #else #define mysql_socket_shutdown(FD, H) \ inline_mysql_socket_shutdown(FD, H) #endif #ifdef HAVE_PSI_SOCKET_INTERFACE static inline void inline_mysql_socket_register( const char *category, PSI_socket_info *info, int count) { PSI_SOCKET_CALL(register_socket)(category, info, count); } #endif /** mysql_socket_fd */ static inline MYSQL_SOCKET inline_mysql_socket_fd ( #ifdef HAVE_PSI_SOCKET_INTERFACE PSI_socket_key key, #endif int fd) { MYSQL_SOCKET mysql_socket= MYSQL_INVALID_SOCKET; mysql_socket.fd= fd; DBUG_ASSERT(mysql_socket.fd != INVALID_SOCKET); #ifdef HAVE_PSI_SOCKET_INTERFACE mysql_socket.m_psi= PSI_SOCKET_CALL(init_socket) (key, (const my_socket*)&mysql_socket.fd, NULL, 0); #endif /** Currently systemd socket activation is the user of this function. Its API (man sd_listen_fds) says FD_CLOSE_EXEC is already called. If there becomes another user, we can call it again without detriment. If needed later: #if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) (void) fcntl(mysql_socket.fd, F_SETFD, FD_CLOEXEC); #endif */ return mysql_socket; } /** mysql_socket_socket */ static inline MYSQL_SOCKET inline_mysql_socket_socket ( #ifdef HAVE_PSI_SOCKET_INTERFACE PSI_socket_key key, #endif int domain, int type, int protocol) { MYSQL_SOCKET mysql_socket= MYSQL_INVALID_SOCKET; mysql_socket.fd= socket(domain, type | SOCK_CLOEXEC, protocol); #ifdef HAVE_PSI_SOCKET_INTERFACE if (likely(mysql_socket.fd != INVALID_SOCKET)) { mysql_socket.m_psi= PSI_SOCKET_CALL(init_socket) (key, (const my_socket*)&mysql_socket.fd, NULL, 0); } #endif /* SOCK_CLOEXEC isn't always a number - can't preprocessor compare */ #if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) && !defined(HAVE_SOCK_CLOEXEC) (void) fcntl(mysql_socket.fd, F_SETFD, FD_CLOEXEC); #endif return mysql_socket; } /** mysql_socket_bind */ static inline int inline_mysql_socket_bind ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, const struct sockaddr *addr, size_t len) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker_state state; PSI_socket_locker *locker; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_BIND, (size_t)0, src_file, src_line); /* Instrumented code */ result= bind(mysql_socket.fd, addr, (int)len); /* Instrumentation end */ if (result == 0) PSI_SOCKET_CALL(set_socket_info)(mysql_socket.m_psi, NULL, addr, (socklen_t)len); if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= bind(mysql_socket.fd, addr, (int)len); return result; } /** mysql_socket_getsockname */ static inline int inline_mysql_socket_getsockname ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, struct sockaddr *addr, socklen_t *len) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_BIND, (size_t)0, src_file, src_line); /* Instrumented code */ result= getsockname(mysql_socket.fd, addr, len); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= getsockname(mysql_socket.fd, addr, len); return result; } /** mysql_socket_connect */ static inline int inline_mysql_socket_connect ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, const struct sockaddr *addr, socklen_t len) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line); /* Instrumented code */ result= connect(mysql_socket.fd, addr, len); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= connect(mysql_socket.fd, addr, len); return result; } /** mysql_socket_getpeername */ static inline int inline_mysql_socket_getpeername ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, struct sockaddr *addr, socklen_t *len) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_BIND, (size_t)0, src_file, src_line); /* Instrumented code */ result= getpeername(mysql_socket.fd, addr, len); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= getpeername(mysql_socket.fd, addr, len); return result; } /** mysql_socket_send */ static inline ssize_t inline_mysql_socket_send ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, const SOCKBUF_T *buf, size_t n, int flags) { ssize_t result; DBUG_ASSERT(mysql_socket.fd != INVALID_SOCKET); #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_SEND, n, src_file, src_line); /* Instrumented code */ result= send(mysql_socket.fd, buf, IF_WIN((int),) n, flags); /* Instrumentation end */ if (locker != NULL) { size_t bytes_written= (result > 0) ? (size_t) result : 0; PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_written); } return result; } #endif /* Non instrumented code */ result= send(mysql_socket.fd, buf, IF_WIN((int),) n, flags); return result; } /** mysql_socket_recv */ static inline ssize_t inline_mysql_socket_recv ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, SOCKBUF_T *buf, size_t n, int flags) { ssize_t result; DBUG_ASSERT(mysql_socket.fd != INVALID_SOCKET); #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_RECV, (size_t)0, src_file, src_line); /* Instrumented code */ result= recv(mysql_socket.fd, buf, IF_WIN((int),) n, flags); /* Instrumentation end */ if (locker != NULL) { size_t bytes_read= (result > 0) ? (size_t) result : 0; PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_read); } return result; } #endif /* Non instrumented code */ result= recv(mysql_socket.fd, buf, IF_WIN((int),) n, flags); return result; } /** mysql_socket_sendto */ static inline ssize_t inline_mysql_socket_sendto ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, const SOCKBUF_T *buf, size_t n, int flags, const struct sockaddr *addr, socklen_t addr_len) { ssize_t result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_SEND, n, src_file, src_line); /* Instrumented code */ result= sendto(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len); /* Instrumentation end */ if (locker != NULL) { size_t bytes_written = (result > 0) ? (size_t) result : 0; PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_written); } return result; } #endif /* Non instrumented code */ result= sendto(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len); return result; } /** mysql_socket_recvfrom */ static inline ssize_t inline_mysql_socket_recvfrom ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, SOCKBUF_T *buf, size_t n, int flags, struct sockaddr *addr, socklen_t *addr_len) { ssize_t result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_RECV, (size_t)0, src_file, src_line); /* Instrumented code */ result= recvfrom(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len); /* Instrumentation end */ if (locker != NULL) { size_t bytes_read= (result > 0) ? (size_t) result : 0; PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_read); } return result; } #endif /* Non instrumented code */ result= recvfrom(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len); return result; } /** mysql_socket_getsockopt */ static inline int inline_mysql_socket_getsockopt ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, int level, int optname, SOCKBUF_T *optval, socklen_t *optlen) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_OPT, (size_t)0, src_file, src_line); /* Instrumented code */ result= getsockopt(mysql_socket.fd, level, optname, optval, optlen); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= getsockopt(mysql_socket.fd, level, optname, optval, optlen); return result; } /** mysql_socket_setsockopt */ static inline int inline_mysql_socket_setsockopt ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, int level, int optname, const SOCKBUF_T *optval, socklen_t optlen) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_OPT, (size_t)0, src_file, src_line); /* Instrumented code */ result= setsockopt(mysql_socket.fd, level, optname, optval, optlen); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= setsockopt(mysql_socket.fd, level, optname, optval, optlen); return result; } /** set_socket_nonblock */ static inline int set_socket_nonblock(my_socket fd) { int ret= 0; #ifdef _WIN32 { u_long nonblocking= 1; ret= ioctlsocket(fd, FIONBIO, &nonblocking); } #else { int fd_flags; fd_flags= fcntl(fd, F_GETFL, 0); if (fd_flags < 0) return errno; #if defined(O_NONBLOCK) fd_flags |= O_NONBLOCK; #elif defined(O_NDELAY) fd_flags |= O_NDELAY; #elif defined(O_FNDELAY) fd_flags |= O_FNDELAY; #else #error "No definition of non-blocking flag found." #endif /* O_NONBLOCK */ if (fcntl(fd, F_SETFL, fd_flags) == -1) ret= errno; } #endif /* _WIN32 */ return ret; } /** mysql_socket_set_nonblocking */ static inline int inline_mysql_sock_set_nonblocking ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket ) { int result= 0; #ifdef HAVE_PSI_SOCKET_INTERFACE if (mysql_socket.m_psi) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_OPT, (size_t)0, src_file, src_line); /* Instrumented code */ result= set_socket_nonblock(mysql_socket.fd); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= set_socket_nonblock(mysql_socket.fd); return result; } /** mysql_socket_listen */ static inline int inline_mysql_socket_listen ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, int backlog) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line); /* Instrumented code */ result= listen(mysql_socket.fd, backlog); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= listen(mysql_socket.fd, backlog); return result; } /** mysql_socket_accept */ static inline MYSQL_SOCKET inline_mysql_socket_accept ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, PSI_socket_key key, #endif MYSQL_SOCKET socket_listen, struct sockaddr *addr, socklen_t *addr_len) { #ifdef FD_CLOEXEC int flags __attribute__ ((unused)); #endif MYSQL_SOCKET socket_accept; #ifdef HAVE_PSI_SOCKET_INTERFACE if (socket_listen.m_psi != NULL) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, socket_listen.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line); /* Instrumented code */ #ifdef HAVE_ACCEPT4 socket_accept.fd= accept4(socket_listen.fd, addr, addr_len, SOCK_CLOEXEC); #else socket_accept.fd= accept(socket_listen.fd, addr, addr_len); #ifdef FD_CLOEXEC if (socket_accept.fd != INVALID_SOCKET) { flags= fcntl(socket_accept.fd, F_GETFD); if (flags != -1) { flags |= FD_CLOEXEC; fcntl(socket_accept.fd, F_SETFD, flags); } } #endif #endif /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); } else #endif { /* Non instrumented code */ #ifdef HAVE_ACCEPT4 socket_accept.fd= accept4(socket_listen.fd, addr, addr_len, SOCK_CLOEXEC); #else socket_accept.fd= accept(socket_listen.fd, addr, addr_len); #ifdef FD_CLOEXEC if (socket_accept.fd != INVALID_SOCKET) { flags= fcntl(socket_accept.fd, F_GETFD); if (flags != -1) { flags |= FD_CLOEXEC; fcntl(socket_accept.fd, F_SETFD, flags); } } #endif #endif } #ifdef HAVE_PSI_SOCKET_INTERFACE if (likely(socket_accept.fd != INVALID_SOCKET)) { /* Initialize the instrument with the new socket descriptor and address */ socket_accept.m_psi= PSI_SOCKET_CALL(init_socket) (key, (const my_socket*)&socket_accept.fd, addr, *addr_len); } #endif return socket_accept; } /** mysql_socket_close */ static inline int inline_mysql_socket_close ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_CLOSE, (size_t)0, src_file, src_line); /* Instrumented code */ result= closesocket(mysql_socket.fd); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); /* Remove the instrumentation for this socket. */ if (mysql_socket.m_psi != NULL) PSI_SOCKET_CALL(destroy_socket)(mysql_socket.m_psi); return result; } #endif /* Non instrumented code */ result= closesocket(mysql_socket.fd); return result; } /** mysql_socket_shutdown */ static inline int inline_mysql_socket_shutdown ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, int how) { int result; #ifdef _WIN32 static LPFN_DISCONNECTEX DisconnectEx = NULL; if (DisconnectEx == NULL) { DWORD dwBytesReturned; GUID guidDisconnectEx = WSAID_DISCONNECTEX; WSAIoctl(mysql_socket.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidDisconnectEx, sizeof(GUID), &DisconnectEx, sizeof(DisconnectEx), &dwBytesReturned, NULL, NULL); } #endif /* Instrumentation start */ #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_SHUTDOWN, (size_t)0, src_file, src_line); /* Instrumented code */ #ifdef _WIN32 if (DisconnectEx) result= (DisconnectEx(mysql_socket.fd, (LPOVERLAPPED) NULL, (DWORD) 0, (DWORD) 0) == TRUE) ? 0 : -1; else #endif result= shutdown(mysql_socket.fd, how); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ #ifdef _WIN32 if (DisconnectEx) result= (DisconnectEx(mysql_socket.fd, (LPOVERLAPPED) NULL, (DWORD) 0, (DWORD) 0) == TRUE) ? 0 : -1; else #endif result= shutdown(mysql_socket.fd, how); return result; } /** @} (end of group Socket_instrumentation) */ #endif psi/mysql_mdl.h000064400000010624151030241300007501 0ustar00/* Copyright (c) 2012, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef MYSQL_MDL_H #define MYSQL_MDL_H /** @file mysql/psi/mysql_mdl.h Instrumentation helpers for metadata locks. */ #include "mysql/psi/psi.h" #ifdef HAVE_PSI_METADATA_INTERFACE #ifndef PSI_METADATA_CALL #define PSI_METADATA_CALL(M) PSI_DYNAMIC_CALL(M) #endif #define PSI_CALL_start_metadata_wait(A,B,C,D) PSI_METADATA_CALL(start_metadata_wait)(A,B,C,D) #define PSI_CALL_end_metadata_wait(A,B) PSI_METADATA_CALL(end_metadata_wait)(A,B) #define PSI_CALL_create_metadata_lock(A,B,C,D,E,F,G) PSI_METADATA_CALL(create_metadata_lock)(A,B,C,D,E,F,G) #define PSI_CALL_set_metadata_lock_status(A,B) PSI_METADATA_CALL(set_metadata_lock_status)(A,B) #define PSI_CALL_destroy_metadata_lock(A) PSI_METADATA_CALL(destroy_metadata_lock)(A) #else #define PSI_CALL_start_metadata_wait(A,B,C,D) 0 #define PSI_CALL_end_metadata_wait(A,B) do { } while(0) #define PSI_CALL_create_metadata_lock(A,B,C,D,E,F,G) 0 #define PSI_CALL_set_metadata_lock_status(A,B) do {} while(0) #define PSI_CALL_destroy_metadata_lock(A) do {} while(0) #endif /** @defgroup Thread_instrumentation Metadata Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_mdl_create(K, M, A) Instrumented metadata lock creation. @param I Metadata lock identity @param K Metadata key @param T Metadata lock type @param D Metadata lock duration @param S Metadata lock status @param F request source file @param L request source line */ #ifdef HAVE_PSI_METADATA_INTERFACE #define mysql_mdl_create(I, K, T, D, S, F, L) \ inline_mysql_mdl_create(I, K, T, D, S, F, L) #else #define mysql_mdl_create(I, K, T, D, S, F, L) NULL #endif #ifdef HAVE_PSI_METADATA_INTERFACE #define mysql_mdl_set_status(L, S) \ inline_mysql_mdl_set_status(L, S) #else #define mysql_mdl_set_status(L, S) \ do {} while (0) #endif /** @def mysql_mdl_destroy(M) Instrumented metadata lock destruction. @param M Metadata lock */ #ifdef HAVE_PSI_METADATA_INTERFACE #define mysql_mdl_destroy(M) \ inline_mysql_mdl_destroy(M, __FILE__, __LINE__) #else #define mysql_mdl_destroy(M) \ do {} while (0) #endif #ifdef HAVE_PSI_METADATA_INTERFACE static inline PSI_metadata_lock * inline_mysql_mdl_create(void *identity, const MDL_key *mdl_key, enum_mdl_type mdl_type, enum_mdl_duration mdl_duration, MDL_ticket::enum_psi_status mdl_status, const char *src_file, uint src_line) { PSI_metadata_lock *result; /* static_cast: Fit a round C++ enum peg into a square C int hole ... */ result= PSI_METADATA_CALL(create_metadata_lock) (identity, mdl_key, static_cast (mdl_type), static_cast (mdl_duration), static_cast (mdl_status), src_file, src_line); return result; } static inline void inline_mysql_mdl_set_status( PSI_metadata_lock *psi, MDL_ticket::enum_psi_status mdl_status) { if (psi != NULL) PSI_METADATA_CALL(set_metadata_lock_status)(psi, mdl_status); } static inline void inline_mysql_mdl_destroy( PSI_metadata_lock *psi, const char *src_file, uint src_line) { if (psi != NULL) PSI_METADATA_CALL(destroy_metadata_lock)(psi); } #endif /* HAVE_PSI_METADATA_INTERFACE */ /** @} (end of group Metadata_instrumentation) */ #endif psi/psi_abi_v2.h000064400000002667151030241300007525 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file mysql/psi/psi_abi_v1.h ABI check for mysql/psi/psi.h, when using PSI_VERSION_2. This file is only used to automate detection of changes between versions. Do not include this file, include mysql/psi/psi.h instead. */ #define USE_PSI_2 #define HAVE_PSI_INTERFACE #define MY_GLOBAL_INCLUDED #include "mysql/psi/psi.h" psi/psi_base.h000064400000011027151030241300007263 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. Without limiting anything contained in the foregoing, this file, which is part of C Driver for MySQL (Connector/C), is also subject to the Universal FOSS Exception, version 1.0, a copy of which can be found at http://oss.oracle.com/licenses/universal-foss-exception. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_PSI_BASE_H #define MYSQL_PSI_BASE_H #ifdef EMBEDDED_LIBRARY #define DISABLE_ALL_PSI #endif /* EMBEDDED_LIBRARY */ #ifdef __cplusplus extern "C" { #endif /** @file mysql/psi/psi_base.h Performance schema instrumentation interface. @defgroup Instrumentation_interface Instrumentation Interface @ingroup Performance_schema @{ */ #define PSI_INSTRUMENT_ME 0 #define PSI_INSTRUMENT_MEM ((PSI_memory_key)0) #define PSI_NOT_INSTRUMENTED 0 /** Global flag. This flag indicate that an instrumentation point is a global variable, or a singleton. */ #define PSI_FLAG_GLOBAL (1 << 0) /** Mutable flag. This flag indicate that an instrumentation point is a general placeholder, that can mutate into a more specific instrumentation point. */ #define PSI_FLAG_MUTABLE (1 << 1) #define PSI_FLAG_THREAD (1 << 2) /** Stage progress flag. This flag apply to the stage instruments only. It indicates the instrumentation provides progress data. */ #define PSI_FLAG_STAGE_PROGRESS (1 << 3) /** Shared Exclusive flag. Indicates that rwlock support the shared exclusive state. */ #define PSI_RWLOCK_FLAG_SX (1 << 4) /** Transferable flag. This flag indicate that an instrumented object can be created by a thread and destroyed by another thread. */ #define PSI_FLAG_TRANSFER (1 << 5) /** Volatility flag. This flag indicate that an instrumented object has a volatility (life cycle) comparable to the volatility of a session. */ #define PSI_FLAG_VOLATILITY_SESSION (1 << 6) /** System thread flag. Indicates that the instrumented object exists on a system thread. */ #define PSI_FLAG_THREAD_SYSTEM (1 << 9) #ifdef HAVE_PSI_INTERFACE /** @def PSI_VERSION_1 Performance Schema Interface number for version 1. This version is supported. */ #define PSI_VERSION_1 1 /** @def PSI_VERSION_2 Performance Schema Interface number for version 2. This version is not implemented, it's a placeholder. */ #define PSI_VERSION_2 2 /** @def PSI_CURRENT_VERSION Performance Schema Interface number for the most recent version. The most current version is @c PSI_VERSION_1 */ #define PSI_CURRENT_VERSION 1 /** @def USE_PSI_1 Define USE_PSI_1 to use the interface version 1. */ /** @def USE_PSI_2 Define USE_PSI_2 to use the interface version 2. */ /** @def HAVE_PSI_1 Define HAVE_PSI_1 if the interface version 1 needs to be compiled in. */ /** @def HAVE_PSI_2 Define HAVE_PSI_2 if the interface version 2 needs to be compiled in. */ #ifndef USE_PSI_2 #ifndef USE_PSI_1 #define USE_PSI_1 #endif #endif #ifdef USE_PSI_1 #define HAVE_PSI_1 #endif #ifdef USE_PSI_2 #define HAVE_PSI_2 #endif /* Allow to override PSI_XXX_CALL at compile time with more efficient implementations, if available. If nothing better is available, make a dynamic call using the PSI_server function pointer. */ #define PSI_DYNAMIC_CALL(M) PSI_server->M #endif /* HAVE_PSI_INTERFACE */ /** @} */ /** Instrumented memory key. To instrument memory, a memory key must be obtained using @c register_memory. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_memory_key; #ifdef __cplusplus } #endif #endif /* MYSQL_PSI_BASE_H */ psi/mysql_table.h000064400000013061151030241300010012 0ustar00/* Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_TABLE_H #define MYSQL_TABLE_H /** @file mysql/psi/mysql_table.h Instrumentation helpers for table io. */ #include "mysql/psi/psi.h" #ifndef PSI_TABLE_CALL #define PSI_TABLE_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Table_instrumentation Table Instrumentation @ingroup Instrumentation_interface @{ */ #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_UNBIND_TABLE(handler) (handler)->unbind_psi() #define PSI_CALL_unbind_table PSI_TABLE_CALL(unbind_table) #define PSI_CALL_rebind_table PSI_TABLE_CALL(rebind_table) #define PSI_CALL_open_table PSI_TABLE_CALL(open_table) #define PSI_CALL_close_table PSI_TABLE_CALL(close_table) #define PSI_CALL_get_table_share PSI_TABLE_CALL(get_table_share) #define PSI_CALL_release_table_share PSI_TABLE_CALL(release_table_share) #define PSI_CALL_drop_table_share PSI_TABLE_CALL(drop_table_share) #else #define MYSQL_UNBIND_TABLE(handler) do { } while(0) #define PSI_CALL_unbind_table(A1) do { } while(0) #define PSI_CALL_rebind_table(A1,A2,A3) NULL #define PSI_CALL_close_table(A1,A2) do { } while(0) #define PSI_CALL_open_table(A1,A2) NULL #define PSI_CALL_get_table_share(A1,A2) NULL #define PSI_CALL_release_table_share(A1) do { } while(0) #define PSI_CALL_drop_table_share(A1,A2,A3,A4,A5) do { } while(0) #endif /** @def MYSQL_TABLE_WAIT_VARIABLES Instrumentation helper for table waits. This instrumentation declares local variables. Do not use a ';' after this macro @param LOCKER the locker @param STATE the locker state @sa MYSQL_START_TABLE_IO_WAIT. @sa MYSQL_END_TABLE_IO_WAIT. @sa MYSQL_START_TABLE_LOCK_WAIT. @sa MYSQL_END_TABLE_LOCK_WAIT. */ #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_TABLE_WAIT_VARIABLES(LOCKER, STATE) \ struct PSI_table_locker* LOCKER; \ PSI_table_locker_state STATE; #else #define MYSQL_TABLE_WAIT_VARIABLES(LOCKER, STATE) #endif /** @def MYSQL_START_TABLE_LOCK_WAIT Instrumentation helper for table lock waits. This instrumentation marks the start of a wait event. @param LOCKER the locker @param STATE the locker state @param PSI the instrumented table @param OP the table operation to be performed @param FLAGS per table operation flags. @sa MYSQL_END_TABLE_LOCK_WAIT. */ #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_START_TABLE_LOCK_WAIT(LOCKER, STATE, PSI, OP, FLAGS) \ LOCKER= inline_mysql_start_table_lock_wait(STATE, PSI, \ OP, FLAGS, __FILE__, __LINE__) #else #define MYSQL_START_TABLE_LOCK_WAIT(LOCKER, STATE, PSI, OP, FLAGS) \ do {} while (0) #endif /** @def MYSQL_END_TABLE_LOCK_WAIT Instrumentation helper for table lock waits. This instrumentation marks the end of a wait event. @param LOCKER the locker @sa MYSQL_START_TABLE_LOCK_WAIT. */ #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_END_TABLE_LOCK_WAIT(LOCKER) \ inline_mysql_end_table_lock_wait(LOCKER) #else #define MYSQL_END_TABLE_LOCK_WAIT(LOCKER) \ do {} while (0) #endif #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_UNLOCK_TABLE(T) \ inline_mysql_unlock_table(T) #else #define MYSQL_UNLOCK_TABLE(T) \ do {} while (0) #endif #ifdef HAVE_PSI_TABLE_INTERFACE /** Instrumentation calls for MYSQL_START_TABLE_LOCK_WAIT. @sa MYSQL_END_TABLE_LOCK_WAIT. */ static inline struct PSI_table_locker * inline_mysql_start_table_lock_wait(PSI_table_locker_state *state, struct PSI_table *psi, enum PSI_table_lock_operation op, ulong flags, const char *src_file, uint src_line) { if (psi_likely(psi != NULL)) { struct PSI_table_locker *locker; locker= PSI_TABLE_CALL(start_table_lock_wait) (state, psi, op, flags, src_file, src_line); return locker; } return NULL; } /** Instrumentation calls for MYSQL_END_TABLE_LOCK_WAIT. @sa MYSQL_START_TABLE_LOCK_WAIT. */ static inline void inline_mysql_end_table_lock_wait(struct PSI_table_locker *locker) { if (psi_likely(locker != NULL)) PSI_TABLE_CALL(end_table_lock_wait)(locker); } static inline void inline_mysql_unlock_table(struct PSI_table *table) { if (table != NULL) PSI_TABLE_CALL(unlock_table)(table); } #endif /** @} (end of group Table_instrumentation) */ #endif psi/psi_abi_v0.h000064400000002630151030241300007511 0ustar00/* Copyright (c) 2011, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file mysql/psi/psi_abi_v0.h ABI check for mysql/psi/psi.h, when compiling without instrumentation. This file is only used to automate detection of changes between versions. Do not include this file, include mysql/psi/psi.h instead. */ #define MY_GLOBAL_INCLUDED #include "mysql/psi/psi.h" psi/mysql_thread.h000064400000077376151030241300010215 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. Copyright (c) 2020, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_THREAD_H #define MYSQL_THREAD_H /** @file mysql/psi/mysql_thread.h Instrumentation helpers for mysys threads, mutexes, read write locks and conditions. This header file provides the necessary declarations to use the mysys thread API with the performance schema instrumentation. In some compilers (SunStudio), 'static inline' functions, when declared but not used, are not optimized away (because they are unused) by default, so that including a static inline function from a header file does create unwanted dependencies, causing unresolved symbols at link time. Other compilers, like gcc, optimize these dependencies by default. Since the instrumented APIs declared here are wrapper on top of my_pthread / safemutex / etc APIs, including mysql/psi/mysql_thread.h assumes that the dependency on my_pthread and safemutex already exists. */ /* Note: there are several orthogonal dimensions here. Dimension 1: Instrumentation HAVE_PSI_INTERFACE is defined when the instrumentation is compiled in. This may happen both in debug or production builds. Dimension 2: Debug SAFE_MUTEX is defined when debug is compiled in. This may happen both with and without instrumentation. Dimension 3: Platform Mutexes are implemented with one of: - the pthread library - fast mutexes - window apis This is implemented by various macro definitions in my_pthread.h This causes complexity with '#ifdef'-ery that can't be avoided. */ #include "mysql/psi/psi.h" #ifdef MYSQL_SERVER #ifndef MYSQL_DYNAMIC_PLUGIN #include "pfs_thread_provider.h" #endif #endif #ifndef PSI_MUTEX_CALL #define PSI_MUTEX_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifndef PSI_RWLOCK_CALL #define PSI_RWLOCK_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifndef PSI_COND_CALL #define PSI_COND_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifndef PSI_THREAD_CALL #define PSI_THREAD_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Thread_instrumentation Thread Instrumentation @ingroup Instrumentation_interface @{ */ #ifdef HAVE_PSI_THREAD_INTERFACE #define PSI_CALL_delete_current_thread PSI_THREAD_CALL(delete_current_thread) #define PSI_CALL_get_thread PSI_THREAD_CALL(get_thread) #define PSI_CALL_new_thread PSI_THREAD_CALL(new_thread) #define PSI_CALL_register_thread PSI_THREAD_CALL(register_thread) #define PSI_CALL_set_thread PSI_THREAD_CALL(set_thread) #define PSI_CALL_set_thread_THD PSI_THREAD_CALL(set_thread_THD) #define PSI_CALL_set_thread_connect_attrs PSI_THREAD_CALL(set_thread_connect_attrs) #define PSI_CALL_set_thread_db PSI_THREAD_CALL(set_thread_db) #define PSI_CALL_set_thread_id PSI_THREAD_CALL(set_thread_id) #define PSI_CALL_set_thread_os_id PSI_THREAD_CALL(set_thread_os_id) #define PSI_CALL_set_thread_info PSI_THREAD_CALL(set_thread_info) #define PSI_CALL_set_thread_start_time PSI_THREAD_CALL(set_thread_start_time) #define PSI_CALL_set_thread_account PSI_THREAD_CALL(set_thread_account) #define PSI_CALL_spawn_thread PSI_THREAD_CALL(spawn_thread) #define PSI_CALL_set_connection_type PSI_THREAD_CALL(set_connection_type) #else #define PSI_CALL_delete_current_thread() do { } while(0) #define PSI_CALL_get_thread() NULL #define PSI_CALL_new_thread(A1,A2,A3) NULL #define PSI_CALL_register_thread(A1,A2,A3) do { } while(0) #define PSI_CALL_set_thread(A1) do { } while(0) #define PSI_CALL_set_thread_THD(A1,A2) do { } while(0) #define PSI_CALL_set_thread_connect_attrs(A1,A2,A3) 0 #define PSI_CALL_set_thread_db(A1,A2) do { } while(0) #define PSI_CALL_set_thread_id(A1,A2) do { } while(0) #define PSI_CALL_set_thread_os_id(A1) do { } while(0) #define PSI_CALL_set_thread_info(A1, A2) do { } while(0) #define PSI_CALL_set_thread_start_time(A1) do { } while(0) #define PSI_CALL_set_thread_account(A1, A2, A3, A4) do { } while(0) #define PSI_CALL_spawn_thread(A1, A2, A3, A4, A5) 0 #define PSI_CALL_set_connection_type(A) do { } while(0) #endif /** An instrumented mutex structure. @sa mysql_mutex_t */ struct st_mysql_mutex { /** The real mutex. */ #ifdef SAFE_MUTEX safe_mutex_t m_mutex; #else pthread_mutex_t m_mutex; #endif /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c mysql_mutex_t interface. */ struct PSI_mutex *m_psi; }; /** Type of an instrumented mutex. @c mysql_mutex_t is a drop-in replacement for @c pthread_mutex_t. @sa mysql_mutex_assert_owner @sa mysql_mutex_assert_not_owner @sa mysql_mutex_init @sa mysql_mutex_lock @sa mysql_mutex_unlock @sa mysql_mutex_destroy */ typedef struct st_mysql_mutex mysql_mutex_t; /** An instrumented rwlock structure. @sa mysql_rwlock_t */ struct st_mysql_rwlock { /** The real rwlock */ rw_lock_t m_rwlock; /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c mysql_rwlock_t interface. */ struct PSI_rwlock *m_psi; }; /** An instrumented prlock structure. @sa mysql_prlock_t */ struct st_mysql_prlock { /** The real prlock */ rw_pr_lock_t m_prlock; /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c mysql_rwlock_t interface. */ struct PSI_rwlock *m_psi; }; /** Type of an instrumented rwlock. @c mysql_rwlock_t is a drop-in replacement for @c pthread_rwlock_t. @sa mysql_rwlock_init @sa mysql_rwlock_rdlock @sa mysql_rwlock_tryrdlock @sa mysql_rwlock_wrlock @sa mysql_rwlock_trywrlock @sa mysql_rwlock_unlock @sa mysql_rwlock_destroy */ typedef struct st_mysql_rwlock mysql_rwlock_t; /** Type of an instrumented prlock. A prlock is a read write lock that 'prefers readers' (pr). @c mysql_prlock_t is a drop-in replacement for @c rw_pr_lock_t. @sa mysql_prlock_init @sa mysql_prlock_rdlock @sa mysql_prlock_wrlock @sa mysql_prlock_unlock @sa mysql_prlock_destroy */ typedef struct st_mysql_prlock mysql_prlock_t; /** An instrumented cond structure. @sa mysql_cond_t */ struct st_mysql_cond { /** The real condition */ pthread_cond_t m_cond; /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c mysql_cond_t interface. */ struct PSI_cond *m_psi; }; /** Type of an instrumented condition. @c mysql_cond_t is a drop-in replacement for @c pthread_cond_t. @sa mysql_cond_init @sa mysql_cond_wait @sa mysql_cond_timedwait @sa mysql_cond_signal @sa mysql_cond_broadcast @sa mysql_cond_destroy */ typedef struct st_mysql_cond mysql_cond_t; /* Consider the following code: static inline void foo() { bar(); } when foo() is never called. With gcc, foo() is a local static function, so the dependencies are optimized away at compile time, and there is no dependency on bar(). With other compilers (HP, Sun Studio), the function foo() implementation is compiled, and bar() needs to be present to link. Due to the existing header dependencies in MySQL code, this header file is sometime used when it is not needed, which in turn cause link failures on some platforms. The proper fix would be to cut these extra dependencies in the calling code. DISABLE_MYSQL_THREAD_H is a work around to limit dependencies. DISABLE_MYSQL_PRLOCK_H is similar, and is used to disable specifically the prlock wrappers. */ #ifndef DISABLE_MYSQL_THREAD_H #define mysql_mutex_is_owner(M) safe_mutex_is_owner(&(M)->m_mutex) /** @def mysql_mutex_assert_owner(M) Wrapper, to use safe_mutex_assert_owner with instrumented mutexes. @c mysql_mutex_assert_owner is a drop-in replacement for @c safe_mutex_assert_owner. */ #define mysql_mutex_assert_owner(M) \ safe_mutex_assert_owner(&(M)->m_mutex) /** @def mysql_mutex_assert_not_owner(M) Wrapper, to use safe_mutex_assert_not_owner with instrumented mutexes. @c mysql_mutex_assert_not_owner is a drop-in replacement for @c safe_mutex_assert_not_owner. */ #define mysql_mutex_assert_not_owner(M) \ safe_mutex_assert_not_owner(&(M)->m_mutex) #define mysql_mutex_setflags(M, F) \ safe_mutex_setflags(&(M)->m_mutex, (F)) /** @def mysql_prlock_assert_write_owner(M) Drop-in replacement for @c rw_pr_lock_assert_write_owner. */ #define mysql_prlock_assert_write_owner(M) \ rw_pr_lock_assert_write_owner(&(M)->m_prlock) /** @def mysql_prlock_assert_not_write_owner(M) Drop-in replacement for @c rw_pr_lock_assert_not_write_owner. */ #define mysql_prlock_assert_not_write_owner(M) \ rw_pr_lock_assert_not_write_owner(&(M)->m_prlock) /** @def mysql_mutex_register(P1, P2, P3) Mutex registration. */ #define mysql_mutex_register(P1, P2, P3) \ inline_mysql_mutex_register(P1, P2, P3) /** @def mysql_mutex_init(K, M, A) Instrumented mutex_init. @c mysql_mutex_init is a replacement for @c pthread_mutex_init. @param K The PSI_mutex_key for this instrumented mutex @param M The mutex to initialize @param A Mutex attributes */ #ifdef HAVE_PSI_MUTEX_INTERFACE #ifdef SAFE_MUTEX #define mysql_mutex_init(K, M, A) \ inline_mysql_mutex_init(K, M, A, #M, __FILE__, __LINE__) #else #define mysql_mutex_init(K, M, A) \ inline_mysql_mutex_init(K, M, A) #endif #else #ifdef SAFE_MUTEX #define mysql_mutex_init(K, M, A) \ inline_mysql_mutex_init(M, A, #M, __FILE__, __LINE__) #else #define mysql_mutex_init(K, M, A) \ inline_mysql_mutex_init(M, A) #endif #endif /** @def mysql_mutex_destroy(M) Instrumented mutex_destroy. @c mysql_mutex_destroy is a drop-in replacement for @c pthread_mutex_destroy. */ #ifdef SAFE_MUTEX #define mysql_mutex_destroy(M) \ inline_mysql_mutex_destroy(M, __FILE__, __LINE__) #else #define mysql_mutex_destroy(M) \ inline_mysql_mutex_destroy(M) #endif /** @def mysql_mutex_lock(M) Instrumented mutex_lock. @c mysql_mutex_lock is a drop-in replacement for @c pthread_mutex_lock. @param M The mutex to lock */ #if defined(SAFE_MUTEX) || defined (HAVE_PSI_MUTEX_INTERFACE) #define mysql_mutex_lock(M) \ inline_mysql_mutex_lock(M, __FILE__, __LINE__) #else #define mysql_mutex_lock(M) \ inline_mysql_mutex_lock(M) #endif /** @def mysql_mutex_trylock(M) Instrumented mutex_lock. @c mysql_mutex_trylock is a drop-in replacement for @c pthread_mutex_trylock. */ #if defined(SAFE_MUTEX) || defined (HAVE_PSI_MUTEX_INTERFACE) #define mysql_mutex_trylock(M) \ inline_mysql_mutex_trylock(M, __FILE__, __LINE__) #else #define mysql_mutex_trylock(M) \ inline_mysql_mutex_trylock(M) #endif /** @def mysql_mutex_unlock(M) Instrumented mutex_unlock. @c mysql_mutex_unlock is a drop-in replacement for @c pthread_mutex_unlock. */ #ifdef SAFE_MUTEX #define mysql_mutex_unlock(M) \ inline_mysql_mutex_unlock(M, __FILE__, __LINE__) #else #define mysql_mutex_unlock(M) \ inline_mysql_mutex_unlock(M) #endif /** @def mysql_rwlock_register(P1, P2, P3) Rwlock registration. */ #define mysql_rwlock_register(P1, P2, P3) \ inline_mysql_rwlock_register(P1, P2, P3) /** @def mysql_rwlock_init(K, RW) Instrumented rwlock_init. @c mysql_rwlock_init is a replacement for @c pthread_rwlock_init. Note that pthread_rwlockattr_t is not supported in MySQL. @param K The PSI_rwlock_key for this instrumented rwlock @param RW The rwlock to initialize */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_rwlock_init(K, RW) inline_mysql_rwlock_init(K, RW) #else #define mysql_rwlock_init(K, RW) inline_mysql_rwlock_init(RW) #endif /** @def mysql_prlock_init(K, RW) Instrumented rw_pr_init. @c mysql_prlock_init is a replacement for @c rw_pr_init. @param K The PSI_rwlock_key for this instrumented prlock @param RW The prlock to initialize */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_prlock_init(K, RW) inline_mysql_prlock_init(K, RW) #else #define mysql_prlock_init(K, RW) inline_mysql_prlock_init(RW) #endif /** @def mysql_rwlock_destroy(RW) Instrumented rwlock_destroy. @c mysql_rwlock_destroy is a drop-in replacement for @c pthread_rwlock_destroy. */ #define mysql_rwlock_destroy(RW) inline_mysql_rwlock_destroy(RW) /** @def mysql_prlock_destroy(RW) Instrumented rw_pr_destroy. @c mysql_prlock_destroy is a drop-in replacement for @c rw_pr_destroy. */ #define mysql_prlock_destroy(RW) inline_mysql_prlock_destroy(RW) /** @def mysql_rwlock_rdlock(RW) Instrumented rwlock_rdlock. @c mysql_rwlock_rdlock is a drop-in replacement for @c pthread_rwlock_rdlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_rwlock_rdlock(RW) \ inline_mysql_rwlock_rdlock(RW, __FILE__, __LINE__) #else #define mysql_rwlock_rdlock(RW) \ inline_mysql_rwlock_rdlock(RW) #endif /** @def mysql_prlock_rdlock(RW) Instrumented rw_pr_rdlock. @c mysql_prlock_rdlock is a drop-in replacement for @c rw_pr_rdlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_prlock_rdlock(RW) \ inline_mysql_prlock_rdlock(RW, __FILE__, __LINE__) #else #define mysql_prlock_rdlock(RW) \ inline_mysql_prlock_rdlock(RW) #endif /** @def mysql_rwlock_wrlock(RW) Instrumented rwlock_wrlock. @c mysql_rwlock_wrlock is a drop-in replacement for @c pthread_rwlock_wrlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_rwlock_wrlock(RW) \ inline_mysql_rwlock_wrlock(RW, __FILE__, __LINE__) #else #define mysql_rwlock_wrlock(RW) \ inline_mysql_rwlock_wrlock(RW) #endif /** @def mysql_prlock_wrlock(RW) Instrumented rw_pr_wrlock. @c mysql_prlock_wrlock is a drop-in replacement for @c rw_pr_wrlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_prlock_wrlock(RW) \ inline_mysql_prlock_wrlock(RW, __FILE__, __LINE__) #else #define mysql_prlock_wrlock(RW) \ inline_mysql_prlock_wrlock(RW) #endif /** @def mysql_rwlock_tryrdlock(RW) Instrumented rwlock_tryrdlock. @c mysql_rwlock_tryrdlock is a drop-in replacement for @c pthread_rwlock_tryrdlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_rwlock_tryrdlock(RW) \ inline_mysql_rwlock_tryrdlock(RW, __FILE__, __LINE__) #else #define mysql_rwlock_tryrdlock(RW) \ inline_mysql_rwlock_tryrdlock(RW) #endif /** @def mysql_rwlock_trywrlock(RW) Instrumented rwlock_trywrlock. @c mysql_rwlock_trywrlock is a drop-in replacement for @c pthread_rwlock_trywrlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_rwlock_trywrlock(RW) \ inline_mysql_rwlock_trywrlock(RW, __FILE__, __LINE__) #else #define mysql_rwlock_trywrlock(RW) \ inline_mysql_rwlock_trywrlock(RW) #endif /** @def mysql_rwlock_unlock(RW) Instrumented rwlock_unlock. @c mysql_rwlock_unlock is a drop-in replacement for @c pthread_rwlock_unlock. */ #define mysql_rwlock_unlock(RW) inline_mysql_rwlock_unlock(RW) /** @def mysql_prlock_unlock(RW) Instrumented rw_pr_unlock. @c mysql_prlock_unlock is a drop-in replacement for @c rw_pr_unlock. */ #define mysql_prlock_unlock(RW) inline_mysql_prlock_unlock(RW) /** @def mysql_cond_register(P1, P2, P3) Cond registration. */ #define mysql_cond_register(P1, P2, P3) \ inline_mysql_cond_register(P1, P2, P3) /** @def mysql_cond_init(K, C, A) Instrumented cond_init. @c mysql_cond_init is a replacement for @c pthread_cond_init. @param C The cond to initialize @param K The PSI_cond_key for this instrumented cond @param A Condition attributes */ #ifdef HAVE_PSI_COND_INTERFACE #define mysql_cond_init(K, C, A) inline_mysql_cond_init(K, C, A) #else #define mysql_cond_init(K, C, A) inline_mysql_cond_init(C, A) #endif /** @def mysql_cond_destroy(C) Instrumented cond_destroy. @c mysql_cond_destroy is a drop-in replacement for @c pthread_cond_destroy. */ #define mysql_cond_destroy(C) inline_mysql_cond_destroy(C) /** @def mysql_cond_wait(C) Instrumented cond_wait. @c mysql_cond_wait is a drop-in replacement for @c pthread_cond_wait. */ #if defined(SAFE_MUTEX) || defined(HAVE_PSI_COND_INTERFACE) #define mysql_cond_wait(C, M) \ inline_mysql_cond_wait(C, M, __FILE__, __LINE__) #else #define mysql_cond_wait(C, M) \ inline_mysql_cond_wait(C, M) #endif /** @def mysql_cond_timedwait(C, M, W) Instrumented cond_timedwait. @c mysql_cond_timedwait is a drop-in replacement for @c pthread_cond_timedwait. */ #if defined(SAFE_MUTEX) || defined(HAVE_PSI_COND_INTERFACE) #define mysql_cond_timedwait(C, M, W) \ inline_mysql_cond_timedwait(C, M, W, __FILE__, __LINE__) #else #define mysql_cond_timedwait(C, M, W) \ inline_mysql_cond_timedwait(C, M, W) #endif /** @def mysql_cond_signal(C) Instrumented cond_signal. @c mysql_cond_signal is a drop-in replacement for @c pthread_cond_signal. */ #define mysql_cond_signal(C) inline_mysql_cond_signal(C) /** @def mysql_cond_broadcast(C) Instrumented cond_broadcast. @c mysql_cond_broadcast is a drop-in replacement for @c pthread_cond_broadcast. */ #define mysql_cond_broadcast(C) inline_mysql_cond_broadcast(C) /** @def mysql_thread_register(P1, P2, P3) Thread registration. */ #define mysql_thread_register(P1, P2, P3) \ inline_mysql_thread_register(P1, P2, P3) /** @def mysql_thread_create(K, P1, P2, P3, P4) Instrumented pthread_create. This function creates both the thread instrumentation and a thread. @c mysql_thread_create is a replacement for @c pthread_create. The parameter P4 (or, if it is NULL, P1) will be used as the instrumented thread "identity". Providing a P1 / P4 parameter with a different value for each call will on average improve performances, since this thread identity value is used internally to randomize access to data and prevent contention. This is optional, and the improvement is not guaranteed, only statistical. @param K The PSI_thread_key for this instrumented thread @param P1 pthread_create parameter 1 @param P2 pthread_create parameter 2 @param P3 pthread_create parameter 3 @param P4 pthread_create parameter 4 */ #ifdef HAVE_PSI_THREAD_INTERFACE #define mysql_thread_create(K, P1, P2, P3, P4) \ inline_mysql_thread_create(K, P1, P2, P3, P4) #else #define mysql_thread_create(K, P1, P2, P3, P4) \ pthread_create(P1, P2, P3, P4) #endif /** @def mysql_thread_set_psi_id(I) Set the thread identifier for the instrumentation. @param I The thread identifier */ #ifdef HAVE_PSI_THREAD_INTERFACE #define mysql_thread_set_psi_id(I) inline_mysql_thread_set_psi_id(I) #else #define mysql_thread_set_psi_id(I) do {} while (0) #endif /** @def mysql_thread_set_psi_THD(T) Set the thread sql session for the instrumentation. @param I The thread identifier */ #ifdef HAVE_PSI_THREAD_INTERFACE #define mysql_thread_set_psi_THD(T) inline_mysql_thread_set_psi_THD(T) #else #define mysql_thread_set_psi_THD(T) do {} while (0) #endif static inline void inline_mysql_mutex_register( #ifdef HAVE_PSI_MUTEX_INTERFACE const char *category, PSI_mutex_info *info, int count #else const char *category __attribute__ ((unused)), void *info __attribute__ ((unused)), int count __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_MUTEX_INTERFACE PSI_MUTEX_CALL(register_mutex)(category, info, count); #endif } static inline int inline_mysql_mutex_init( #ifdef HAVE_PSI_MUTEX_INTERFACE PSI_mutex_key key, #endif mysql_mutex_t *that, const pthread_mutexattr_t *attr #ifdef SAFE_MUTEX , const char *src_name, const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_MUTEX_INTERFACE that->m_psi= PSI_MUTEX_CALL(init_mutex)(key, &that->m_mutex); #else that->m_psi= NULL; #endif #ifdef SAFE_MUTEX return safe_mutex_init(&that->m_mutex, attr, src_name, src_file, src_line); #else return pthread_mutex_init(&that->m_mutex, attr); #endif } static inline int inline_mysql_mutex_destroy( mysql_mutex_t *that #ifdef SAFE_MUTEX , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_MUTEX_INTERFACE if (that->m_psi != NULL) { PSI_MUTEX_CALL(destroy_mutex)(that->m_psi); that->m_psi= NULL; } #endif #ifdef SAFE_MUTEX return safe_mutex_destroy(&that->m_mutex, src_file, src_line); #else return pthread_mutex_destroy(&that->m_mutex); #endif } #ifdef HAVE_PSI_MUTEX_INTERFACE ATTRIBUTE_COLD int psi_mutex_lock(mysql_mutex_t *that, const char *file, uint line); ATTRIBUTE_COLD int psi_mutex_trylock(mysql_mutex_t *that, const char *file, uint line); #endif static inline int inline_mysql_mutex_lock( mysql_mutex_t *that #if defined(SAFE_MUTEX) || defined (HAVE_PSI_MUTEX_INTERFACE) , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_MUTEX_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_mutex_lock(that, src_file, src_line); #endif /* Non instrumented code */ #ifdef SAFE_MUTEX return safe_mutex_lock(&that->m_mutex, FALSE, src_file, src_line); #else return pthread_mutex_lock(&that->m_mutex); #endif } static inline int inline_mysql_mutex_trylock( mysql_mutex_t *that #if defined(SAFE_MUTEX) || defined (HAVE_PSI_MUTEX_INTERFACE) , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_MUTEX_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_mutex_trylock(that, src_file, src_line); #endif /* Non instrumented code */ #ifdef SAFE_MUTEX return safe_mutex_lock(&that->m_mutex, TRUE, src_file, src_line); #else return pthread_mutex_trylock(&that->m_mutex); #endif } static inline int inline_mysql_mutex_unlock( mysql_mutex_t *that #ifdef SAFE_MUTEX , const char *src_file, uint src_line #endif ) { int result; #ifdef HAVE_PSI_MUTEX_INTERFACE if (psi_likely(that->m_psi != NULL)) PSI_MUTEX_CALL(unlock_mutex)(that->m_psi); #endif #ifdef SAFE_MUTEX result= safe_mutex_unlock(&that->m_mutex, src_file, src_line); #else result= pthread_mutex_unlock(&that->m_mutex); #endif return result; } static inline void inline_mysql_rwlock_register( #ifdef HAVE_PSI_RWLOCK_INTERFACE const char *category, PSI_rwlock_info *info, int count #else const char *category __attribute__ ((unused)), void *info __attribute__ ((unused)), int count __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE PSI_RWLOCK_CALL(register_rwlock)(category, info, count); #endif } static inline int inline_mysql_rwlock_init( #ifdef HAVE_PSI_RWLOCK_INTERFACE PSI_rwlock_key key, #endif mysql_rwlock_t *that) { #ifdef HAVE_PSI_RWLOCK_INTERFACE that->m_psi= PSI_RWLOCK_CALL(init_rwlock)(key, &that->m_rwlock); #else that->m_psi= NULL; #endif /* pthread_rwlockattr_t is not used in MySQL. */ return my_rwlock_init(&that->m_rwlock, NULL); } #ifndef DISABLE_MYSQL_PRLOCK_H static inline int inline_mysql_prlock_init( #ifdef HAVE_PSI_RWLOCK_INTERFACE PSI_rwlock_key key, #endif mysql_prlock_t *that) { #ifdef HAVE_PSI_RWLOCK_INTERFACE that->m_psi= PSI_RWLOCK_CALL(init_rwlock)(key, &that->m_prlock); #else that->m_psi= NULL; #endif return rw_pr_init(&that->m_prlock); } #endif static inline int inline_mysql_rwlock_destroy( mysql_rwlock_t *that) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) { PSI_RWLOCK_CALL(destroy_rwlock)(that->m_psi); that->m_psi= NULL; } #endif return rwlock_destroy(&that->m_rwlock); } #ifndef DISABLE_MYSQL_PRLOCK_H static inline int inline_mysql_prlock_destroy( mysql_prlock_t *that) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) { PSI_RWLOCK_CALL(destroy_rwlock)(that->m_psi); that->m_psi= NULL; } #endif return rw_pr_destroy(&that->m_prlock); } #endif #ifdef HAVE_PSI_RWLOCK_INTERFACE ATTRIBUTE_COLD int psi_rwlock_rdlock(mysql_rwlock_t *that, const char *file, uint line); ATTRIBUTE_COLD int psi_rwlock_tryrdlock(mysql_rwlock_t *that, const char *file, uint line); ATTRIBUTE_COLD int psi_rwlock_wrlock(mysql_rwlock_t *that, const char *file, uint line); ATTRIBUTE_COLD int psi_rwlock_trywrlock(mysql_rwlock_t *that, const char *file, uint line); # ifndef DISABLE_MYSQL_PRLOCK_H ATTRIBUTE_COLD int psi_prlock_rdlock(mysql_prlock_t *that, const char *file, uint line); ATTRIBUTE_COLD int psi_prlock_wrlock(mysql_prlock_t *that, const char *file, uint line); # endif #endif static inline int inline_mysql_rwlock_rdlock( mysql_rwlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_rwlock_rdlock(that, src_file, src_line); #endif return rw_rdlock(&that->m_rwlock); } #ifndef DISABLE_MYSQL_PRLOCK_H static inline int inline_mysql_prlock_rdlock( mysql_prlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_prlock_rdlock(that, src_file, src_line); #endif return rw_pr_rdlock(&that->m_prlock); } #endif static inline int inline_mysql_rwlock_wrlock( mysql_rwlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_rwlock_wrlock(that, src_file, src_line); #endif return rw_wrlock(&that->m_rwlock); } #ifndef DISABLE_MYSQL_PRLOCK_H static inline int inline_mysql_prlock_wrlock( mysql_prlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_prlock_wrlock(that, src_file, src_line); #endif return rw_pr_wrlock(&that->m_prlock); } #endif static inline int inline_mysql_rwlock_tryrdlock( mysql_rwlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_rwlock_tryrdlock(that, src_file, src_line); #endif return rw_tryrdlock(&that->m_rwlock); } static inline int inline_mysql_rwlock_trywrlock( mysql_rwlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_rwlock_trywrlock(that, src_file, src_line); #endif return rw_trywrlock(&that->m_rwlock); } static inline int inline_mysql_rwlock_unlock( mysql_rwlock_t *that) { int result; #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) PSI_RWLOCK_CALL(unlock_rwlock)(that->m_psi); #endif result= rw_unlock(&that->m_rwlock); return result; } #ifndef DISABLE_MYSQL_PRLOCK_H static inline int inline_mysql_prlock_unlock( mysql_prlock_t *that) { int result; #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) PSI_RWLOCK_CALL(unlock_rwlock)(that->m_psi); #endif result= rw_pr_unlock(&that->m_prlock); return result; } #endif static inline void inline_mysql_cond_register( #ifdef HAVE_PSI_COND_INTERFACE const char *category, PSI_cond_info *info, int count #else const char *category __attribute__ ((unused)), void *info __attribute__ ((unused)), int count __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_COND_INTERFACE PSI_COND_CALL(register_cond)(category, info, count); #endif } static inline int inline_mysql_cond_init( #ifdef HAVE_PSI_COND_INTERFACE PSI_cond_key key, #endif mysql_cond_t *that, const pthread_condattr_t *attr) { #ifdef HAVE_PSI_COND_INTERFACE that->m_psi= PSI_COND_CALL(init_cond)(key, &that->m_cond); #else that->m_psi= NULL; #endif return pthread_cond_init(&that->m_cond, attr); } static inline int inline_mysql_cond_destroy( mysql_cond_t *that) { #ifdef HAVE_PSI_COND_INTERFACE if (psi_likely(that->m_psi != NULL)) { PSI_COND_CALL(destroy_cond)(that->m_psi); that->m_psi= NULL; } #endif return pthread_cond_destroy(&that->m_cond); } #ifdef HAVE_PSI_COND_INTERFACE ATTRIBUTE_COLD int psi_cond_wait(mysql_cond_t *that, mysql_mutex_t *mutex, const char *file, uint line); ATTRIBUTE_COLD int psi_cond_timedwait(mysql_cond_t *that, mysql_mutex_t *mutex, const struct timespec *abstime, const char *file, uint line); #endif static inline int inline_mysql_cond_wait( mysql_cond_t *that, mysql_mutex_t *mutex #if defined(SAFE_MUTEX) || defined(HAVE_PSI_COND_INTERFACE) , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_COND_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_cond_wait(that, mutex, src_file, src_line); #endif return my_cond_wait(&that->m_cond, &mutex->m_mutex); } static inline int inline_mysql_cond_timedwait( mysql_cond_t *that, mysql_mutex_t *mutex, const struct timespec *abstime #if defined(SAFE_MUTEX) || defined(HAVE_PSI_COND_INTERFACE) , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_COND_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_cond_timedwait(that, mutex, abstime, src_file, src_line); #endif return my_cond_timedwait(&that->m_cond, &mutex->m_mutex, abstime); } static inline int inline_mysql_cond_signal( mysql_cond_t *that) { int result; #ifdef HAVE_PSI_COND_INTERFACE if (psi_likely(that->m_psi != NULL)) PSI_COND_CALL(signal_cond)(that->m_psi); #endif result= pthread_cond_signal(&that->m_cond); return result; } static inline int inline_mysql_cond_broadcast( mysql_cond_t *that) { int result; #ifdef HAVE_PSI_COND_INTERFACE if (psi_likely(that->m_psi != NULL)) PSI_COND_CALL(broadcast_cond)(that->m_psi); #endif result= pthread_cond_broadcast(&that->m_cond); return result; } static inline void inline_mysql_thread_register( #ifdef HAVE_PSI_THREAD_INTERFACE const char *category, PSI_thread_info *info, int count #else const char *category __attribute__ ((unused)), void *info __attribute__ ((unused)), int count __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_THREAD_INTERFACE PSI_THREAD_CALL(register_thread)(category, info, count); #endif } #ifdef HAVE_PSI_THREAD_INTERFACE static inline int inline_mysql_thread_create( PSI_thread_key key, pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg) { int result; result= PSI_THREAD_CALL(spawn_thread)(key, thread, attr, start_routine, arg); return result; } static inline void inline_mysql_thread_set_psi_id(my_thread_id id) { struct PSI_thread *psi= PSI_THREAD_CALL(get_thread)(); PSI_THREAD_CALL(set_thread_id)(psi, id); } #ifdef __cplusplus class THD; static inline void inline_mysql_thread_set_psi_THD(THD *thd) { struct PSI_thread *psi= PSI_THREAD_CALL(get_thread)(); PSI_THREAD_CALL(set_thread_THD)(psi, thd); } #endif /* __cplusplus */ static inline void mysql_thread_set_peer_port(uint port __attribute__ ((unused))) { #ifdef HAVE_PSI_THREAD_INTERFACE struct PSI_thread *psi = PSI_THREAD_CALL(get_thread)(); PSI_THREAD_CALL(set_thread_peer_port)(psi, port); #endif } #endif #endif /* DISABLE_MYSQL_THREAD_H */ /** @} (end of group Thread_instrumentation) */ #endif psi/mysql_stage.h000064400000012112151030241300010022 0ustar00/* Copyright (c) 2010, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_STAGE_H #define MYSQL_STAGE_H /** @file mysql/psi/mysql_stage.h Instrumentation helpers for stages. */ #include "mysql/psi/psi.h" #ifndef PSI_STAGE_CALL #define PSI_STAGE_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Stage_instrumentation Stage Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_stage_register(P1, P2, P3) Stage registration. */ #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_stage_register(P1, P2, P3) \ inline_mysql_stage_register(P1, P2, P3) #else #define mysql_stage_register(P1, P2, P3) \ do {} while (0) #endif /** @def MYSQL_SET_STAGE Set the current stage. Use this API when the file and line is passed from the caller. @param K the stage key @param F the source file name @param L the source file line @return the current stage progress */ #ifdef HAVE_PSI_STAGE_INTERFACE #define MYSQL_SET_STAGE(K, F, L) \ inline_mysql_set_stage(K, F, L) #else #define MYSQL_SET_STAGE(K, F, L) \ NULL #endif /** @def mysql_set_stage Set the current stage. @param K the stage key @return the current stage progress */ #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_set_stage(K) \ inline_mysql_set_stage(K, __FILE__, __LINE__) #else #define mysql_set_stage(K) \ NULL #endif /** @def mysql_end_stage End the last stage */ #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_end_stage() \ inline_mysql_end_stage() #else #define mysql_end_stage() \ do {} while (0) #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline void inline_mysql_stage_register( const char *category, PSI_stage_info **info, int count) { PSI_STAGE_CALL(register_stage)(category, info, count); } #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline PSI_stage_progress* inline_mysql_set_stage(PSI_stage_key key, const char *src_file, int src_line) { return PSI_STAGE_CALL(start_stage)(key, src_file, src_line); } #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline void inline_mysql_end_stage() { PSI_STAGE_CALL(end_stage)(); } #endif #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_stage_set_work_completed(P1, P2) \ inline_mysql_stage_set_work_completed(P1, P2) #define mysql_stage_get_work_completed(P1) \ inline_mysql_stage_get_work_completed(P1) #else #define mysql_stage_set_work_completed(P1, P2) \ do {} while (0) #define mysql_stage_get_work_completed(P1) \ do {} while (0) #endif #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_stage_inc_work_completed(P1, P2) \ inline_mysql_stage_inc_work_completed(P1, P2) #else #define mysql_stage_inc_work_completed(P1, P2) \ do {} while (0) #endif #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_stage_set_work_estimated(P1, P2) \ inline_mysql_stage_set_work_estimated(P1, P2) #define mysql_stage_get_work_estimated(P1) \ inline_mysql_stage_get_work_estimated(P1) #else #define mysql_stage_set_work_estimated(P1, P2) \ do {} while (0) #define mysql_stage_get_work_estimated(P1) \ do {} while (0) #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline void inline_mysql_stage_set_work_completed(PSI_stage_progress *progress, ulonglong val) { if (progress != NULL) progress->m_work_completed= val; } static inline ulonglong inline_mysql_stage_get_work_completed(PSI_stage_progress *progress) { return progress->m_work_completed; } #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline void inline_mysql_stage_inc_work_completed(PSI_stage_progress *progress, ulonglong val) { if (progress != NULL) progress->m_work_completed+= val; } #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline void inline_mysql_stage_set_work_estimated(PSI_stage_progress *progress, ulonglong val) { if (progress != NULL) progress->m_work_estimated= val; } static inline ulonglong inline_mysql_stage_get_work_estimated(PSI_stage_progress *progress) { return progress->m_work_estimated; } #endif /** @} (end of group Stage_instrumentation) */ #endif psi/mysql_ps.h000064400000007447151030241300007360 0ustar00/* Copyright (c) 2014, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MYSQL_PS_H #define MYSQL_PS_H /** @file mysql/psi/mysql_ps.h Instrumentation helpers for prepared statements. */ #include "mysql/psi/psi.h" #ifndef PSI_PS_CALL #define PSI_PS_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifdef HAVE_PSI_PS_INTERFACE #define MYSQL_CREATE_PS(IDENTITY, ID, LOCKER, NAME, NAME_LENGTH) \ inline_mysql_create_prepared_stmt(IDENTITY, ID, LOCKER, NAME, NAME_LENGTH) #define MYSQL_EXECUTE_PS(LOCKER, PREPARED_STMT) \ inline_mysql_execute_prepared_stmt(LOCKER, PREPARED_STMT) #define MYSQL_DESTROY_PS(PREPARED_STMT) \ inline_mysql_destroy_prepared_stmt(PREPARED_STMT) #define MYSQL_REPREPARE_PS(PREPARED_STMT) \ inline_mysql_reprepare_prepared_stmt(PREPARED_STMT) #define MYSQL_SET_PS_TEXT(PREPARED_STMT, SQLTEXT, SQLTEXT_LENGTH) \ inline_mysql_set_prepared_stmt_text(PREPARED_STMT, SQLTEXT, SQLTEXT_LENGTH) #else #define MYSQL_CREATE_PS(IDENTITY, ID, LOCKER, NAME, NAME_LENGTH) \ NULL #define MYSQL_EXECUTE_PS(LOCKER, PREPARED_STMT) \ do {} while (0) #define MYSQL_DESTROY_PS(PREPARED_STMT) \ do {} while (0) #define MYSQL_REPREPARE_PS(PREPARED_STMT) \ do {} while (0) #define MYSQL_SET_PS_TEXT(PREPARED_STMT, SQLTEXT, SQLTEXT_LENGTH) \ do {} while (0) #endif #ifdef HAVE_PSI_PS_INTERFACE static inline struct PSI_prepared_stmt* inline_mysql_create_prepared_stmt(void *identity, uint stmt_id, PSI_statement_locker *locker, const char *stmt_name, size_t stmt_name_length) { if (locker == NULL) return NULL; return PSI_PS_CALL(create_prepared_stmt)(identity, stmt_id, locker, stmt_name, stmt_name_length); } static inline void inline_mysql_execute_prepared_stmt(PSI_statement_locker *locker, PSI_prepared_stmt* prepared_stmt) { if (prepared_stmt != NULL && locker != NULL) PSI_PS_CALL(execute_prepared_stmt)(locker, prepared_stmt); } static inline void inline_mysql_destroy_prepared_stmt(PSI_prepared_stmt *prepared_stmt) { if (prepared_stmt != NULL) PSI_PS_CALL(destroy_prepared_stmt)(prepared_stmt); } static inline void inline_mysql_reprepare_prepared_stmt(PSI_prepared_stmt *prepared_stmt) { if (prepared_stmt != NULL) PSI_PS_CALL(reprepare_prepared_stmt)(prepared_stmt); } static inline void inline_mysql_set_prepared_stmt_text(PSI_prepared_stmt *prepared_stmt, const char *text, uint text_len) { if (prepared_stmt != NULL) { PSI_PS_CALL(set_prepared_stmt_text)(prepared_stmt, text, text_len); } } #endif #endif psi/mysql_memory.h000064400000005067151030241300010242 0ustar00/* Copyright (c) 2012, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef MYSQL_MEMORY_H #define MYSQL_MEMORY_H /** @file mysql/psi/mysql_memory.h Instrumentation helpers for memory allocation. */ #include "mysql/psi/psi.h" #ifdef HAVE_PSI_MEMORY_INTERFACE #define PSI_CALL_memory_alloc(A1,A2,A3) PSI_MEMORY_CALL(memory_alloc)(A1,A2,A3) #define PSI_CALL_memory_free(A1,A2,A3) PSI_MEMORY_CALL(memory_free)(A1,A2,A3) #define PSI_CALL_memory_realloc(A1,A2,A3,A4) PSI_MEMORY_CALL(memory_realloc)(A1,A2,A3,A4) #define PSI_CALL_register_memory(A1,A2,A3) PSI_MEMORY_CALL(register_memory)(A1,A2,A3) #else #define PSI_CALL_memory_alloc(A1,A2,A3) 0 #define PSI_CALL_memory_free(A1,A2,A3) do { } while(0) #define PSI_CALL_memory_realloc(A1,A2,A3,A4) 0 #define PSI_CALL_register_memory(A1,A2,A3) do { } while(0) #endif #ifndef PSI_MEMORY_CALL #define PSI_MEMORY_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Memory_instrumentation Memory Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_memory_register(P1, P2, P3) Memory registration. */ #define mysql_memory_register(P1, P2, P3) \ inline_mysql_memory_register(P1, P2, P3) static inline void inline_mysql_memory_register( #ifdef HAVE_PSI_MEMORY_INTERFACE const char *category, PSI_memory_info *info, int count) #else const char *category __attribute__((unused)), void *info __attribute__((unused)), int count __attribute__((unused))) #endif { PSI_CALL_register_memory(category, info, count); } /** @} (end of group Memory_instrumentation) */ #endif psi/mysql_transaction.h000064400000016100151030241300011245 0ustar00/* Copyright (c) 2013, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MYSQL_TRANSACTION_H #define MYSQL_TRANSACTION_H /** @file mysql/psi/mysql_transaction.h Instrumentation helpers for transactions. */ #include "mysql/psi/psi.h" #ifndef PSI_TRANSACTION_CALL #define PSI_TRANSACTION_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Transaction_instrumentation Transaction Instrumentation @ingroup Instrumentation_interface @{ */ #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_START_TRANSACTION(STATE, XID, TRXID, ISO, RO, AC) \ inline_mysql_start_transaction(STATE, XID, TRXID, ISO, RO, AC, __FILE__, __LINE__) #else #define MYSQL_START_TRANSACTION(STATE, XID, TRXID, ISO, RO, AC) \ 0 #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_SET_TRANSACTION_GTID(LOCKER, P1, P2) \ inline_mysql_set_transaction_gtid(LOCKER, P1, P2) #else #define MYSQL_SET_TRANSACTION_GTID(LOCKER, P1, P2) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_SET_TRANSACTION_XID(LOCKER, P1, P2) \ inline_mysql_set_transaction_xid(LOCKER, P1, P2) #else #define MYSQL_SET_TRANSACTION_XID(LOCKER, P1, P2) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_SET_TRANSACTION_XA_STATE(LOCKER, P1) \ inline_mysql_set_transaction_xa_state(LOCKER, P1) #else #define MYSQL_SET_TRANSACTION_XA_STATE(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_SET_TRANSACTION_TRXID(LOCKER, P1) \ inline_mysql_set_transaction_trxid(LOCKER, P1) #else #define MYSQL_SET_TRANSACTION_TRXID(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_INC_TRANSACTION_SAVEPOINTS(LOCKER, P1) \ inline_mysql_inc_transaction_savepoints(LOCKER, P1) #else #define MYSQL_INC_TRANSACTION_SAVEPOINTS(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_INC_TRANSACTION_ROLLBACK_TO_SAVEPOINT(LOCKER, P1) \ inline_mysql_inc_transaction_rollback_to_savepoint(LOCKER, P1) #else #define MYSQL_INC_TRANSACTION_ROLLBACK_TO_SAVEPOINT(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_INC_TRANSACTION_RELEASE_SAVEPOINT(LOCKER, P1) \ inline_mysql_inc_transaction_release_savepoint(LOCKER, P1) #else #define MYSQL_INC_TRANSACTION_RELEASE_SAVEPOINT(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_ROLLBACK_TRANSACTION(LOCKER) \ inline_mysql_rollback_transaction(LOCKER) #else #define MYSQL_ROLLBACK_TRANSACTION(LOCKER) \ do { } while(0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_COMMIT_TRANSACTION(LOCKER) \ inline_mysql_commit_transaction(LOCKER) #else #define MYSQL_COMMIT_TRANSACTION(LOCKER) \ do { } while(0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE static inline struct PSI_transaction_locker * inline_mysql_start_transaction(PSI_transaction_locker_state *state, const void *xid, ulonglong trxid, int isolation_level, my_bool read_only, my_bool autocommit, const char *src_file, int src_line) { PSI_transaction_locker *locker; locker= PSI_TRANSACTION_CALL(get_thread_transaction_locker)(state, xid, trxid, isolation_level, read_only, autocommit); if (likely(locker != NULL)) PSI_TRANSACTION_CALL(start_transaction)(locker, src_file, src_line); return locker; } static inline void inline_mysql_set_transaction_gtid(PSI_transaction_locker *locker, const void *sid, const void *gtid_spec) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(set_transaction_gtid)(locker, sid, gtid_spec); } static inline void inline_mysql_set_transaction_xid(PSI_transaction_locker *locker, const void *xid, int xa_state) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(set_transaction_xid)(locker, xid, xa_state); } static inline void inline_mysql_set_transaction_xa_state(PSI_transaction_locker *locker, int xa_state) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(set_transaction_xa_state)(locker, xa_state); } static inline void inline_mysql_set_transaction_trxid(PSI_transaction_locker *locker, const ulonglong *trxid) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(set_transaction_trxid)(locker, trxid); } static inline void inline_mysql_inc_transaction_savepoints(PSI_transaction_locker *locker, ulong count) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(inc_transaction_savepoints)(locker, count); } static inline void inline_mysql_inc_transaction_rollback_to_savepoint(PSI_transaction_locker *locker, ulong count) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(inc_transaction_rollback_to_savepoint)(locker, count); } static inline void inline_mysql_inc_transaction_release_savepoint(PSI_transaction_locker *locker, ulong count) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(inc_transaction_release_savepoint)(locker, count); } static inline void inline_mysql_rollback_transaction(struct PSI_transaction_locker *locker) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(end_transaction)(locker, false); } static inline void inline_mysql_commit_transaction(struct PSI_transaction_locker *locker) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(end_transaction)(locker, true); } #endif /** @} (end of group Transaction_instrumentation) */ #endif psi/mysql_sp.h000064400000006250151030241300007347 0ustar00/* Copyright (c) 2013, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MYSQL_SP_H #define MYSQL_SP_H /** @file mysql/psi/mysql_sp.h Instrumentation helpers for stored programs. */ #include "mysql/psi/psi.h" #ifndef PSI_SP_CALL #define PSI_SP_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifdef HAVE_PSI_SP_INTERFACE #define MYSQL_START_SP(STATE, SP_SHARE) \ inline_mysql_start_sp(STATE, SP_SHARE) #else #define MYSQL_START_SP(STATE, SP_SHARE) \ NULL #endif #ifdef HAVE_PSI_SP_INTERFACE #define MYSQL_END_SP(LOCKER) \ inline_mysql_end_sp(LOCKER) #else #define MYSQL_END_SP(LOCKER) \ do {} while (0) #endif #ifdef HAVE_PSI_SP_INTERFACE #define MYSQL_DROP_SP(OT, SN, SNL, ON, ONL) \ inline_mysql_drop_sp(OT, SN, SNL, ON, ONL) #else #define MYSQL_DROP_SP(OT, SN, SNL, ON, ONL) \ do {} while (0) #endif #ifdef HAVE_PSI_SP_INTERFACE #define MYSQL_GET_SP_SHARE(OT, SN, SNL, ON, ONL) \ inline_mysql_get_sp_share(OT, SN, SNL, ON, ONL) #else #define MYSQL_GET_SP_SHARE(OT, SN, SNL, ON, ONL) \ NULL #endif #ifdef HAVE_PSI_SP_INTERFACE static inline struct PSI_sp_locker* inline_mysql_start_sp(PSI_sp_locker_state *state, PSI_sp_share *sp_share) { return PSI_SP_CALL(start_sp)(state, sp_share); } static inline void inline_mysql_end_sp(PSI_sp_locker *locker) { if (likely(locker != NULL)) PSI_SP_CALL(end_sp)(locker); } static inline void inline_mysql_drop_sp(uint sp_type, const char* schema_name, uint shcema_name_length, const char* object_name, uint object_name_length) { PSI_SP_CALL(drop_sp)(sp_type, schema_name, shcema_name_length, object_name, object_name_length); } static inline PSI_sp_share* inline_mysql_get_sp_share(uint sp_type, const char* schema_name, uint shcema_name_length, const char* object_name, uint object_name_length) { return PSI_SP_CALL(get_sp_share)(sp_type, schema_name, shcema_name_length, object_name, object_name_length); } #endif #endif psi/mysql_file.h000064400000117763151030241300007660 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_FILE_H #define MYSQL_FILE_H /* For strlen() */ #include /* For MY_STAT */ #include /* For my_chsize */ #include /** @file mysql/psi/mysql_file.h Instrumentation helpers for mysys file io. This header file provides the necessary declarations to use the mysys file API with the performance schema instrumentation. In some compilers (SunStudio), 'static inline' functions, when declared but not used, are not optimized away (because they are unused) by default, so that including a static inline function from a header file does create unwanted dependencies, causing unresolved symbols at link time. Other compilers, like gcc, optimize these dependencies by default. Since the instrumented APIs declared here are wrapper on top of mysys file io APIs, including mysql/psi/mysql_file.h assumes that the dependency on my_sys already exists. */ #include "mysql/psi/psi.h" #ifndef PSI_FILE_CALL #define PSI_FILE_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup File_instrumentation File Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_file_register(P1, P2, P3) File registration. */ #define mysql_file_register(P1, P2, P3) \ inline_mysql_file_register(P1, P2, P3) /** @def mysql_file_fgets(P1, P2, F) Instrumented fgets. @c mysql_file_fgets is a replacement for @c fgets. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fgets(P1, P2, F) \ inline_mysql_file_fgets(__FILE__, __LINE__, P1, P2, F) #else #define mysql_file_fgets(P1, P2, F) \ inline_mysql_file_fgets(P1, P2, F) #endif /** @def mysql_file_fgetc(F) Instrumented fgetc. @c mysql_file_fgetc is a replacement for @c fgetc. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fgetc(F) inline_mysql_file_fgetc(__FILE__, __LINE__, F) #else #define mysql_file_fgetc(F) inline_mysql_file_fgetc(F) #endif /** @def mysql_file_fputs(P1, F) Instrumented fputs. @c mysql_file_fputs is a replacement for @c fputs. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fputs(P1, F) \ inline_mysql_file_fputs(__FILE__, __LINE__, P1, F) #else #define mysql_file_fputs(P1, F)\ inline_mysql_file_fputs(P1, F) #endif /** @def mysql_file_fputc(P1, F) Instrumented fputc. @c mysql_file_fputc is a replacement for @c fputc. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fputc(P1, F) \ inline_mysql_file_fputc(__FILE__, __LINE__, P1, F) #else #define mysql_file_fputc(P1, F) \ inline_mysql_file_fputc(P1, F) #endif /** @def mysql_file_fprintf Instrumented fprintf. @c mysql_file_fprintf is a replacement for @c fprintf. */ #define mysql_file_fprintf inline_mysql_file_fprintf /** @def mysql_file_vfprintf(F, P1, P2) Instrumented vfprintf. @c mysql_file_vfprintf is a replacement for @c vfprintf. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_vfprintf(F, P1, P2) \ inline_mysql_file_vfprintf(__FILE__, __LINE__, F, P1, P2) #else #define mysql_file_vfprintf(F, P1, P2) \ inline_mysql_file_vfprintf(F, P1, P2) #endif /** @def mysql_file_fflush(F, P1, P2) Instrumented fflush. @c mysql_file_fflush is a replacement for @c fflush. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fflush(F) \ inline_mysql_file_fflush(__FILE__, __LINE__, F) #else #define mysql_file_fflush(F) \ inline_mysql_file_fflush(F) #endif /** @def mysql_file_feof(F) Instrumented feof. @c mysql_file_feof is a replacement for @c feof. */ #define mysql_file_feof(F) inline_mysql_file_feof(F) /** @def mysql_file_fstat(FN, S, FL) Instrumented fstat. @c mysql_file_fstat is a replacement for @c my_fstat. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fstat(FN, S, FL) \ inline_mysql_file_fstat(__FILE__, __LINE__, FN, S, FL) #else #define mysql_file_fstat(FN, S, FL) \ inline_mysql_file_fstat(FN, S, FL) #endif /** @def mysql_file_stat(K, FN, S, FL) Instrumented stat. @c mysql_file_stat is a replacement for @c my_stat. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_stat(K, FN, S, FL) \ inline_mysql_file_stat(K, __FILE__, __LINE__, FN, S, FL) #else #define mysql_file_stat(K, FN, S, FL) \ inline_mysql_file_stat(FN, S, FL) #endif /** @def mysql_file_chsize(F, P1, P2, P3) Instrumented chsize. @c mysql_file_chsize is a replacement for @c my_chsize. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_chsize(F, P1, P2, P3) \ inline_mysql_file_chsize(__FILE__, __LINE__, F, P1, P2, P3) #else #define mysql_file_chsize(F, P1, P2, P3) \ inline_mysql_file_chsize(F, P1, P2, P3) #endif /** @def mysql_file_fopen(K, N, F1, F2) Instrumented fopen. @c mysql_file_fopen is a replacement for @c my_fopen. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fopen(K, N, F1, F2) \ inline_mysql_file_fopen(K, __FILE__, __LINE__, N, F1, F2) #else #define mysql_file_fopen(K, N, F1, F2) \ inline_mysql_file_fopen(N, F1, F2) #endif /** @def mysql_file_fclose(FD, FL) Instrumented fclose. @c mysql_file_fclose is a replacement for @c my_fclose. Without the instrumentation, this call will have the same behavior as the undocumented and possibly platform specific my_fclose(NULL, ...) behavior. With the instrumentation, mysql_fclose(NULL, ...) will safely return 0, which is an extension compared to my_fclose and is therefore compliant. mysql_fclose is on purpose *not* implementing @code assert(file != NULL) @endcode, since doing so could introduce regressions. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fclose(FD, FL) \ inline_mysql_file_fclose(__FILE__, __LINE__, FD, FL) #else #define mysql_file_fclose(FD, FL) \ inline_mysql_file_fclose(FD, FL) #endif /** @def mysql_file_fread(FD, P1, P2, P3) Instrumented fread. @c mysql_file_fread is a replacement for @c my_fread. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fread(FD, P1, P2, P3) \ inline_mysql_file_fread(__FILE__, __LINE__, FD, P1, P2, P3) #else #define mysql_file_fread(FD, P1, P2, P3) \ inline_mysql_file_fread(FD, P1, P2, P3) #endif /** @def mysql_file_fwrite(FD, P1, P2, P3) Instrumented fwrite. @c mysql_file_fwrite is a replacement for @c my_fwrite. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fwrite(FD, P1, P2, P3) \ inline_mysql_file_fwrite(__FILE__, __LINE__, FD, P1, P2, P3) #else #define mysql_file_fwrite(FD, P1, P2, P3) \ inline_mysql_file_fwrite(FD, P1, P2, P3) #endif /** @def mysql_file_fseek(FD, P, W, F) Instrumented fseek. @c mysql_file_fseek is a replacement for @c my_fseek. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fseek(FD, P, W, F) \ inline_mysql_file_fseek(__FILE__, __LINE__, FD, P, W, F) #else #define mysql_file_fseek(FD, P, W, F) \ inline_mysql_file_fseek(FD, P, W, F) #endif /** @def mysql_file_ftell(FD, F) Instrumented ftell. @c mysql_file_ftell is a replacement for @c my_ftell. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_ftell(FD, F) \ inline_mysql_file_ftell(__FILE__, __LINE__, FD, F) #else #define mysql_file_ftell(FD, F) \ inline_mysql_file_ftell(FD, F) #endif /** @def mysql_file_create(K, N, F1, F2, F3) Instrumented create. @c mysql_file_create is a replacement for @c my_create. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_create(K, N, F1, F2, F3) \ inline_mysql_file_create(K, __FILE__, __LINE__, N, F1, F2, F3) #else #define mysql_file_create(K, N, F1, F2, F3) \ inline_mysql_file_create(N, F1, F2, F3) #endif /** @def mysql_file_create_temp(K, T, D, P, M, F) Instrumented create_temp_file. @c mysql_file_create_temp is a replacement for @c create_temp_file. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_create_temp(K, T, D, P, M, F) \ inline_mysql_file_create_temp(K, __FILE__, __LINE__, T, D, P, M, F) #else #define mysql_file_create_temp(K, T, D, P, M, F) \ inline_mysql_file_create_temp(T, D, P, M, F) #endif /** @def mysql_file_open(K, N, F1, F2) Instrumented open. @c mysql_file_open is a replacement for @c my_open. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_open(K, N, F1, F2) \ inline_mysql_file_open(K, __FILE__, __LINE__, N, F1, F2) #else #define mysql_file_open(K, N, F1, F2) \ inline_mysql_file_open(N, F1, F2) #endif /** @def mysql_file_close(FD, F) Instrumented close. @c mysql_file_close is a replacement for @c my_close. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_close(FD, F) \ inline_mysql_file_close(__FILE__, __LINE__, FD, F) #else #define mysql_file_close(FD, F) \ inline_mysql_file_close(FD, F) #endif /** @def mysql_file_read(FD, B, S, F) Instrumented read. @c mysql_read is a replacement for @c my_read. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_read(FD, B, S, F) \ inline_mysql_file_read(__FILE__, __LINE__, FD, B, S, F) #else #define mysql_file_read(FD, B, S, F) \ inline_mysql_file_read(FD, B, S, F) #endif /** @def mysql_file_write(FD, B, S, F) Instrumented write. @c mysql_file_write is a replacement for @c my_write. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_write(FD, B, S, F) \ inline_mysql_file_write(__FILE__, __LINE__, FD, B, S, F) #else #define mysql_file_write(FD, B, S, F) \ inline_mysql_file_write(FD, B, S, F) #endif /** @def mysql_file_pread(FD, B, S, O, F) Instrumented pread. @c mysql_pread is a replacement for @c my_pread. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_pread(FD, B, S, O, F) \ inline_mysql_file_pread(__FILE__, __LINE__, FD, B, S, O, F) #else #define mysql_file_pread(FD, B, S, O, F) \ inline_mysql_file_pread(FD, B, S, O, F) #endif /** @def mysql_file_pwrite(FD, B, S, O, F) Instrumented pwrite. @c mysql_file_pwrite is a replacement for @c my_pwrite. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_pwrite(FD, B, S, O, F) \ inline_mysql_file_pwrite(__FILE__, __LINE__, FD, B, S, O, F) #else #define mysql_file_pwrite(FD, B, S, O, F) \ inline_mysql_file_pwrite(FD, B, S, O, F) #endif /** @def mysql_file_seek(FD, P, W, F) Instrumented seek. @c mysql_file_seek is a replacement for @c my_seek. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_seek(FD, P, W, F) \ inline_mysql_file_seek(__FILE__, __LINE__, FD, P, W, F) #else #define mysql_file_seek(FD, P, W, F) \ inline_mysql_file_seek(FD, P, W, F) #endif /** @def mysql_file_tell(FD, F) Instrumented tell. @c mysql_file_tell is a replacement for @c my_tell. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_tell(FD, F) \ inline_mysql_file_tell(__FILE__, __LINE__, FD, F) #else #define mysql_file_tell(FD, F) \ inline_mysql_file_tell(FD, F) #endif /** @def mysql_file_delete(K, P1, P2) Instrumented delete. @c mysql_file_delete is a replacement for @c my_delete. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_delete(K, P1, P2) \ inline_mysql_file_delete(K, __FILE__, __LINE__, P1, P2) #else #define mysql_file_delete(K, P1, P2) \ inline_mysql_file_delete(P1, P2) #endif /** @def mysql_file_rename(K, P1, P2, P3) Instrumented rename. @c mysql_file_rename is a replacement for @c my_rename. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_rename(K, P1, P2, P3) \ inline_mysql_file_rename(K, __FILE__, __LINE__, P1, P2, P3) #else #define mysql_file_rename(K, P1, P2, P3) \ inline_mysql_file_rename(P1, P2, P3) #endif /** @def mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) Instrumented create with symbolic link. @c mysql_file_create_with_symlink is a replacement for @c my_create_with_symlink. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) \ inline_mysql_file_create_with_symlink(K, __FILE__, __LINE__, \ P1, P2, P3, P4, P5) #else #define mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) \ inline_mysql_file_create_with_symlink(P1, P2, P3, P4, P5) #endif /** @def mysql_file_delete_with_symlink(K, P1, P2, P3) Instrumented delete with symbolic link. @c mysql_file_delete_with_symlink is a replacement for @c my_handler_delete_with_symlink. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_delete_with_symlink(K, P1, P2, P3) \ inline_mysql_file_delete_with_symlink(K, __FILE__, __LINE__, P1, P2, P3) #else #define mysql_file_delete_with_symlink(K, P1, P2, P3) \ inline_mysql_file_delete_with_symlink(P1, P2, P3) #endif /** @def mysql_file_rename_with_symlink(K, P1, P2, P3) Instrumented rename with symbolic link. @c mysql_file_rename_with_symlink is a replacement for @c my_rename_with_symlink. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_rename_with_symlink(K, P1, P2, P3) \ inline_mysql_file_rename_with_symlink(K, __FILE__, __LINE__, P1, P2, P3) #else #define mysql_file_rename_with_symlink(K, P1, P2, P3) \ inline_mysql_file_rename_with_symlink(P1, P2, P3) #endif /** @def mysql_file_sync(P1, P2) Instrumented file sync. @c mysql_file_sync is a replacement for @c my_sync. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_sync(P1, P2) \ inline_mysql_file_sync(__FILE__, __LINE__, P1, P2) #else #define mysql_file_sync(P1, P2) \ inline_mysql_file_sync(P1, P2) #endif /** An instrumented FILE structure. @sa MYSQL_FILE */ struct st_mysql_file { /** The real file. */ FILE *m_file; /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c MYSQL_FILE interface. */ struct PSI_file *m_psi; }; /** Type of an instrumented file. @c MYSQL_FILE is a drop-in replacement for @c FILE. @sa mysql_file_open */ typedef struct st_mysql_file MYSQL_FILE; static inline void inline_mysql_file_register( #ifdef HAVE_PSI_FILE_INTERFACE const char *category, PSI_file_info *info, int count #else const char *category __attribute__ ((unused)), void *info __attribute__ ((unused)), int count __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_FILE_INTERFACE PSI_FILE_CALL(register_file)(category, info, count); #endif } static inline char * inline_mysql_file_fgets( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif char *str, int size, MYSQL_FILE *file) { char *result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker) (&state, file->m_psi, PSI_FILE_READ); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) size, src_file, src_line); result= fgets(str, size, file->m_file); PSI_FILE_CALL(end_file_wait)(locker, result ? strlen(result) : 0); return result; } } #endif result= fgets(str, size, file->m_file); return result; } static inline int inline_mysql_file_fgetc( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file) { int result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_READ); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 1, src_file, src_line); result= fgetc(file->m_file); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 1); return result; } } #endif result= fgetc(file->m_file); return result; } static inline int inline_mysql_file_fputs( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif const char *str, MYSQL_FILE *file) { int result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes; locker= PSI_FILE_CALL(get_thread_file_stream_locker) (&state, file->m_psi, PSI_FILE_WRITE); if (likely(locker != NULL)) { bytes= str ? strlen(str) : 0; PSI_FILE_CALL(start_file_wait)(locker, bytes, src_file, src_line); result= fputs(str, file->m_file); PSI_FILE_CALL(end_file_wait)(locker, bytes); return result; } } #endif result= fputs(str, file->m_file); return result; } static inline int inline_mysql_file_fputc( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif char c, MYSQL_FILE *file) { int result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker) (&state, file->m_psi, PSI_FILE_WRITE); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 1, src_file, src_line); result= fputc(c, file->m_file); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 1); return result; } } #endif result= fputc(c, file->m_file); return result; } static inline int inline_mysql_file_fprintf(MYSQL_FILE *file, const char *format, ...) { /* TODO: figure out how to pass src_file and src_line from the caller. */ int result; va_list args; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker) (&state, file->m_psi, PSI_FILE_WRITE); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, __FILE__, __LINE__); va_start(args, format); result= vfprintf(file->m_file, format, args); va_end(args); PSI_FILE_CALL(end_file_wait)(locker, (size_t) result); return result; } } #endif va_start(args, format); result= vfprintf(file->m_file, format, args); va_end(args); return result; } static inline int inline_mysql_file_vfprintf( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, const char *format, va_list args) { int result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker) (&state, file->m_psi, PSI_FILE_WRITE); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= vfprintf(file->m_file, format, args); PSI_FILE_CALL(end_file_wait)(locker, (size_t) result); return result; } } #endif result= vfprintf(file->m_file, format, args); return result; } static inline int inline_mysql_file_fflush( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file) { int result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_FLUSH); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= fflush(file->m_file); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } } #endif result= fflush(file->m_file); return result; } static inline int inline_mysql_file_feof(MYSQL_FILE *file) { /* Not instrumented, there is no wait involved */ return feof(file->m_file); } static inline int inline_mysql_file_fstat( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif int filenr, MY_STAT *stat_area, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, filenr, PSI_FILE_FSTAT); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_fstat(filenr, stat_area, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } #endif result= my_fstat(filenr, stat_area, flags); return result; } static inline MY_STAT * inline_mysql_file_stat( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *path, MY_STAT *stat_area, myf flags) { MY_STAT *result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_STAT, path, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); result= my_stat(path, stat_area, flags); PSI_FILE_CALL(end_file_open_wait)(locker, result); return result; } #endif result= my_stat(path, stat_area, flags); return result; } static inline int inline_mysql_file_chsize( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, my_off_t newlength, int filler, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_CHSIZE); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) newlength, src_file, src_line); result= my_chsize(file, newlength, filler, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) newlength); return result; } #endif result= my_chsize(file, newlength, filler, flags); return result; } static inline MYSQL_FILE* inline_mysql_file_fopen( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *filename, int flags, myf myFlags) { MYSQL_FILE *that; that= (MYSQL_FILE*) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(MYSQL_FILE), MYF(MY_WME)); if (likely(that != NULL)) { #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_STREAM_OPEN, filename, that); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); that->m_file= my_fopen(filename, flags, myFlags); that->m_psi= PSI_FILE_CALL(end_file_open_wait)(locker, that->m_file); if (unlikely(that->m_file == NULL)) { my_free(that); return NULL; } return that; } #endif that->m_psi= NULL; that->m_file= my_fopen(filename, flags, myFlags); if (unlikely(that->m_file == NULL)) { my_free(that); return NULL; } } return that; } static inline int inline_mysql_file_fclose( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, myf flags) { int result= 0; if (likely(file != NULL)) { #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_STREAM_CLOSE); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_close_wait)(locker, src_file, src_line); result= my_fclose(file->m_file, flags); PSI_FILE_CALL(end_file_close_wait)(locker, result); my_free(file); return result; } } #endif result= my_fclose(file->m_file, flags); my_free(file); } return result; } static inline size_t inline_mysql_file_fread( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, uchar *buffer, size_t count, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_read; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_READ); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_fread(file->m_file, buffer, count, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_read= (result == 0) ? count : 0; else bytes_read= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_read); return result; } } #endif result= my_fread(file->m_file, buffer, count, flags); return result; } static inline size_t inline_mysql_file_fwrite( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, const uchar *buffer, size_t count, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_written; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_WRITE); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_fwrite(file->m_file, buffer, count, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_written= (result == 0) ? count : 0; else bytes_written= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_written); return result; } } #endif result= my_fwrite(file->m_file, buffer, count, flags); return result; } static inline my_off_t inline_mysql_file_fseek( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, my_off_t pos, int whence, myf flags) { my_off_t result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_SEEK); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_fseek(file->m_file, pos, whence, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } } #endif result= my_fseek(file->m_file, pos, whence, flags); return result; } static inline my_off_t inline_mysql_file_ftell( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, myf flags) { my_off_t result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_TELL); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_ftell(file->m_file, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } } #endif result= my_ftell(file->m_file, flags); return result; } static inline File inline_mysql_file_create( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *filename, mode_t create_flags, int access_flags, myf myFlags) { File file; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_CREATE, filename, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); file= my_create(filename, create_flags, access_flags, myFlags); PSI_FILE_CALL(end_file_open_wait_and_bind_to_descriptor)(locker, file); return file; } #endif file= my_create(filename, create_flags, access_flags, myFlags); return file; } static inline File inline_mysql_file_create_temp( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif char *to, const char *dir, const char *pfx, int mode, myf myFlags) { File file; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker) (&state, key, PSI_FILE_CREATE, NULL, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); /* The file name is generated by create_temp_file(). */ file= create_temp_file(to, dir, pfx, mode, myFlags); PSI_FILE_CALL(end_temp_file_open_wait_and_bind_to_descriptor)(locker, file, (const char*)to); return file; } #endif file= create_temp_file(to, dir, pfx, mode, myFlags); return file; } static inline File inline_mysql_file_open( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *filename, int flags, myf myFlags) { File file; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_OPEN, filename, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); file= my_open(filename, flags, myFlags); PSI_FILE_CALL(end_file_open_wait_and_bind_to_descriptor)(locker, file); return file; } #endif file= my_open(filename, flags, myFlags); return file; } static inline int inline_mysql_file_close( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_CLOSE); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_close_wait)(locker, src_file, src_line); result= my_close(file, flags); PSI_FILE_CALL(end_file_close_wait)(locker, result); return result; } #endif result= my_close(file, flags); return result; } static inline size_t inline_mysql_file_read( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, uchar *buffer, size_t count, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_read; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_READ); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_read(file, buffer, count, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_read= (result == 0) ? count : 0; else bytes_read= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_read); return result; } #endif result= my_read(file, buffer, count, flags); return result; } static inline size_t inline_mysql_file_write( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, const uchar *buffer, size_t count, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_written; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_WRITE); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_write(file, buffer, count, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_written= (result == 0) ? count : 0; else bytes_written= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_written); return result; } #endif result= my_write(file, buffer, count, flags); return result; } static inline size_t inline_mysql_file_pread( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, uchar *buffer, size_t count, my_off_t offset, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_read; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_READ); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_pread(file, buffer, count, offset, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_read= (result == 0) ? count : 0; else bytes_read= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_read); return result; } #endif result= my_pread(file, buffer, count, offset, flags); return result; } static inline size_t inline_mysql_file_pwrite( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, const uchar *buffer, size_t count, my_off_t offset, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_written; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_WRITE); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_pwrite(file, buffer, count, offset, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_written= (result == 0) ? count : 0; else bytes_written= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_written); return result; } #endif result= my_pwrite(file, buffer, count, offset, flags); return result; } static inline my_off_t inline_mysql_file_seek( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, my_off_t pos, int whence, myf flags) { my_off_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_SEEK); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_seek(file, pos, whence, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } #endif result= my_seek(file, pos, whence, flags); return result; } static inline my_off_t inline_mysql_file_tell( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, myf flags) { my_off_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_TELL); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_tell(file, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } #endif result= my_tell(file, flags); return result; } static inline int inline_mysql_file_delete( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *name, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_DELETE, name, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_close_wait)(locker, src_file, src_line); result= my_delete(name, flags); PSI_FILE_CALL(end_file_close_wait)(locker, result); return result; } #endif result= my_delete(name, flags); return result; } static inline int inline_mysql_file_rename( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *from, const char *to, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker) (&state, key, PSI_FILE_RENAME, from, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_rename(from, to, flags); PSI_FILE_CALL(end_file_rename_wait)(locker, from, to, result); return result; } #endif result= my_rename(from, to, flags); return result; } static inline File inline_mysql_file_create_with_symlink( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *linkname, const char *filename, mode_t create_flags, int access_flags, myf flags) { File file; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_CREATE, filename, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); file= my_create_with_symlink(linkname, filename, create_flags, access_flags, flags); PSI_FILE_CALL(end_file_open_wait_and_bind_to_descriptor)(locker, file); return file; } #endif file= my_create_with_symlink(linkname, filename, create_flags, access_flags, flags); return file; } static inline int inline_mysql_file_delete_with_symlink( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *name, const char *ext, myf flags) { int result; char buf[FN_REFLEN]; char *fullname= fn_format(buf, name, "", ext, MY_UNPACK_FILENAME | MY_APPEND_EXT); #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_DELETE, fullname, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_close_wait)(locker, src_file, src_line); result= my_handler_delete_with_symlink(fullname, flags); PSI_FILE_CALL(end_file_close_wait)(locker, result); return result; } #endif result= my_handler_delete_with_symlink(fullname, flags); return result; } static inline int inline_mysql_file_rename_with_symlink( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *from, const char *to, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker) (&state, key, PSI_FILE_RENAME, from, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_rename_with_symlink(from, to, flags); PSI_FILE_CALL(end_file_rename_wait)(locker, from, to, result); return result; } #endif result= my_rename_with_symlink(from, to, flags); return result; } static inline int inline_mysql_file_sync( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File fd, myf flags) { int result= 0; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, fd, PSI_FILE_SYNC); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_sync(fd, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } #endif result= my_sync(fd, flags); return result; } /** @} (end of group File_instrumentation) */ #endif psi/mysql_idle.h000064400000005743151030241300007650 0ustar00/* Copyright (c) 2011, 2023, Oracle and/or its affiliates Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_IDLE_H #define MYSQL_IDLE_H /** @file mysql/psi/mysql_idle.h Instrumentation helpers for idle waits. */ #include "mysql/psi/psi.h" #ifndef PSI_IDLE_CALL #define PSI_IDLE_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Idle_instrumentation Idle Instrumentation @ingroup Instrumentation_interface @{ */ /** @def MYSQL_START_IDLE_WAIT Instrumentation helper for table io_waits. This instrumentation marks the start of a wait event. @param LOCKER the locker @param STATE the locker state @sa MYSQL_END_IDLE_WAIT. */ #ifdef HAVE_PSI_IDLE_INTERFACE #define MYSQL_START_IDLE_WAIT(LOCKER, STATE) \ LOCKER= inline_mysql_start_idle_wait(STATE, __FILE__, __LINE__) #else #define MYSQL_START_IDLE_WAIT(LOCKER, STATE) \ do {} while (0) #endif /** @def MYSQL_END_IDLE_WAIT Instrumentation helper for idle waits. This instrumentation marks the end of a wait event. @param LOCKER the locker @sa MYSQL_START_IDLE_WAIT. */ #ifdef HAVE_PSI_IDLE_INTERFACE #define MYSQL_END_IDLE_WAIT(LOCKER) \ inline_mysql_end_idle_wait(LOCKER) #else #define MYSQL_END_IDLE_WAIT(LOCKER) \ do {} while (0) #endif #ifdef HAVE_PSI_IDLE_INTERFACE /** Instrumentation calls for MYSQL_START_IDLE_WAIT. @sa MYSQL_END_IDLE_WAIT. */ static inline struct PSI_idle_locker * inline_mysql_start_idle_wait(PSI_idle_locker_state *state, const char *src_file, uint src_line) { struct PSI_idle_locker *locker; locker= PSI_IDLE_CALL(start_idle_wait)(state, src_file, src_line); return locker; } /** Instrumentation calls for MYSQL_END_IDLE_WAIT. @sa MYSQL_START_IDLE_WAIT. */ static inline void inline_mysql_end_idle_wait(struct PSI_idle_locker *locker) { if (psi_likely(locker != NULL)) PSI_IDLE_CALL(end_idle_wait)(locker); } #endif /** @} (end of group Idle_instrumentation) */ #endif psi/psi_abi_v1.h000064400000002667151030241300007524 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file mysql/psi/psi_abi_v1.h ABI check for mysql/psi/psi.h, when using PSI_VERSION_1. This file is only used to automate detection of changes between versions. Do not include this file, include mysql/psi/psi.h instead. */ #define USE_PSI_1 #define HAVE_PSI_INTERFACE #define MY_GLOBAL_INCLUDED #include "mysql/psi/psi.h" psi/psi_memory.h000064400000010771151030241300007666 0ustar00/* Copyright (c) 2013, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. Without limiting anything contained in the foregoing, this file, which is part of C Driver for MySQL (Connector/C), is also subject to the Universal FOSS Exception, version 1.0, a copy of which can be found at http://oss.oracle.com/licenses/universal-foss-exception. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_PSI_MEMORY_H #define MYSQL_PSI_MEMORY_H #include "psi_base.h" #ifdef __cplusplus extern "C" { #endif /** @file mysql/psi/psi_memory.h Performance schema instrumentation interface. @defgroup Instrumentation_interface Instrumentation Interface @ingroup Performance_schema @{ */ #ifdef HAVE_PSI_INTERFACE #ifndef DISABLE_ALL_PSI #ifndef DISABLE_PSI_MEMORY #define HAVE_PSI_MEMORY_INTERFACE #endif /* DISABLE_PSI_MEMORY */ #endif /* DISABLE_ALL_PSI */ #endif /* HAVE_PSI_INTERFACE */ struct PSI_thread; #ifdef HAVE_PSI_1 /** @defgroup Group_PSI_v1 Application Binary Interface, version 1 @ingroup Instrumentation_interface @{ */ /** Memory instrument information. @since PSI_VERSION_1 This structure is used to register instrumented memory. */ struct PSI_memory_info_v1 { /** Pointer to the key assigned to the registered memory. */ PSI_memory_key *m_key; /** The name of the memory instrument to register. */ const char *m_name; /** The flags of the socket instrument to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_memory_info_v1 PSI_memory_info_v1; /** Memory registration API. @param category a category name (typically a plugin name) @param info an array of memory info to register @param count the size of the info array */ typedef void (*register_memory_v1_t) (const char *category, struct PSI_memory_info_v1 *info, int count); /** Instrument memory allocation. @param key the memory instrument key @param size the size of memory allocated @param[out] owner the memory owner @return the effective memory instrument key */ typedef PSI_memory_key (*memory_alloc_v1_t) (PSI_memory_key key, size_t size, struct PSI_thread ** owner); /** Instrument memory re allocation. @param key the memory instrument key @param old_size the size of memory previously allocated @param new_size the size of memory re allocated @param[in, out] owner the memory owner @return the effective memory instrument key */ typedef PSI_memory_key (*memory_realloc_v1_t) (PSI_memory_key key, size_t old_size, size_t new_size, struct PSI_thread ** owner); /** Instrument memory claim. @param key the memory instrument key @param size the size of memory allocated @param[in, out] owner the memory owner @return the effective memory instrument key */ typedef PSI_memory_key (*memory_claim_v1_t) (PSI_memory_key key, size_t size, struct PSI_thread ** owner); /** Instrument memory free. @param key the memory instrument key @param size the size of memory allocated @param owner the memory owner */ typedef void (*memory_free_v1_t) (PSI_memory_key key, size_t size, struct PSI_thread * owner); /** @} (end of group Group_PSI_v1) */ #ifdef _AIX PSI_memory_key key_memory_log_event; #endif #endif /* HAVE_PSI_1 */ #ifdef HAVE_PSI_2 struct PSI_memory_info_v2 { int placeholder; }; #endif /* HAVE_PSI_2 */ #ifdef USE_PSI_1 typedef struct PSI_memory_info_v1 PSI_memory_info; #endif #ifdef USE_PSI_2 typedef struct PSI_memory_info_v2 PSI_memory_info; #endif /** @} (end of group Instrumentation_interface) */ #ifdef __cplusplus } #endif #endif /* MYSQL_PSI_MEMORY_H */ psi/psi.h000064400000253735151030241300006307 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H #define MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H #ifndef MY_GLOBAL_INCLUDED /* Make sure a .c or .cc file contains an include to my_global.h first. When this include is missing, all the #ifdef HAVE_XXX have no effect, and the resulting binary won't build, or won't link, or will crash at runtime since various structures will have different binary definitions. */ #error "You must include my_global.h in the code for the build to be correct." #endif /* If PSI_ON_BY_DFAULT is defined, assume PSI will be enabled by default and optimize jumps testing for PSI this case. If not, optimize the binary for that PSI is not enabled */ #ifdef PSI_ON_BY_DEFAULT #define psi_likely(A) likely(A) #define psi_unlikely(A) unlikely(A) #else #define psi_likely(A) unlikely(A) #define psi_unlikely(A) likely(A) #endif #include "psi_base.h" #include "psi_memory.h" #ifdef _WIN32 typedef struct thread_attr pthread_attr_t; typedef DWORD pthread_t; typedef DWORD pthread_key_t; #endif /* MAINTAINER: The following pattern: typedef struct XYZ XYZ; is not needed in C++, but required for C. */ C_MODE_START /** @sa MDL_key. */ struct MDL_key; typedef struct MDL_key MDL_key; /** @sa enum_mdl_type. */ typedef int opaque_mdl_type; /** @sa enum_mdl_duration. */ typedef int opaque_mdl_duration; /** @sa MDL_wait::enum_wait_status. */ typedef int opaque_mdl_status; /** @sa enum_vio_type. */ typedef int opaque_vio_type; struct TABLE_SHARE; struct sql_digest_storage; #ifdef __cplusplus class THD; #else /* Phony declaration when compiling C code. This is ok, because the C code will never have a THD anyway. */ struct opaque_THD { int dummy; }; typedef struct opaque_THD THD; #endif /** @file mysql/psi/psi.h Performance schema instrumentation interface. @defgroup Instrumentation_interface Instrumentation Interface @ingroup Performance_schema @{ */ /** Interface for an instrumented mutex. This is an opaque structure. */ struct PSI_mutex; typedef struct PSI_mutex PSI_mutex; /** Interface for an instrumented rwlock. This is an opaque structure. */ struct PSI_rwlock; typedef struct PSI_rwlock PSI_rwlock; /** Interface for an instrumented condition. This is an opaque structure. */ struct PSI_cond; typedef struct PSI_cond PSI_cond; /** Interface for an instrumented table share. This is an opaque structure. */ struct PSI_table_share; typedef struct PSI_table_share PSI_table_share; /** Interface for an instrumented table handle. This is an opaque structure. */ struct PSI_table; typedef struct PSI_table PSI_table; /** Interface for an instrumented thread. This is an opaque structure. */ struct PSI_thread; typedef struct PSI_thread PSI_thread; /** Interface for an instrumented file handle. This is an opaque structure. */ struct PSI_file; typedef struct PSI_file PSI_file; /** Interface for an instrumented socket descriptor. This is an opaque structure. */ struct PSI_socket; typedef struct PSI_socket PSI_socket; /** Interface for an instrumented prepared statement. This is an opaque structure. */ struct PSI_prepared_stmt; typedef struct PSI_prepared_stmt PSI_prepared_stmt; /** Interface for an instrumented table operation. This is an opaque structure. */ struct PSI_table_locker; typedef struct PSI_table_locker PSI_table_locker; /** Interface for an instrumented statement. This is an opaque structure. */ struct PSI_statement_locker; typedef struct PSI_statement_locker PSI_statement_locker; /** Interface for an instrumented transaction. This is an opaque structure. */ struct PSI_transaction_locker; typedef struct PSI_transaction_locker PSI_transaction_locker; /** Interface for an instrumented idle operation. This is an opaque structure. */ struct PSI_idle_locker; typedef struct PSI_idle_locker PSI_idle_locker; /** Interface for an instrumented statement digest operation. This is an opaque structure. */ struct PSI_digest_locker; typedef struct PSI_digest_locker PSI_digest_locker; /** Interface for an instrumented stored procedure share. This is an opaque structure. */ struct PSI_sp_share; typedef struct PSI_sp_share PSI_sp_share; /** Interface for an instrumented stored program. This is an opaque structure. */ struct PSI_sp_locker; typedef struct PSI_sp_locker PSI_sp_locker; /** Interface for an instrumented metadata lock. This is an opaque structure. */ struct PSI_metadata_lock; typedef struct PSI_metadata_lock PSI_metadata_lock; /** Interface for an instrumented stage progress. This is a public structure, for efficiency. */ struct PSI_stage_progress { ulonglong m_work_completed; ulonglong m_work_estimated; }; typedef struct PSI_stage_progress PSI_stage_progress; /** IO operation performed on an instrumented table. */ enum PSI_table_io_operation { /** Row fetch. */ PSI_TABLE_FETCH_ROW= 0, /** Row write. */ PSI_TABLE_WRITE_ROW= 1, /** Row update. */ PSI_TABLE_UPDATE_ROW= 2, /** Row delete. */ PSI_TABLE_DELETE_ROW= 3 }; typedef enum PSI_table_io_operation PSI_table_io_operation; /** State data storage for @c start_table_io_wait_v1_t, @c start_table_lock_wait_v1_t. This structure provide temporary storage to a table locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_table_io_wait_v1_t @sa start_table_lock_wait_v1_t */ struct PSI_table_locker_state { /** Internal state. */ uint m_flags; /** Current io operation. */ enum PSI_table_io_operation m_io_operation; /** Current table handle. */ struct PSI_table *m_table; /** Current table share. */ struct PSI_table_share *m_table_share; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; /** Implementation specific. For table io, the table io index. For table lock, the lock type. */ uint m_index; }; typedef struct PSI_table_locker_state PSI_table_locker_state; /** Entry point for the performance schema interface. */ struct PSI_bootstrap { /** ABI interface finder. Calling this method with an interface version number returns either an instance of the ABI for this version, or NULL. @param version the interface version number to find @return a versioned interface (PSI_v1, PSI_v2 or PSI) @sa PSI_VERSION_1 @sa PSI_v1 @sa PSI_VERSION_2 @sa PSI_v2 @sa PSI_CURRENT_VERSION @sa PSI */ void* (*get_interface)(int version); }; typedef struct PSI_bootstrap PSI_bootstrap; #ifdef HAVE_PSI_INTERFACE #ifdef DISABLE_ALL_PSI #ifndef DISABLE_PSI_THREAD #define DISABLE_PSI_THREAD #endif #ifndef DISABLE_PSI_MUTEX #define DISABLE_PSI_MUTEX #endif #ifndef DISABLE_PSI_RWLOCK #define DISABLE_PSI_RWLOCK #endif #ifndef DISABLE_PSI_COND #define DISABLE_PSI_COND #endif #ifndef DISABLE_PSI_FILE #define DISABLE_PSI_FILE #endif #ifndef DISABLE_PSI_TABLE #define DISABLE_PSI_TABLE #endif #ifndef DISABLE_PSI_SOCKET #define DISABLE_PSI_SOCKET #endif #ifndef DISABLE_PSI_STAGE #define DISABLE_PSI_STAGE #endif #ifndef DISABLE_PSI_STATEMENT #define DISABLE_PSI_STATEMENT #endif #ifndef DISABLE_PSI_SP #define DISABLE_PSI_SP #endif #ifndef DISABLE_PSI_IDLE #define DISABLE_PSI_IDLE #endif #ifndef DISABLE_PSI_STATEMENT_DIGEST #define DISABLE_PSI_STATEMENT_DIGEST #endif #ifndef DISABLE_PSI_METADATA #define DISABLE_PSI_METADATA #endif #ifndef DISABLE_PSI_MEMORY #define DISABLE_PSI_MEMORY #endif #ifndef DISABLE_PSI_TRANSACTION #define DISABLE_PSI_TRANSACTION #endif #ifndef DISABLE_PSI_SP #define DISABLE_PSI_SP #endif #ifndef DISABLE_PSI_PS #define DISABLE_PSI_PS #endif #endif /** @def DISABLE_PSI_MUTEX Compiling option to disable the mutex instrumentation. This option is mostly intended to be used during development, when doing special builds with only a subset of the performance schema instrumentation, for code analysis / profiling / performance tuning of a specific instrumentation alone. @sa DISABLE_PSI_RWLOCK @sa DISABLE_PSI_COND @sa DISABLE_PSI_FILE @sa DISABLE_PSI_THREAD @sa DISABLE_PSI_TABLE @sa DISABLE_PSI_STAGE @sa DISABLE_PSI_STATEMENT @sa DISABLE_PSI_SP @sa DISABLE_PSI_STATEMENT_DIGEST @sa DISABLE_PSI_SOCKET @sa DISABLE_PSI_MEMORY @sa DISABLE_PSI_IDLE @sa DISABLE_PSI_METADATA @sa DISABLE PSI_TRANSACTION */ #ifndef DISABLE_PSI_MUTEX #define HAVE_PSI_MUTEX_INTERFACE #endif /** @def DISABLE_PSI_RWLOCK Compiling option to disable the rwlock instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_RWLOCK #define HAVE_PSI_RWLOCK_INTERFACE #endif /** @def DISABLE_PSI_COND Compiling option to disable the cond instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_COND #define HAVE_PSI_COND_INTERFACE #endif /** @def DISABLE_PSI_FILE Compiling option to disable the file instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_FILE #define HAVE_PSI_FILE_INTERFACE #endif /** @def DISABLE_PSI_THREAD Compiling option to disable the thread instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_THREAD #define HAVE_PSI_THREAD_INTERFACE #endif /** @def DISABLE_PSI_TABLE Compiling option to disable the table instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_TABLE #define HAVE_PSI_TABLE_INTERFACE #endif /** @def DISABLE_PSI_STAGE Compiling option to disable the stage instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_STAGE #define HAVE_PSI_STAGE_INTERFACE #endif /** @def DISABLE_PSI_STATEMENT Compiling option to disable the statement instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_STATEMENT #define HAVE_PSI_STATEMENT_INTERFACE #endif /** @def DISABLE_PSI_SP Compiling option to disable the stored program instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_SP #define HAVE_PSI_SP_INTERFACE #endif /** @def DISABLE_PSI_PS Compiling option to disable the prepared statement instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_STATEMENT #ifndef DISABLE_PSI_PS #define HAVE_PSI_PS_INTERFACE #endif #endif /** @def DISABLE_PSI_STATEMENT_DIGEST Compiling option to disable the statement digest instrumentation. */ #ifndef DISABLE_PSI_STATEMENT #ifndef DISABLE_PSI_STATEMENT_DIGEST #define HAVE_PSI_STATEMENT_DIGEST_INTERFACE #endif #endif /** @def DISABLE_PSI_TRANSACTION Compiling option to disable the transaction instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_TRANSACTION #define HAVE_PSI_TRANSACTION_INTERFACE #endif /** @def DISABLE_PSI_SOCKET Compiling option to disable the statement instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_SOCKET #define HAVE_PSI_SOCKET_INTERFACE #endif /** @def DISABLE_PSI_MEMORY Compiling option to disable the memory instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_MEMORY #define HAVE_PSI_MEMORY_INTERFACE #endif /** @def DISABLE_PSI_IDLE Compiling option to disable the idle instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_IDLE #define HAVE_PSI_IDLE_INTERFACE #endif /** @def DISABLE_PSI_METADATA Compiling option to disable the metadata instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_METADATA #define HAVE_PSI_METADATA_INTERFACE #endif /** @def PSI_VERSION_1 Performance Schema Interface number for version 1. This version is supported. */ #define PSI_VERSION_1 1 /** @def PSI_VERSION_2 Performance Schema Interface number for version 2. This version is not implemented, it's a placeholder. */ #define PSI_VERSION_2 2 /** @def PSI_CURRENT_VERSION Performance Schema Interface number for the most recent version. The most current version is @c PSI_VERSION_1 */ #define PSI_CURRENT_VERSION 1 #ifndef USE_PSI_2 #ifndef USE_PSI_1 #define USE_PSI_1 #endif #endif /** Interface for an instrumented mutex operation. This is an opaque structure. */ struct PSI_mutex_locker; typedef struct PSI_mutex_locker PSI_mutex_locker; /** Interface for an instrumented rwlock operation. This is an opaque structure. */ struct PSI_rwlock_locker; typedef struct PSI_rwlock_locker PSI_rwlock_locker; /** Interface for an instrumented condition operation. This is an opaque structure. */ struct PSI_cond_locker; typedef struct PSI_cond_locker PSI_cond_locker; /** Interface for an instrumented file operation. This is an opaque structure. */ struct PSI_file_locker; typedef struct PSI_file_locker PSI_file_locker; /** Interface for an instrumented socket operation. This is an opaque structure. */ struct PSI_socket_locker; typedef struct PSI_socket_locker PSI_socket_locker; /** Interface for an instrumented MDL operation. This is an opaque structure. */ struct PSI_metadata_locker; typedef struct PSI_metadata_locker PSI_metadata_locker; /** Operation performed on an instrumented mutex. */ enum PSI_mutex_operation { /** Lock. */ PSI_MUTEX_LOCK= 0, /** Lock attempt. */ PSI_MUTEX_TRYLOCK= 1 }; typedef enum PSI_mutex_operation PSI_mutex_operation; /** Operation performed on an instrumented rwlock. For basic READ / WRITE lock, operations are "READ" or "WRITE". For SX-locks, operations are "SHARED", "SHARED-EXCLUSIVE" or "EXCLUSIVE". */ enum PSI_rwlock_operation { /** Read lock. */ PSI_RWLOCK_READLOCK= 0, /** Write lock. */ PSI_RWLOCK_WRITELOCK= 1, /** Read lock attempt. */ PSI_RWLOCK_TRYREADLOCK= 2, /** Write lock attempt. */ PSI_RWLOCK_TRYWRITELOCK= 3, /** Shared lock. */ PSI_RWLOCK_SHAREDLOCK= 4, /** Shared Exclusive lock. */ PSI_RWLOCK_SHAREDEXCLUSIVELOCK= 5, /** Exclusive lock. */ PSI_RWLOCK_EXCLUSIVELOCK= 6, /** Shared lock attempt. */ PSI_RWLOCK_TRYSHAREDLOCK= 7, /** Shared Exclusive lock attempt. */ PSI_RWLOCK_TRYSHAREDEXCLUSIVELOCK= 8, /** Exclusive lock attempt. */ PSI_RWLOCK_TRYEXCLUSIVELOCK= 9 }; typedef enum PSI_rwlock_operation PSI_rwlock_operation; /** Operation performed on an instrumented condition. */ enum PSI_cond_operation { /** Wait. */ PSI_COND_WAIT= 0, /** Wait, with timeout. */ PSI_COND_TIMEDWAIT= 1 }; typedef enum PSI_cond_operation PSI_cond_operation; /** Operation performed on an instrumented file. */ enum PSI_file_operation { /** File creation, as in @c create(). */ PSI_FILE_CREATE= 0, /** Temporary file creation, as in @c create_temp_file(). */ PSI_FILE_CREATE_TMP= 1, /** File open, as in @c open(). */ PSI_FILE_OPEN= 2, /** File open, as in @c fopen(). */ PSI_FILE_STREAM_OPEN= 3, /** File close, as in @c close(). */ PSI_FILE_CLOSE= 4, /** File close, as in @c fclose(). */ PSI_FILE_STREAM_CLOSE= 5, /** Generic file read, such as @c fgets(), @c fgetc(), @c fread(), @c read(), @c pread(). */ PSI_FILE_READ= 6, /** Generic file write, such as @c fputs(), @c fputc(), @c fprintf(), @c vfprintf(), @c fwrite(), @c write(), @c pwrite(). */ PSI_FILE_WRITE= 7, /** Generic file seek, such as @c fseek() or @c seek(). */ PSI_FILE_SEEK= 8, /** Generic file tell, such as @c ftell() or @c tell(). */ PSI_FILE_TELL= 9, /** File flush, as in @c fflush(). */ PSI_FILE_FLUSH= 10, /** File stat, as in @c stat(). */ PSI_FILE_STAT= 11, /** File stat, as in @c fstat(). */ PSI_FILE_FSTAT= 12, /** File chsize, as in @c my_chsize(). */ PSI_FILE_CHSIZE= 13, /** File delete, such as @c my_delete() or @c my_handler_delete_with_symlink(). */ PSI_FILE_DELETE= 14, /** File rename, such as @c my_rename() or @c my_rename_with_symlink(). */ PSI_FILE_RENAME= 15, /** File sync, as in @c fsync() or @c my_sync(). */ PSI_FILE_SYNC= 16 }; typedef enum PSI_file_operation PSI_file_operation; /** Lock operation performed on an instrumented table. */ enum PSI_table_lock_operation { /** Table lock, in the server layer. */ PSI_TABLE_LOCK= 0, /** Table lock, in the storage engine layer. */ PSI_TABLE_EXTERNAL_LOCK= 1 }; typedef enum PSI_table_lock_operation PSI_table_lock_operation; /** State of an instrumented socket. */ enum PSI_socket_state { /** Idle, waiting for the next command. */ PSI_SOCKET_STATE_IDLE= 1, /** Active, executing a command. */ PSI_SOCKET_STATE_ACTIVE= 2 }; typedef enum PSI_socket_state PSI_socket_state; /** Operation performed on an instrumented socket. */ enum PSI_socket_operation { /** Socket creation, as in @c socket() or @c socketpair(). */ PSI_SOCKET_CREATE= 0, /** Socket connection, as in @c connect(), @c listen() and @c accept(). */ PSI_SOCKET_CONNECT= 1, /** Socket bind, as in @c bind(), @c getsockname() and @c getpeername(). */ PSI_SOCKET_BIND= 2, /** Socket close, as in @c shutdown(). */ PSI_SOCKET_CLOSE= 3, /** Socket send, @c send(). */ PSI_SOCKET_SEND= 4, /** Socket receive, @c recv(). */ PSI_SOCKET_RECV= 5, /** Socket send, @c sendto(). */ PSI_SOCKET_SENDTO= 6, /** Socket receive, @c recvfrom). */ PSI_SOCKET_RECVFROM= 7, /** Socket send, @c sendmsg(). */ PSI_SOCKET_SENDMSG= 8, /** Socket receive, @c recvmsg(). */ PSI_SOCKET_RECVMSG= 9, /** Socket seek, such as @c fseek() or @c seek(). */ PSI_SOCKET_SEEK= 10, /** Socket options, as in @c getsockopt() and @c setsockopt(). */ PSI_SOCKET_OPT= 11, /** Socket status, as in @c sockatmark() and @c isfdtype(). */ PSI_SOCKET_STAT= 12, /** Socket shutdown, as in @c shutdown(). */ PSI_SOCKET_SHUTDOWN= 13, /** Socket select, as in @c select() and @c poll(). */ PSI_SOCKET_SELECT= 14 }; typedef enum PSI_socket_operation PSI_socket_operation; #endif /** Instrumented mutex key. To instrument a mutex, a mutex key must be obtained using @c register_mutex. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_mutex_key; /** Instrumented rwlock key. To instrument a rwlock, a rwlock key must be obtained using @c register_rwlock. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_rwlock_key; /** Instrumented cond key. To instrument a condition, a condition key must be obtained using @c register_cond. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_cond_key; /** Instrumented thread key. To instrument a thread, a thread key must be obtained using @c register_thread. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_thread_key; /** Instrumented file key. To instrument a file, a file key must be obtained using @c register_file. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_file_key; /** Instrumented stage key. To instrument a stage, a stage key must be obtained using @c register_stage. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_stage_key; /** Instrumented statement key. To instrument a statement, a statement key must be obtained using @c register_statement. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_statement_key; /** Instrumented socket key. To instrument a socket, a socket key must be obtained using @c register_socket. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_socket_key; #ifdef HAVE_PSI_1 /** @defgroup Group_PSI_v1 Application Binary Interface, version 1 @ingroup Instrumentation_interface @{ */ /** Mutex information. @since PSI_VERSION_1 This structure is used to register an instrumented mutex. */ struct PSI_mutex_info_v1 { /** Pointer to the key assigned to the registered mutex. */ PSI_mutex_key *m_key; /** The name of the mutex to register. */ const char *m_name; /** The flags of the mutex to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_mutex_info_v1 PSI_mutex_info_v1; /** Rwlock information. @since PSI_VERSION_1 This structure is used to register an instrumented rwlock. */ struct PSI_rwlock_info_v1 { /** Pointer to the key assigned to the registered rwlock. */ PSI_rwlock_key *m_key; /** The name of the rwlock to register. */ const char *m_name; /** The flags of the rwlock to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_rwlock_info_v1 PSI_rwlock_info_v1; /** Condition information. @since PSI_VERSION_1 This structure is used to register an instrumented cond. */ struct PSI_cond_info_v1 { /** Pointer to the key assigned to the registered cond. */ PSI_cond_key *m_key; /** The name of the cond to register. */ const char *m_name; /** The flags of the cond to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_cond_info_v1 PSI_cond_info_v1; /** Thread instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented thread. */ struct PSI_thread_info_v1 { /** Pointer to the key assigned to the registered thread. */ PSI_thread_key *m_key; /** The name of the thread instrument to register. */ const char *m_name; /** The flags of the thread to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_thread_info_v1 PSI_thread_info_v1; /** File instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented file. */ struct PSI_file_info_v1 { /** Pointer to the key assigned to the registered file. */ PSI_file_key *m_key; /** The name of the file instrument to register. */ const char *m_name; /** The flags of the file instrument to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_file_info_v1 PSI_file_info_v1; /** Stage instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented stage. */ struct PSI_stage_info_v1 { /** The registered stage key. */ PSI_stage_key m_key; /** The name of the stage instrument to register. */ const char *m_name; /** The flags of the stage instrument to register. */ int m_flags; }; typedef struct PSI_stage_info_v1 PSI_stage_info_v1; /** Statement instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented statement. */ struct PSI_statement_info_v1 { /** The registered statement key. */ PSI_statement_key m_key; /** The name of the statement instrument to register. */ const char *m_name; /** The flags of the statement instrument to register. */ int m_flags; }; typedef struct PSI_statement_info_v1 PSI_statement_info_v1; /** Socket instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented socket. */ struct PSI_socket_info_v1 { /** Pointer to the key assigned to the registered socket. */ PSI_socket_key *m_key; /** The name of the socket instrument to register. */ const char *m_name; /** The flags of the socket instrument to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_socket_info_v1 PSI_socket_info_v1; /** State data storage for @c start_idle_wait_v1_t. This structure provide temporary storage to an idle locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_idle_wait_v1_t. */ struct PSI_idle_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_idle_locker_state_v1 PSI_idle_locker_state_v1; /** State data storage for @c start_mutex_wait_v1_t. This structure provide temporary storage to a mutex locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_mutex_wait_v1_t */ struct PSI_mutex_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current operation. */ enum PSI_mutex_operation m_operation; /** Current mutex. */ struct PSI_mutex *m_mutex; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_mutex_locker_state_v1 PSI_mutex_locker_state_v1; /** State data storage for @c start_rwlock_rdwait_v1_t, @c start_rwlock_wrwait_v1_t. This structure provide temporary storage to a rwlock locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_rwlock_rdwait_v1_t @sa start_rwlock_wrwait_v1_t */ struct PSI_rwlock_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current operation. */ enum PSI_rwlock_operation m_operation; /** Current rwlock. */ struct PSI_rwlock *m_rwlock; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_rwlock_locker_state_v1 PSI_rwlock_locker_state_v1; /** State data storage for @c start_cond_wait_v1_t. This structure provide temporary storage to a condition locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_cond_wait_v1_t */ struct PSI_cond_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current operation. */ enum PSI_cond_operation m_operation; /** Current condition. */ struct PSI_cond *m_cond; /** Current mutex. */ struct PSI_mutex *m_mutex; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_cond_locker_state_v1 PSI_cond_locker_state_v1; /** State data storage for @c get_thread_file_name_locker_v1_t. This structure provide temporary storage to a file locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa get_thread_file_name_locker_v1_t @sa get_thread_file_stream_locker_v1_t @sa get_thread_file_descriptor_locker_v1_t */ struct PSI_file_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current operation. */ enum PSI_file_operation m_operation; /** Current file. */ struct PSI_file *m_file; /** Current file name. */ const char *m_name; /** Current file class. */ void *m_class; /** Current thread. */ struct PSI_thread *m_thread; /** Operation number of bytes. */ size_t m_number_of_bytes; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_file_locker_state_v1 PSI_file_locker_state_v1; /** State data storage for @c start_metadata_wait_v1_t. This structure provide temporary storage to a metadata locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_metadata_wait_v1_t */ struct PSI_metadata_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current metadata lock. */ struct PSI_metadata_lock *m_metadata_lock; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_metadata_locker_state_v1 PSI_metadata_locker_state_v1; /* Duplicate of NAME_LEN, to avoid dependency on mysql_com.h */ #define PSI_SCHEMA_NAME_LEN (64 * 3) /** State data storage for @c get_thread_statement_locker_v1_t, @c get_thread_statement_locker_v1_t. This structure provide temporary storage to a statement locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa get_thread_statement_locker_v1_t */ struct PSI_statement_locker_state_v1 { /** Discarded flag. */ my_bool m_discarded; /** In prepare flag. */ my_bool m_in_prepare; /** Metric, no index used flag. */ uchar m_no_index_used; /** Metric, no good index used flag. */ uchar m_no_good_index_used; /** Internal state. */ uint m_flags; /** Instrumentation class. */ void *m_class; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_statement; /** Locked time. */ ulonglong m_lock_time; /** Rows sent. */ ulonglong m_rows_sent; /** Rows examined. */ ulonglong m_rows_examined; /** Metric, temporary tables created on disk. */ ulong m_created_tmp_disk_tables; /** Metric, temporary tables created. */ ulong m_created_tmp_tables; /** Metric, number of select full join. */ ulong m_select_full_join; /** Metric, number of select full range join. */ ulong m_select_full_range_join; /** Metric, number of select range. */ ulong m_select_range; /** Metric, number of select range check. */ ulong m_select_range_check; /** Metric, number of select scan. */ ulong m_select_scan; /** Metric, number of sort merge passes. */ ulong m_sort_merge_passes; /** Metric, number of sort merge. */ ulong m_sort_range; /** Metric, number of sort rows. */ ulong m_sort_rows; /** Metric, number of sort scans. */ ulong m_sort_scan; /** Statement digest. */ const struct sql_digest_storage *m_digest; /** Current schema name. */ char m_schema_name[PSI_SCHEMA_NAME_LEN]; /** Length in bytes of @c m_schema_name. */ uint m_schema_name_length; /** Statement character set number. */ uint m_cs_number; PSI_sp_share *m_parent_sp_share; PSI_prepared_stmt *m_parent_prepared_stmt; }; typedef struct PSI_statement_locker_state_v1 PSI_statement_locker_state_v1; /** State data storage for @c get_thread_transaction_locker_v1_t, @c get_thread_transaction_locker_v1_t. This structure provide temporary storage to a transaction locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa get_thread_transaction_locker_v1_t */ struct PSI_transaction_locker_state_v1 { /** Internal state. */ uint m_flags; /** Instrumentation class. */ void *m_class; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_transaction; /** True if read-only transaction, false if read-write. */ my_bool m_read_only; /** True if transaction is autocommit. */ my_bool m_autocommit; /** Number of statements. */ ulong m_statement_count; /** Total number of savepoints. */ ulong m_savepoint_count; /** Number of rollback_to_savepoint. */ ulong m_rollback_to_savepoint_count; /** Number of release_savepoint. */ ulong m_release_savepoint_count; }; typedef struct PSI_transaction_locker_state_v1 PSI_transaction_locker_state_v1; /** State data storage for @c start_socket_wait_v1_t. This structure provide temporary storage to a socket locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_socket_wait_v1_t */ struct PSI_socket_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current socket. */ struct PSI_socket *m_socket; /** Current thread. */ struct PSI_thread *m_thread; /** Operation number of bytes. */ size_t m_number_of_bytes; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Current operation. */ enum PSI_socket_operation m_operation; /** Source file. */ const char* m_src_file; /** Source line number. */ int m_src_line; /** Internal data. */ void *m_wait; }; typedef struct PSI_socket_locker_state_v1 PSI_socket_locker_state_v1; struct PSI_sp_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Stored Procedure share. */ PSI_sp_share* m_sp_share; }; typedef struct PSI_sp_locker_state_v1 PSI_sp_locker_state_v1; /* Using typedef to make reuse between PSI_v1 and PSI_v2 easier later. */ /** Mutex registration API. @param category a category name (typically a plugin name) @param info an array of mutex info to register @param count the size of the info array */ typedef void (*register_mutex_v1_t) (const char *category, struct PSI_mutex_info_v1 *info, int count); /** Rwlock registration API. @param category a category name (typically a plugin name) @param info an array of rwlock info to register @param count the size of the info array */ typedef void (*register_rwlock_v1_t) (const char *category, struct PSI_rwlock_info_v1 *info, int count); /** Cond registration API. @param category a category name (typically a plugin name) @param info an array of cond info to register @param count the size of the info array */ typedef void (*register_cond_v1_t) (const char *category, struct PSI_cond_info_v1 *info, int count); /** Thread registration API. @param category a category name (typically a plugin name) @param info an array of thread info to register @param count the size of the info array */ typedef void (*register_thread_v1_t) (const char *category, struct PSI_thread_info_v1 *info, int count); /** File registration API. @param category a category name (typically a plugin name) @param info an array of file info to register @param count the size of the info array */ typedef void (*register_file_v1_t) (const char *category, struct PSI_file_info_v1 *info, int count); /** Stage registration API. @param category a category name @param info an array of stage info to register @param count the size of the info array */ typedef void (*register_stage_v1_t) (const char *category, struct PSI_stage_info_v1 **info, int count); /** Statement registration API. @param category a category name @param info an array of stage info to register @param count the size of the info array */ typedef void (*register_statement_v1_t) (const char *category, struct PSI_statement_info_v1 *info, int count); /** Socket registration API. @param category a category name (typically a plugin name) @param info an array of socket info to register @param count the size of the info array */ typedef void (*register_socket_v1_t) (const char *category, struct PSI_socket_info_v1 *info, int count); /** Mutex instrumentation initialisation API. @param key the registered mutex key @param identity the address of the mutex itself @return an instrumented mutex */ typedef struct PSI_mutex* (*init_mutex_v1_t) (PSI_mutex_key key, void *identity); /** Mutex instrumentation destruction API. @param mutex the mutex to destroy */ typedef void (*destroy_mutex_v1_t)(struct PSI_mutex *mutex); /** Rwlock instrumentation initialisation API. @param key the registered rwlock key @param identity the address of the rwlock itself @return an instrumented rwlock */ typedef struct PSI_rwlock* (*init_rwlock_v1_t) (PSI_rwlock_key key, void *identity); /** Rwlock instrumentation destruction API. @param rwlock the rwlock to destroy */ typedef void (*destroy_rwlock_v1_t)(struct PSI_rwlock *rwlock); /** Cond instrumentation initialisation API. @param key the registered key @param identity the address of the rwlock itself @return an instrumented cond */ typedef struct PSI_cond* (*init_cond_v1_t) (PSI_cond_key key, void *identity); /** Cond instrumentation destruction API. @param cond the rcond to destroy */ typedef void (*destroy_cond_v1_t)(struct PSI_cond *cond); /** Socket instrumentation initialisation API. @param key the registered mutex key @param socket descriptor @param addr the socket ip address @param addr_len length of socket ip address @return an instrumented socket */ typedef struct PSI_socket* (*init_socket_v1_t) (PSI_socket_key key, const my_socket *fd, const struct sockaddr *addr, socklen_t addr_len); /** socket instrumentation destruction API. @param socket the socket to destroy */ typedef void (*destroy_socket_v1_t)(struct PSI_socket *socket); /** Acquire a table share instrumentation. @param temporary True for temporary tables @param share The SQL layer table share @return a table share instrumentation, or NULL */ typedef struct PSI_table_share* (*get_table_share_v1_t) (my_bool temporary, struct TABLE_SHARE *share); /** Release a table share. @param info the table share to release */ typedef void (*release_table_share_v1_t)(struct PSI_table_share *share); /** Drop a table share. @param temporary True for temporary tables @param schema_name the table schema name @param schema_name_length the table schema name length @param table_name the table name @param table_name_length the table name length */ typedef void (*drop_table_share_v1_t) (my_bool temporary, const char *schema_name, int schema_name_length, const char *table_name, int table_name_length); /** Open an instrumentation table handle. @param share the table to open @param identity table handle identity @return a table handle, or NULL */ typedef struct PSI_table* (*open_table_v1_t) (struct PSI_table_share *share, const void *identity); /** Unbind a table handle from the current thread. This operation happens when an opened table is added to the open table cache. @param table the table to unbind */ typedef void (*unbind_table_v1_t) (struct PSI_table *table); /** Rebind a table handle to the current thread. This operation happens when a table from the open table cache is reused for a thread. @param table the table to unbind */ typedef PSI_table* (*rebind_table_v1_t) (PSI_table_share *share, const void *identity, PSI_table *table); /** Close an instrumentation table handle. Note that the table handle is invalid after this call. @param table the table handle to close */ typedef void (*close_table_v1_t)(struct TABLE_SHARE *server_share, struct PSI_table *table); /** Create a file instrumentation for a created file. This method does not create the file itself, but is used to notify the instrumentation interface that a file was just created. @param key the file instrumentation key for this file @param name the file name @param file the file handle */ typedef void (*create_file_v1_t)(PSI_file_key key, const char *name, File file); /** Spawn a thread. This method creates a new thread, with instrumentation. @param key the instrumentation key for this thread @param thread the resulting thread @param attr the thread attributes @param start_routine the thread start routine @param arg the thread start routine argument */ typedef int (*spawn_thread_v1_t)(PSI_thread_key key, pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); /** Create instrumentation for a thread. @param key the registered key @param identity an address typical of the thread @return an instrumented thread */ typedef struct PSI_thread* (*new_thread_v1_t) (PSI_thread_key key, const void *identity, ulonglong thread_id); /** Assign a THD to an instrumented thread. @param thread the instrumented thread @param THD the sql layer THD to assign */ typedef void (*set_thread_THD_v1_t)(struct PSI_thread *thread, THD *thd); /** Assign an id to an instrumented thread. @param thread the instrumented thread @param id the id to assign */ typedef void (*set_thread_id_v1_t)(struct PSI_thread *thread, ulonglong id); /** Assign the current operating system thread id to an instrumented thread. The operating system task id is obtained from @c gettid() @param thread the instrumented thread */ typedef void (*set_thread_os_id_v1_t)(struct PSI_thread *thread); /** Get the instrumentation for the running thread. For this function to return a result, the thread instrumentation must have been attached to the running thread using @c set_thread() @return the instrumentation for the running thread */ typedef struct PSI_thread* (*get_thread_v1_t)(void); /** Assign a user name to the instrumented thread. @param user the user name @param user_len the user name length */ typedef void (*set_thread_user_v1_t)(const char *user, int user_len); /** Assign a user name and host name to the instrumented thread. @param user the user name @param user_len the user name length @param host the host name @param host_len the host name length */ typedef void (*set_thread_account_v1_t)(const char *user, int user_len, const char *host, int host_len); /** Assign a current database to the instrumented thread. @param db the database name @param db_len the database name length */ typedef void (*set_thread_db_v1_t)(const char* db, int db_len); /** Assign a current command to the instrumented thread. @param command the current command */ typedef void (*set_thread_command_v1_t)(int command); /** Assign a connection type to the instrumented thread. @param conn_type the connection type */ typedef void (*set_connection_type_v1_t)(opaque_vio_type conn_type); /** Assign a start time to the instrumented thread. @param start_time the thread start time */ typedef void (*set_thread_start_time_v1_t)(time_t start_time); /** Assign a state to the instrumented thread. @param state the thread state */ typedef void (*set_thread_state_v1_t)(const char* state); /** Assign a process info to the instrumented thread. @param info the process into string @param info_len the process into string length */ typedef void (*set_thread_info_v1_t)(const char* info, uint info_len); /** Attach a thread instrumentation to the running thread. In case of thread pools, this method should be called when a worker thread picks a work item and runs it. Also, this method should be called if the instrumented code does not keep the pointer returned by @c new_thread() and relies on @c get_thread() instead. @param thread the thread instrumentation */ typedef void (*set_thread_v1_t)(struct PSI_thread *thread); /** Assign the remote (peer) port to the instrumented thread. @param thread pointer to the thread instrumentation @param port the remote port */ typedef void (*set_thread_peer_port_v1_t)(PSI_thread *thread, unsigned int port); /** Delete the current thread instrumentation. */ typedef void (*delete_current_thread_v1_t)(void); /** Delete a thread instrumentation. */ typedef void (*delete_thread_v1_t)(struct PSI_thread *thread); /** Get a file instrumentation locker, for opening or creating a file. @param state data storage for the locker @param key the file instrumentation key @param op the operation to perform @param name the file name @param identity a pointer representative of this file. @return a file locker, or NULL */ typedef struct PSI_file_locker* (*get_thread_file_name_locker_v1_t) (struct PSI_file_locker_state_v1 *state, PSI_file_key key, enum PSI_file_operation op, const char *name, const void *identity); /** Get a file stream instrumentation locker. @param state data storage for the locker @param file the file stream to access @param op the operation to perform @return a file locker, or NULL */ typedef struct PSI_file_locker* (*get_thread_file_stream_locker_v1_t) (struct PSI_file_locker_state_v1 *state, struct PSI_file *file, enum PSI_file_operation op); /** Get a file instrumentation locker. @param state data storage for the locker @param file the file descriptor to access @param op the operation to perform @return a file locker, or NULL */ typedef struct PSI_file_locker* (*get_thread_file_descriptor_locker_v1_t) (struct PSI_file_locker_state_v1 *state, File file, enum PSI_file_operation op); /** Record a mutex instrumentation unlock event. @param mutex the mutex instrumentation */ typedef void (*unlock_mutex_v1_t) (struct PSI_mutex *mutex); /** Record a rwlock instrumentation unlock event. @param rwlock the rwlock instrumentation */ typedef void (*unlock_rwlock_v1_t) (struct PSI_rwlock *rwlock); /** Record a condition instrumentation signal event. @param cond the cond instrumentation */ typedef void (*signal_cond_v1_t) (struct PSI_cond *cond); /** Record a condition instrumentation broadcast event. @param cond the cond instrumentation */ typedef void (*broadcast_cond_v1_t) (struct PSI_cond *cond); /** Record an idle instrumentation wait start event. @param state data storage for the locker @param file the source file name @param line the source line number @return an idle locker, or NULL */ typedef struct PSI_idle_locker* (*start_idle_wait_v1_t) (struct PSI_idle_locker_state_v1 *state, const char *src_file, uint src_line); /** Record an idle instrumentation wait end event. @param locker a thread locker for the running thread */ typedef void (*end_idle_wait_v1_t) (struct PSI_idle_locker *locker); /** Record a mutex instrumentation wait start event. @param state data storage for the locker @param mutex the instrumented mutex to lock @param op the operation to perform @param file the source file name @param line the source line number @return a mutex locker, or NULL */ typedef struct PSI_mutex_locker* (*start_mutex_wait_v1_t) (struct PSI_mutex_locker_state_v1 *state, struct PSI_mutex *mutex, enum PSI_mutex_operation op, const char *src_file, uint src_line); /** Record a mutex instrumentation wait end event. @param locker a thread locker for the running thread @param rc the wait operation return code */ typedef void (*end_mutex_wait_v1_t) (struct PSI_mutex_locker *locker, int rc); /** Record a rwlock instrumentation read wait start event. @param locker a thread locker for the running thread @param must must block: 1 for lock, 0 for trylock */ typedef struct PSI_rwlock_locker* (*start_rwlock_rdwait_v1_t) (struct PSI_rwlock_locker_state_v1 *state, struct PSI_rwlock *rwlock, enum PSI_rwlock_operation op, const char *src_file, uint src_line); /** Record a rwlock instrumentation read wait end event. @param locker a thread locker for the running thread @param rc the wait operation return code */ typedef void (*end_rwlock_rdwait_v1_t) (struct PSI_rwlock_locker *locker, int rc); /** Record a rwlock instrumentation write wait start event. @param locker a thread locker for the running thread @param must must block: 1 for lock, 0 for trylock */ typedef struct PSI_rwlock_locker* (*start_rwlock_wrwait_v1_t) (struct PSI_rwlock_locker_state_v1 *state, struct PSI_rwlock *rwlock, enum PSI_rwlock_operation op, const char *src_file, uint src_line); /** Record a rwlock instrumentation write wait end event. @param locker a thread locker for the running thread @param rc the wait operation return code */ typedef void (*end_rwlock_wrwait_v1_t) (struct PSI_rwlock_locker *locker, int rc); /** Record a condition instrumentation wait start event. @param locker a thread locker for the running thread @param must must block: 1 for wait, 0 for timedwait */ typedef struct PSI_cond_locker* (*start_cond_wait_v1_t) (struct PSI_cond_locker_state_v1 *state, struct PSI_cond *cond, struct PSI_mutex *mutex, enum PSI_cond_operation op, const char *src_file, uint src_line); /** Record a condition instrumentation wait end event. @param locker a thread locker for the running thread @param rc the wait operation return code */ typedef void (*end_cond_wait_v1_t) (struct PSI_cond_locker *locker, int rc); /** Record a table instrumentation io wait start event. @param locker a table locker for the running thread @param file the source file name @param line the source line number */ typedef struct PSI_table_locker* (*start_table_io_wait_v1_t) (struct PSI_table_locker_state *state, struct PSI_table *table, enum PSI_table_io_operation op, uint index, const char *src_file, uint src_line); /** Record a table instrumentation io wait end event. @param locker a table locker for the running thread @param numrows the number of rows involved in io */ typedef void (*end_table_io_wait_v1_t) (struct PSI_table_locker *locker, ulonglong numrows); /** Record a table instrumentation lock wait start event. @param locker a table locker for the running thread @param file the source file name @param line the source line number */ typedef struct PSI_table_locker* (*start_table_lock_wait_v1_t) (struct PSI_table_locker_state *state, struct PSI_table *table, enum PSI_table_lock_operation op, ulong flags, const char *src_file, uint src_line); /** Record a table instrumentation lock wait end event. @param locker a table locker for the running thread */ typedef void (*end_table_lock_wait_v1_t)(struct PSI_table_locker *locker); typedef void (*unlock_table_v1_t)(struct PSI_table *table); /** Start a file instrumentation open operation. @param locker the file locker @param op the operation to perform @param src_file the source file name @param src_line the source line number */ typedef void (*start_file_open_wait_v1_t) (struct PSI_file_locker *locker, const char *src_file, uint src_line); /** End a file instrumentation open operation, for file streams. @param locker the file locker. @param result the opened file (NULL indicates failure, non NULL success). @return an instrumented file handle */ typedef struct PSI_file* (*end_file_open_wait_v1_t) (struct PSI_file_locker *locker, void *result); /** End a file instrumentation open operation, for non stream files. @param locker the file locker. @param file the file number assigned by open() or create() for this file. */ typedef void (*end_file_open_wait_and_bind_to_descriptor_v1_t) (struct PSI_file_locker *locker, File file); /** End a file instrumentation open operation, for non stream temporary files. @param locker the file locker. @param file the file number assigned by open() or create() for this file. @param filename the file name generated during temporary file creation. */ typedef void (*end_temp_file_open_wait_and_bind_to_descriptor_v1_t) (struct PSI_file_locker *locker, File file, const char *filename); /** Record a file instrumentation start event. @param locker a file locker for the running thread @param op file operation to be performed @param count the number of bytes requested, or 0 if not applicable @param src_file the source file name @param src_line the source line number */ typedef void (*start_file_wait_v1_t) (struct PSI_file_locker *locker, size_t count, const char *src_file, uint src_line); /** Record a file instrumentation end event. Note that for file close operations, the instrumented file handle associated with the file (which was provided to obtain a locker) is invalid after this call. @param locker a file locker for the running thread @param count the number of bytes actually used in the operation, or 0 if not applicable, or -1 if the operation failed @sa get_thread_file_name_locker @sa get_thread_file_stream_locker @sa get_thread_file_descriptor_locker */ typedef void (*end_file_wait_v1_t) (struct PSI_file_locker *locker, size_t count); /** Start a file instrumentation close operation. @param locker the file locker @param op the operation to perform @param src_file the source file name @param src_line the source line number */ typedef void (*start_file_close_wait_v1_t) (struct PSI_file_locker *locker, const char *src_file, uint src_line); /** End a file instrumentation close operation. @param locker the file locker. @param rc the close operation return code (0 for success). @return an instrumented file handle */ typedef void (*end_file_close_wait_v1_t) (struct PSI_file_locker *locker, int rc); /** Rename a file instrumentation close operation. @param locker the file locker. @param old_name name of the file to be renamed. @param new_name name of the file after rename. @param rc the rename operation return code (0 for success). */ typedef void (*end_file_rename_wait_v1_t) (struct PSI_file_locker *locker, const char *old_name, const char *new_name, int rc); /** Start a new stage, and implicitly end the previous stage. @param key the key of the new stage @param src_file the source file name @param src_line the source line number @return the new stage progress */ typedef PSI_stage_progress* (*start_stage_v1_t) (PSI_stage_key key, const char *src_file, int src_line); typedef PSI_stage_progress* (*get_current_stage_progress_v1_t)(void); /** End the current stage. */ typedef void (*end_stage_v1_t) (void); /** Get a statement instrumentation locker. @param state data storage for the locker @param key the statement instrumentation key @param charset client character set @return a statement locker, or NULL */ typedef struct PSI_statement_locker* (*get_thread_statement_locker_v1_t) (struct PSI_statement_locker_state_v1 *state, PSI_statement_key key, const void *charset, PSI_sp_share *sp_share); /** Refine a statement locker to a more specific key. Note that only events declared mutable can be refined. @param the statement locker for the current event @param key the new key for the event @sa PSI_FLAG_MUTABLE */ typedef struct PSI_statement_locker* (*refine_statement_v1_t) (struct PSI_statement_locker *locker, PSI_statement_key key); /** Start a new statement event. @param locker the statement locker for this event @param db the active database name for this statement @param db_length the active database name length for this statement @param src_file source file name @param src_line source line number */ typedef void (*start_statement_v1_t) (struct PSI_statement_locker *locker, const char *db, uint db_length, const char *src_file, uint src_line); /** Set the statement text for a statement event. @param locker the current statement locker @param text the statement text @param text_len the statement text length */ typedef void (*set_statement_text_v1_t) (struct PSI_statement_locker *locker, const char *text, uint text_len); /** Set a statement event lock time. @param locker the statement locker @param lock_time the locked time, in microseconds */ typedef void (*set_statement_lock_time_t) (struct PSI_statement_locker *locker, ulonglong lock_time); /** Set a statement event rows sent metric. @param locker the statement locker @param count the number of rows sent */ typedef void (*set_statement_rows_sent_t) (struct PSI_statement_locker *locker, ulonglong count); /** Set a statement event rows examined metric. @param locker the statement locker @param count the number of rows examined */ typedef void (*set_statement_rows_examined_t) (struct PSI_statement_locker *locker, ulonglong count); /** Increment a statement event "created tmp disk tables" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_created_tmp_disk_tables_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "created tmp tables" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_created_tmp_tables_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "select full join" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_select_full_join_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "select full range join" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_select_full_range_join_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "select range join" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_select_range_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "select range check" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_select_range_check_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "select scan" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_select_scan_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "sort merge passes" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_sort_merge_passes_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "sort range" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_sort_range_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "sort rows" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_sort_rows_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "sort scan" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_sort_scan_t) (struct PSI_statement_locker *locker, ulong count); /** Set a statement event "no index used" metric. @param locker the statement locker @param count the metric value */ typedef void (*set_statement_no_index_used_t) (struct PSI_statement_locker *locker); /** Set a statement event "no good index used" metric. @param locker the statement locker @param count the metric value */ typedef void (*set_statement_no_good_index_used_t) (struct PSI_statement_locker *locker); /** End a statement event. @param locker the statement locker @param stmt_da the statement diagnostics area. @sa Diagnostics_area */ typedef void (*end_statement_v1_t) (struct PSI_statement_locker *locker, void *stmt_da); /** Get a transaction instrumentation locker. @param state data storage for the locker @param xid the xid for this transaction @param trxid the InnoDB transaction id @param iso_level isolation level for this transaction @param read_only true if transaction access mode is read-only @param autocommit true if transaction is autocommit @return a transaction locker, or NULL */ typedef struct PSI_transaction_locker* (*get_thread_transaction_locker_v1_t) (struct PSI_transaction_locker_state_v1 *state, const void *xid, ulonglong trxid, int isolation_level, my_bool read_only, my_bool autocommit); /** Start a new transaction event. @param locker the transaction locker for this event @param src_file source file name @param src_line source line number */ typedef void (*start_transaction_v1_t) (struct PSI_transaction_locker *locker, const char *src_file, uint src_line); /** Set the transaction xid. @param locker the transaction locker for this event @param xid the id of the XA transaction #param xa_state is the state of the XA transaction */ typedef void (*set_transaction_xid_v1_t) (struct PSI_transaction_locker *locker, const void *xid, int xa_state); /** Set the state of the XA transaction. @param locker the transaction locker for this event @param xa_state the new state of the xa transaction */ typedef void (*set_transaction_xa_state_v1_t) (struct PSI_transaction_locker *locker, int xa_state); /** Set the transaction gtid. @param locker the transaction locker for this event @param sid the source id for the transaction, mapped from sidno @param gtid_spec the gtid specifier for the transaction */ typedef void (*set_transaction_gtid_v1_t) (struct PSI_transaction_locker *locker, const void *sid, const void *gtid_spec); /** Set the transaction trx_id. @param locker the transaction locker for this event @param trxid the storage engine transaction ID */ typedef void (*set_transaction_trxid_v1_t) (struct PSI_transaction_locker *locker, const ulonglong *trxid); /** Increment a transaction event savepoint count. @param locker the transaction locker @param count the increment value */ typedef void (*inc_transaction_savepoints_v1_t) (struct PSI_transaction_locker *locker, ulong count); /** Increment a transaction event rollback to savepoint count. @param locker the transaction locker @param count the increment value */ typedef void (*inc_transaction_rollback_to_savepoint_v1_t) (struct PSI_transaction_locker *locker, ulong count); /** Increment a transaction event release savepoint count. @param locker the transaction locker @param count the increment value */ typedef void (*inc_transaction_release_savepoint_v1_t) (struct PSI_transaction_locker *locker, ulong count); /** Commit or rollback the transaction. @param locker the transaction locker for this event @param commit true if transaction was committed, false if rolled back */ typedef void (*end_transaction_v1_t) (struct PSI_transaction_locker *locker, my_bool commit); /** Record a socket instrumentation start event. @param locker a socket locker for the running thread @param op socket operation to be performed @param count the number of bytes requested, or 0 if not applicable @param src_file the source file name @param src_line the source line number */ typedef struct PSI_socket_locker* (*start_socket_wait_v1_t) (struct PSI_socket_locker_state_v1 *state, struct PSI_socket *socket, enum PSI_socket_operation op, size_t count, const char *src_file, uint src_line); /** Record a socket instrumentation end event. Note that for socket close operations, the instrumented socket handle associated with the socket (which was provided to obtain a locker) is invalid after this call. @param locker a socket locker for the running thread @param count the number of bytes actually used in the operation, or 0 if not applicable, or -1 if the operation failed @sa get_thread_socket_locker */ typedef void (*end_socket_wait_v1_t) (struct PSI_socket_locker *locker, size_t count); /** Set the socket state for an instrumented socket. @param socket the instrumented socket @param state socket state */ typedef void (*set_socket_state_v1_t)(struct PSI_socket *socket, enum PSI_socket_state state); /** Set the socket info for an instrumented socket. @param socket the instrumented socket @param fd the socket descriptor @param addr the socket ip address @param addr_len length of socket ip address @param thread_id associated thread id */ typedef void (*set_socket_info_v1_t)(struct PSI_socket *socket, const my_socket *fd, const struct sockaddr *addr, socklen_t addr_len); /** Bind a socket to the thread that owns it. @param socket instrumented socket */ typedef void (*set_socket_thread_owner_v1_t)(struct PSI_socket *socket); /** Get a prepare statement. @param locker a statement locker for the running thread. */ typedef PSI_prepared_stmt* (*create_prepared_stmt_v1_t) (void *identity, uint stmt_id, PSI_statement_locker *locker, const char *stmt_name, size_t stmt_name_length); /** destroy a prepare statement. @param prepared_stmt prepared statement. */ typedef void (*destroy_prepared_stmt_v1_t) (PSI_prepared_stmt *prepared_stmt); /** repreare a prepare statement. @param prepared_stmt prepared statement. */ typedef void (*reprepare_prepared_stmt_v1_t) (PSI_prepared_stmt *prepared_stmt); /** Record a prepare statement instrumentation execute event. @param locker a statement locker for the running thread. @param prepared_stmt prepared statement. */ typedef void (*execute_prepared_stmt_v1_t) (PSI_statement_locker *locker, PSI_prepared_stmt* prepared_stmt); /** Set the statement text for a prepared statement event. @param prepared_stmt prepared statement. @param text the prepared statement text @param text_len the prepared statement text length */ typedef void (*set_prepared_stmt_text_v1_t)(PSI_prepared_stmt *prepared_stmt, const char *text, uint text_len); /** Get a digest locker for the current statement. @param locker a statement locker for the running thread */ typedef struct PSI_digest_locker * (*digest_start_v1_t) (struct PSI_statement_locker *locker); /** Add a token to the current digest instrumentation. @param locker a digest locker for the current statement @param token the lexical token to add @param yylval the lexical token attributes */ typedef void (*digest_end_v1_t) (struct PSI_digest_locker *locker, const struct sql_digest_storage *digest); typedef PSI_sp_locker* (*start_sp_v1_t) (struct PSI_sp_locker_state_v1 *state, struct PSI_sp_share* sp_share); typedef void (*end_sp_v1_t) (struct PSI_sp_locker *locker); typedef void (*drop_sp_v1_t) (uint object_type, const char *schema_name, uint schema_name_length, const char *object_name, uint object_name_length); /** Acquire a sp share instrumentation. @param type of stored program @param schema name of stored program @param name of stored program @return a stored program share instrumentation, or NULL */ typedef struct PSI_sp_share* (*get_sp_share_v1_t) (uint object_type, const char *schema_name, uint schema_name_length, const char *object_name, uint object_name_length); /** Release a stored program share. @param info the stored program share to release */ typedef void (*release_sp_share_v1_t)(struct PSI_sp_share *share); typedef PSI_metadata_lock* (*create_metadata_lock_v1_t) (void *identity, const MDL_key *key, opaque_mdl_type mdl_type, opaque_mdl_duration mdl_duration, opaque_mdl_status mdl_status, const char *src_file, uint src_line); typedef void (*set_metadata_lock_status_v1_t)(PSI_metadata_lock *lock, opaque_mdl_status mdl_status); typedef void (*destroy_metadata_lock_v1_t)(PSI_metadata_lock *lock); typedef struct PSI_metadata_locker* (*start_metadata_wait_v1_t) (struct PSI_metadata_locker_state_v1 *state, struct PSI_metadata_lock *mdl, const char *src_file, uint src_line); typedef void (*end_metadata_wait_v1_t) (struct PSI_metadata_locker *locker, int rc); /** Stores an array of connection attributes @param buffer char array of length encoded connection attributes in network format @param length length of the data in buffer @param from_cs charset in which @c buffer is encoded @return state @retval non_0 attributes truncated @retval 0 stored the attribute */ typedef int (*set_thread_connect_attrs_v1_t)(const char *buffer, uint length, const void *from_cs); /** Performance Schema Interface, version 1. @since PSI_VERSION_1 */ struct PSI_v1 { /** @sa register_mutex_v1_t. */ register_mutex_v1_t register_mutex; /** @sa register_rwlock_v1_t. */ register_rwlock_v1_t register_rwlock; /** @sa register_cond_v1_t. */ register_cond_v1_t register_cond; /** @sa register_thread_v1_t. */ register_thread_v1_t register_thread; /** @sa register_file_v1_t. */ register_file_v1_t register_file; /** @sa register_stage_v1_t. */ register_stage_v1_t register_stage; /** @sa register_statement_v1_t. */ register_statement_v1_t register_statement; /** @sa register_socket_v1_t. */ register_socket_v1_t register_socket; /** @sa init_mutex_v1_t. */ init_mutex_v1_t init_mutex; /** @sa destroy_mutex_v1_t. */ destroy_mutex_v1_t destroy_mutex; /** @sa init_rwlock_v1_t. */ init_rwlock_v1_t init_rwlock; /** @sa destroy_rwlock_v1_t. */ destroy_rwlock_v1_t destroy_rwlock; /** @sa init_cond_v1_t. */ init_cond_v1_t init_cond; /** @sa destroy_cond_v1_t. */ destroy_cond_v1_t destroy_cond; /** @sa init_socket_v1_t. */ init_socket_v1_t init_socket; /** @sa destroy_socket_v1_t. */ destroy_socket_v1_t destroy_socket; /** @sa get_table_share_v1_t. */ get_table_share_v1_t get_table_share; /** @sa release_table_share_v1_t. */ release_table_share_v1_t release_table_share; /** @sa drop_table_share_v1_t. */ drop_table_share_v1_t drop_table_share; /** @sa open_table_v1_t. */ open_table_v1_t open_table; /** @sa unbind_table_v1_t. */ unbind_table_v1_t unbind_table; /** @sa rebind_table_v1_t. */ rebind_table_v1_t rebind_table; /** @sa close_table_v1_t. */ close_table_v1_t close_table; /** @sa create_file_v1_t. */ create_file_v1_t create_file; /** @sa spawn_thread_v1_t. */ spawn_thread_v1_t spawn_thread; /** @sa new_thread_v1_t. */ new_thread_v1_t new_thread; /** @sa set_thread_id_v1_t. */ set_thread_id_v1_t set_thread_id; /** @sa set_thread_THD_v1_t. */ set_thread_THD_v1_t set_thread_THD; /** @sa set_thread_os_id_v1_t. */ set_thread_os_id_v1_t set_thread_os_id; /** @sa get_thread_v1_t. */ get_thread_v1_t get_thread; /** @sa set_thread_user_v1_t. */ set_thread_user_v1_t set_thread_user; /** @sa set_thread_account_v1_t. */ set_thread_account_v1_t set_thread_account; /** @sa set_thread_db_v1_t. */ set_thread_db_v1_t set_thread_db; /** @sa set_thread_command_v1_t. */ set_thread_command_v1_t set_thread_command; /** @sa set_connection_type_v1_t. */ set_connection_type_v1_t set_connection_type; /** @sa set_thread_start_time_v1_t. */ set_thread_start_time_v1_t set_thread_start_time; /** @sa set_thread_state_v1_t. */ set_thread_state_v1_t set_thread_state; /** @sa set_thread_info_v1_t. */ set_thread_info_v1_t set_thread_info; /** @sa set_thread_v1_t. */ set_thread_v1_t set_thread; /** @sa delete_current_thread_v1_t. */ delete_current_thread_v1_t delete_current_thread; /** @sa delete_thread_v1_t. */ delete_thread_v1_t delete_thread; /** @sa get_thread_file_name_locker_v1_t. */ get_thread_file_name_locker_v1_t get_thread_file_name_locker; /** @sa get_thread_file_stream_locker_v1_t. */ get_thread_file_stream_locker_v1_t get_thread_file_stream_locker; /** @sa get_thread_file_descriptor_locker_v1_t. */ get_thread_file_descriptor_locker_v1_t get_thread_file_descriptor_locker; /** @sa unlock_mutex_v1_t. */ unlock_mutex_v1_t unlock_mutex; /** @sa unlock_rwlock_v1_t. */ unlock_rwlock_v1_t unlock_rwlock; /** @sa signal_cond_v1_t. */ signal_cond_v1_t signal_cond; /** @sa broadcast_cond_v1_t. */ broadcast_cond_v1_t broadcast_cond; /** @sa start_idle_wait_v1_t. */ start_idle_wait_v1_t start_idle_wait; /** @sa end_idle_wait_v1_t. */ end_idle_wait_v1_t end_idle_wait; /** @sa start_mutex_wait_v1_t. */ start_mutex_wait_v1_t start_mutex_wait; /** @sa end_mutex_wait_v1_t. */ end_mutex_wait_v1_t end_mutex_wait; /** @sa start_rwlock_rdwait_v1_t. */ start_rwlock_rdwait_v1_t start_rwlock_rdwait; /** @sa end_rwlock_rdwait_v1_t. */ end_rwlock_rdwait_v1_t end_rwlock_rdwait; /** @sa start_rwlock_wrwait_v1_t. */ start_rwlock_wrwait_v1_t start_rwlock_wrwait; /** @sa end_rwlock_wrwait_v1_t. */ end_rwlock_wrwait_v1_t end_rwlock_wrwait; /** @sa start_cond_wait_v1_t. */ start_cond_wait_v1_t start_cond_wait; /** @sa end_cond_wait_v1_t. */ end_cond_wait_v1_t end_cond_wait; /** @sa start_table_io_wait_v1_t. */ start_table_io_wait_v1_t start_table_io_wait; /** @sa end_table_io_wait_v1_t. */ end_table_io_wait_v1_t end_table_io_wait; /** @sa start_table_lock_wait_v1_t. */ start_table_lock_wait_v1_t start_table_lock_wait; /** @sa end_table_lock_wait_v1_t. */ end_table_lock_wait_v1_t end_table_lock_wait; /** @sa start_file_open_wait_v1_t. */ start_file_open_wait_v1_t start_file_open_wait; /** @sa end_file_open_wait_v1_t. */ end_file_open_wait_v1_t end_file_open_wait; /** @sa end_file_open_wait_and_bind_to_descriptor_v1_t. */ end_file_open_wait_and_bind_to_descriptor_v1_t end_file_open_wait_and_bind_to_descriptor; /** @sa end_temp_file_open_wait_and_bind_to_descriptor_v1_t. */ end_temp_file_open_wait_and_bind_to_descriptor_v1_t end_temp_file_open_wait_and_bind_to_descriptor; /** @sa start_file_wait_v1_t. */ start_file_wait_v1_t start_file_wait; /** @sa end_file_wait_v1_t. */ end_file_wait_v1_t end_file_wait; /** @sa start_file_close_wait_v1_t. */ start_file_close_wait_v1_t start_file_close_wait; /** @sa end_file_close_wait_v1_t. */ end_file_close_wait_v1_t end_file_close_wait; /** @sa rename_file_close_wait_v1_t. */ end_file_rename_wait_v1_t end_file_rename_wait; /** @sa start_stage_v1_t. */ start_stage_v1_t start_stage; /** @sa get_current_stage_progress_v1_t. */ get_current_stage_progress_v1_t get_current_stage_progress; /** @sa end_stage_v1_t. */ end_stage_v1_t end_stage; /** @sa get_thread_statement_locker_v1_t. */ get_thread_statement_locker_v1_t get_thread_statement_locker; /** @sa refine_statement_v1_t. */ refine_statement_v1_t refine_statement; /** @sa start_statement_v1_t. */ start_statement_v1_t start_statement; /** @sa set_statement_text_v1_t. */ set_statement_text_v1_t set_statement_text; /** @sa set_statement_lock_time_t. */ set_statement_lock_time_t set_statement_lock_time; /** @sa set_statement_rows_sent_t. */ set_statement_rows_sent_t set_statement_rows_sent; /** @sa set_statement_rows_examined_t. */ set_statement_rows_examined_t set_statement_rows_examined; /** @sa inc_statement_created_tmp_disk_tables. */ inc_statement_created_tmp_disk_tables_t inc_statement_created_tmp_disk_tables; /** @sa inc_statement_created_tmp_tables. */ inc_statement_created_tmp_tables_t inc_statement_created_tmp_tables; /** @sa inc_statement_select_full_join. */ inc_statement_select_full_join_t inc_statement_select_full_join; /** @sa inc_statement_select_full_range_join. */ inc_statement_select_full_range_join_t inc_statement_select_full_range_join; /** @sa inc_statement_select_range. */ inc_statement_select_range_t inc_statement_select_range; /** @sa inc_statement_select_range_check. */ inc_statement_select_range_check_t inc_statement_select_range_check; /** @sa inc_statement_select_scan. */ inc_statement_select_scan_t inc_statement_select_scan; /** @sa inc_statement_sort_merge_passes. */ inc_statement_sort_merge_passes_t inc_statement_sort_merge_passes; /** @sa inc_statement_sort_range. */ inc_statement_sort_range_t inc_statement_sort_range; /** @sa inc_statement_sort_rows. */ inc_statement_sort_rows_t inc_statement_sort_rows; /** @sa inc_statement_sort_scan. */ inc_statement_sort_scan_t inc_statement_sort_scan; /** @sa set_statement_no_index_used. */ set_statement_no_index_used_t set_statement_no_index_used; /** @sa set_statement_no_good_index_used. */ set_statement_no_good_index_used_t set_statement_no_good_index_used; /** @sa end_statement_v1_t. */ end_statement_v1_t end_statement; /** @sa get_thread_transaction_locker_v1_t. */ get_thread_transaction_locker_v1_t get_thread_transaction_locker; /** @sa start_transaction_v1_t. */ start_transaction_v1_t start_transaction; /** @sa set_transaction_xid_v1_t. */ set_transaction_xid_v1_t set_transaction_xid; /** @sa set_transaction_xa_state_v1_t. */ set_transaction_xa_state_v1_t set_transaction_xa_state; /** @sa set_transaction_gtid_v1_t. */ set_transaction_gtid_v1_t set_transaction_gtid; /** @sa set_transaction_trxid_v1_t. */ set_transaction_trxid_v1_t set_transaction_trxid; /** @sa inc_transaction_savepoints_v1_t. */ inc_transaction_savepoints_v1_t inc_transaction_savepoints; /** @sa inc_transaction_rollback_to_savepoint_v1_t. */ inc_transaction_rollback_to_savepoint_v1_t inc_transaction_rollback_to_savepoint; /** @sa inc_transaction_release_savepoint_v1_t. */ inc_transaction_release_savepoint_v1_t inc_transaction_release_savepoint; /** @sa end_transaction_v1_t. */ end_transaction_v1_t end_transaction; /** @sa start_socket_wait_v1_t. */ start_socket_wait_v1_t start_socket_wait; /** @sa end_socket_wait_v1_t. */ end_socket_wait_v1_t end_socket_wait; /** @sa set_socket_state_v1_t. */ set_socket_state_v1_t set_socket_state; /** @sa set_socket_info_v1_t. */ set_socket_info_v1_t set_socket_info; /** @sa set_socket_thread_owner_v1_t. */ set_socket_thread_owner_v1_t set_socket_thread_owner; /** @sa create_prepared_stmt_v1_t. */ create_prepared_stmt_v1_t create_prepared_stmt; /** @sa destroy_prepared_stmt_v1_t. */ destroy_prepared_stmt_v1_t destroy_prepared_stmt; /** @sa reprepare_prepared_stmt_v1_t. */ reprepare_prepared_stmt_v1_t reprepare_prepared_stmt; /** @sa execute_prepared_stmt_v1_t. */ execute_prepared_stmt_v1_t execute_prepared_stmt; /** @sa set_prepared_stmt_text_v1_t. */ set_prepared_stmt_text_v1_t set_prepared_stmt_text; /** @sa digest_start_v1_t. */ digest_start_v1_t digest_start; /** @sa digest_end_v1_t. */ digest_end_v1_t digest_end; /** @sa set_thread_connect_attrs_v1_t. */ set_thread_connect_attrs_v1_t set_thread_connect_attrs; /** @sa start_sp_v1_t. */ start_sp_v1_t start_sp; /** @sa start_sp_v1_t. */ end_sp_v1_t end_sp; /** @sa drop_sp_v1_t. */ drop_sp_v1_t drop_sp; /** @sa get_sp_share_v1_t. */ get_sp_share_v1_t get_sp_share; /** @sa release_sp_share_v1_t. */ release_sp_share_v1_t release_sp_share; /** @sa register_memory_v1_t. */ register_memory_v1_t register_memory; /** @sa memory_alloc_v1_t. */ memory_alloc_v1_t memory_alloc; /** @sa memory_realloc_v1_t. */ memory_realloc_v1_t memory_realloc; /** @sa memory_claim_v1_t. */ memory_claim_v1_t memory_claim; /** @sa memory_free_v1_t. */ memory_free_v1_t memory_free; unlock_table_v1_t unlock_table; create_metadata_lock_v1_t create_metadata_lock; set_metadata_lock_status_v1_t set_metadata_lock_status; destroy_metadata_lock_v1_t destroy_metadata_lock; start_metadata_wait_v1_t start_metadata_wait; end_metadata_wait_v1_t end_metadata_wait; set_thread_peer_port_v1_t set_thread_peer_port; }; /** @} (end of group Group_PSI_v1) */ #endif /* HAVE_PSI_1 */ #ifdef USE_PSI_2 #define HAVE_PSI_2 #endif #ifdef HAVE_PSI_2 /** @defgroup Group_PSI_v2 Application Binary Interface, version 2 @ingroup Instrumentation_interface @{ */ /** Performance Schema Interface, version 2. This is a placeholder, this interface is not defined yet. @since PSI_VERSION_2 */ struct PSI_v2 { /** Placeholder */ int placeholder; /* ... extended interface ... */ }; /** Placeholder */ struct PSI_mutex_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_rwlock_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_cond_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_thread_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_file_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_stage_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_statement_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_transaction_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_idle_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_mutex_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_rwlock_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_cond_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_file_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_statement_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_transaction_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_socket_locker_state_v2 { /** Placeholder */ int placeholder; }; struct PSI_metadata_locker_state_v2 { int placeholder; }; /** @} (end of group Group_PSI_v2) */ #endif /* HAVE_PSI_2 */ /** @typedef PSI The instrumentation interface for the current version. @sa PSI_CURRENT_VERSION */ /** @typedef PSI_mutex_info The mutex information structure for the current version. */ /** @typedef PSI_rwlock_info The rwlock information structure for the current version. */ /** @typedef PSI_cond_info The cond information structure for the current version. */ /** @typedef PSI_thread_info The thread information structure for the current version. */ /** @typedef PSI_file_info The file information structure for the current version. */ /* Export the required version */ #ifdef USE_PSI_1 typedef struct PSI_v1 PSI; typedef struct PSI_mutex_info_v1 PSI_mutex_info; typedef struct PSI_rwlock_info_v1 PSI_rwlock_info; typedef struct PSI_cond_info_v1 PSI_cond_info; typedef struct PSI_thread_info_v1 PSI_thread_info; typedef struct PSI_file_info_v1 PSI_file_info; typedef struct PSI_stage_info_v1 PSI_stage_info; typedef struct PSI_statement_info_v1 PSI_statement_info; typedef struct PSI_transaction_info_v1 PSI_transaction_info; typedef struct PSI_socket_info_v1 PSI_socket_info; typedef struct PSI_idle_locker_state_v1 PSI_idle_locker_state; typedef struct PSI_mutex_locker_state_v1 PSI_mutex_locker_state; typedef struct PSI_rwlock_locker_state_v1 PSI_rwlock_locker_state; typedef struct PSI_cond_locker_state_v1 PSI_cond_locker_state; typedef struct PSI_file_locker_state_v1 PSI_file_locker_state; typedef struct PSI_statement_locker_state_v1 PSI_statement_locker_state; typedef struct PSI_transaction_locker_state_v1 PSI_transaction_locker_state; typedef struct PSI_socket_locker_state_v1 PSI_socket_locker_state; typedef struct PSI_sp_locker_state_v1 PSI_sp_locker_state; typedef struct PSI_metadata_locker_state_v1 PSI_metadata_locker_state; #endif #ifdef USE_PSI_2 typedef struct PSI_v2 PSI; typedef struct PSI_mutex_info_v2 PSI_mutex_info; typedef struct PSI_rwlock_info_v2 PSI_rwlock_info; typedef struct PSI_cond_info_v2 PSI_cond_info; typedef struct PSI_thread_info_v2 PSI_thread_info; typedef struct PSI_file_info_v2 PSI_file_info; typedef struct PSI_stage_info_v2 PSI_stage_info; typedef struct PSI_statement_info_v2 PSI_statement_info; typedef struct PSI_transaction_info_v2 PSI_transaction_info; typedef struct PSI_socket_info_v2 PSI_socket_info; typedef struct PSI_idle_locker_state_v2 PSI_idle_locker_state; typedef struct PSI_mutex_locker_state_v2 PSI_mutex_locker_state; typedef struct PSI_rwlock_locker_state_v2 PSI_rwlock_locker_state; typedef struct PSI_cond_locker_state_v2 PSI_cond_locker_state; typedef struct PSI_file_locker_state_v2 PSI_file_locker_state; typedef struct PSI_statement_locker_state_v2 PSI_statement_locker_state; typedef struct PSI_transaction_locker_state_v2 PSI_transaction_locker_state; typedef struct PSI_socket_locker_state_v2 PSI_socket_locker_state; typedef struct PSI_sp_locker_state_v2 PSI_sp_locker_state; typedef struct PSI_metadata_locker_state_v2 PSI_metadata_locker_state; #endif #ifndef HAVE_PSI_INTERFACE /** Dummy structure, used to declare PSI_server when no instrumentation is available. The content does not matter, since PSI_server will be NULL. */ struct PSI_none { int opaque; }; typedef struct PSI_none PSI; /** Stage instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented stage. */ struct PSI_stage_info_none { /** Unused stage key. */ unsigned int m_key; /** The name of the stage instrument. */ const char *m_name; /** Unused stage flags. */ int m_flags; }; /** The stage instrumentation has to co exist with the legacy THD::set_proc_info instrumentation. To avoid duplication of the instrumentation in the server, the common PSI_stage_info structure is used, so we export it here, even when not building with HAVE_PSI_INTERFACE. */ typedef struct PSI_stage_info_none PSI_stage_info; typedef struct PSI_stage_info_none PSI_statement_info; typedef struct PSI_stage_info_none PSI_sp_locker_state; typedef struct PSI_stage_info_none PSI_metadata_locker_state; typedef struct PSI_stage_info_none PSI_metadata_locker; #endif /* HAVE_PSI_INTERFACE */ extern MYSQL_PLUGIN_IMPORT PSI *PSI_server; /* Allow to override PSI_XXX_CALL at compile time with more efficient implementations, if available. If nothing better is available, make a dynamic call using the PSI_server function pointer. */ #define PSI_DYNAMIC_CALL(M) PSI_server->M /** @} */ C_MODE_END #endif /* MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H */ psi/mysql_statement.h000064400000015706151030241300010737 0ustar00/* Copyright (c) 2010, 2023, Oracle and/or its affiliates. Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_STATEMENT_H #define MYSQL_STATEMENT_H /** @file mysql/psi/mysql_statement.h Instrumentation helpers for statements. */ #include "mysql/psi/psi.h" class Diagnostics_area; typedef const struct charset_info_st CHARSET_INFO; #ifndef PSI_STATEMENT_CALL #define PSI_STATEMENT_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifndef PSI_DIGEST_CALL #define PSI_DIGEST_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Statement_instrumentation Statement Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_statement_register(P1, P2, P3) Statement registration. */ #ifdef HAVE_PSI_STATEMENT_INTERFACE #define mysql_statement_register(P1, P2, P3) \ inline_mysql_statement_register(P1, P2, P3) #else #define mysql_statement_register(P1, P2, P3) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE #define MYSQL_DIGEST_START(LOCKER) \ inline_mysql_digest_start(LOCKER) #else #define MYSQL_DIGEST_START(LOCKER) \ NULL #endif #ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE #define MYSQL_DIGEST_END(LOCKER, DIGEST) \ inline_mysql_digest_end(LOCKER, DIGEST) #else #define MYSQL_DIGEST_END(LOCKER, DIGEST) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_START_STATEMENT(STATE, K, DB, DB_LEN, CS, SPS) \ inline_mysql_start_statement(STATE, K, DB, DB_LEN, CS, SPS, __FILE__, __LINE__) #else #define MYSQL_START_STATEMENT(STATE, K, DB, DB_LEN, CS, SPS) \ NULL #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_REFINE_STATEMENT(LOCKER, K) \ inline_mysql_refine_statement(LOCKER, K) #else #define MYSQL_REFINE_STATEMENT(LOCKER, K) \ NULL #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_SET_STATEMENT_TEXT(LOCKER, P1, P2) \ inline_mysql_set_statement_text(LOCKER, P1, P2) #else #define MYSQL_SET_STATEMENT_TEXT(LOCKER, P1, P2) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_SET_STATEMENT_LOCK_TIME(LOCKER, P1) \ inline_mysql_set_statement_lock_time(LOCKER, P1) #else #define MYSQL_SET_STATEMENT_LOCK_TIME(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_SET_STATEMENT_ROWS_SENT(LOCKER, P1) \ inline_mysql_set_statement_rows_sent(LOCKER, P1) #else #define MYSQL_SET_STATEMENT_ROWS_SENT(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_SET_STATEMENT_ROWS_EXAMINED(LOCKER, P1) \ inline_mysql_set_statement_rows_examined(LOCKER, P1) #else #define MYSQL_SET_STATEMENT_ROWS_EXAMINED(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_END_STATEMENT(LOCKER, DA) \ inline_mysql_end_statement(LOCKER, DA) #else #define MYSQL_END_STATEMENT(LOCKER, DA) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE static inline void inline_mysql_statement_register( const char *category, PSI_statement_info *info, int count) { PSI_STATEMENT_CALL(register_statement)(category, info, count); } #ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE static inline struct PSI_digest_locker * inline_mysql_digest_start(PSI_statement_locker *locker) { PSI_digest_locker* digest_locker= NULL; if (psi_likely(locker != NULL)) digest_locker= PSI_DIGEST_CALL(digest_start)(locker); return digest_locker; } #endif #ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE static inline void inline_mysql_digest_end(PSI_digest_locker *locker, const sql_digest_storage *digest) { if (psi_likely(locker != NULL)) PSI_DIGEST_CALL(digest_end)(locker, digest); } #endif static inline struct PSI_statement_locker * inline_mysql_start_statement(PSI_statement_locker_state *state, PSI_statement_key key, const char *db, size_t db_len, CHARSET_INFO *charset, PSI_sp_share *sp_share, const char *src_file, uint src_line) { PSI_statement_locker *locker; locker= PSI_STATEMENT_CALL(get_thread_statement_locker)(state, key, charset, sp_share); if (psi_likely(locker != NULL)) PSI_STATEMENT_CALL(start_statement)(locker, db, (uint)db_len, src_file, src_line); return locker; } static inline struct PSI_statement_locker * inline_mysql_refine_statement(PSI_statement_locker *locker, PSI_statement_key key) { if (psi_likely(locker != NULL)) { locker= PSI_STATEMENT_CALL(refine_statement)(locker, key); } return locker; } static inline void inline_mysql_set_statement_text(PSI_statement_locker *locker, const char *text, uint text_len) { if (psi_likely(locker != NULL)) { PSI_STATEMENT_CALL(set_statement_text)(locker, text, text_len); } } static inline void inline_mysql_set_statement_lock_time(PSI_statement_locker *locker, ulonglong count) { if (psi_likely(locker != NULL)) { PSI_STATEMENT_CALL(set_statement_lock_time)(locker, count); } } static inline void inline_mysql_set_statement_rows_sent(PSI_statement_locker *locker, ulonglong count) { if (psi_likely(locker != NULL)) { PSI_STATEMENT_CALL(set_statement_rows_sent)(locker, count); } } static inline void inline_mysql_set_statement_rows_examined(PSI_statement_locker *locker, ulonglong count) { if (psi_likely(locker != NULL)) { PSI_STATEMENT_CALL(set_statement_rows_examined)(locker, count); } } static inline void inline_mysql_end_statement(struct PSI_statement_locker *locker, Diagnostics_area *stmt_da) { PSI_STAGE_CALL(end_stage)(); if (psi_likely(locker != NULL)) PSI_STATEMENT_CALL(end_statement)(locker, stmt_da); } #endif /** @} (end of group Statement_instrumentation) */ #endif plugin_encryption.h000064400000010521151030241300010451 0ustar00#ifndef MYSQL_PLUGIN_ENCRYPTION_INCLUDED /* Copyright (C) 2014, 2015 Sergei Golubchik and MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Encryption Plugin API. This file defines the API for server plugins that manage encryption keys for MariaDB on-disk data encryption. */ #define MYSQL_PLUGIN_ENCRYPTION_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #define MariaDB_ENCRYPTION_INTERFACE_VERSION 0x0300 /** Encryption plugin descriptor */ struct st_mariadb_encryption { int interface_version; /**< version plugin uses */ /*********** KEY MANAGEMENT ********************************************/ /** function returning latest key version for a given key id @return a version or ENCRYPTION_KEY_VERSION_INVALID to indicate an error. */ unsigned int (*get_latest_key_version)(unsigned int key_id); /** function returning a key for a key version @param version the requested key version @param key the key will be stored there. Can be NULL - in which case no key will be returned @param key_length in: key buffer size out: the actual length of the key This method can be used to query the key length - the required buffer size - by passing key==NULL. If the buffer size is less than the key length the content of the key buffer is undefined (the plugin is free to partially fill it with the key data or leave it untouched). @return 0 on success, or ENCRYPTION_KEY_VERSION_INVALID, ENCRYPTION_KEY_BUFFER_TOO_SMALL or any other non-zero number for errors */ unsigned int (*get_key)(unsigned int key_id, unsigned int version, unsigned char *key, unsigned int *key_length); /*********** ENCRYPTION ************************************************/ /* the caller uses encryption as follows: 1. create the encryption context object of the crypt_ctx_size() bytes. 2. initialize it with crypt_ctx_init(). 3. repeat crypt_ctx_update() until there are no more data to encrypt. 4. write the remaining output bytes and destroy the context object with crypt_ctx_finish(). */ /** returns the size of the encryption context object in bytes */ unsigned int (*crypt_ctx_size)(unsigned int key_id, unsigned int key_version); /** initializes the encryption context object. */ int (*crypt_ctx_init)(void *ctx, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen, int flags, unsigned int key_id, unsigned int key_version); /** processes (encrypts or decrypts) a chunk of data writes the output to th dst buffer. note that it might write more bytes that were in the input. or less. or none at all. */ int (*crypt_ctx_update)(void *ctx, const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen); /** writes the remaining output bytes and destroys the encryption context crypt_ctx_update might've cached part of the output in the context, this method will flush these data out. */ int (*crypt_ctx_finish)(void *ctx, unsigned char* dst, unsigned int* dlen); /** returns the length of the encrypted data it returns the exact length, given only the source length. which means, this API only supports encryption algorithms where the length of the encrypted data only depends on the length of the input (a.k.a. compression is not supported). */ unsigned int (*encrypted_length)(unsigned int slen, unsigned int key_id, unsigned int key_version); }; #ifdef __cplusplus } #endif #endif auth_dialog_client.h000064400000004015151030241300010520 0ustar00#ifndef MYSQL_AUTH_DIALOG_CLIENT_INCLUDED /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Definitions needed to use Dialog client authentication plugin */ struct st_mysql; #define MYSQL_AUTH_DIALOG_CLIENT_INCLUDED /** type of the mysql_authentication_dialog_ask function @param mysql mysql @param type type of the input 1 - ordinary string input 2 - password string @param prompt prompt @param buf a buffer to store the use input @param buf_len the length of the buffer @retval a pointer to the user input string. It may be equal to 'buf' or to 'mysql->password'. In all other cases it is assumed to be an allocated string, and the "dialog" plugin will free() it. */ typedef char *(*mysql_authentication_dialog_ask_t)(struct st_mysql *mysql, int type, const char *prompt, char *buf, int buf_len); /** first byte of the question string is the question "type". It can be an "ordinary" or a "password" question. The last bit set marks a last question in the authentication exchange. */ #define ORDINARY_QUESTION "\2" #define LAST_QUESTION "\3" #define PASSWORD_QUESTION "\4" #define LAST_PASSWORD "\5" #endif service_progress_report.h000064400000006434151030241300011670 0ustar00#ifndef MYSQL_SERVICE_PROGRESS_REPORT_INCLUDED /* Copyright (C) 2011 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service allows plugins to report progress of long running operations to the server. The progress report is visible in SHOW PROCESSLIST, INFORMATION_SCHEMA.PROCESSLIST, and is sent to the client if requested. The functions are documented at https://mariadb.com/kb/en/progress-reporting/#how-to-add-support-for-progress-reporting-to-a-storage-engine */ #ifdef __cplusplus extern "C" { #endif #define thd_proc_info(thd, msg) set_thd_proc_info(thd, msg, \ __func__, __FILE__, __LINE__) extern struct progress_report_service_st { void (*thd_progress_init_func)(MYSQL_THD thd, unsigned int max_stage); void (*thd_progress_report_func)(MYSQL_THD thd, unsigned long long progress, unsigned long long max_progress); void (*thd_progress_next_stage_func)(MYSQL_THD thd); void (*thd_progress_end_func)(MYSQL_THD thd); const char *(*set_thd_proc_info_func)(MYSQL_THD, const char *info, const char *func, const char *file, unsigned int line); } *progress_report_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_progress_init(thd,max_stage) (progress_report_service->thd_progress_init_func((thd),(max_stage))) #define thd_progress_report(thd, progress, max_progress) (progress_report_service->thd_progress_report_func((thd), (progress), (max_progress))) #define thd_progress_next_stage(thd) (progress_report_service->thd_progress_next_stage_func(thd)) #define thd_progress_end(thd) (progress_report_service->thd_progress_end_func(thd)) #define set_thd_proc_info(thd,info,func,file,line) (progress_report_service->set_thd_proc_info_func((thd),(info),(func),(file),(line))) #else /** Report progress for long running operations @param thd User thread connection handle @param progress Where we are now @param max_progress Progress will continue up to this */ void thd_progress_init(MYSQL_THD thd, unsigned int max_stage); void thd_progress_report(MYSQL_THD thd, unsigned long long progress, unsigned long long max_progress); void thd_progress_next_stage(MYSQL_THD thd); void thd_progress_end(MYSQL_THD thd); const char *set_thd_proc_info(MYSQL_THD, const char * info, const char *func, const char *file, unsigned int line); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_PROGRESS_REPORT_INCLUDED #endif service_thd_alloc.h000064400000010612151030241300010353 0ustar00#ifndef MYSQL_SERVICE_THD_ALLOC_INCLUDED /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service provides functions to allocate memory in a connection local memory pool. The memory allocated there will be automatically freed at the end of the statement, don't use it for allocations that should live longer than that. For short living allocations this is more efficient than using my_malloc and friends, and automatic "garbage collection" allows not to think about memory leaks. The pool is best for small to medium objects, don't use it for large allocations - they are better served with my_malloc. */ #ifndef MYSQL_ABI_CHECK #include #endif #ifdef __cplusplus extern "C" { #endif struct st_mysql_lex_string { char *str; size_t length; }; typedef struct st_mysql_lex_string MYSQL_LEX_STRING; struct st_mysql_const_lex_string { const char *str; size_t length; }; typedef struct st_mysql_const_lex_string MYSQL_CONST_LEX_STRING; extern struct thd_alloc_service_st { void *(*thd_alloc_func)(MYSQL_THD, size_t); void *(*thd_calloc_func)(MYSQL_THD, size_t); char *(*thd_strdup_func)(MYSQL_THD, const char *); char *(*thd_strmake_func)(MYSQL_THD, const char *, size_t); void *(*thd_memdup_func)(MYSQL_THD, const void*, size_t); MYSQL_CONST_LEX_STRING *(*thd_make_lex_string_func)(MYSQL_THD, MYSQL_CONST_LEX_STRING *, const char *, size_t, int); } *thd_alloc_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_alloc(thd,size) (thd_alloc_service->thd_alloc_func((thd), (size))) #define thd_calloc(thd,size) (thd_alloc_service->thd_calloc_func((thd), (size))) #define thd_strdup(thd,str) (thd_alloc_service->thd_strdup_func((thd), (str))) #define thd_strmake(thd,str,size) \ (thd_alloc_service->thd_strmake_func((thd), (str), (size))) #define thd_memdup(thd,str,size) \ (thd_alloc_service->thd_memdup_func((thd), (str), (size))) #define thd_make_lex_string(thd, lex_str, str, size, allocate_lex_string) \ (thd_alloc_service->thd_make_lex_string_func((thd), (lex_str), (str), \ (size), (allocate_lex_string))) #else /** Allocate memory in the connection's local memory pool @details When properly used in place of @c my_malloc(), this can significantly improve concurrency. Don't use this or related functions to allocate large chunks of memory. Use for temporary storage only. The memory will be freed automatically at the end of the statement; no explicit code is required to prevent memory leaks. @see alloc_root() */ void *thd_alloc(MYSQL_THD thd, size_t size); /** @see thd_alloc() */ void *thd_calloc(MYSQL_THD thd, size_t size); /** @see thd_alloc() */ char *thd_strdup(MYSQL_THD thd, const char *str); /** @see thd_alloc() */ char *thd_strmake(MYSQL_THD thd, const char *str, size_t size); /** @see thd_alloc() */ void *thd_memdup(MYSQL_THD thd, const void* str, size_t size); /** Create a LEX_STRING in this connection's local memory pool @param thd user thread connection handle @param lex_str pointer to LEX_STRING object to be initialized @param str initializer to be copied into lex_str @param size length of str, in bytes @param allocate_lex_string flag: if TRUE, allocate new LEX_STRING object, instead of using lex_str value @return NULL on failure, or pointer to the LEX_STRING object @see thd_alloc() */ MYSQL_CONST_LEX_STRING *thd_make_lex_string(MYSQL_THD thd, MYSQL_CONST_LEX_STRING *lex_str, const char *str, size_t size, int allocate_lex_string); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_ALLOC_INCLUDED #endif service_encryption.h000064400000013031151030241300010612 0ustar00#ifndef MYSQL_SERVICE_ENCRYPTION_INCLUDED /* Copyright (c) 2015, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file encryption service Functions to support data encryption and encryption key management. They are normally implemented in an encryption plugin, so this service connects encryption *consumers* (e.g. storage engines) to the encryption *provider* (encryption plugin). */ #ifndef MYSQL_ABI_CHECK #include #ifdef _WIN32 #ifndef __cplusplus #define inline __inline #endif #endif #endif #ifdef __cplusplus extern "C" { #endif /* returned from encryption_key_get_latest_version() */ #define ENCRYPTION_KEY_VERSION_INVALID (~(unsigned int)0) #define ENCRYPTION_KEY_NOT_ENCRYPTED (0) #define ENCRYPTION_KEY_SYSTEM_DATA 1 #define ENCRYPTION_KEY_TEMPORARY_DATA 2 /* returned from encryption_key_get() */ #define ENCRYPTION_KEY_BUFFER_TOO_SMALL (100) #define ENCRYPTION_FLAG_DECRYPT 0 #define ENCRYPTION_FLAG_ENCRYPT 1 #define ENCRYPTION_FLAG_NOPAD 2 struct encryption_service_st { unsigned int (*encryption_key_get_latest_version_func)(unsigned int key_id); unsigned int (*encryption_key_get_func)(unsigned int key_id, unsigned int key_version, unsigned char* buffer, unsigned int* length); unsigned int (*encryption_ctx_size_func)(unsigned int key_id, unsigned int key_version); int (*encryption_ctx_init_func)(void *ctx, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen, int flags, unsigned int key_id, unsigned int key_version); int (*encryption_ctx_update_func)(void *ctx, const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen); int (*encryption_ctx_finish_func)(void *ctx, unsigned char* dst, unsigned int* dlen); unsigned int (*encryption_encrypted_length_func)(unsigned int slen, unsigned int key_id, unsigned int key_version); }; #ifdef MYSQL_DYNAMIC_PLUGIN extern struct encryption_service_st *encryption_service; #define encryption_key_get_latest_version(KI) encryption_service->encryption_key_get_latest_version_func(KI) #define encryption_key_get(KI,KV,K,S) encryption_service->encryption_key_get_func((KI),(KV),(K),(S)) #define encryption_ctx_size(KI,KV) encryption_service->encryption_ctx_size_func((KI),(KV)) #define encryption_ctx_init(CTX,K,KL,IV,IVL,F,KI,KV) encryption_service->encryption_ctx_init_func((CTX),(K),(KL),(IV),(IVL),(F),(KI),(KV)) #define encryption_ctx_update(CTX,S,SL,D,DL) encryption_service->encryption_ctx_update_func((CTX),(S),(SL),(D),(DL)) #define encryption_ctx_finish(CTX,D,DL) encryption_service->encryption_ctx_finish_func((CTX),(D),(DL)) #define encryption_encrypted_length(SL,KI,KV) encryption_service->encryption_encrypted_length_func((SL),(KI),(KV)) #else extern struct encryption_service_st encryption_handler; #define encryption_key_get_latest_version(KI) encryption_handler.encryption_key_get_latest_version_func(KI) #define encryption_key_get(KI,KV,K,S) encryption_handler.encryption_key_get_func((KI),(KV),(K),(S)) #define encryption_ctx_size(KI,KV) encryption_handler.encryption_ctx_size_func((KI),(KV)) #define encryption_ctx_init(CTX,K,KL,IV,IVL,F,KI,KV) encryption_handler.encryption_ctx_init_func((CTX),(K),(KL),(IV),(IVL),(F),(KI),(KV)) #define encryption_ctx_update(CTX,S,SL,D,DL) encryption_handler.encryption_ctx_update_func((CTX),(S),(SL),(D),(DL)) #define encryption_ctx_finish(CTX,D,DL) encryption_handler.encryption_ctx_finish_func((CTX),(D),(DL)) #define encryption_encrypted_length(SL,KI,KV) encryption_handler.encryption_encrypted_length_func((SL),(KI),(KV)) #endif static inline unsigned int encryption_key_id_exists(unsigned int id) { return encryption_key_get_latest_version(id) != ENCRYPTION_KEY_VERSION_INVALID; } static inline unsigned int encryption_key_version_exists(unsigned int id, unsigned int version) { unsigned int unused; return encryption_key_get(id, version, NULL, &unused) != ENCRYPTION_KEY_VERSION_INVALID; } static inline int encryption_crypt(const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen, int flags, unsigned int key_id, unsigned int key_version) { void *ctx= alloca(encryption_ctx_size(key_id, key_version)); int res1, res2; unsigned int d1, d2; if ((res1= encryption_ctx_init(ctx, key, klen, iv, ivlen, flags, key_id, key_version))) return res1; res1= encryption_ctx_update(ctx, src, slen, dst, &d1); res2= encryption_ctx_finish(ctx, dst + d1, &d2); *dlen= d1 + d2; return res1 ? res1 : res2; } #ifdef __cplusplus } #endif #define MYSQL_SERVICE_ENCRYPTION_INCLUDED #endif plugin_audit.h000064400000012641151030241300007372 0ustar00/* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_audit_h #define _my_audit_h /************************************************************************* API for Audit plugin. (MYSQL_AUDIT_PLUGIN) */ #include "plugin.h" #ifdef __cplusplus extern "C" { #endif #define MYSQL_AUDIT_CLASS_MASK_SIZE 1 #define MYSQL_AUDIT_INTERFACE_VERSION 0x0302 /************************************************************************* AUDIT CLASS : GENERAL LOG events occurs before emitting to the general query log. ERROR events occur before transmitting errors to the user. RESULT events occur after transmitting a resultset to the user. STATUS events occur after transmitting a resultset or errors to the user. */ #define MYSQL_AUDIT_GENERAL_CLASS 0 #define MYSQL_AUDIT_GENERAL_CLASSMASK (1 << MYSQL_AUDIT_GENERAL_CLASS) #define MYSQL_AUDIT_GENERAL_LOG 0 #define MYSQL_AUDIT_GENERAL_ERROR 1 #define MYSQL_AUDIT_GENERAL_RESULT 2 #define MYSQL_AUDIT_GENERAL_STATUS 3 struct mysql_event_general { unsigned int event_subclass; int general_error_code; unsigned long general_thread_id; const char *general_user; unsigned int general_user_length; const char *general_command; unsigned int general_command_length; const char *general_query; unsigned int general_query_length; const struct charset_info_st *general_charset; unsigned long long general_time; unsigned long long general_rows; /* Added in version 0x302 */ unsigned long long query_id; MYSQL_CONST_LEX_STRING database; }; /* AUDIT CLASS : CONNECTION CONNECT occurs after authentication phase is completed. DISCONNECT occurs after connection is terminated. CHANGE_USER occurs after COM_CHANGE_USER RPC is completed. */ #define MYSQL_AUDIT_CONNECTION_CLASS 1 #define MYSQL_AUDIT_CONNECTION_CLASSMASK (1 << MYSQL_AUDIT_CONNECTION_CLASS) #define MYSQL_AUDIT_CONNECTION_CONNECT 0 #define MYSQL_AUDIT_CONNECTION_DISCONNECT 1 #define MYSQL_AUDIT_CONNECTION_CHANGE_USER 2 struct mysql_event_connection { unsigned int event_subclass; int status; unsigned long thread_id; const char *user; unsigned int user_length; const char *priv_user; unsigned int priv_user_length; const char *external_user; unsigned int external_user_length; const char *proxy_user; unsigned int proxy_user_length; const char *host; unsigned int host_length; const char *ip; unsigned int ip_length; MYSQL_CONST_LEX_STRING database; }; /* AUDIT CLASS : TABLE LOCK occurs when a connection "locks" (this does not necessarily mean a table lock and also happens for row-locking engines) the table at the beginning of a statement. This event is generated at the beginning of every statement for every affected table, unless there's a LOCK TABLES statement in effect (in which case it is generated once for LOCK TABLES and then is suppressed until the tables are unlocked). CREATE/DROP/RENAME occur when a table is created, dropped, or renamed. */ #define MYSQL_AUDIT_TABLE_CLASS 15 #define MYSQL_AUDIT_TABLE_CLASSMASK (1 << MYSQL_AUDIT_TABLE_CLASS) #define MYSQL_AUDIT_TABLE_LOCK 0 #define MYSQL_AUDIT_TABLE_CREATE 1 #define MYSQL_AUDIT_TABLE_DROP 2 #define MYSQL_AUDIT_TABLE_RENAME 3 #define MYSQL_AUDIT_TABLE_ALTER 4 struct mysql_event_table { unsigned int event_subclass; unsigned long thread_id; const char *user; const char *priv_user; const char *priv_host; const char *external_user; const char *proxy_user; const char *host; const char *ip; MYSQL_CONST_LEX_STRING database; MYSQL_CONST_LEX_STRING table; /* for MYSQL_AUDIT_TABLE_RENAME */ MYSQL_CONST_LEX_STRING new_database; MYSQL_CONST_LEX_STRING new_table; /* for MYSQL_AUDIT_TABLE_LOCK, true if read-only, false if read/write */ int read_only; /* Added in version 0x302 */ unsigned long long query_id; }; /************************************************************************* Here we define the descriptor structure, that is referred from st_mysql_plugin. release_thd() event occurs when the event class consumer is to be disassociated from the specified THD. This would typically occur before some operation which may require sleeping - such as when waiting for the next query from the client. event_notify() is invoked whenever an event occurs which is of any class for which the plugin has interest. The second argument indicates the specific event class and the third argument is data as required for that class. class_mask is an array of bits used to indicate what event classes that this plugin wants to receive. */ struct st_mysql_audit { int interface_version; void (*release_thd)(MYSQL_THD); void (*event_notify)(MYSQL_THD, unsigned int, const void *); unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; }; #ifdef __cplusplus } #endif #endif service_print_check_msg.h000064400000003020151030241300011554 0ustar00/* Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #pragma once /** @file include/mysql/service_print_check_msg.h This service provides functions to write messages for check or repair */ #ifdef __cplusplus extern "C" { #endif extern struct print_check_msg_service_st { void (*print_check_msg)(MYSQL_THD, const char *db_name, const char *table_name, const char *op, const char *msg_type, const char *message, my_bool print_to_log); } *print_check_msg_service; #ifdef MYSQL_DYNAMIC_PLUGIN # define print_check_msg_context(_THD) print_check_msg_service->print_check_msg #else extern void print_check_msg(MYSQL_THD, const char *db_name, const char *table_name, const char *op, const char *msg_type, const char *message, my_bool print_to_log); #endif #ifdef __cplusplus } #endif plugin_auth_common.h000064400000010635151030241300010576 0ustar00#ifndef MYSQL_PLUGIN_AUTH_COMMON_INCLUDED /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab Copyright (c) 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef _WIN32 #include #endif /** @file This file defines constants and data structures that are the same for both client- and server-side authentication plugins. */ #define MYSQL_PLUGIN_AUTH_COMMON_INCLUDED /** the max allowed length for a user name */ #define MYSQL_USERNAME_LENGTH 512 /** return values of the plugin authenticate_user() method. */ /** Authentication failed, plugin internal error. An error occurred in the authentication plugin itself. These errors are reported in table performance_schema.host_cache, column COUNT_AUTH_PLUGIN_ERRORS. */ #define CR_AUTH_PLUGIN_ERROR 3 /** Authentication failed, client server handshake. An error occurred during the client server handshake. These errors are reported in table performance_schema.host_cache, column COUNT_HANDSHAKE_ERRORS. */ #define CR_AUTH_HANDSHAKE 2 /** Authentication failed, user credentials. For example, wrong passwords. These errors are reported in table performance_schema.host_cache, column COUNT_AUTHENTICATION_ERRORS. */ #define CR_AUTH_USER_CREDENTIALS 1 /** Authentication failed. Additionally, all other CR_xxx values (libmysql error code) can be used too. The client plugin may set the error code and the error message directly in the MYSQL structure and return CR_ERROR. If a CR_xxx specific error code was returned, an error message in the MYSQL structure will be overwritten. If CR_ERROR is returned without setting the error in MYSQL, CR_UNKNOWN_ERROR will be user. */ #define CR_ERROR 0 /** Authentication (client part) was successful. It does not mean that the authentication as a whole was successful, usually it only means that the client was able to send the user name and the password to the server. If CR_OK is returned, the libmysql reads the next packet expecting it to be one of OK, ERROR, or CHANGE_PLUGIN packets. */ #define CR_OK -1 /** Authentication was successful. It means that the client has done its part successfully and also that a plugin has read the last packet (one of OK, ERROR, CHANGE_PLUGIN). In this case, libmysql will not read a packet from the server, but it will use the data at mysql->net.read_pos. A plugin may return this value if the number of roundtrips in the authentication protocol is not known in advance, and the client plugin needs to read one packet more to determine if the authentication is finished or not. */ #define CR_OK_HANDSHAKE_COMPLETE -2 typedef struct st_plugin_vio_info { enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET, MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol; int socket; /**< it's set, if the protocol is SOCKET or TCP */ #ifdef _WIN32 HANDLE handle; /**< it's set, if the protocol is PIPE or MEMORY */ #endif } MYSQL_PLUGIN_VIO_INFO; /** Provides plugin access to communication channel */ typedef struct st_plugin_vio { /** Plugin provides a pointer reference and this function sets it to the contents of any incoming packet. Returns the packet length, or -1 if the plugin should terminate. */ int (*read_packet)(struct st_plugin_vio *vio, unsigned char **buf); /** Plugin provides a buffer with data and the length and this function sends it as a packet. Returns 0 on success, 1 on failure. */ int (*write_packet)(struct st_plugin_vio *vio, const unsigned char *packet, int packet_len); /** Fills in a st_plugin_vio_info structure, providing the information about the connection. */ void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info); } MYSQL_PLUGIN_VIO; #endif service_my_snprintf.h000064400000007212151030241300010774 0ustar00#ifndef MYSQL_SERVICE_MY_SNPRINTF_INCLUDED /* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my_snprintf service Portable and limited vsnprintf() implementation. This is a portable, limited vsnprintf() implementation, with some extra features. "Portable" means that it'll produce identical result on all platforms (for example, on Windows and Linux system printf %e formats the exponent differently, on different systems %p either prints leading 0x or not, %s may accept null pointer or crash on it). "Limited" means that it does not support all the C89 features. But it supports few extensions, not in any standard. my_vsnprintf(to, n, fmt, ap) @param[out] to A buffer to store the result in @param[in] n Store up to n-1 characters, followed by an end 0 @param[in] fmt printf-like format string @param[in] ap Arguments @return a number of bytes written to a buffer *excluding* terminating '\0' @post The syntax of a format string is generally the same: % where everything but the format is optional. Three one-character flags are recognized: '0' has the standard zero-padding semantics; '-' is parsed, but silently ignored; '`' (backtick) is only supported for strings (%s) and means that the string will be quoted according to MySQL identifier quoting rules. Both and can be specified as numbers or '*'. If an asterisk is used, an argument of type int is consumed. can be 'l', 'll', or 'z'. Supported formats are 's' (null pointer is accepted, printed as "(null)"), 'b' (extension, see below), 'c', 'd', 'i', 'u', 'x', 'o', 'X', 'p' (works as 0x%x), 'f', 'g', 'M' (extension, see below), 'T' (extension, see below). Standard syntax for positional arguments $n is supported. Extensions: Flag '`' (backtick): see above. Format 'b': binary buffer, prints exactly bytes from the argument, without stopping at '\0'. Format 'M': takes one integer, prints this integer, space, double quote error message, double quote. In other words printf("%M", n) === printf("%d \"%s\"", n, strerror(n)) Format 'T': takes string and print it like s but if the strints should be truncated puts "..." at the end. */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #include #endif extern struct my_snprintf_service_st { size_t (*my_snprintf_type)(char*, size_t, const char*, ...); size_t (*my_vsnprintf_type)(char *, size_t, const char*, va_list); } *my_snprintf_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_vsnprintf my_snprintf_service->my_vsnprintf_type #define my_snprintf my_snprintf_service->my_snprintf_type #else size_t my_snprintf(char* to, size_t n, const char* fmt, ...); size_t my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_MY_SNPRINTF_INCLUDED #endif service_sha1.h000064400000004162151030241300007261 0ustar00#ifndef MYSQL_SERVICE_SHA1_INCLUDED /* Copyright (c) 2013, 2014, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my sha1 service Functions to calculate SHA1 hash from a memory buffer */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #endif #define MY_SHA1_HASH_SIZE 20 /* Hash size in bytes */ extern struct my_sha1_service_st { void (*my_sha1_type)(unsigned char*, const char*, size_t); void (*my_sha1_multi_type)(unsigned char*, ...); size_t (*my_sha1_context_size_type)(); void (*my_sha1_init_type)(void *); void (*my_sha1_input_type)(void *, const unsigned char *, size_t); void (*my_sha1_result_type)(void *, unsigned char *); } *my_sha1_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_sha1(A,B,C) my_sha1_service->my_sha1_type(A,B,C) #define my_sha1_multi my_sha1_service->my_sha1_multi_type #define my_sha1_context_size() my_sha1_service->my_sha1_context_size_type() #define my_sha1_init(A) my_sha1_service->my_sha1_init_type(A) #define my_sha1_input(A,B,C) my_sha1_service->my_sha1_input_type(A,B,C) #define my_sha1_result(A,B) my_sha1_service->my_sha1_result_type(A,B) #else void my_sha1(unsigned char*, const char*, size_t); void my_sha1_multi(unsigned char*, ...); size_t my_sha1_context_size(); void my_sha1_init(void *context); void my_sha1_input(void *context, const unsigned char *buf, size_t len); void my_sha1_result(void *context, unsigned char *digest); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_SHA1_INCLUDED #endif service_encryption_scheme.h000064400000013016151030241300012141 0ustar00#ifndef MYSQL_SERVICE_ENCRYPTION_SCHEME_INCLUDED /* Copyright (c) 2015, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file encryption scheme service A higher-level access to encryption service. This is a helper service that storage engines use to encrypt tables on disk. It requests keys from the plugin, generates temporary or local keys from the global (as returned by the plugin) keys, etc. To use the service: * st_encryption_scheme object is created per space. A "space" can be a table space in XtraDB/InnoDB, a file in Aria, etc. The whole space is encrypted with the one key id. * The service does not take the key and the IV as parameters for encryption or decryption. Instead it takes two 32-bit integers and one 64-bit integer (and requests the key from an encryption plugin, if needed). * The service requests the global key from the encryption plugin automatically as needed. Three last keys are cached in the st_encryption_scheme. Number of key requests (number of cache misses) are counted in st_encryption_scheme::keyserver_requests * If an st_encryption_scheme can be used concurrently by different threads, it needs to be able to lock itself when accessing the key cache. Set the st_encryption_scheme::locker appropriately. If non-zero, it will be invoked by encrypt/decrypt functions to lock and unlock the scheme when needed. * Implementation details (in particular, key derivation) are defined by the scheme type. Currently only schema type 1 is supported. In the schema type 1, every "space" (table space in XtraDB/InnoDB, file in Aria) is encrypted with a different space-local key: * Every space has a 16-byte unique identifier (typically it's generated randomly and stored in the space). The caller should put it into st_encryption_scheme::iv. * Space-local key is generated by encrypting this identifier with the global encryption key (of the given id and version) using AES_ECB. * Encryption/decryption parameters for a page are typically the 4-byte space id, 4-byte page position (offset, page number, etc), and the 8-byte LSN. This guarantees that they'll be different for any two pages (of the same or different tablespaces) and also that they'll change for the same page when it's modified. They don't need to be secret (they create the IV, not the encryption key). */ #ifdef __cplusplus extern "C" { #endif #define ENCRYPTION_SCHEME_KEY_INVALID -1 #define ENCRYPTION_SCHEME_BLOCK_LENGTH 16 struct st_encryption_scheme_key { unsigned int version; unsigned char key[ENCRYPTION_SCHEME_BLOCK_LENGTH]; }; struct st_encryption_scheme { unsigned char iv[ENCRYPTION_SCHEME_BLOCK_LENGTH]; struct st_encryption_scheme_key key[3]; unsigned int keyserver_requests; unsigned int key_id; unsigned int type; void (*locker)(struct st_encryption_scheme *self, int release); }; extern struct encryption_scheme_service_st { int (*encryption_scheme_encrypt_func) (const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen, struct st_encryption_scheme *scheme, unsigned int key_version, unsigned int i32_1, unsigned int i32_2, unsigned long long i64); int (*encryption_scheme_decrypt_func) (const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen, struct st_encryption_scheme *scheme, unsigned int key_version, unsigned int i32_1, unsigned int i32_2, unsigned long long i64); } *encryption_scheme_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define encryption_scheme_encrypt(S,SL,D,DL,SCH,KV,I32,J32,I64) encryption_scheme_service->encryption_scheme_encrypt_func(S,SL,D,DL,SCH,KV,I32,J32,I64) #define encryption_scheme_decrypt(S,SL,D,DL,SCH,KV,I32,J32,I64) encryption_scheme_service->encryption_scheme_decrypt_func(S,SL,D,DL,SCH,KV,I32,J32,I64) #else int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen, struct st_encryption_scheme *scheme, unsigned int key_version, unsigned int i32_1, unsigned int i32_2, unsigned long long i64); int encryption_scheme_decrypt(const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen, struct st_encryption_scheme *scheme, unsigned int key_version, unsigned int i32_1, unsigned int i32_2, unsigned long long i64); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_ENCRYPTION_SCHEME_INCLUDED #endif service_json.h000064400000010707151030241300007400 0ustar00/* Copyright (C) 2018 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #ifndef MYSQL_SERVICE_JSON #define MYSQL_SERVICE_JSON /** @file json service Exports JSON parsing methods for plugins to use. Functions of the service: json_type - returns the type of the JSON argument, and the parsed value if it's scalar (not object or array) json_get_array_item - expects JSON array as an argument, and returns the type of the element at index `n_item`. Returns JSV_NOTHING type if the array is shorter than n_item and the actual length of the array in value_len. If successful, then `value` up till `value[value_len]` contains the array element at the desired index (n_item). json_get_object_key - expects JSON object as an argument, searches for a key in the object, return it's type and stores its value in `value`. JSV_NOTHING if no such key found, the number of keys in v_len. json_get_object_nkey - expects JSON object as an argument. finds n_key's key in the object, returns it's name, type and value. JSV_NOTHING if object has less keys than n_key. */ #ifdef __cplusplus extern "C" { #endif enum json_types { JSV_BAD_JSON=-1, JSV_NOTHING=0, JSV_OBJECT=1, JSV_ARRAY=2, JSV_STRING=3, JSV_NUMBER=4, JSV_TRUE=5, JSV_FALSE=6, JSV_NULL=7 }; extern struct json_service_st { enum json_types (*json_type)(const char *js, const char *js_end, const char **value, int *value_len); enum json_types (*json_get_array_item)(const char *js, const char *js_end, int n_item, const char **value, int *value_len); enum json_types (*json_get_object_key)(const char *js, const char *js_end, const char *key, const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, const char **value, int *value_len); int (*json_escape_string)(const char *str,const char *str_end, char *json, char *json_end); int (*json_unescape_json)(const char *json_str, const char *json_end, char *res, char *res_end); } *json_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define json_type json_service->json_type #define json_get_array_item json_service->json_get_array_item #define json_get_object_key json_service->json_get_object_key #define json_get_object_nkey json_service->json_get_object_nkey #define json_escape_string json_service->json_escape_string #define json_unescape_json json_service->json_unescape_json #else enum json_types json_type(const char *js, const char *js_end, const char **value, int *value_len); enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, const char **value, int *value_len); enum json_types json_get_object_key(const char *js, const char *js_end, const char *key, const char **value, int *value_len); enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, const char **value, int *value_len); int json_escape_string(const char *str,const char *str_end, char *json, char *json_end); int json_unescape_json(const char *json_str, const char *json_end, char *res, char *res_end); #endif /*MYSQL_DYNAMIC_PLUGIN*/ #ifdef __cplusplus } #endif #endif /*MYSQL_SERVICE_JSON */ service_thd_specifics.h000064400000007146151030241300011241 0ustar00#ifndef MYSQL_SERVICE_THD_SPECIFICS_INCLUDED /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file THD specific for plugin(s) This API provides pthread_getspecific like functionality to plugin authors. This is a functional alternative to the declarative MYSQL_THDVAR A plugin should at init call thd_key_create that create a key that will have storage in each THD. The key should be used by all threads and can be used concurrently from all threads. A plugin should at deinit call thd_key_delete. Alternatively, a plugin can use thd_key_create_from_var(K,V) to create a key that corresponds to a named MYSQL_THDVAR variable. This API is also safe when using pool-of-threads in which case pthread_getspecific is not, because the actual OS thread may change. @note Normally one should prefer MYSQL_THDVAR declarative API. The benefits are: - It supports typed variables (int, char*, enum, etc), not only void*. - The memory allocated for MYSQL_THDVAR is free'd automatically (if PLUGIN_VAR_MEMALLOC is specified). - Continuous loading and unloading of the same plugin does not allocate memory for same variables over and over again. An example of using MYSQL_THDVAR for a thd local storage: MYSQL_THDVAR_STR(my_tls, PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT, "thd local storage example", 0, 0, 0); */ #ifdef __cplusplus extern "C" { #endif typedef int MYSQL_THD_KEY_T; extern struct thd_specifics_service_st { int (*thd_key_create_func)(MYSQL_THD_KEY_T *key); void (*thd_key_delete_func)(MYSQL_THD_KEY_T *key); void *(*thd_getspecific_func)(MYSQL_THD thd, MYSQL_THD_KEY_T key); int (*thd_setspecific_func)(MYSQL_THD thd, MYSQL_THD_KEY_T key, void *value); } *thd_specifics_service; #define thd_key_create_from_var(K, V) do { *(K)= MYSQL_SYSVAR_NAME(V).offset; } while(0) #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_key_create(K) (thd_specifics_service->thd_key_create_func(K)) #define thd_key_delete(K) (thd_specifics_service->thd_key_delete_func(K)) #define thd_getspecific(T, K) (thd_specifics_service->thd_getspecific_func(T, K)) #define thd_setspecific(T, K, V) (thd_specifics_service->thd_setspecific_func(T, K, V)) #else /** * create THD specific storage * @return 0 on success * else errno is returned */ int thd_key_create(MYSQL_THD_KEY_T *key); /** * delete THD specific storage */ void thd_key_delete(MYSQL_THD_KEY_T *key); /** * get/set thd specific storage * - first time this is called from a thread it will return 0 * - this call is thread-safe in that different threads may call this * simultaneously if operating on different THDs. * - this call acquires no mutexes and is implemented as an array lookup */ void* thd_getspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key); int thd_setspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key, void *value); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_SPECIFICS_INCLUDED #endif service_base64.h000064400000005564151030241300007520 0ustar00#ifndef MYSQL_SERVICE_BASE64_INCLUDED /* Copyright (c) 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my base64 service Functions for base64 en- and decoding */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #endif /* Allow multiple chunks 'AAA= AA== AA==', binlog uses this */ #define MY_BASE64_DECODE_ALLOW_MULTIPLE_CHUNKS 1 extern struct base64_service_st { int (*base64_needed_encoded_length_ptr)(int length_of_data); int (*base64_encode_max_arg_length_ptr)(void); int (*base64_needed_decoded_length_ptr)(int length_of_encoded_data); int (*base64_decode_max_arg_length_ptr)(); int (*base64_encode_ptr)(const void *src, size_t src_len, char *dst); int (*base64_decode_ptr)(const char *src, size_t src_len, void *dst, const char **end_ptr, int flags); } *base64_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_base64_needed_encoded_length(A) base64_service->base64_needed_encoded_length_ptr(A) #define my_base64_encode_max_arg_length() base64_service->base64_encode_max_arg_length_ptr() #define my_base64_needed_decoded_length(A) base64_service->base64_needed_decoded_length_ptr(A) #define my_base64_decode_max_arg_length() base64_service->base64_decode_max_arg_length_ptr() #define my_base64_encode(A,B,C) base64_service->base64_encode_ptr(A,B,C) #define my_base64_decode(A,B,C,D,E) base64_service->base64_decode_ptr(A,B,C,D,E) #else /* Calculate how much memory needed for dst of my_base64_encode() */ int my_base64_needed_encoded_length(int length_of_data); /* Maximum length my_base64_encode_needed_length() can accept with no overflow. */ int my_base64_encode_max_arg_length(void); /* Calculate how much memory needed for dst of my_base64_decode() */ int my_base64_needed_decoded_length(int length_of_encoded_data); /* Maximum length my_base64_decode_needed_length() can accept with no overflow. */ int my_base64_decode_max_arg_length(); /* Encode data as a my_base64 string */ int my_base64_encode(const void *src, size_t src_len, char *dst); /* Decode a my_base64 string into data */ int my_base64_decode(const char *src, size_t src_len, void *dst, const char **end_ptr, int flags); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_BASE64_INCLUDED #endif service_thd_autoinc.h000064400000003234151030241300010725 0ustar00#ifndef MYSQL_SERVICE_THD_AUTOINC_INCLUDED /* Copyright (C) 2013 MariaDB Foundation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service provides access to the auto_increment related system variables: @@auto_increment_offset @@auto_increment_increment */ #ifdef __cplusplus extern "C" { #endif extern struct thd_autoinc_service_st { void (*thd_get_autoinc_func)(const MYSQL_THD thd, unsigned long* off, unsigned long* inc); } *thd_autoinc_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_get_autoinc(thd, off, inc) \ (thd_autoinc_service->thd_get_autoinc_func((thd), (off), (inc))) #else /** Return autoincrement system variables @param IN thd user thread connection handle @param OUT off the value of @@SESSION.auto_increment_offset @param OUT inc the value of @@SESSION.auto_increment_increment */ void thd_get_autoinc(const MYSQL_THD thd, unsigned long* off, unsigned long* inc); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_AUTOINC_INCLUDED #endif mysqld_error.h000064400000135573151031265040007452 0ustar00/* Autogenerated file, please don't edit */ #ifndef ER_ERROR_FIRST #define ER_ERROR_FIRST 1000 #define ER_HASHCHK 1000 #define ER_NISAMCHK 1001 #define ER_NO 1002 #define ER_YES 1003 #define ER_CANT_CREATE_FILE 1004 #define ER_CANT_CREATE_TABLE 1005 #define ER_CANT_CREATE_DB 1006 #define ER_DB_CREATE_EXISTS 1007 #define ER_DB_DROP_EXISTS 1008 #define ER_DB_DROP_DELETE 1009 #define ER_DB_DROP_RMDIR 1010 #define ER_CANT_DELETE_FILE 1011 #define ER_CANT_FIND_SYSTEM_REC 1012 #define ER_CANT_GET_STAT 1013 #define ER_CANT_GET_WD 1014 #define ER_CANT_LOCK 1015 #define ER_CANT_OPEN_FILE 1016 #define ER_FILE_NOT_FOUND 1017 #define ER_CANT_READ_DIR 1018 #define ER_CANT_SET_WD 1019 #define ER_CHECKREAD 1020 #define ER_DISK_FULL 1021 #define ER_DUP_KEY 1022 #define ER_ERROR_ON_CLOSE 1023 #define ER_ERROR_ON_READ 1024 #define ER_ERROR_ON_RENAME 1025 #define ER_ERROR_ON_WRITE 1026 #define ER_FILE_USED 1027 #define ER_FILSORT_ABORT 1028 #define ER_FORM_NOT_FOUND 1029 #define ER_GET_ERRNO 1030 #define ER_ILLEGAL_HA 1031 #define ER_KEY_NOT_FOUND 1032 #define ER_NOT_FORM_FILE 1033 #define ER_NOT_KEYFILE 1034 #define ER_OLD_KEYFILE 1035 #define ER_OPEN_AS_READONLY 1036 #define ER_OUTOFMEMORY 1037 #define ER_OUT_OF_SORTMEMORY 1038 #define ER_UNEXPECTED_EOF 1039 #define ER_CON_COUNT_ERROR 1040 #define ER_OUT_OF_RESOURCES 1041 #define ER_BAD_HOST_ERROR 1042 #define ER_HANDSHAKE_ERROR 1043 #define ER_DBACCESS_DENIED_ERROR 1044 #define ER_ACCESS_DENIED_ERROR 1045 #define ER_NO_DB_ERROR 1046 #define ER_UNKNOWN_COM_ERROR 1047 #define ER_BAD_NULL_ERROR 1048 #define ER_BAD_DB_ERROR 1049 #define ER_TABLE_EXISTS_ERROR 1050 #define ER_BAD_TABLE_ERROR 1051 #define ER_NON_UNIQ_ERROR 1052 #define ER_SERVER_SHUTDOWN 1053 #define ER_BAD_FIELD_ERROR 1054 #define ER_WRONG_FIELD_WITH_GROUP 1055 #define ER_WRONG_GROUP_FIELD 1056 #define ER_WRONG_SUM_SELECT 1057 #define ER_WRONG_VALUE_COUNT 1058 #define ER_TOO_LONG_IDENT 1059 #define ER_DUP_FIELDNAME 1060 #define ER_DUP_KEYNAME 1061 #define ER_DUP_ENTRY 1062 #define ER_WRONG_FIELD_SPEC 1063 #define ER_PARSE_ERROR 1064 #define ER_EMPTY_QUERY 1065 #define ER_NONUNIQ_TABLE 1066 #define ER_INVALID_DEFAULT 1067 #define ER_MULTIPLE_PRI_KEY 1068 #define ER_TOO_MANY_KEYS 1069 #define ER_TOO_MANY_KEY_PARTS 1070 #define ER_TOO_LONG_KEY 1071 #define ER_KEY_COLUMN_DOES_NOT_EXITS 1072 #define ER_BLOB_USED_AS_KEY 1073 #define ER_TOO_BIG_FIELDLENGTH 1074 #define ER_WRONG_AUTO_KEY 1075 #define ER_BINLOG_CANT_DELETE_GTID_DOMAIN 1076 #define ER_NORMAL_SHUTDOWN 1077 #define ER_GOT_SIGNAL 1078 #define ER_SHUTDOWN_COMPLETE 1079 #define ER_FORCING_CLOSE 1080 #define ER_IPSOCK_ERROR 1081 #define ER_NO_SUCH_INDEX 1082 #define ER_WRONG_FIELD_TERMINATORS 1083 #define ER_BLOBS_AND_NO_TERMINATED 1084 #define ER_TEXTFILE_NOT_READABLE 1085 #define ER_FILE_EXISTS_ERROR 1086 #define ER_LOAD_INFO 1087 #define ER_ALTER_INFO 1088 #define ER_WRONG_SUB_KEY 1089 #define ER_CANT_REMOVE_ALL_FIELDS 1090 #define ER_CANT_DROP_FIELD_OR_KEY 1091 #define ER_INSERT_INFO 1092 #define ER_UPDATE_TABLE_USED 1093 #define ER_NO_SUCH_THREAD 1094 #define ER_KILL_DENIED_ERROR 1095 #define ER_NO_TABLES_USED 1096 #define ER_TOO_BIG_SET 1097 #define ER_NO_UNIQUE_LOGFILE 1098 #define ER_TABLE_NOT_LOCKED_FOR_WRITE 1099 #define ER_TABLE_NOT_LOCKED 1100 #define ER_UNUSED_17 1101 #define ER_WRONG_DB_NAME 1102 #define ER_WRONG_TABLE_NAME 1103 #define ER_TOO_BIG_SELECT 1104 #define ER_UNKNOWN_ERROR 1105 #define ER_UNKNOWN_PROCEDURE 1106 #define ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107 #define ER_WRONG_PARAMETERS_TO_PROCEDURE 1108 #define ER_UNKNOWN_TABLE 1109 #define ER_FIELD_SPECIFIED_TWICE 1110 #define ER_INVALID_GROUP_FUNC_USE 1111 #define ER_UNSUPPORTED_EXTENSION 1112 #define ER_TABLE_MUST_HAVE_COLUMNS 1113 #define ER_RECORD_FILE_FULL 1114 #define ER_UNKNOWN_CHARACTER_SET 1115 #define ER_TOO_MANY_TABLES 1116 #define ER_TOO_MANY_FIELDS 1117 #define ER_TOO_BIG_ROWSIZE 1118 #define ER_STACK_OVERRUN 1119 #define ER_WRONG_OUTER_JOIN 1120 #define ER_NULL_COLUMN_IN_INDEX 1121 #define ER_CANT_FIND_UDF 1122 #define ER_CANT_INITIALIZE_UDF 1123 #define ER_UDF_NO_PATHS 1124 #define ER_UDF_EXISTS 1125 #define ER_CANT_OPEN_LIBRARY 1126 #define ER_CANT_FIND_DL_ENTRY 1127 #define ER_FUNCTION_NOT_DEFINED 1128 #define ER_HOST_IS_BLOCKED 1129 #define ER_HOST_NOT_PRIVILEGED 1130 #define ER_PASSWORD_ANONYMOUS_USER 1131 #define ER_PASSWORD_NOT_ALLOWED 1132 #define ER_PASSWORD_NO_MATCH 1133 #define ER_UPDATE_INFO 1134 #define ER_CANT_CREATE_THREAD 1135 #define ER_WRONG_VALUE_COUNT_ON_ROW 1136 #define ER_CANT_REOPEN_TABLE 1137 #define ER_INVALID_USE_OF_NULL 1138 #define ER_REGEXP_ERROR 1139 #define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140 #define ER_NONEXISTING_GRANT 1141 #define ER_TABLEACCESS_DENIED_ERROR 1142 #define ER_COLUMNACCESS_DENIED_ERROR 1143 #define ER_ILLEGAL_GRANT_FOR_TABLE 1144 #define ER_GRANT_WRONG_HOST_OR_USER 1145 #define ER_NO_SUCH_TABLE 1146 #define ER_NONEXISTING_TABLE_GRANT 1147 #define ER_NOT_ALLOWED_COMMAND 1148 #define ER_SYNTAX_ERROR 1149 #define ER_DELAYED_CANT_CHANGE_LOCK 1150 #define ER_TOO_MANY_DELAYED_THREADS 1151 #define ER_ABORTING_CONNECTION 1152 #define ER_NET_PACKET_TOO_LARGE 1153 #define ER_NET_READ_ERROR_FROM_PIPE 1154 #define ER_NET_FCNTL_ERROR 1155 #define ER_NET_PACKETS_OUT_OF_ORDER 1156 #define ER_NET_UNCOMPRESS_ERROR 1157 #define ER_NET_READ_ERROR 1158 #define ER_NET_READ_INTERRUPTED 1159 #define ER_NET_ERROR_ON_WRITE 1160 #define ER_NET_WRITE_INTERRUPTED 1161 #define ER_TOO_LONG_STRING 1162 #define ER_TABLE_CANT_HANDLE_BLOB 1163 #define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164 #define ER_DELAYED_INSERT_TABLE_LOCKED 1165 #define ER_WRONG_COLUMN_NAME 1166 #define ER_WRONG_KEY_COLUMN 1167 #define ER_WRONG_MRG_TABLE 1168 #define ER_DUP_UNIQUE 1169 #define ER_BLOB_KEY_WITHOUT_LENGTH 1170 #define ER_PRIMARY_CANT_HAVE_NULL 1171 #define ER_TOO_MANY_ROWS 1172 #define ER_REQUIRES_PRIMARY_KEY 1173 #define ER_NO_RAID_COMPILED 1174 #define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175 #define ER_KEY_DOES_NOT_EXISTS 1176 #define ER_CHECK_NO_SUCH_TABLE 1177 #define ER_CHECK_NOT_IMPLEMENTED 1178 #define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179 #define ER_ERROR_DURING_COMMIT 1180 #define ER_ERROR_DURING_ROLLBACK 1181 #define ER_ERROR_DURING_FLUSH_LOGS 1182 #define ER_ERROR_DURING_CHECKPOINT 1183 #define ER_NEW_ABORTING_CONNECTION 1184 #define ER_UNUSED_10 1185 #define ER_FLUSH_MASTER_BINLOG_CLOSED 1186 #define ER_INDEX_REBUILD 1187 #define ER_MASTER 1188 #define ER_MASTER_NET_READ 1189 #define ER_MASTER_NET_WRITE 1190 #define ER_FT_MATCHING_KEY_NOT_FOUND 1191 #define ER_LOCK_OR_ACTIVE_TRANSACTION 1192 #define ER_UNKNOWN_SYSTEM_VARIABLE 1193 #define ER_CRASHED_ON_USAGE 1194 #define ER_CRASHED_ON_REPAIR 1195 #define ER_WARNING_NOT_COMPLETE_ROLLBACK 1196 #define ER_TRANS_CACHE_FULL 1197 #define ER_SLAVE_MUST_STOP 1198 #define ER_SLAVE_NOT_RUNNING 1199 #define ER_BAD_SLAVE 1200 #define ER_MASTER_INFO 1201 #define ER_SLAVE_THREAD 1202 #define ER_TOO_MANY_USER_CONNECTIONS 1203 #define ER_SET_CONSTANTS_ONLY 1204 #define ER_LOCK_WAIT_TIMEOUT 1205 #define ER_LOCK_TABLE_FULL 1206 #define ER_READ_ONLY_TRANSACTION 1207 #define ER_DROP_DB_WITH_READ_LOCK 1208 #define ER_CREATE_DB_WITH_READ_LOCK 1209 #define ER_WRONG_ARGUMENTS 1210 #define ER_NO_PERMISSION_TO_CREATE_USER 1211 #define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 #define ER_LOCK_DEADLOCK 1213 #define ER_TABLE_CANT_HANDLE_FT 1214 #define ER_CANNOT_ADD_FOREIGN 1215 #define ER_NO_REFERENCED_ROW 1216 #define ER_ROW_IS_REFERENCED 1217 #define ER_CONNECT_TO_MASTER 1218 #define ER_QUERY_ON_MASTER 1219 #define ER_ERROR_WHEN_EXECUTING_COMMAND 1220 #define ER_WRONG_USAGE 1221 #define ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1222 #define ER_CANT_UPDATE_WITH_READLOCK 1223 #define ER_MIXING_NOT_ALLOWED 1224 #define ER_DUP_ARGUMENT 1225 #define ER_USER_LIMIT_REACHED 1226 #define ER_SPECIFIC_ACCESS_DENIED_ERROR 1227 #define ER_LOCAL_VARIABLE 1228 #define ER_GLOBAL_VARIABLE 1229 #define ER_NO_DEFAULT 1230 #define ER_WRONG_VALUE_FOR_VAR 1231 #define ER_WRONG_TYPE_FOR_VAR 1232 #define ER_VAR_CANT_BE_READ 1233 #define ER_CANT_USE_OPTION_HERE 1234 #define ER_NOT_SUPPORTED_YET 1235 #define ER_MASTER_FATAL_ERROR_READING_BINLOG 1236 #define ER_SLAVE_IGNORED_TABLE 1237 #define ER_INCORRECT_GLOBAL_LOCAL_VAR 1238 #define ER_WRONG_FK_DEF 1239 #define ER_KEY_REF_DO_NOT_MATCH_TABLE_REF 1240 #define ER_OPERAND_COLUMNS 1241 #define ER_SUBQUERY_NO_1_ROW 1242 #define ER_UNKNOWN_STMT_HANDLER 1243 #define ER_CORRUPT_HELP_DB 1244 #define ER_CYCLIC_REFERENCE 1245 #define ER_AUTO_CONVERT 1246 #define ER_ILLEGAL_REFERENCE 1247 #define ER_DERIVED_MUST_HAVE_ALIAS 1248 #define ER_SELECT_REDUCED 1249 #define ER_TABLENAME_NOT_ALLOWED_HERE 1250 #define ER_NOT_SUPPORTED_AUTH_MODE 1251 #define ER_SPATIAL_CANT_HAVE_NULL 1252 #define ER_COLLATION_CHARSET_MISMATCH 1253 #define ER_SLAVE_WAS_RUNNING 1254 #define ER_SLAVE_WAS_NOT_RUNNING 1255 #define ER_TOO_BIG_FOR_UNCOMPRESS 1256 #define ER_ZLIB_Z_MEM_ERROR 1257 #define ER_ZLIB_Z_BUF_ERROR 1258 #define ER_ZLIB_Z_DATA_ERROR 1259 #define ER_CUT_VALUE_GROUP_CONCAT 1260 #define ER_WARN_TOO_FEW_RECORDS 1261 #define ER_WARN_TOO_MANY_RECORDS 1262 #define ER_WARN_NULL_TO_NOTNULL 1263 #define ER_WARN_DATA_OUT_OF_RANGE 1264 #define WARN_DATA_TRUNCATED 1265 #define ER_WARN_USING_OTHER_HANDLER 1266 #define ER_CANT_AGGREGATE_2COLLATIONS 1267 #define ER_DROP_USER 1268 #define ER_REVOKE_GRANTS 1269 #define ER_CANT_AGGREGATE_3COLLATIONS 1270 #define ER_CANT_AGGREGATE_NCOLLATIONS 1271 #define ER_VARIABLE_IS_NOT_STRUCT 1272 #define ER_UNKNOWN_COLLATION 1273 #define ER_SLAVE_IGNORED_SSL_PARAMS 1274 #define ER_SERVER_IS_IN_SECURE_AUTH_MODE 1275 #define ER_WARN_FIELD_RESOLVED 1276 #define ER_BAD_SLAVE_UNTIL_COND 1277 #define ER_MISSING_SKIP_SLAVE 1278 #define ER_UNTIL_COND_IGNORED 1279 #define ER_WRONG_NAME_FOR_INDEX 1280 #define ER_WRONG_NAME_FOR_CATALOG 1281 #define ER_WARN_QC_RESIZE 1282 #define ER_BAD_FT_COLUMN 1283 #define ER_UNKNOWN_KEY_CACHE 1284 #define ER_WARN_HOSTNAME_WONT_WORK 1285 #define ER_UNKNOWN_STORAGE_ENGINE 1286 #define ER_WARN_DEPRECATED_SYNTAX 1287 #define ER_NON_UPDATABLE_TABLE 1288 #define ER_FEATURE_DISABLED 1289 #define ER_OPTION_PREVENTS_STATEMENT 1290 #define ER_DUPLICATED_VALUE_IN_TYPE 1291 #define ER_TRUNCATED_WRONG_VALUE 1292 #define ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293 #define ER_INVALID_ON_UPDATE 1294 #define ER_UNSUPPORTED_PS 1295 #define ER_GET_ERRMSG 1296 #define ER_GET_TEMPORARY_ERRMSG 1297 #define ER_UNKNOWN_TIME_ZONE 1298 #define ER_WARN_INVALID_TIMESTAMP 1299 #define ER_INVALID_CHARACTER_STRING 1300 #define ER_WARN_ALLOWED_PACKET_OVERFLOWED 1301 #define ER_CONFLICTING_DECLARATIONS 1302 #define ER_SP_NO_RECURSIVE_CREATE 1303 #define ER_SP_ALREADY_EXISTS 1304 #define ER_SP_DOES_NOT_EXIST 1305 #define ER_SP_DROP_FAILED 1306 #define ER_SP_STORE_FAILED 1307 #define ER_SP_LILABEL_MISMATCH 1308 #define ER_SP_LABEL_REDEFINE 1309 #define ER_SP_LABEL_MISMATCH 1310 #define ER_SP_UNINIT_VAR 1311 #define ER_SP_BADSELECT 1312 #define ER_SP_BADRETURN 1313 #define ER_SP_BADSTATEMENT 1314 #define ER_UPDATE_LOG_DEPRECATED_IGNORED 1315 #define ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1316 #define ER_QUERY_INTERRUPTED 1317 #define ER_SP_WRONG_NO_OF_ARGS 1318 #define ER_SP_COND_MISMATCH 1319 #define ER_SP_NORETURN 1320 #define ER_SP_NORETURNEND 1321 #define ER_SP_BAD_CURSOR_QUERY 1322 #define ER_SP_BAD_CURSOR_SELECT 1323 #define ER_SP_CURSOR_MISMATCH 1324 #define ER_SP_CURSOR_ALREADY_OPEN 1325 #define ER_SP_CURSOR_NOT_OPEN 1326 #define ER_SP_UNDECLARED_VAR 1327 #define ER_SP_WRONG_NO_OF_FETCH_ARGS 1328 #define ER_SP_FETCH_NO_DATA 1329 #define ER_SP_DUP_PARAM 1330 #define ER_SP_DUP_VAR 1331 #define ER_SP_DUP_COND 1332 #define ER_SP_DUP_CURS 1333 #define ER_SP_CANT_ALTER 1334 #define ER_SP_SUBSELECT_NYI 1335 #define ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 1336 #define ER_SP_VARCOND_AFTER_CURSHNDLR 1337 #define ER_SP_CURSOR_AFTER_HANDLER 1338 #define ER_SP_CASE_NOT_FOUND 1339 #define ER_FPARSER_TOO_BIG_FILE 1340 #define ER_FPARSER_BAD_HEADER 1341 #define ER_FPARSER_EOF_IN_COMMENT 1342 #define ER_FPARSER_ERROR_IN_PARAMETER 1343 #define ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER 1344 #define ER_VIEW_NO_EXPLAIN 1345 #define ER_FRM_UNKNOWN_TYPE 1346 #define ER_WRONG_OBJECT 1347 #define ER_NONUPDATEABLE_COLUMN 1348 #define ER_VIEW_SELECT_DERIVED 1349 #define ER_VIEW_SELECT_CLAUSE 1350 #define ER_VIEW_SELECT_VARIABLE 1351 #define ER_VIEW_SELECT_TMPTABLE 1352 #define ER_VIEW_WRONG_LIST 1353 #define ER_WARN_VIEW_MERGE 1354 #define ER_WARN_VIEW_WITHOUT_KEY 1355 #define ER_VIEW_INVALID 1356 #define ER_SP_NO_DROP_SP 1357 #define ER_SP_GOTO_IN_HNDLR 1358 #define ER_TRG_ALREADY_EXISTS 1359 #define ER_TRG_DOES_NOT_EXIST 1360 #define ER_TRG_ON_VIEW_OR_TEMP_TABLE 1361 #define ER_TRG_CANT_CHANGE_ROW 1362 #define ER_TRG_NO_SUCH_ROW_IN_TRG 1363 #define ER_NO_DEFAULT_FOR_FIELD 1364 #define ER_DIVISION_BY_ZERO 1365 #define ER_TRUNCATED_WRONG_VALUE_FOR_FIELD 1366 #define ER_ILLEGAL_VALUE_FOR_TYPE 1367 #define ER_VIEW_NONUPD_CHECK 1368 #define ER_VIEW_CHECK_FAILED 1369 #define ER_PROCACCESS_DENIED_ERROR 1370 #define ER_RELAY_LOG_FAIL 1371 #define ER_PASSWD_LENGTH 1372 #define ER_UNKNOWN_TARGET_BINLOG 1373 #define ER_IO_ERR_LOG_INDEX_READ 1374 #define ER_BINLOG_PURGE_PROHIBITED 1375 #define ER_FSEEK_FAIL 1376 #define ER_BINLOG_PURGE_FATAL_ERR 1377 #define ER_LOG_IN_USE 1378 #define ER_LOG_PURGE_UNKNOWN_ERR 1379 #define ER_RELAY_LOG_INIT 1380 #define ER_NO_BINARY_LOGGING 1381 #define ER_RESERVED_SYNTAX 1382 #define ER_WSAS_FAILED 1383 #define ER_DIFF_GROUPS_PROC 1384 #define ER_NO_GROUP_FOR_PROC 1385 #define ER_ORDER_WITH_PROC 1386 #define ER_LOGGING_PROHIBIT_CHANGING_OF 1387 #define ER_NO_FILE_MAPPING 1388 #define ER_WRONG_MAGIC 1389 #define ER_PS_MANY_PARAM 1390 #define ER_KEY_PART_0 1391 #define ER_VIEW_CHECKSUM 1392 #define ER_VIEW_MULTIUPDATE 1393 #define ER_VIEW_NO_INSERT_FIELD_LIST 1394 #define ER_VIEW_DELETE_MERGE_VIEW 1395 #define ER_CANNOT_USER 1396 #define ER_XAER_NOTA 1397 #define ER_XAER_INVAL 1398 #define ER_XAER_RMFAIL 1399 #define ER_XAER_OUTSIDE 1400 #define ER_XAER_RMERR 1401 #define ER_XA_RBROLLBACK 1402 #define ER_NONEXISTING_PROC_GRANT 1403 #define ER_PROC_AUTO_GRANT_FAIL 1404 #define ER_PROC_AUTO_REVOKE_FAIL 1405 #define ER_DATA_TOO_LONG 1406 #define ER_SP_BAD_SQLSTATE 1407 #define ER_STARTUP 1408 #define ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR 1409 #define ER_CANT_CREATE_USER_WITH_GRANT 1410 #define ER_WRONG_VALUE_FOR_TYPE 1411 #define ER_TABLE_DEF_CHANGED 1412 #define ER_SP_DUP_HANDLER 1413 #define ER_SP_NOT_VAR_ARG 1414 #define ER_SP_NO_RETSET 1415 #define ER_CANT_CREATE_GEOMETRY_OBJECT 1416 #define ER_FAILED_ROUTINE_BREAK_BINLOG 1417 #define ER_BINLOG_UNSAFE_ROUTINE 1418 #define ER_BINLOG_CREATE_ROUTINE_NEED_SUPER 1419 #define ER_EXEC_STMT_WITH_OPEN_CURSOR 1420 #define ER_STMT_HAS_NO_OPEN_CURSOR 1421 #define ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG 1422 #define ER_NO_DEFAULT_FOR_VIEW_FIELD 1423 #define ER_SP_NO_RECURSION 1424 #define ER_TOO_BIG_SCALE 1425 #define ER_TOO_BIG_PRECISION 1426 #define ER_M_BIGGER_THAN_D 1427 #define ER_WRONG_LOCK_OF_SYSTEM_TABLE 1428 #define ER_CONNECT_TO_FOREIGN_DATA_SOURCE 1429 #define ER_QUERY_ON_FOREIGN_DATA_SOURCE 1430 #define ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST 1431 #define ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE 1432 #define ER_FOREIGN_DATA_STRING_INVALID 1433 #define ER_CANT_CREATE_FEDERATED_TABLE 1434 #define ER_TRG_IN_WRONG_SCHEMA 1435 #define ER_STACK_OVERRUN_NEED_MORE 1436 #define ER_TOO_LONG_BODY 1437 #define ER_WARN_CANT_DROP_DEFAULT_KEYCACHE 1438 #define ER_TOO_BIG_DISPLAYWIDTH 1439 #define ER_XAER_DUPID 1440 #define ER_DATETIME_FUNCTION_OVERFLOW 1441 #define ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG 1442 #define ER_VIEW_PREVENT_UPDATE 1443 #define ER_PS_NO_RECURSION 1444 #define ER_SP_CANT_SET_AUTOCOMMIT 1445 #define ER_MALFORMED_DEFINER 1446 #define ER_VIEW_FRM_NO_USER 1447 #define ER_VIEW_OTHER_USER 1448 #define ER_NO_SUCH_USER 1449 #define ER_FORBID_SCHEMA_CHANGE 1450 #define ER_ROW_IS_REFERENCED_2 1451 #define ER_NO_REFERENCED_ROW_2 1452 #define ER_SP_BAD_VAR_SHADOW 1453 #define ER_TRG_NO_DEFINER 1454 #define ER_OLD_FILE_FORMAT 1455 #define ER_SP_RECURSION_LIMIT 1456 #define ER_SP_PROC_TABLE_CORRUPT 1457 #define ER_SP_WRONG_NAME 1458 #define ER_TABLE_NEEDS_UPGRADE 1459 #define ER_SP_NO_AGGREGATE 1460 #define ER_MAX_PREPARED_STMT_COUNT_REACHED 1461 #define ER_VIEW_RECURSIVE 1462 #define ER_NON_GROUPING_FIELD_USED 1463 #define ER_TABLE_CANT_HANDLE_SPKEYS 1464 #define ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA 1465 #define ER_REMOVED_SPACES 1466 #define ER_AUTOINC_READ_FAILED 1467 #define ER_USERNAME 1468 #define ER_HOSTNAME 1469 #define ER_WRONG_STRING_LENGTH 1470 #define ER_NON_INSERTABLE_TABLE 1471 #define ER_ADMIN_WRONG_MRG_TABLE 1472 #define ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT 1473 #define ER_NAME_BECOMES_EMPTY 1474 #define ER_AMBIGUOUS_FIELD_TERM 1475 #define ER_FOREIGN_SERVER_EXISTS 1476 #define ER_FOREIGN_SERVER_DOESNT_EXIST 1477 #define ER_ILLEGAL_HA_CREATE_OPTION 1478 #define ER_PARTITION_REQUIRES_VALUES_ERROR 1479 #define ER_PARTITION_WRONG_VALUES_ERROR 1480 #define ER_PARTITION_MAXVALUE_ERROR 1481 #define ER_PARTITION_SUBPARTITION_ERROR 1482 #define ER_PARTITION_SUBPART_MIX_ERROR 1483 #define ER_PARTITION_WRONG_NO_PART_ERROR 1484 #define ER_PARTITION_WRONG_NO_SUBPART_ERROR 1485 #define ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR 1486 #define ER_NOT_CONSTANT_EXPRESSION 1487 #define ER_FIELD_NOT_FOUND_PART_ERROR 1488 #define ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR 1489 #define ER_INCONSISTENT_PARTITION_INFO_ERROR 1490 #define ER_PARTITION_FUNC_NOT_ALLOWED_ERROR 1491 #define ER_PARTITIONS_MUST_BE_DEFINED_ERROR 1492 #define ER_RANGE_NOT_INCREASING_ERROR 1493 #define ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR 1494 #define ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR 1495 #define ER_PARTITION_ENTRY_ERROR 1496 #define ER_MIX_HANDLER_ERROR 1497 #define ER_PARTITION_NOT_DEFINED_ERROR 1498 #define ER_TOO_MANY_PARTITIONS_ERROR 1499 #define ER_SUBPARTITION_ERROR 1500 #define ER_CANT_CREATE_HANDLER_FILE 1501 #define ER_BLOB_FIELD_IN_PART_FUNC_ERROR 1502 #define ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF 1503 #define ER_NO_PARTS_ERROR 1504 #define ER_PARTITION_MGMT_ON_NONPARTITIONED 1505 #define ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING 1506 #define ER_DROP_PARTITION_NON_EXISTENT 1507 #define ER_DROP_LAST_PARTITION 1508 #define ER_COALESCE_ONLY_ON_HASH_PARTITION 1509 #define ER_REORG_HASH_ONLY_ON_SAME_NO 1510 #define ER_REORG_NO_PARAM_ERROR 1511 #define ER_ONLY_ON_RANGE_LIST_PARTITION 1512 #define ER_ADD_PARTITION_SUBPART_ERROR 1513 #define ER_ADD_PARTITION_NO_NEW_PARTITION 1514 #define ER_COALESCE_PARTITION_NO_PARTITION 1515 #define ER_REORG_PARTITION_NOT_EXIST 1516 #define ER_SAME_NAME_PARTITION 1517 #define ER_NO_BINLOG_ERROR 1518 #define ER_CONSECUTIVE_REORG_PARTITIONS 1519 #define ER_REORG_OUTSIDE_RANGE 1520 #define ER_PARTITION_FUNCTION_FAILURE 1521 #define ER_PART_STATE_ERROR 1522 #define ER_LIMITED_PART_RANGE 1523 #define ER_PLUGIN_IS_NOT_LOADED 1524 #define ER_WRONG_VALUE 1525 #define ER_NO_PARTITION_FOR_GIVEN_VALUE 1526 #define ER_FILEGROUP_OPTION_ONLY_ONCE 1527 #define ER_CREATE_FILEGROUP_FAILED 1528 #define ER_DROP_FILEGROUP_FAILED 1529 #define ER_TABLESPACE_AUTO_EXTEND_ERROR 1530 #define ER_WRONG_SIZE_NUMBER 1531 #define ER_SIZE_OVERFLOW_ERROR 1532 #define ER_ALTER_FILEGROUP_FAILED 1533 #define ER_BINLOG_ROW_LOGGING_FAILED 1534 #define ER_BINLOG_ROW_WRONG_TABLE_DEF 1535 #define ER_BINLOG_ROW_RBR_TO_SBR 1536 #define ER_EVENT_ALREADY_EXISTS 1537 #define ER_EVENT_STORE_FAILED 1538 #define ER_EVENT_DOES_NOT_EXIST 1539 #define ER_EVENT_CANT_ALTER 1540 #define ER_EVENT_DROP_FAILED 1541 #define ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG 1542 #define ER_EVENT_ENDS_BEFORE_STARTS 1543 #define ER_EVENT_EXEC_TIME_IN_THE_PAST 1544 #define ER_EVENT_OPEN_TABLE_FAILED 1545 #define ER_EVENT_NEITHER_M_EXPR_NOR_M_AT 1546 #define ER_UNUSED_2 1547 #define ER_UNUSED_3 1548 #define ER_EVENT_CANNOT_DELETE 1549 #define ER_EVENT_COMPILE_ERROR 1550 #define ER_EVENT_SAME_NAME 1551 #define ER_EVENT_DATA_TOO_LONG 1552 #define ER_DROP_INDEX_FK 1553 #define ER_WARN_DEPRECATED_SYNTAX_WITH_VER 1554 #define ER_CANT_WRITE_LOCK_LOG_TABLE 1555 #define ER_CANT_LOCK_LOG_TABLE 1556 #define ER_UNUSED_4 1557 #define ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE 1558 #define ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR 1559 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT 1560 #define ER_UNUSED_13 1561 #define ER_PARTITION_NO_TEMPORARY 1562 #define ER_PARTITION_CONST_DOMAIN_ERROR 1563 #define ER_PARTITION_FUNCTION_IS_NOT_ALLOWED 1564 #define ER_DDL_LOG_ERROR 1565 #define ER_NULL_IN_VALUES_LESS_THAN 1566 #define ER_WRONG_PARTITION_NAME 1567 #define ER_CANT_CHANGE_TX_CHARACTERISTICS 1568 #define ER_DUP_ENTRY_AUTOINCREMENT_CASE 1569 #define ER_EVENT_MODIFY_QUEUE_ERROR 1570 #define ER_EVENT_SET_VAR_ERROR 1571 #define ER_PARTITION_MERGE_ERROR 1572 #define ER_CANT_ACTIVATE_LOG 1573 #define ER_RBR_NOT_AVAILABLE 1574 #define ER_BASE64_DECODE_ERROR 1575 #define ER_EVENT_RECURSION_FORBIDDEN 1576 #define ER_EVENTS_DB_ERROR 1577 #define ER_ONLY_INTEGERS_ALLOWED 1578 #define ER_UNSUPORTED_LOG_ENGINE 1579 #define ER_BAD_LOG_STATEMENT 1580 #define ER_CANT_RENAME_LOG_TABLE 1581 #define ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 1582 #define ER_WRONG_PARAMETERS_TO_NATIVE_FCT 1583 #define ER_WRONG_PARAMETERS_TO_STORED_FCT 1584 #define ER_NATIVE_FCT_NAME_COLLISION 1585 #define ER_DUP_ENTRY_WITH_KEY_NAME 1586 #define ER_BINLOG_PURGE_EMFILE 1587 #define ER_EVENT_CANNOT_CREATE_IN_THE_PAST 1588 #define ER_EVENT_CANNOT_ALTER_IN_THE_PAST 1589 #define ER_SLAVE_INCIDENT 1590 #define ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT 1591 #define ER_BINLOG_UNSAFE_STATEMENT 1592 #define ER_SLAVE_FATAL_ERROR 1593 #define ER_SLAVE_RELAY_LOG_READ_FAILURE 1594 #define ER_SLAVE_RELAY_LOG_WRITE_FAILURE 1595 #define ER_SLAVE_CREATE_EVENT_FAILURE 1596 #define ER_SLAVE_MASTER_COM_FAILURE 1597 #define ER_BINLOG_LOGGING_IMPOSSIBLE 1598 #define ER_VIEW_NO_CREATION_CTX 1599 #define ER_VIEW_INVALID_CREATION_CTX 1600 #define ER_SR_INVALID_CREATION_CTX 1601 #define ER_TRG_CORRUPTED_FILE 1602 #define ER_TRG_NO_CREATION_CTX 1603 #define ER_TRG_INVALID_CREATION_CTX 1604 #define ER_EVENT_INVALID_CREATION_CTX 1605 #define ER_TRG_CANT_OPEN_TABLE 1606 #define ER_CANT_CREATE_SROUTINE 1607 #define ER_UNUSED_11 1608 #define ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT 1609 #define ER_SLAVE_CORRUPT_EVENT 1610 #define ER_LOAD_DATA_INVALID_COLUMN 1611 #define ER_LOG_PURGE_NO_FILE 1612 #define ER_XA_RBTIMEOUT 1613 #define ER_XA_RBDEADLOCK 1614 #define ER_NEED_REPREPARE 1615 #define ER_DELAYED_NOT_SUPPORTED 1616 #define WARN_NO_MASTER_INFO 1617 #define WARN_OPTION_IGNORED 1618 #define ER_PLUGIN_DELETE_BUILTIN 1619 #define WARN_PLUGIN_BUSY 1620 #define ER_VARIABLE_IS_READONLY 1621 #define ER_WARN_ENGINE_TRANSACTION_ROLLBACK 1622 #define ER_SLAVE_HEARTBEAT_FAILURE 1623 #define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE 1624 #define ER_UNUSED_14 1625 #define ER_CONFLICT_FN_PARSE_ERROR 1626 #define ER_EXCEPTIONS_WRITE_ERROR 1627 #define ER_TOO_LONG_TABLE_COMMENT 1628 #define ER_TOO_LONG_FIELD_COMMENT 1629 #define ER_FUNC_INEXISTENT_NAME_COLLISION 1630 #define ER_DATABASE_NAME 1631 #define ER_TABLE_NAME 1632 #define ER_PARTITION_NAME 1633 #define ER_SUBPARTITION_NAME 1634 #define ER_TEMPORARY_NAME 1635 #define ER_RENAMED_NAME 1636 #define ER_TOO_MANY_CONCURRENT_TRXS 1637 #define WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED 1638 #define ER_DEBUG_SYNC_TIMEOUT 1639 #define ER_DEBUG_SYNC_HIT_LIMIT 1640 #define ER_DUP_SIGNAL_SET 1641 #define ER_SIGNAL_WARN 1642 #define ER_SIGNAL_NOT_FOUND 1643 #define ER_SIGNAL_EXCEPTION 1644 #define ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER 1645 #define ER_SIGNAL_BAD_CONDITION_TYPE 1646 #define WARN_COND_ITEM_TRUNCATED 1647 #define ER_COND_ITEM_TOO_LONG 1648 #define ER_UNKNOWN_LOCALE 1649 #define ER_SLAVE_IGNORE_SERVER_IDS 1650 #define ER_QUERY_CACHE_DISABLED 1651 #define ER_SAME_NAME_PARTITION_FIELD 1652 #define ER_PARTITION_COLUMN_LIST_ERROR 1653 #define ER_WRONG_TYPE_COLUMN_VALUE_ERROR 1654 #define ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR 1655 #define ER_MAXVALUE_IN_VALUES_IN 1656 #define ER_TOO_MANY_VALUES_ERROR 1657 #define ER_ROW_SINGLE_PARTITION_FIELD_ERROR 1658 #define ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD 1659 #define ER_PARTITION_FIELDS_TOO_LONG 1660 #define ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE 1661 #define ER_BINLOG_ROW_MODE_AND_STMT_ENGINE 1662 #define ER_BINLOG_UNSAFE_AND_STMT_ENGINE 1663 #define ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE 1664 #define ER_BINLOG_STMT_MODE_AND_ROW_ENGINE 1665 #define ER_BINLOG_ROW_INJECTION_AND_STMT_MODE 1666 #define ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1667 #define ER_BINLOG_UNSAFE_LIMIT 1668 #define ER_BINLOG_UNSAFE_INSERT_DELAYED 1669 #define ER_BINLOG_UNSAFE_SYSTEM_TABLE 1670 #define ER_BINLOG_UNSAFE_AUTOINC_COLUMNS 1671 #define ER_BINLOG_UNSAFE_UDF 1672 #define ER_BINLOG_UNSAFE_SYSTEM_VARIABLE 1673 #define ER_BINLOG_UNSAFE_SYSTEM_FUNCTION 1674 #define ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS 1675 #define ER_MESSAGE_AND_STATEMENT 1676 #define ER_SLAVE_CONVERSION_FAILED 1677 #define ER_SLAVE_CANT_CREATE_CONVERSION 1678 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT 1679 #define ER_PATH_LENGTH 1680 #define ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT 1681 #define ER_WRONG_NATIVE_TABLE_STRUCTURE 1682 #define ER_WRONG_PERFSCHEMA_USAGE 1683 #define ER_WARN_I_S_SKIPPED_TABLE 1684 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT 1685 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT 1686 #define ER_SPATIAL_MUST_HAVE_GEOM_COL 1687 #define ER_TOO_LONG_INDEX_COMMENT 1688 #define ER_LOCK_ABORTED 1689 #define ER_DATA_OUT_OF_RANGE 1690 #define ER_WRONG_SPVAR_TYPE_IN_LIMIT 1691 #define ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1692 #define ER_BINLOG_UNSAFE_MIXED_STATEMENT 1693 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN 1694 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN 1695 #define ER_FAILED_READ_FROM_PAR_FILE 1696 #define ER_VALUES_IS_NOT_INT_TYPE_ERROR 1697 #define ER_ACCESS_DENIED_NO_PASSWORD_ERROR 1698 #define ER_SET_PASSWORD_AUTH_PLUGIN 1699 #define ER_GRANT_PLUGIN_USER_EXISTS 1700 #define ER_TRUNCATE_ILLEGAL_FK 1701 #define ER_PLUGIN_IS_PERMANENT 1702 #define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN 1703 #define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX 1704 #define ER_STMT_CACHE_FULL 1705 #define ER_MULTI_UPDATE_KEY_CONFLICT 1706 #define ER_TABLE_NEEDS_REBUILD 1707 #define WARN_OPTION_BELOW_LIMIT 1708 #define ER_INDEX_COLUMN_TOO_LONG 1709 #define ER_ERROR_IN_TRIGGER_BODY 1710 #define ER_ERROR_IN_UNKNOWN_TRIGGER_BODY 1711 #define ER_INDEX_CORRUPT 1712 #define ER_UNDO_RECORD_TOO_BIG 1713 #define ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT 1714 #define ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE 1715 #define ER_BINLOG_UNSAFE_REPLACE_SELECT 1716 #define ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT 1717 #define ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT 1718 #define ER_BINLOG_UNSAFE_UPDATE_IGNORE 1719 #define ER_UNUSED_15 1720 #define ER_UNUSED_16 1721 #define ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT 1722 #define ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC 1723 #define ER_BINLOG_UNSAFE_INSERT_TWO_KEYS 1724 #define ER_UNUSED_28 1725 #define ER_VERS_NOT_ALLOWED 1726 #define ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST 1727 #define ER_CANNOT_LOAD_FROM_TABLE_V2 1728 #define ER_MASTER_DELAY_VALUE_OUT_OF_RANGE 1729 #define ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT 1730 #define ER_PARTITION_EXCHANGE_DIFFERENT_OPTION 1731 #define ER_PARTITION_EXCHANGE_PART_TABLE 1732 #define ER_PARTITION_EXCHANGE_TEMP_TABLE 1733 #define ER_PARTITION_INSTEAD_OF_SUBPARTITION 1734 #define ER_UNKNOWN_PARTITION 1735 #define ER_TABLES_DIFFERENT_METADATA 1736 #define ER_ROW_DOES_NOT_MATCH_PARTITION 1737 #define ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX 1738 #define ER_WARN_INDEX_NOT_APPLICABLE 1739 #define ER_PARTITION_EXCHANGE_FOREIGN_KEY 1740 #define ER_NO_SUCH_KEY_VALUE 1741 #define ER_VALUE_TOO_LONG 1742 #define ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE 1743 #define ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE 1744 #define ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX 1745 #define ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT 1746 #define ER_PARTITION_CLAUSE_ON_NONPARTITIONED 1747 #define ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET 1748 #define ER_UNUSED_5 1749 #define ER_CHANGE_RPL_INFO_REPOSITORY_FAILURE 1750 #define ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE 1751 #define ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE 1752 #define ER_MTS_FEATURE_IS_NOT_SUPPORTED 1753 #define ER_MTS_UPDATED_DBS_GREATER_MAX 1754 #define ER_MTS_CANT_PARALLEL 1755 #define ER_MTS_INCONSISTENT_DATA 1756 #define ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING 1757 #define ER_DA_INVALID_CONDITION_NUMBER 1758 #define ER_INSECURE_PLAIN_TEXT 1759 #define ER_INSECURE_CHANGE_MASTER 1760 #define ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO 1761 #define ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO 1762 #define ER_SQLTHREAD_WITH_SECURE_SLAVE 1763 #define ER_TABLE_HAS_NO_FT 1764 #define ER_VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER 1765 #define ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION 1766 #define ER_GTID_NEXT_IS_NOT_IN_GTID_NEXT_LIST 1767 #define ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION_WHEN_GTID_NEXT_LIST_IS_NULL 1768 #define ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION 1769 #define ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL 1770 #define ER_SKIPPING_LOGGED_TRANSACTION 1771 #define ER_MALFORMED_GTID_SET_SPECIFICATION 1772 #define ER_MALFORMED_GTID_SET_ENCODING 1773 #define ER_MALFORMED_GTID_SPECIFICATION 1774 #define ER_GNO_EXHAUSTED 1775 #define ER_BAD_SLAVE_AUTO_POSITION 1776 #define ER_AUTO_POSITION_REQUIRES_GTID_MODE_ON 1777 #define ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET 1778 #define ER_GTID_MODE_2_OR_3_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON 1779 #define ER_GTID_MODE_REQUIRES_BINLOG 1780 #define ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF 1781 #define ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON 1782 #define ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF 1783 #define ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF 1784 #define ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE 1785 #define ER_GTID_UNSAFE_CREATE_SELECT 1786 #define ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION 1787 #define ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME 1788 #define ER_MASTER_HAS_PURGED_REQUIRED_GTIDS 1789 #define ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID 1790 #define ER_UNKNOWN_EXPLAIN_FORMAT 1791 #define ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION 1792 #define ER_TOO_LONG_TABLE_PARTITION_COMMENT 1793 #define ER_SLAVE_CONFIGURATION 1794 #define ER_INNODB_FT_LIMIT 1795 #define ER_INNODB_NO_FT_TEMP_TABLE 1796 #define ER_INNODB_FT_WRONG_DOCID_COLUMN 1797 #define ER_INNODB_FT_WRONG_DOCID_INDEX 1798 #define ER_INNODB_ONLINE_LOG_TOO_BIG 1799 #define ER_UNKNOWN_ALTER_ALGORITHM 1800 #define ER_UNKNOWN_ALTER_LOCK 1801 #define ER_MTS_CHANGE_MASTER_CANT_RUN_WITH_GAPS 1802 #define ER_MTS_RECOVERY_FAILURE 1803 #define ER_MTS_RESET_WORKERS 1804 #define ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2 1805 #define ER_SLAVE_SILENT_RETRY_TRANSACTION 1806 #define ER_UNUSED_22 1807 #define ER_TABLE_SCHEMA_MISMATCH 1808 #define ER_TABLE_IN_SYSTEM_TABLESPACE 1809 #define ER_IO_READ_ERROR 1810 #define ER_IO_WRITE_ERROR 1811 #define ER_TABLESPACE_MISSING 1812 #define ER_TABLESPACE_EXISTS 1813 #define ER_TABLESPACE_DISCARDED 1814 #define ER_INTERNAL_ERROR 1815 #define ER_INNODB_IMPORT_ERROR 1816 #define ER_INNODB_INDEX_CORRUPT 1817 #define ER_INVALID_YEAR_COLUMN_LENGTH 1818 #define ER_NOT_VALID_PASSWORD 1819 #define ER_MUST_CHANGE_PASSWORD 1820 #define ER_FK_NO_INDEX_CHILD 1821 #define ER_FK_NO_INDEX_PARENT 1822 #define ER_FK_FAIL_ADD_SYSTEM 1823 #define ER_FK_CANNOT_OPEN_PARENT 1824 #define ER_FK_INCORRECT_OPTION 1825 #define ER_DUP_CONSTRAINT_NAME 1826 #define ER_PASSWORD_FORMAT 1827 #define ER_FK_COLUMN_CANNOT_DROP 1828 #define ER_FK_COLUMN_CANNOT_DROP_CHILD 1829 #define ER_FK_COLUMN_NOT_NULL 1830 #define ER_DUP_INDEX 1831 #define ER_FK_COLUMN_CANNOT_CHANGE 1832 #define ER_FK_COLUMN_CANNOT_CHANGE_CHILD 1833 #define ER_FK_CANNOT_DELETE_PARENT 1834 #define ER_MALFORMED_PACKET 1835 #define ER_READ_ONLY_MODE 1836 #define ER_GTID_NEXT_TYPE_UNDEFINED_GROUP 1837 #define ER_VARIABLE_NOT_SETTABLE_IN_SP 1838 #define ER_CANT_SET_GTID_PURGED_WHEN_GTID_MODE_IS_OFF 1839 #define ER_CANT_SET_GTID_PURGED_WHEN_GTID_EXECUTED_IS_NOT_EMPTY 1840 #define ER_CANT_SET_GTID_PURGED_WHEN_OWNED_GTIDS_IS_NOT_EMPTY 1841 #define ER_GTID_PURGED_WAS_CHANGED 1842 #define ER_GTID_EXECUTED_WAS_CHANGED 1843 #define ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES 1844 #define ER_ALTER_OPERATION_NOT_SUPPORTED 1845 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON 1846 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY 1847 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION 1848 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME 1849 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE 1850 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_CHECK 1851 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_IGNORE 1852 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOPK 1853 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_AUTOINC 1854 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_HIDDEN_FTS 1855 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_CHANGE_FTS 1856 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS 1857 #define ER_SQL_SLAVE_SKIP_COUNTER_NOT_SETTABLE_IN_GTID_MODE 1858 #define ER_DUP_UNKNOWN_IN_INDEX 1859 #define ER_IDENT_CAUSES_TOO_LONG_PATH 1860 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL 1861 #define ER_MUST_CHANGE_PASSWORD_LOGIN 1862 #define ER_ROW_IN_WRONG_PARTITION 1863 #define ER_MTS_EVENT_BIGGER_PENDING_JOBS_SIZE_MAX 1864 #define ER_INNODB_NO_FT_USES_PARSER 1865 #define ER_BINLOG_LOGICAL_CORRUPTION 1866 #define ER_WARN_PURGE_LOG_IN_USE 1867 #define ER_WARN_PURGE_LOG_IS_ACTIVE 1868 #define ER_AUTO_INCREMENT_CONFLICT 1869 #define WARN_ON_BLOCKHOLE_IN_RBR 1870 #define ER_SLAVE_MI_INIT_REPOSITORY 1871 #define ER_SLAVE_RLI_INIT_REPOSITORY 1872 #define ER_ACCESS_DENIED_CHANGE_USER_ERROR 1873 #define ER_INNODB_READ_ONLY 1874 #define ER_STOP_SLAVE_SQL_THREAD_TIMEOUT 1875 #define ER_STOP_SLAVE_IO_THREAD_TIMEOUT 1876 #define ER_TABLE_CORRUPT 1877 #define ER_TEMP_FILE_WRITE_FAILURE 1878 #define ER_INNODB_FT_AUX_NOT_HEX_ID 1879 #define ER_LAST_MYSQL_ERROR_MESSAGE 1880 #define ER_ERROR_LAST_SECTION_1 1880 /* New section */ #define ER_ERROR_FIRST_SECTION_2 1900 #define ER_UNUSED_18 1900 #define ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED 1901 #define ER_UNUSED_19 1902 #define ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN 1903 #define ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN 1904 #define ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN 1905 #define ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN 1906 #define ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN 1907 #define ER_UNUSED_20 1908 #define ER_UNUSED_21 1909 #define ER_UNSUPPORTED_ENGINE_FOR_GENERATED_COLUMNS 1910 #define ER_UNKNOWN_OPTION 1911 #define ER_BAD_OPTION_VALUE 1912 #define ER_UNUSED_6 1913 #define ER_UNUSED_7 1914 #define ER_UNUSED_8 1915 #define ER_DATA_OVERFLOW 1916 #define ER_DATA_TRUNCATED 1917 #define ER_BAD_DATA 1918 #define ER_DYN_COL_WRONG_FORMAT 1919 #define ER_DYN_COL_IMPLEMENTATION_LIMIT 1920 #define ER_DYN_COL_DATA 1921 #define ER_DYN_COL_WRONG_CHARSET 1922 #define ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES 1923 #define ER_QUERY_CACHE_IS_DISABLED 1924 #define ER_QUERY_CACHE_IS_GLOBALY_DISABLED 1925 #define ER_VIEW_ORDERBY_IGNORED 1926 #define ER_CONNECTION_KILLED 1927 #define ER_UNUSED_12 1928 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION 1929 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION 1930 #define ER_QUERY_RESULT_INCOMPLETE 1931 #define ER_NO_SUCH_TABLE_IN_ENGINE 1932 #define ER_TARGET_NOT_EXPLAINABLE 1933 #define ER_CONNECTION_ALREADY_EXISTS 1934 #define ER_MASTER_LOG_PREFIX 1935 #define ER_CANT_START_STOP_SLAVE 1936 #define ER_SLAVE_STARTED 1937 #define ER_SLAVE_STOPPED 1938 #define ER_SQL_DISCOVER_ERROR 1939 #define ER_FAILED_GTID_STATE_INIT 1940 #define ER_INCORRECT_GTID_STATE 1941 #define ER_CANNOT_UPDATE_GTID_STATE 1942 #define ER_DUPLICATE_GTID_DOMAIN 1943 #define ER_GTID_OPEN_TABLE_FAILED 1944 #define ER_GTID_POSITION_NOT_FOUND_IN_BINLOG 1945 #define ER_CANNOT_LOAD_SLAVE_GTID_STATE 1946 #define ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG 1947 #define ER_MASTER_GTID_POS_MISSING_DOMAIN 1948 #define ER_UNTIL_REQUIRES_USING_GTID 1949 #define ER_GTID_STRICT_OUT_OF_ORDER 1950 #define ER_GTID_START_FROM_BINLOG_HOLE 1951 #define ER_SLAVE_UNEXPECTED_MASTER_SWITCH 1952 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO 1953 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO 1954 #define ER_GTID_POSITION_NOT_FOUND_IN_BINLOG2 1955 #define ER_BINLOG_MUST_BE_EMPTY 1956 #define ER_NO_SUCH_QUERY 1957 #define ER_BAD_BASE64_DATA 1958 #define ER_INVALID_ROLE 1959 #define ER_INVALID_CURRENT_USER 1960 #define ER_CANNOT_GRANT_ROLE 1961 #define ER_CANNOT_REVOKE_ROLE 1962 #define ER_CHANGE_SLAVE_PARALLEL_THREADS_ACTIVE 1963 #define ER_PRIOR_COMMIT_FAILED 1964 #define ER_IT_IS_A_VIEW 1965 #define ER_SLAVE_SKIP_NOT_IN_GTID 1966 #define ER_TABLE_DEFINITION_TOO_BIG 1967 #define ER_PLUGIN_INSTALLED 1968 #define ER_STATEMENT_TIMEOUT 1969 #define ER_SUBQUERIES_NOT_SUPPORTED 1970 #define ER_SET_STATEMENT_NOT_SUPPORTED 1971 #define ER_UNUSED_9 1972 #define ER_USER_CREATE_EXISTS 1973 #define ER_USER_DROP_EXISTS 1974 #define ER_ROLE_CREATE_EXISTS 1975 #define ER_ROLE_DROP_EXISTS 1976 #define ER_CANNOT_CONVERT_CHARACTER 1977 #define ER_INVALID_DEFAULT_VALUE_FOR_FIELD 1978 #define ER_KILL_QUERY_DENIED_ERROR 1979 #define ER_NO_EIS_FOR_FIELD 1980 #define ER_WARN_AGGFUNC_DEPENDENCE 1981 #define WARN_INNODB_PARTITION_OPTION_IGNORED 1982 #define ER_ERROR_LAST_SECTION_2 1982 /* New section */ #define ER_ERROR_FIRST_SECTION_3 2000 #define ER_ERROR_LAST_SECTION_3 2000 /* New section */ #define ER_ERROR_FIRST_SECTION_4 3000 #define ER_FILE_CORRUPT 3000 #define ER_ERROR_ON_MASTER 3001 #define ER_INCONSISTENT_ERROR 3002 #define ER_STORAGE_ENGINE_NOT_LOADED 3003 #define ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER 3004 #define ER_WARN_LEGACY_SYNTAX_CONVERTED 3005 #define ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN 3006 #define ER_CANNOT_DISCARD_TEMPORARY_TABLE 3007 #define ER_FK_DEPTH_EXCEEDED 3008 #define ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2 3009 #define ER_WARN_TRIGGER_DOESNT_HAVE_CREATED 3010 #define ER_REFERENCED_TRG_DOES_NOT_EXIST_MYSQL 3011 #define ER_EXPLAIN_NOT_SUPPORTED 3012 #define ER_INVALID_FIELD_SIZE 3013 #define ER_MISSING_HA_CREATE_OPTION 3014 #define ER_ENGINE_OUT_OF_MEMORY 3015 #define ER_PASSWORD_EXPIRE_ANONYMOUS_USER 3016 #define ER_SLAVE_SQL_THREAD_MUST_STOP 3017 #define ER_NO_FT_MATERIALIZED_SUBQUERY 3018 #define ER_INNODB_UNDO_LOG_FULL 3019 #define ER_INVALID_ARGUMENT_FOR_LOGARITHM 3020 #define ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP 3021 #define ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO 3022 #define ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS 3023 #define ER_UNUSED_1 3024 #define ER_NON_RO_SELECT_DISABLE_TIMER 3025 #define ER_DUP_LIST_ENTRY 3026 #define ER_SQL_MODE_NO_EFFECT 3027 #define ER_AGGREGATE_ORDER_FOR_UNION 3028 #define ER_AGGREGATE_ORDER_NON_AGG_QUERY 3029 #define ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR 3030 #define ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER 3031 #define ER_SERVER_OFFLINE_MODE 3032 #define ER_GIS_DIFFERENT_SRIDS 3033 #define ER_GIS_UNSUPPORTED_ARGUMENT 3034 #define ER_GIS_UNKNOWN_ERROR 3035 #define ER_GIS_UNKNOWN_EXCEPTION 3036 #define ER_GIS_INVALID_DATA 3037 #define ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION 3038 #define ER_BOOST_GEOMETRY_CENTROID_EXCEPTION 3039 #define ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION 3040 #define ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION 3041 #define ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION 3042 #define ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION 3043 #define ER_STD_BAD_ALLOC_ERROR 3044 #define ER_STD_DOMAIN_ERROR 3045 #define ER_STD_LENGTH_ERROR 3046 #define ER_STD_INVALID_ARGUMENT 3047 #define ER_STD_OUT_OF_RANGE_ERROR 3048 #define ER_STD_OVERFLOW_ERROR 3049 #define ER_STD_RANGE_ERROR 3050 #define ER_STD_UNDERFLOW_ERROR 3051 #define ER_STD_LOGIC_ERROR 3052 #define ER_STD_RUNTIME_ERROR 3053 #define ER_STD_UNKNOWN_EXCEPTION 3054 #define ER_GIS_DATA_WRONG_ENDIANESS 3055 #define ER_CHANGE_MASTER_PASSWORD_LENGTH 3056 #define ER_USER_LOCK_WRONG_NAME 3057 #define ER_USER_LOCK_DEADLOCK 3058 #define ER_REPLACE_INACCESSIBLE_ROWS 3059 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS 3060 #define ER_ERROR_LAST_SECTION_4 3060 /* New section */ #define ER_ERROR_FIRST_SECTION_5 4000 #define ER_UNUSED_26 4000 #define ER_UNUSED_27 4001 #define ER_WITH_COL_WRONG_LIST 4002 #define ER_TOO_MANY_DEFINITIONS_IN_WITH_CLAUSE 4003 #define ER_DUP_QUERY_NAME 4004 #define ER_RECURSIVE_WITHOUT_ANCHORS 4005 #define ER_UNACCEPTABLE_MUTUAL_RECURSION 4006 #define ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED 4007 #define ER_NOT_STANDARD_COMPLIANT_RECURSIVE 4008 #define ER_WRONG_WINDOW_SPEC_NAME 4009 #define ER_DUP_WINDOW_NAME 4010 #define ER_PARTITION_LIST_IN_REFERENCING_WINDOW_SPEC 4011 #define ER_ORDER_LIST_IN_REFERENCING_WINDOW_SPEC 4012 #define ER_WINDOW_FRAME_IN_REFERENCED_WINDOW_SPEC 4013 #define ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS 4014 #define ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION 4015 #define ER_WINDOW_FUNCTION_IN_WINDOW_SPEC 4016 #define ER_NOT_ALLOWED_WINDOW_FRAME 4017 #define ER_NO_ORDER_LIST_IN_WINDOW_SPEC 4018 #define ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY 4019 #define ER_WRONG_TYPE_FOR_ROWS_FRAME 4020 #define ER_WRONG_TYPE_FOR_RANGE_FRAME 4021 #define ER_FRAME_EXCLUSION_NOT_SUPPORTED 4022 #define ER_WINDOW_FUNCTION_DONT_HAVE_FRAME 4023 #define ER_INVALID_NTILE_ARGUMENT 4024 #define ER_CONSTRAINT_FAILED 4025 #define ER_EXPRESSION_IS_TOO_BIG 4026 #define ER_ERROR_EVALUATING_EXPRESSION 4027 #define ER_CALCULATING_DEFAULT_VALUE 4028 #define ER_EXPRESSION_REFERS_TO_UNINIT_FIELD 4029 #define ER_PARTITION_DEFAULT_ERROR 4030 #define ER_REFERENCED_TRG_DOES_NOT_EXIST 4031 #define ER_INVALID_DEFAULT_PARAM 4032 #define ER_BINLOG_NON_SUPPORTED_BULK 4033 #define ER_BINLOG_UNCOMPRESS_ERROR 4034 #define ER_JSON_BAD_CHR 4035 #define ER_JSON_NOT_JSON_CHR 4036 #define ER_JSON_EOS 4037 #define ER_JSON_SYNTAX 4038 #define ER_JSON_ESCAPING 4039 #define ER_JSON_DEPTH 4040 #define ER_JSON_PATH_EOS 4041 #define ER_JSON_PATH_SYNTAX 4042 #define ER_JSON_PATH_DEPTH 4043 #define ER_JSON_PATH_NO_WILDCARD 4044 #define ER_JSON_PATH_ARRAY 4045 #define ER_JSON_ONE_OR_ALL 4046 #define ER_UNSUPPORTED_COMPRESSED_TABLE 4047 #define ER_GEOJSON_INCORRECT 4048 #define ER_GEOJSON_TOO_FEW_POINTS 4049 #define ER_GEOJSON_NOT_CLOSED 4050 #define ER_JSON_PATH_EMPTY 4051 #define ER_SLAVE_SAME_ID 4052 #define ER_FLASHBACK_NOT_SUPPORTED 4053 #define ER_KEYS_OUT_OF_ORDER 4054 #define ER_OVERLAPPING_KEYS 4055 #define ER_REQUIRE_ROW_BINLOG_FORMAT 4056 #define ER_ISOLATION_MODE_NOT_SUPPORTED 4057 #define ER_ON_DUPLICATE_DISABLED 4058 #define ER_UPDATES_WITH_CONSISTENT_SNAPSHOT 4059 #define ER_ROLLBACK_ONLY 4060 #define ER_ROLLBACK_TO_SAVEPOINT 4061 #define ER_ISOLATION_LEVEL_WITH_CONSISTENT_SNAPSHOT 4062 #define ER_UNSUPPORTED_COLLATION 4063 #define ER_METADATA_INCONSISTENCY 4064 #define ER_CF_DIFFERENT 4065 #define ER_RDB_TTL_DURATION_FORMAT 4066 #define ER_RDB_STATUS_GENERAL 4067 #define ER_RDB_STATUS_MSG 4068 #define ER_RDB_TTL_UNSUPPORTED 4069 #define ER_RDB_TTL_COL_FORMAT 4070 #define ER_PER_INDEX_CF_DEPRECATED 4071 #define ER_KEY_CREATE_DURING_ALTER 4072 #define ER_SK_POPULATE_DURING_ALTER 4073 #define ER_SUM_FUNC_WITH_WINDOW_FUNC_AS_ARG 4074 #define ER_NET_OK_PACKET_TOO_LARGE 4075 #define ER_GEOJSON_EMPTY_COORDINATES 4076 #define ER_MYROCKS_CANT_NOPAD_COLLATION 4077 #define ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION 4078 #define ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION 4079 #define ER_WRONG_PARAMCOUNT_TO_CURSOR 4080 #define ER_UNKNOWN_STRUCTURED_VARIABLE 4081 #define ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD 4082 #define ER_END_IDENTIFIER_DOES_NOT_MATCH 4083 #define ER_SEQUENCE_RUN_OUT 4084 #define ER_SEQUENCE_INVALID_DATA 4085 #define ER_SEQUENCE_INVALID_TABLE_STRUCTURE 4086 #define ER_SEQUENCE_ACCESS_ERROR 4087 #define ER_SEQUENCE_BINLOG_FORMAT 4088 #define ER_NOT_SEQUENCE 4089 #define ER_NOT_SEQUENCE2 4090 #define ER_UNKNOWN_SEQUENCES 4091 #define ER_UNKNOWN_VIEW 4092 #define ER_WRONG_INSERT_INTO_SEQUENCE 4093 #define ER_SP_STACK_TRACE 4094 #define ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY 4095 #define ER_PACKAGE_ROUTINE_FORWARD_DECLARATION_NOT_DEFINED 4096 #define ER_COMPRESSED_COLUMN_USED_AS_KEY 4097 #define ER_UNKNOWN_COMPRESSION_METHOD 4098 #define ER_WRONG_NUMBER_OF_VALUES_IN_TVC 4099 #define ER_FIELD_REFERENCE_IN_TVC 4100 #define ER_WRONG_TYPE_FOR_PERCENTILE_FUNC 4101 #define ER_ARGUMENT_NOT_CONSTANT 4102 #define ER_ARGUMENT_OUT_OF_RANGE 4103 #define ER_WRONG_TYPE_OF_ARGUMENT 4104 #define ER_NOT_AGGREGATE_FUNCTION 4105 #define ER_INVALID_AGGREGATE_FUNCTION 4106 #define ER_INVALID_VALUE_TO_LIMIT 4107 #define ER_INVISIBLE_NOT_NULL_WITHOUT_DEFAULT 4108 #define ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING 4109 #define ER_VERS_FIELD_WRONG_TYPE 4110 #define ER_VERS_ENGINE_UNSUPPORTED 4111 #define ER_UNUSED_23 4112 #define ER_PARTITION_WRONG_TYPE 4113 #define WARN_VERS_PART_FULL 4114 #define WARN_VERS_PARAMETERS 4115 #define ER_VERS_DROP_PARTITION_INTERVAL 4116 #define ER_UNUSED_25 4117 #define WARN_VERS_PART_NON_HISTORICAL 4118 #define ER_VERS_ALTER_NOT_ALLOWED 4119 #define ER_VERS_ALTER_ENGINE_PROHIBITED 4120 #define ER_VERS_RANGE_PROHIBITED 4121 #define ER_CONFLICTING_FOR_SYSTEM_TIME 4122 #define ER_VERS_TABLE_MUST_HAVE_COLUMNS 4123 #define ER_VERS_NOT_VERSIONED 4124 #define ER_MISSING 4125 #define ER_VERS_PERIOD_COLUMNS 4126 #define ER_PART_WRONG_VALUE 4127 #define ER_VERS_WRONG_PARTS 4128 #define ER_VERS_NO_TRX_ID 4129 #define ER_VERS_ALTER_SYSTEM_FIELD 4130 #define ER_DROP_VERSIONING_SYSTEM_TIME_PARTITION 4131 #define ER_VERS_DB_NOT_SUPPORTED 4132 #define ER_VERS_TRT_IS_DISABLED 4133 #define ER_VERS_DUPLICATE_ROW_START_END 4134 #define ER_VERS_ALREADY_VERSIONED 4135 #define ER_UNUSED_24 4136 #define ER_VERS_NOT_SUPPORTED 4137 #define ER_VERS_TRX_PART_HISTORIC_ROW_NOT_SUPPORTED 4138 #define ER_INDEX_FILE_FULL 4139 #define ER_UPDATED_COLUMN_ONLY_ONCE 4140 #define ER_EMPTY_ROW_IN_TVC 4141 #define ER_VERS_QUERY_IN_PARTITION 4142 #define ER_KEY_DOESNT_SUPPORT 4143 #define ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD 4144 #define ER_BACKUP_LOCK_IS_ACTIVE 4145 #define ER_BACKUP_NOT_RUNNING 4146 #define ER_BACKUP_WRONG_STAGE 4147 #define ER_BACKUP_STAGE_FAILED 4148 #define ER_BACKUP_UNKNOWN_STAGE 4149 #define ER_USER_IS_BLOCKED 4150 #define ER_ACCOUNT_HAS_BEEN_LOCKED 4151 #define ER_PERIOD_TEMPORARY_NOT_ALLOWED 4152 #define ER_PERIOD_TYPES_MISMATCH 4153 #define ER_MORE_THAN_ONE_PERIOD 4154 #define ER_PERIOD_FIELD_WRONG_ATTRIBUTES 4155 #define ER_PERIOD_NOT_FOUND 4156 #define ER_PERIOD_COLUMNS_UPDATED 4157 #define ER_PERIOD_CONSTRAINT_DROP 4158 #define ER_TOO_LONG_KEYPART 4159 #define ER_TOO_LONG_DATABASE_COMMENT 4160 #define ER_UNKNOWN_DATA_TYPE 4161 #define ER_UNKNOWN_OPERATOR 4162 #define ER_WARN_HISTORY_ROW_START_TIME 4163 #define ER_PART_STARTS_BEYOND_INTERVAL 4164 #define ER_GALERA_REPLICATION_NOT_SUPPORTED 4165 #define ER_LOAD_INFILE_CAPABILITY_DISABLED 4166 #define ER_NO_SECURE_TRANSPORTS_CONFIGURED 4167 #define ER_SLAVE_IGNORED_SHARED_TABLE 4168 #define ER_NO_AUTOINCREMENT_WITH_UNIQUE 4169 #define ER_KEY_CONTAINS_PERIOD_FIELDS 4170 #define ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS 4171 #define ER_NOT_ALLOWED_IN_THIS_CONTEXT 4172 #define ER_DATA_WAS_COMMITED_UNDER_ROLLBACK 4173 #define ER_PK_INDEX_CANT_BE_IGNORED 4174 #define ER_BINLOG_UNSAFE_SKIP_LOCKED 4175 #define ER_JSON_TABLE_ERROR_ON_FIELD 4176 #define ER_JSON_TABLE_ALIAS_REQUIRED 4177 #define ER_JSON_TABLE_SCALAR_EXPECTED 4178 #define ER_JSON_TABLE_MULTIPLE_MATCHES 4179 #define ER_WITH_TIES_NEEDS_ORDER 4180 #define ER_REMOVED_ORPHAN_TRIGGER 4181 #define ER_STORAGE_ENGINE_DISABLED 4182 #define ER_ERROR_LAST 4182 #endif /* ER_ERROR_FIRST */ mariadb/ma_io.h000064400000003126151031265040007377 0ustar00/* Copyright (C) 2015 MariaDB Corporation AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA */ #ifndef _ma_io_h_ #define _ma_io_h_ #ifdef HAVE_REMOTEIO #include #endif enum enum_file_type { MA_FILE_NONE=0, MA_FILE_LOCAL=1, MA_FILE_REMOTE=2 }; typedef struct { enum enum_file_type type; void *ptr; } MA_FILE; #ifdef HAVE_REMOTEIO struct st_rio_methods { MA_FILE *(*mopen)(const char *url, const char *mode); int (*mclose)(MA_FILE *ptr); int (*mfeof)(MA_FILE *file); size_t (*mread)(void *ptr, size_t size, size_t nmemb, MA_FILE *file); char * (*mgets)(char *ptr, size_t size, MA_FILE *file); }; #endif /* function prototypes */ MA_FILE *ma_open(const char *location, const char *mode, MYSQL *mysql); int ma_close(MA_FILE *file); int ma_feof(MA_FILE *file); size_t ma_read(void *ptr, size_t size, size_t nmemb, MA_FILE *file); char *ma_gets(char *ptr, size_t size, MA_FILE *file); #endif ma_pvio.h000064400000010744151031265040006352 0ustar00#ifndef _ma_pvio_h_ #define _ma_pvio_h_ #define cio_defined #ifdef HAVE_TLS #include #else #define MARIADB_TLS void #endif /* CONC-492: Allow to build plugins outside of MariaDB Connector/C source tree when ma_global.h was not included. */ #if !defined(_global_h) && !defined(MY_GLOBAL_INCLUDED) typedef unsigned char uchar; #endif #define PVIO_SET_ERROR if (pvio->set_error) \ pvio->set_error #define PVIO_READ_AHEAD_CACHE_SIZE 16384 #define PVIO_READ_AHEAD_CACHE_MIN_SIZE 2048 #define PVIO_EINTR_TRIES 2 struct st_ma_pvio_methods; typedef struct st_ma_pvio_methods PVIO_METHODS; #define IS_PVIO_ASYNC(a) \ ((a)->mysql && (a)->mysql->options.extension && (a)->mysql->options.extension->async_context) #define IS_PVIO_ASYNC_ACTIVE(a) \ (IS_PVIO_ASYNC(a)&& (a)->mysql->options.extension->async_context->active) #define IS_MYSQL_ASYNC(a) \ ((a)->options.extension && (a)->options.extension->async_context) #define IS_MYSQL_ASYNC_ACTIVE(a) \ (IS_MYSQL_ASYNC(a)&& (a)->options.extension->async_context->active) enum enum_pvio_timeout { PVIO_CONNECT_TIMEOUT= 0, PVIO_READ_TIMEOUT, PVIO_WRITE_TIMEOUT }; enum enum_pvio_io_event { VIO_IO_EVENT_READ, VIO_IO_EVENT_WRITE, VIO_IO_EVENT_CONNECT }; enum enum_pvio_type { PVIO_TYPE_UNIXSOCKET= 0, PVIO_TYPE_SOCKET, PVIO_TYPE_NAMEDPIPE, PVIO_TYPE_SHAREDMEM, }; enum enum_pvio_operation { PVIO_READ= 0, PVIO_WRITE=1 }; #define SHM_DEFAULT_NAME "MYSQL" struct st_pvio_callback; typedef struct st_pvio_callback { void (*callback)(MYSQL *mysql, uchar *buffer, size_t size); struct st_pvio_callback *next; } PVIO_CALLBACK; struct st_ma_pvio { void *data; /* read ahead cache */ uchar *cache; uchar *cache_pos; size_t cache_size; enum enum_pvio_type type; int timeout[3]; int ssl_type; /* todo: change to enum (ssl plugins) */ MARIADB_TLS *ctls; MYSQL *mysql; PVIO_METHODS *methods; void (*set_error)(MYSQL *mysql, unsigned int error_nr, const char *sqlstate, const char *format, ...); void (*callback)(MARIADB_PVIO *pvio, my_bool is_read, const uchar *buffer, size_t length); size_t bytes_read; size_t bytes_sent; }; typedef struct st_ma_pvio_cinfo { const char *host; const char *unix_socket; int port; enum enum_pvio_type type; MYSQL *mysql; } MA_PVIO_CINFO; struct st_ma_pvio_methods { my_bool (*set_timeout)(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout); int (*get_timeout)(MARIADB_PVIO *pvio, enum enum_pvio_timeout type); ssize_t (*read)(MARIADB_PVIO *pvio, uchar *buffer, size_t length); ssize_t (*async_read)(MARIADB_PVIO *pvio, uchar *buffer, size_t length); ssize_t (*write)(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); ssize_t (*async_write)(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); int (*wait_io_or_timeout)(MARIADB_PVIO *pvio, my_bool is_read, int timeout); int (*blocking)(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value); my_bool (*connect)(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); my_bool (*close)(MARIADB_PVIO *pvio); int (*fast_send)(MARIADB_PVIO *pvio); int (*keepalive)(MARIADB_PVIO *pvio); my_bool (*get_handle)(MARIADB_PVIO *pvio, void *handle); my_bool (*is_blocking)(MARIADB_PVIO *pvio); my_bool (*is_alive)(MARIADB_PVIO *pvio); my_bool (*has_data)(MARIADB_PVIO *pvio, ssize_t *data_len); int(*shutdown)(MARIADB_PVIO *pvio); }; /* Function prototypes */ MARIADB_PVIO *ma_pvio_init(MA_PVIO_CINFO *cinfo); void ma_pvio_close(MARIADB_PVIO *pvio); ssize_t ma_pvio_cache_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length); ssize_t ma_pvio_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length); ssize_t ma_pvio_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length); int ma_pvio_get_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type); my_bool ma_pvio_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout); int ma_pvio_fast_send(MARIADB_PVIO *pvio); int ma_pvio_keepalive(MARIADB_PVIO *pvio); my_socket ma_pvio_get_socket(MARIADB_PVIO *pvio); my_bool ma_pvio_is_blocking(MARIADB_PVIO *pvio); my_bool ma_pvio_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode); my_bool ma_pvio_is_blocking(MARIADB_PVIO *pvio); int ma_pvio_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout); my_bool ma_pvio_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo); my_bool ma_pvio_is_alive(MARIADB_PVIO *pvio); my_bool ma_pvio_get_handle(MARIADB_PVIO *pvio, void *handle); my_bool ma_pvio_has_data(MARIADB_PVIO *pvio, ssize_t *length); #endif /* _ma_pvio_h_ */ ma_list.h000064400000003123151031265040006341 0ustar00/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA */ #ifndef _list_h_ #define _list_h_ #ifdef __cplusplus extern "C" { #endif typedef struct st_list { struct st_list *prev,*next; void *data; } LIST; typedef int (*list_walk_action)(void *,void *); extern LIST *list_add(LIST *root,LIST *element); extern LIST *list_delete(LIST *root,LIST *element); extern LIST *list_cons(void *data,LIST *root); extern LIST *list_reverse(LIST *root); extern void list_free(LIST *root,unsigned int free_data); extern unsigned int list_length(LIST *list); extern int list_walk(LIST *list,list_walk_action action,char * argument); #define list_rest(a) ((a)->next) #define list_push(a,b) (a)=list_cons((b),(a)) #define list_pop(A) do {LIST *old=(A); (A)=list_delete(old,old) ; ma_free((char *) old,MYF(MY_FAE)); } while(0) #ifdef __cplusplus } #endif #endif errmsg.h000064400000011461151031265040006214 0ustar00/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB 2012-2016 SkySQL AB, MariaDB Corporation AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA */ /* Error messages for mysql clients */ /* error messages for the demon is in share/language/errmsg.sys */ #ifndef _errmsg_h_ #define _errmsg_h_ #ifdef __cplusplus extern "C" { #endif void init_client_errs(void); extern const char *client_errors[]; /* Error messages */ extern const char *mariadb_client_errors[]; /* Error messages */ #ifdef __cplusplus } #endif #define CR_MIN_ERROR 2000 /* For easier client code */ #define CR_MAX_ERROR 2999 #define CER_MIN_ERROR 5000 #define CER_MAX_ERROR 5999 #define CLIENT_ERRMAP 2 /* Errormap used by ma_error() */ #define ER_UNKNOWN_ERROR_CODE "Unknown or undefined error code (%d)" #define CR_UNKNOWN_ERROR 2000 #define CR_SOCKET_CREATE_ERROR 2001 #define CR_CONNECTION_ERROR 2002 #define CR_CONN_HOST_ERROR 2003 /* never sent to a client, message only */ #define CR_IPSOCK_ERROR 2004 #define CR_UNKNOWN_HOST 2005 #define CR_SERVER_GONE_ERROR 2006 /* disappeared _between_ queries */ #define CR_VERSION_ERROR 2007 #define CR_OUT_OF_MEMORY 2008 #define CR_WRONG_HOST_INFO 2009 #define CR_LOCALHOST_CONNECTION 2010 #define CR_TCP_CONNECTION 2011 #define CR_SERVER_HANDSHAKE_ERR 2012 #define CR_SERVER_LOST 2013 /* disappeared _during_ a query */ #define CR_COMMANDS_OUT_OF_SYNC 2014 #define CR_NAMEDPIPE_CONNECTION 2015 #define CR_NAMEDPIPEWAIT_ERROR 2016 #define CR_NAMEDPIPEOPEN_ERROR 2017 #define CR_NAMEDPIPESETSTATE_ERROR 2018 #define CR_CANT_READ_CHARSET 2019 #define CR_NET_PACKET_TOO_LARGE 2020 #define CR_SSL_CONNECTION_ERROR 2026 #define CR_MALFORMED_PACKET 2027 #define CR_NO_PREPARE_STMT 2030 #define CR_PARAMS_NOT_BOUND 2031 #define CR_INVALID_PARAMETER_NO 2034 #define CR_INVALID_BUFFER_USE 2035 #define CR_UNSUPPORTED_PARAM_TYPE 2036 #define CR_SHARED_MEMORY_CONNECTION 2037 #define CR_SHARED_MEMORY_CONNECT_ERROR 2038 #define CR_CONN_UNKNOWN_PROTOCOL 2047 #define CR_SECURE_AUTH 2049 #define CR_NO_DATA 2051 #define CR_NO_STMT_METADATA 2052 #define CR_NOT_IMPLEMENTED 2054 #define CR_SERVER_LOST_EXTENDED 2055 /* never sent to a client, message only */ #define CR_STMT_CLOSED 2056 #define CR_NEW_STMT_METADATA 2057 #define CR_ALREADY_CONNECTED 2058 #define CR_AUTH_PLUGIN_CANNOT_LOAD 2059 #define CR_DUPLICATE_CONNECTION_ATTR 2060 #define CR_AUTH_PLUGIN_ERR 2061 /* Always last, if you add new error codes please update the value for CR_MYSQL_LAST_ERROR */ #define CR_MYSQL_LAST_ERROR CR_AUTH_PLUGIN_ERR /* * MariaDB Connector/C errors: */ #define CR_EVENT_CREATE_FAILED 5000 #define CR_BIND_ADDR_FAILED 5001 #define CR_ASYNC_NOT_SUPPORTED 5002 #define CR_FUNCTION_NOT_SUPPORTED 5003 #define CR_FILE_NOT_FOUND 5004 #define CR_FILE_READ 5005 #define CR_BULK_WITHOUT_PARAMETERS 5006 #define CR_INVALID_STMT 5007 #define CR_VERSION_MISMATCH 5008 #define CR_INVALID_PARAMETER 5009 #define CR_PLUGIN_NOT_ALLOWED 5010 #define CR_CONNSTR_PARSE_ERROR 5011 #define CR_ERR_LOAD_PLUGIN 5012 #define CR_ERR_NET_READ 5013 #define CR_ERR_NET_WRITE 5014 #define CR_ERR_NET_UNCOMPRESS 5015 #define CR_ERR_STMT_PARAM_CALLBACK 5016 #define CR_ERR_BINLOG_UNCOMPRESS 5017 #define CR_ERR_CHECKSUM_VERIFICATION_ERROR 5018 #define CR_ERR_UNSUPPORTED_BINLOG_FORMAT 5019 #define CR_UNKNOWN_BINLOG_EVENT 5020 #define CR_BINLOG_ERROR 5021 #define CR_BINLOG_INVALID_FILE 5022 #define CR_BINLOG_SEMI_SYNC_ERROR 5023 #define CR_INVALID_CLIENT_FLAG 5024 #define CR_ERR_MISSING_ERROR_INFO 5026 /* Always last, if you add new error codes please update the value for CR_MARIADB_LAST_ERROR */ #define CR_MARIADB_LAST_ERROR CR_ERR_MISSING_ERROR_INFO #endif #define IS_MYSQL_ERROR(code) ((code) > CR_MIN_ERROR && (code) <= CR_MYSQL_LAST_ERROR) #define IS_MARIADB_ERROR(code) ((code) > CER_MIN_ERROR && (code) <= CR_MARIADB_LAST_ERROR) #define ER(code) IS_MYSQL_ERROR((code)) ? client_errors[(code) - CR_MIN_ERROR] : \ IS_MARIADB_ERROR((code)) ? mariadb_client_errors[(code) - CER_MIN_ERROR] : \ "Unknown or undefined error code" #define CER(code) ER((code)) mysql/client_plugin.h000064400000021746151031265040010725 0ustar00/* Copyright (C) 2010 - 2012 Sergei Golubchik and Monty Program Ab 2014, 2022 MariaDB Corporation AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not see or write to the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor, Boston, MA 02110, USA */ /** @file MySQL Client Plugin API This file defines the API for plugins that work on the client side */ #ifndef MYSQL_CLIENT_PLUGIN_INCLUDED #define MYSQL_CLIENT_PLUGIN_INCLUDED #ifndef MYSQL_ABI_CHECK #include #include #endif #ifndef PLUGINDIR #define PLUGINDIR "lib/plugin" #endif #define plugin_declarations_sym "_mysql_client_plugin_declaration_" /* known plugin types */ #define MYSQL_CLIENT_PLUGIN_RESERVED 0 #define MYSQL_CLIENT_PLUGIN_RESERVED2 1 #define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2 /* authentication */ #define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0100 #define MYSQL_CLIENT_MAX_PLUGINS 3 /* Connector/C specific plugin types */ #define MARIADB_CLIENT_REMOTEIO_PLUGIN 100 /* communication IO */ #define MARIADB_CLIENT_PVIO_PLUGIN 101 #define MARIADB_CLIENT_TRACE_PLUGIN 102 #define MARIADB_CLIENT_CONNECTION_PLUGIN 103 #define MARIADB_CLIENT_COMPRESSION_PLUGIN 104 #define MARIADB_CLIENT_REMOTEIO_PLUGIN_INTERFACE_VERSION 0x0100 #define MARIADB_CLIENT_PVIO_PLUGIN_INTERFACE_VERSION 0x0100 #define MARIADB_CLIENT_TRACE_PLUGIN_INTERFACE_VERSION 0x0100 #define MARIADB_CLIENT_CONNECTION_PLUGIN_INTERFACE_VERSION 0x0100 #define MARIADB_CLIENT_COMPRESSION_PLUGIN_INTERFACE_VERSION 0x0100 #define MARIADB_CLIENT_MAX_PLUGINS 5 #define mysql_declare_client_plugin(X) \ struct st_mysql_client_plugin_ ## X \ _mysql_client_plugin_declaration_ = { \ MYSQL_CLIENT_ ## X ## _PLUGIN, \ MYSQL_CLIENT_ ## X ## _PLUGIN_INTERFACE_VERSION, #define mysql_end_client_plugin } /* generic plugin header structure */ #ifndef MYSQL_CLIENT_PLUGIN_HEADER #define MYSQL_CLIENT_PLUGIN_HEADER \ int type; \ unsigned int interface_version; \ const char *name; \ const char *author; \ const char *desc; \ unsigned int version[3]; \ const char *license; \ void *mysql_api; \ int (*init)(char *, size_t, int, va_list); \ int (*deinit)(void); \ int (*options)(const char *option, const void *); struct st_mysql_client_plugin { MYSQL_CLIENT_PLUGIN_HEADER }; #endif struct st_mysql; /********* connection handler plugin specific declarations **********/ typedef struct st_ma_connection_plugin { MYSQL_CLIENT_PLUGIN_HEADER /* functions */ MYSQL *(*connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); void (*close)(MYSQL *mysql); int (*set_optionsv)(MYSQL *mysql, unsigned int option, ...); int (*set_connection)(MYSQL *mysql,enum enum_server_command command, const char *arg, size_t length, my_bool skipp_check, void *opt_arg); my_bool (*reconnect)(MYSQL *mysql); int (*reset)(MYSQL *mysql); } MARIADB_CONNECTION_PLUGIN; #define MARIADB_DB_DRIVER(a) ((a)->ext_db) /******************* Communication IO plugin *****************/ #include typedef struct st_mariadb_client_plugin_PVIO { MYSQL_CLIENT_PLUGIN_HEADER struct st_ma_pvio_methods *methods; } MARIADB_PVIO_PLUGIN; /******** authentication plugin specific declarations *********/ #include struct st_mysql_client_plugin_AUTHENTICATION { MYSQL_CLIENT_PLUGIN_HEADER int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql); }; /******** trace plugin *******/ struct st_mysql_client_plugin_TRACE { MYSQL_CLIENT_PLUGIN_HEADER }; #include typedef struct st_mariadb_client_plugin_COMPRESS { MYSQL_CLIENT_PLUGIN_HEADER ma_compress_ctx *(*init_ctx)(int compression_level); void (*free_ctx)(ma_compress_ctx *ctx); my_bool (*compress)(ma_compress_ctx *ctx, void *dst, size_t *dst_len, void *source, size_t source_len); my_bool (*decompress)(ma_compress_ctx *ctx, void *dst, size_t *dst_len, void *source, size_t *source_len); } MARIADB_COMPRESSION_PLUGIN; /** type of the mysql_authentication_dialog_ask function @param mysql mysql @param type type of the input 1 - ordinary string input 2 - password string @param prompt prompt @param buf a buffer to store the use input @param buf_len the length of the buffer @retval a pointer to the user input string. It may be equal to 'buf' or to 'mysql->password'. In all other cases it is assumed to be an allocated string, and the "dialog" plugin will free() it. */ typedef char *(*mysql_authentication_dialog_ask_t)(struct st_mysql *mysql, int type, const char *prompt, char *buf, int buf_len); /********************** remote IO plugin **********************/ #ifdef HAVE_REMOTEIO #include /* Remote IO plugin */ typedef struct st_mysql_client_plugin_REMOTEIO { MYSQL_CLIENT_PLUGIN_HEADER struct st_rio_methods *methods; } MARIADB_REMOTEIO_PLUGIN; #endif /******** using plugins ************/ /** loads a plugin and initializes it @param mysql MYSQL structure. only MYSQL_PLUGIN_DIR option value is used, and last_errno/last_error, for error reporting @param name a name of the plugin to load @param type type of plugin that should be loaded, -1 to disable type check @param argc number of arguments to pass to the plugin initialization function @param ... arguments for the plugin initialization function @retval a pointer to the loaded plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, int argc, ...); /** loads a plugin and initializes it, taking va_list as an argument This is the same as mysql_load_plugin, but take va_list instead of a list of arguments. @param mysql MYSQL structure. only MYSQL_PLUGIN_DIR option value is used, and last_errno/last_error, for error reporting @param name a name of the plugin to load @param type type of plugin that should be loaded, -1 to disable type check @param argc number of arguments to pass to the plugin initialization function @param args arguments for the plugin initialization function @retval a pointer to the loaded plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * STDCALL mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type, int argc, va_list args); /** finds an already loaded plugin by name, or loads it, if necessary @param mysql MYSQL structure. only MYSQL_PLUGIN_DIR option value is used, and last_errno/last_error, for error reporting @param name a name of the plugin to load @param type type of plugin that should be loaded @retval a pointer to the plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * STDCALL mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type); /** adds a plugin structure to the list of loaded plugins This is useful if an application has the necessary functionality (for example, a special load data handler) statically linked into the application binary. It can use this function to register the plugin directly, avoiding the need to factor it out into a shared object. @param mysql MYSQL structure. It is only used for error reporting @param plugin an st_mysql_client_plugin structure to register @retval a pointer to the plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * STDCALL mysql_client_register_plugin(struct st_mysql *mysql, struct st_mysql_client_plugin *plugin); extern struct st_mysql_client_plugin *mysql_client_builtins[]; #endif mysql/plugin_auth.h000064400000007321151031265040010401 0ustar00#ifndef MYSQL_PLUGIN_AUTH_COMMON_INCLUDED /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA */ /** @file This file defines constants and data structures that are the same for both client- and server-side authentication plugins. */ #define MYSQL_PLUGIN_AUTH_COMMON_INCLUDED /** the max allowed length for a user name */ #define MYSQL_USERNAME_LENGTH 512 /** return values of the plugin authenticate_user() method. */ /** Authentication failed. Additionally, all other CR_xxx values (libmariadb error code) can be used too. The client plugin may set the error code and the error message directly in the MYSQL structure and return CR_ERROR. If a CR_xxx specific error code was returned, an error message in the MYSQL structure will be overwritten. If CR_ERROR is returned without setting the error in MYSQL, CR_UNKNOWN_ERROR will be user. */ #define CR_ERROR 0 /** Authentication (client part) was successful. It does not mean that the authentication as a whole was successful, usually it only means that the client was able to send the user name and the password to the server. If CR_OK is returned, the libmariadb reads the next packet expecting it to be one of OK, ERROR, or CHANGE_PLUGIN packets. */ #define CR_OK -1 /** Authentication was successful. It means that the client has done its part successfully and also that a plugin has read the last packet (one of OK, ERROR, CHANGE_PLUGIN). In this case, libmariadb will not read a packet from the server, but it will use the data at mysql->net.read_pos. A plugin may return this value if the number of roundtrips in the authentication protocol is not known in advance, and the client plugin needs to read one packet more to determine if the authentication is finished or not. */ #define CR_OK_HANDSHAKE_COMPLETE -2 typedef struct st_plugin_vio_info { enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET, MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol; int socket; /**< it's set, if the protocol is SOCKET or TCP */ #ifdef _WIN32 HANDLE handle; /**< it's set, if the protocol is PIPE or MEMORY */ #endif } MYSQL_PLUGIN_VIO_INFO; /** Provides plugin access to communication channel */ typedef struct st_plugin_vio { /** Plugin provides a pointer reference and this function sets it to the contents of any incoming packet. Returns the packet length, or -1 if the plugin should terminate. */ int (*read_packet)(struct st_plugin_vio *vio, unsigned char **buf); /** Plugin provides a buffer with data and the length and this function sends it as a packet. Returns 0 on success, 1 on failure. */ int (*write_packet)(struct st_plugin_vio *vio, const unsigned char *packet, int packet_len); /** Fills in a st_plugin_vio_info structure, providing the information about the connection. */ void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info); } MYSQL_PLUGIN_VIO; #endif my_config.h000064400000000224151031265040006662 0ustar00/* Do not edit this file directly, it was auto-generated by cmake */ #warning This file should not be included by clients, include only my_alloca.h000064400000000224151031265040006650 0ustar00/* Do not edit this file directly, it was auto-generated by cmake */ #warning This file should not be included by clients, include only mariadb_stmt.h000064400000022642151031265040007366 0ustar00/************************************************************************ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA Part of this code includes code from PHP's mysqlnd extension (written by Andrey Hristov, Georg Richter and Ulf Wendel), freely available from http://www.php.net/software *************************************************************************/ #define MYSQL_NO_DATA 100 #define MYSQL_DATA_TRUNCATED 101 #define MYSQL_DEFAULT_PREFETCH_ROWS (unsigned long) 1 /* Bind flags */ #define MADB_BIND_DUMMY 1 #define MARIADB_STMT_BULK_SUPPORTED(stmt)\ ((stmt)->mysql && \ (!((stmt)->mysql->server_capabilities & CLIENT_MYSQL) &&\ ((stmt)->mysql->extension->mariadb_server_capabilities & \ (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32)))) #define CLEAR_CLIENT_STMT_ERROR(a) \ do { \ (a)->last_errno= 0;\ strcpy((a)->sqlstate, "00000");\ (a)->last_error[0]= 0;\ } while (0) #define MYSQL_PS_SKIP_RESULT_W_LEN -1 #define MYSQL_PS_SKIP_RESULT_STR -2 #define STMT_ID_LENGTH 4 typedef struct st_mysql_stmt MYSQL_STMT; typedef MYSQL_RES* (*mysql_stmt_use_or_store_func)(MYSQL_STMT *); enum enum_stmt_attr_type { STMT_ATTR_UPDATE_MAX_LENGTH, STMT_ATTR_CURSOR_TYPE, STMT_ATTR_PREFETCH_ROWS, /* MariaDB only */ STMT_ATTR_PREBIND_PARAMS=200, STMT_ATTR_ARRAY_SIZE, STMT_ATTR_ROW_SIZE, STMT_ATTR_STATE, STMT_ATTR_CB_USER_DATA, STMT_ATTR_CB_PARAM, STMT_ATTR_CB_RESULT }; enum enum_cursor_type { CURSOR_TYPE_NO_CURSOR= 0, CURSOR_TYPE_READ_ONLY= 1, CURSOR_TYPE_FOR_UPDATE= 2, CURSOR_TYPE_SCROLLABLE= 4 }; enum enum_indicator_type { STMT_INDICATOR_NTS=-1, STMT_INDICATOR_NONE=0, STMT_INDICATOR_NULL=1, STMT_INDICATOR_DEFAULT=2, STMT_INDICATOR_IGNORE=3, STMT_INDICATOR_IGNORE_ROW=4 }; /* bulk PS flags */ #define STMT_BULK_FLAG_CLIENT_SEND_TYPES 128 #define STMT_BULK_FLAG_INSERT_ID_REQUEST 64 typedef enum mysql_stmt_state { MYSQL_STMT_INITTED = 0, MYSQL_STMT_PREPARED, MYSQL_STMT_EXECUTED, MYSQL_STMT_WAITING_USE_OR_STORE, MYSQL_STMT_USE_OR_STORE_CALLED, MYSQL_STMT_USER_FETCHING, /* fetch_row_buff or fetch_row_unbuf */ MYSQL_STMT_FETCH_DONE } enum_mysqlnd_stmt_state; typedef struct st_mysql_bind { unsigned long *length; /* output length pointer */ my_bool *is_null; /* Pointer to null indicator */ void *buffer; /* buffer to get/put data */ /* set this if you want to track data truncations happened during fetch */ my_bool *error; union { unsigned char *row_ptr; /* for the current data position */ char *indicator; /* indicator variable */ } u; void (*store_param_func)(NET *net, struct st_mysql_bind *param); void (*fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *, unsigned char **row); void (*skip_result)(struct st_mysql_bind *, MYSQL_FIELD *, unsigned char **row); /* output buffer length, must be set when fetching str/binary */ unsigned long buffer_length; unsigned long offset; /* offset position for char/binary fetch */ unsigned long length_value; /* Used if length is 0 */ unsigned int flags; /* special flags, e.g. for dummy bind */ unsigned int pack_length; /* Internal length for packed data */ enum enum_field_types buffer_type; /* buffer type */ my_bool error_value; /* used if error is 0 */ my_bool is_unsigned; /* set if integer type is unsigned */ my_bool long_data_used; /* If used with mysql_send_long_data */ my_bool is_null_value; /* Used if is_null is 0 */ void *extension; } MYSQL_BIND; typedef struct st_mysqlnd_upsert_result { unsigned int warning_count; unsigned int server_status; unsigned long long affected_rows; unsigned long long last_insert_id; } mysql_upsert_status; typedef struct st_mysql_cmd_buffer { unsigned char *buffer; size_t length; } MYSQL_CMD_BUFFER; typedef struct st_mysql_error_info { unsigned int error_no; char error[MYSQL_ERRMSG_SIZE+1]; char sqlstate[SQLSTATE_LENGTH + 1]; } mysql_error_info; typedef int (*mysql_stmt_fetch_row_func)(MYSQL_STMT *stmt, unsigned char **row); typedef void (*ps_result_callback)(void *data, unsigned int column, unsigned char **row); typedef my_bool (*ps_param_callback)(void *data, MYSQL_BIND *bind, unsigned int row_nr); struct st_mysql_stmt { MA_MEM_ROOT mem_root; MYSQL *mysql; unsigned long stmt_id; unsigned long flags;/* cursor is set here */ enum_mysqlnd_stmt_state state; MYSQL_FIELD *fields; unsigned int field_count; unsigned int param_count; unsigned char send_types_to_server; MYSQL_BIND *params; MYSQL_BIND *bind; MYSQL_DATA result; /* we don't use mysqlnd's result set logic */ MYSQL_ROWS *result_cursor; my_bool bind_result_done; my_bool bind_param_done; mysql_upsert_status upsert_status; unsigned int last_errno; char last_error[MYSQL_ERRMSG_SIZE+1]; char sqlstate[SQLSTATE_LENGTH + 1]; my_bool update_max_length; unsigned long prefetch_rows; LIST list; my_bool cursor_exists; void *extension; mysql_stmt_fetch_row_func fetch_row_func; unsigned int execute_count;/* count how many times the stmt was executed */ mysql_stmt_use_or_store_func default_rset_handler; unsigned char *request_buffer; unsigned int array_size; size_t row_size; unsigned int prebind_params; void *user_data; ps_result_callback result_callback; ps_param_callback param_callback; size_t request_length; }; typedef void (*ps_field_fetch_func)(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row); typedef struct st_mysql_perm_bind { ps_field_fetch_func func; /* should be signed int */ int pack_len; unsigned long max_len; } MYSQL_PS_CONVERSION; extern MYSQL_PS_CONVERSION mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1]; unsigned long ma_net_safe_read(MYSQL *mysql); void mysql_init_ps_subsystem(void); unsigned long net_field_length(unsigned char **packet); int ma_simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, size_t length, my_bool skipp_check, void *opt_arg); void stmt_set_error(MYSQL_STMT *stmt, unsigned int error_nr, const char *sqlstate, const char *format, ...); /* * function prototypes */ MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql); int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length); int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt); int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt); int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg, unsigned int column, unsigned long offset); int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt); unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT * stmt); my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *attr); my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *attr); my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); my_bool STDCALL mysql_stmt_close(MYSQL_STMT * stmt); my_bool STDCALL mysql_stmt_reset(MYSQL_STMT * stmt); my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt); my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length); MYSQL_RES *STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt); MYSQL_RES *STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt); unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT * stmt); const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt); const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt); MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET offset); MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt); void STDCALL mysql_stmt_data_seek(MYSQL_STMT *stmt, unsigned long long offset); unsigned long long STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt); unsigned long long STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt); unsigned long long STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt); unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt); int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt); my_bool STDCALL mysql_stmt_more_results(MYSQL_STMT *stmt); int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt, const char *stmt_str, size_t length); MYSQL_FIELD * STDCALL mariadb_stmt_fetch_fields(MYSQL_STMT *stmt); mysql_version.h000064400000000346151031265040007627 0ustar00/* Do not edit this file directly, it was auto-generated by cmake */ #warning This file should not be included by clients, include only #include #define LIBMYSQL_VERSION MARIADB_CLIENT_VERSION_STR mariadb_ctype.h000064400000005041151031265040007515 0ustar00/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA */ /* A better implementation of the UNIX ctype(3) library. Notes: my_global.h should be included before ctype.h */ #ifndef _mariadb_ctype_h #define _mariadb_ctype_h #include #ifdef __cplusplus extern "C" { #endif #define CHARSET_DIR "charsets/" #define MY_CS_NAME_SIZE 32 #define MADB_DEFAULT_CHARSET_NAME "latin1" #define MADB_DEFAULT_COLLATION_NAME "latin1_swedish_ci" #define MADB_AUTODETECT_CHARSET_NAME "auto" /* we use the mysqlnd implementation */ typedef struct ma_charset_info_st { unsigned int nr; /* so far only 1 byte for charset */ unsigned int state; const char *csname; const char *name; const char *dir; unsigned int codepage; const char *encoding; unsigned int char_minlen; unsigned int char_maxlen; unsigned int (*mb_charlen)(unsigned int c); unsigned int (*mb_valid)(const char *start, const char *end); } MARIADB_CHARSET_INFO; extern const MARIADB_CHARSET_INFO mariadb_compiled_charsets[]; extern MARIADB_CHARSET_INFO *ma_default_charset_info; extern MARIADB_CHARSET_INFO *ma_charset_bin; extern MARIADB_CHARSET_INFO *ma_charset_latin1; extern MARIADB_CHARSET_INFO *ma_charset_utf8_general_ci; extern MARIADB_CHARSET_INFO *ma_charset_utf16le_general_ci; MARIADB_CHARSET_INFO *find_compiled_charset(unsigned int cs_number); MARIADB_CHARSET_INFO *find_compiled_charset_by_name(const char *name); size_t mysql_cset_escape_quotes(const MARIADB_CHARSET_INFO *cset, char *newstr, const char *escapestr, size_t escapestr_len); size_t mysql_cset_escape_slashes(const MARIADB_CHARSET_INFO *cset, char *newstr, const char *escapestr, size_t escapestr_len); const char* madb_get_os_character_set(void); #ifdef _WIN32 int madb_get_windows_cp(const char *charset); #endif #ifdef __cplusplus } #endif #endif my_sys.h000064400000000224151031265040006233 0ustar00/* Do not edit this file directly, it was auto-generated by cmake */ #warning This file should not be included by clients, include only mariadb_com.h000064400000044522151031265040007156 0ustar00/************************************************************************************ Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB, Monty Program AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not see or write to the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor, Boston, MA 02110, USA Part of this code includes code from the PHP project which is freely available from http://www.php.net *************************************************************************************/ /* ** Common definition between mysql server & client */ #ifndef _mysql_com_h #define _mysql_com_h #define NAME_CHAR_LEN 64 #define NAME_LEN 256 /* Field/table name length */ #define HOSTNAME_LENGTH 255 #define SYSTEM_MB_MAX_CHAR_LENGTH 4 #define USERNAME_CHAR_LENGTH 128 #define USERNAME_LENGTH (USERNAME_CHAR_LENGTH * SYSTEM_MB_MAX_CHAR_LENGTH) #define SERVER_VERSION_LENGTH 60 #define SQLSTATE_LENGTH 5 #define SCRAMBLE_LENGTH 20 #define SCRAMBLE_LENGTH_323 8 #define LOCAL_HOST "localhost" #define LOCAL_HOST_NAMEDPIPE "." #if defined(_WIN32) && !defined( _CUSTOMCONFIG_) #define MARIADB_NAMEDPIPE "MySQL" #define MYSQL_SERVICENAME "MySql" #endif /* _WIN32 */ /* for use in mysql client tools only */ #define MYSQL_AUTODETECT_CHARSET_NAME "auto" #define BINCMP_FLAG 131072 enum Item_result {STRING_RESULT,REAL_RESULT,INT_RESULT,ROW_RESULT,DECIMAL_RESULT}; enum mysql_enum_shutdown_level { SHUTDOWN_DEFAULT = 0, KILL_QUERY= 254, KILL_CONNECTION= 255 }; enum enum_server_command { COM_SLEEP = 0, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, COM_TIME = 15, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, COM_TABLE_DUMP, COM_CONNECT_OUT = 20, COM_REGISTER_SLAVE, COM_STMT_PREPARE = 22, COM_STMT_EXECUTE = 23, COM_STMT_SEND_LONG_DATA = 24, COM_STMT_CLOSE = 25, COM_STMT_RESET = 26, COM_SET_OPTION = 27, COM_STMT_FETCH = 28, COM_DAEMON= 29, COM_UNSUPPORTED= 30, COM_RESET_CONNECTION = 31, COM_STMT_BULK_EXECUTE = 250, COM_RESERVED_1 = 254, /* former COM_MULTI, now removed */ COM_END }; #define NOT_NULL_FLAG 1 /* Field can't be NULL */ #define PRI_KEY_FLAG 2 /* Field is part of a primary key */ #define UNIQUE_KEY_FLAG 4 /* Field is part of a unique key */ #define MULTIPLE_KEY_FLAG 8 /* Field is part of a key */ #define BLOB_FLAG 16 /* Field is a blob */ #define UNSIGNED_FLAG 32 /* Field is unsigned */ #define ZEROFILL_FLAG 64 /* Field is zerofill */ #define BINARY_FLAG 128 /* The following are only sent to new clients */ #define ENUM_FLAG 256 /* field is an enum */ #define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */ #define TIMESTAMP_FLAG 1024 /* Field is a timestamp */ #define SET_FLAG 2048 /* field is a set */ /* new since 3.23.58 */ #define NO_DEFAULT_VALUE_FLAG 4096 /* Field doesn't have default value */ #define ON_UPDATE_NOW_FLAG 8192 /* Field is set to NOW on UPDATE */ /* end new */ #define NUM_FLAG 32768 /* Field is num (for clients) */ #define PART_KEY_FLAG 16384 /* Intern; Part of some key */ #define GROUP_FLAG 32768 /* Intern: Group field */ #define UNIQUE_FLAG 65536 /* Intern: Used by sql_yacc */ #define REFRESH_GRANT 1 /* Refresh grant tables */ #define REFRESH_LOG 2 /* Start on new log file */ #define REFRESH_TABLES 4 /* close all tables */ #define REFRESH_HOSTS 8 /* Flush host cache */ #define REFRESH_STATUS 16 /* Flush status variables */ #define REFRESH_THREADS 32 /* Flush thread cache */ #define REFRESH_SLAVE 64 /* Reset master info and restart slave thread */ #define REFRESH_MASTER 128 /* Remove all bin logs in the index and truncate the index */ /* The following can't be set with mysql_refresh() */ #define REFRESH_READ_LOCK 16384 /* Lock tables for read */ #define REFRESH_FAST 32768 /* Intern flag */ #define CLIENT_MYSQL 1 #define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ #define CLIENT_LONG_FLAG 4 /* Get all column flags */ #define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ #define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */ #define CLIENT_COMPRESS 32 /* Can use compression protocol */ #define CLIENT_ODBC 64 /* Odbc client */ #define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ #define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ #define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ #define CLIENT_SSL 2048 /* Switch to SSL after handshake */ #define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ #define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ /* added in 4.x */ #define CLIENT_PROTOCOL_41 512 #define CLIENT_RESERVED 16384 #define CLIENT_SECURE_CONNECTION 32768 #define CLIENT_MULTI_STATEMENTS (1UL << 16) #define CLIENT_MULTI_RESULTS (1UL << 17) #define CLIENT_PS_MULTI_RESULTS (1UL << 18) #define CLIENT_PLUGIN_AUTH (1UL << 19) #define CLIENT_CONNECT_ATTRS (1UL << 20) #define CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA (1UL << 21) #define CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS (1UL << 22) #define CLIENT_SESSION_TRACKING (1UL << 23) #define CLIENT_ZSTD_COMPRESSION (1UL << 26) #define CLIENT_PROGRESS (1UL << 29) /* client supports progress indicator */ #define CLIENT_PROGRESS_OBSOLETE CLIENT_PROGRESS #define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) #define CLIENT_SSL_VERIFY_SERVER_CERT_OBSOLETE CLIENT_SSL_VERIFY_SERVER_CERT #define CLIENT_REMEMBER_OPTIONS (1UL << 31) /* MariaDB-specific capabilities */ #define MARIADB_CLIENT_FLAGS 0xFFFFFFFF00000000ULL #define MARIADB_CLIENT_PROGRESS (1ULL << 32) #define MARIADB_CLIENT_RESERVED_1 (1ULL << 33) /* Former COM_MULTI, don't use */ #define MARIADB_CLIENT_STMT_BULK_OPERATIONS (1ULL << 34) /* support of extended data type/format information, since 10.5.0 */ #define MARIADB_CLIENT_EXTENDED_METADATA (1ULL << 35) /* Do not resend metadata for prepared statements, since 10.6*/ #define MARIADB_CLIENT_CACHE_METADATA (1ULL << 36) #define IS_MARIADB_EXTENDED_SERVER(mysql)\ (!(mysql->server_capabilities & CLIENT_MYSQL)) #define MARIADB_CLIENT_SUPPORTED_FLAGS (MARIADB_CLIENT_PROGRESS |\ MARIADB_CLIENT_STMT_BULK_OPERATIONS|\ MARIADB_CLIENT_EXTENDED_METADATA|\ MARIADB_CLIENT_CACHE_METADATA) #define CLIENT_SUPPORTED_FLAGS (CLIENT_MYSQL |\ CLIENT_FOUND_ROWS |\ CLIENT_LONG_FLAG |\ CLIENT_CONNECT_WITH_DB |\ CLIENT_NO_SCHEMA |\ CLIENT_COMPRESS |\ CLIENT_ODBC |\ CLIENT_LOCAL_FILES |\ CLIENT_IGNORE_SPACE |\ CLIENT_INTERACTIVE |\ CLIENT_SSL |\ CLIENT_IGNORE_SIGPIPE |\ CLIENT_TRANSACTIONS |\ CLIENT_PROTOCOL_41 |\ CLIENT_RESERVED |\ CLIENT_SECURE_CONNECTION |\ CLIENT_MULTI_STATEMENTS |\ CLIENT_MULTI_RESULTS |\ CLIENT_PROGRESS |\ CLIENT_SSL_VERIFY_SERVER_CERT |\ CLIENT_REMEMBER_OPTIONS |\ CLIENT_PLUGIN_AUTH |\ CLIENT_SESSION_TRACKING |\ CLIENT_CONNECT_ATTRS) #define CLIENT_ALLOWED_FLAGS (CLIENT_SUPPORTED_FLAGS |\ CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA |\ CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS |\ CLIENT_ZSTD_COMPRESSION |\ CLIENT_PS_MULTI_RESULTS |\ CLIENT_REMEMBER_OPTIONS) #define CLIENT_CAPABILITIES (CLIENT_MYSQL | \ CLIENT_LONG_FLAG |\ CLIENT_TRANSACTIONS |\ CLIENT_SECURE_CONNECTION |\ CLIENT_MULTI_RESULTS | \ CLIENT_PS_MULTI_RESULTS |\ CLIENT_PROTOCOL_41 |\ CLIENT_PLUGIN_AUTH |\ CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \ CLIENT_SESSION_TRACKING |\ CLIENT_CONNECT_ATTRS) #define CLIENT_DEFAULT_FLAGS ((CLIENT_SUPPORTED_FLAGS & ~CLIENT_COMPRESS)\ & ~CLIENT_SSL) #define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */ #define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ #define SERVER_MORE_RESULTS_EXIST 8 #define SERVER_QUERY_NO_GOOD_INDEX_USED 16 #define SERVER_QUERY_NO_INDEX_USED 32 #define SERVER_STATUS_CURSOR_EXISTS 64 #define SERVER_STATUS_LAST_ROW_SENT 128 #define SERVER_STATUS_DB_DROPPED 256 #define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512 #define SERVER_STATUS_METADATA_CHANGED 1024 #define SERVER_QUERY_WAS_SLOW 2048 #define SERVER_PS_OUT_PARAMS 4096 #define SERVER_STATUS_IN_TRANS_READONLY 8192 #define SERVER_SESSION_STATE_CHANGED 16384 #define SERVER_STATUS_ANSI_QUOTES 32768 #define MYSQL_ERRMSG_SIZE 512 #define NET_READ_TIMEOUT 30 /* Timeout on read */ #define NET_WRITE_TIMEOUT 60 /* Timeout on write */ #define NET_WAIT_TIMEOUT (8*60*60) /* Wait for new query */ /* for server integration (mysqlbinlog) */ #define LIST_PROCESS_HOST_LEN 64 #define MYSQL50_TABLE_NAME_PREFIX "#mysql50#" #define MYSQL50_TABLE_NAME_PREFIX_LENGTH (sizeof(MYSQL50_TABLE_NAME_PREFIX)-1) #define SAFE_NAME_LEN (NAME_LEN + MYSQL50_TABLE_NAME_PREFIX_LENGTH) struct st_ma_pvio; typedef struct st_ma_pvio MARIADB_PVIO; #define MAX_CHAR_WIDTH 255 /* Max length for a CHAR column */ #define MAX_BLOB_WIDTH 8192 /* Default width for blob */ /* the following defines were added for PHP's mysqli and pdo extensions: see: CONC-56 */ #define MAX_TINYINT_WIDTH 3 #define MAX_SMALLINT_WIDTH 5 #define MAX_MEDIUMINT_WIDTH 8 #define MAX_INT_WIDTH 10 #define MAX_BIGINT_WIDTH 20 struct st_ma_connection_plugin; typedef struct st_net { MARIADB_PVIO *pvio; unsigned char *buff; unsigned char *buff_end,*write_pos,*read_pos; my_socket fd; /* For Perl DBI/dbd */ unsigned long remain_in_buf,length; unsigned long buf_length, where_b; unsigned long max_packet, max_packet_size; unsigned int pkt_nr, compress_pkt_nr; unsigned int write_timeout, read_timeout, retry_count; int fcntl; unsigned int *return_status; unsigned char reading_or_writing; char save_char; char unused_1; my_bool unused_2; my_bool compress; my_bool unused_3; void *unused_4; unsigned int last_errno; unsigned char error; my_bool unused_5; my_bool unused_6; char last_error[MYSQL_ERRMSG_SIZE]; char sqlstate[SQLSTATE_LENGTH+1]; struct st_mariadb_net_extension *extension; } NET; #define packet_error ((unsigned int) -1) /* used by mysql_set_server_option */ enum enum_mysql_set_option { MYSQL_OPTION_MULTI_STATEMENTS_ON, MYSQL_OPTION_MULTI_STATEMENTS_OFF }; /* for status callback function */ enum enum_mariadb_status_info { STATUS_TYPE= 0, SESSION_TRACK_TYPE }; enum enum_session_state_type { SESSION_TRACK_SYSTEM_VARIABLES= 0, SESSION_TRACK_SCHEMA, SESSION_TRACK_STATE_CHANGE, /* currently not supported by MariaDB Server */ SESSION_TRACK_GTIDS, SESSION_TRACK_TRANSACTION_CHARACTERISTICS, SESSION_TRACK_TRANSACTION_STATE /* make sure that SESSION_TRACK_END always points to last element of enum !! */ }; #define SESSION_TRACK_BEGIN 0 #define SESSION_TRACK_END SESSION_TRACK_TRANSACTION_STATE #define SESSION_TRACK_TYPES (SESSION_TRACK_END + 1) /* SESSION_TRACK_TRANSACTION_TYPE was renamed to SESSION_TRACK_TRANSACTION_STATE in 3e699a1738cdfb0a2c5b8eabfa8301b8d11cf711. This is a workaround to prevent breaking of travis and buildbot tests. TODO: Remove this after server fixes */ #define SESSION_TRACK_TRANSACTION_TYPE SESSION_TRACK_TRANSACTION_STATE enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE, MYSQL_TYPE_NULL, MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24, MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR, MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR, MYSQL_TYPE_BIT, /* the following types are not used by client, only for mysqlbinlog!! */ MYSQL_TYPE_TIMESTAMP2, MYSQL_TYPE_DATETIME2, MYSQL_TYPE_TIME2, /* --------------------------------------------- */ MYSQL_TYPE_JSON=245, MYSQL_TYPE_NEWDECIMAL=246, MYSQL_TYPE_ENUM=247, MYSQL_TYPE_SET=248, MYSQL_TYPE_TINY_BLOB=249, MYSQL_TYPE_MEDIUM_BLOB=250, MYSQL_TYPE_LONG_BLOB=251, MYSQL_TYPE_BLOB=252, MYSQL_TYPE_VAR_STRING=253, MYSQL_TYPE_STRING=254, MYSQL_TYPE_GEOMETRY=255, MAX_NO_FIELD_TYPES }; #define FIELD_TYPE_CHAR FIELD_TYPE_TINY /* For compatibility */ #define FIELD_TYPE_INTERVAL FIELD_TYPE_ENUM /* For compatibility */ #define FIELD_TYPE_DECIMAL MYSQL_TYPE_DECIMAL #define FIELD_TYPE_NEWDECIMAL MYSQL_TYPE_NEWDECIMAL #define FIELD_TYPE_TINY MYSQL_TYPE_TINY #define FIELD_TYPE_SHORT MYSQL_TYPE_SHORT #define FIELD_TYPE_LONG MYSQL_TYPE_LONG #define FIELD_TYPE_FLOAT MYSQL_TYPE_FLOAT #define FIELD_TYPE_DOUBLE MYSQL_TYPE_DOUBLE #define FIELD_TYPE_NULL MYSQL_TYPE_NULL #define FIELD_TYPE_TIMESTAMP MYSQL_TYPE_TIMESTAMP #define FIELD_TYPE_LONGLONG MYSQL_TYPE_LONGLONG #define FIELD_TYPE_INT24 MYSQL_TYPE_INT24 #define FIELD_TYPE_DATE MYSQL_TYPE_DATE #define FIELD_TYPE_TIME MYSQL_TYPE_TIME #define FIELD_TYPE_DATETIME MYSQL_TYPE_DATETIME #define FIELD_TYPE_YEAR MYSQL_TYPE_YEAR #define FIELD_TYPE_NEWDATE MYSQL_TYPE_NEWDATE #define FIELD_TYPE_ENUM MYSQL_TYPE_ENUM #define FIELD_TYPE_SET MYSQL_TYPE_SET #define FIELD_TYPE_TINY_BLOB MYSQL_TYPE_TINY_BLOB #define FIELD_TYPE_MEDIUM_BLOB MYSQL_TYPE_MEDIUM_BLOB #define FIELD_TYPE_LONG_BLOB MYSQL_TYPE_LONG_BLOB #define FIELD_TYPE_BLOB MYSQL_TYPE_BLOB #define FIELD_TYPE_VAR_STRING MYSQL_TYPE_VAR_STRING #define FIELD_TYPE_STRING MYSQL_TYPE_STRING #define FIELD_TYPE_GEOMETRY MYSQL_TYPE_GEOMETRY #define FIELD_TYPE_BIT MYSQL_TYPE_BIT extern unsigned long max_allowed_packet; extern unsigned long net_buffer_length; #define net_new_transaction(net) ((net)->pkt_nr=0) int ma_net_init(NET *net, MARIADB_PVIO *pvio); void ma_net_end(NET *net); void ma_net_clear(NET *net); int ma_net_flush(NET *net); int ma_net_write(NET *net,const unsigned char *packet, size_t len); int ma_net_write_command(NET *net,unsigned char command,const char *packet, size_t len, my_bool disable_flush); int ma_net_real_write(NET *net,const char *packet, size_t len); extern unsigned long ma_net_read(NET *net); struct rand_struct { unsigned long seed1,seed2,max_value; double max_value_dbl; }; /* The following is for user defined functions */ typedef struct st_udf_args { unsigned int arg_count; /* Number of arguments */ enum Item_result *arg_type; /* Pointer to item_results */ char **args; /* Pointer to argument */ unsigned long *lengths; /* Length of string arguments */ char *maybe_null; /* Set to 1 for all maybe_null args */ } UDF_ARGS; /* This holds information about the result */ typedef struct st_udf_init { my_bool maybe_null; /* 1 if function can return NULL */ unsigned int decimals; /* for real functions */ unsigned int max_length; /* For string functions */ char *ptr; /* free pointer for function data */ my_bool const_item; /* 0 if result is independent of arguments */ } UDF_INIT; /* Connection types */ #define MARIADB_CONNECTION_UNIXSOCKET 0 #define MARIADB_CONNECTION_TCP 1 #define MARIADB_CONNECTION_NAMEDPIPE 2 #define MARIADB_CONNECTION_SHAREDMEM 3 /* Constants when using compression */ #define NET_HEADER_SIZE 4 /* standard header size */ #define COMP_HEADER_SIZE 3 /* compression header extra size */ /* Prototypes to password functions */ #define native_password_plugin_name "mysql_native_password" #define old_password_plugin_name "mysql_old_password" #ifdef __cplusplus extern "C" { #endif char *ma_scramble_323(char *to,const char *message,const char *password); void ma_scramble_41(const unsigned char *buffer, const char *scramble, const char *password); void ma_hash_password(unsigned long *result, const char *password, size_t len); void ma_make_scrambled_password(char *to,const char *password); /* Some other useful functions */ void mariadb_load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv); my_bool ma_thread_init(void); void ma_thread_end(void); #ifdef __cplusplus } #endif #define NULL_LENGTH ((unsigned long) ~0) /* For net_store_length */ #endif mysql.h000064400000121625151031265040006066 0ustar00/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB 2012 by MontyProgram AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA */ /* defines for the libmariadb library */ #ifndef _mysql_h #define _mysql_h #ifdef __cplusplus extern "C" { #endif #ifndef LIBMARIADB #define LIBMARIADB #endif #ifndef MYSQL_CLIENT #define MYSQL_CLIENT #endif #include #if !defined (_global_h) && !defined (MY_GLOBAL_INCLUDED) /* If not standard header */ #include typedef char my_bool; typedef unsigned long long my_ulonglong; #if !defined(_WIN32) #define STDCALL #else #define STDCALL __stdcall #endif #ifndef my_socket_defined #define my_socket_defined #if defined(_WIN64) #define my_socket unsigned long long #elif defined(_WIN32) #define my_socket unsigned int #else typedef int my_socket; #endif #endif #endif #include "mariadb_com.h" #include "mariadb_version.h" #include "ma_list.h" #include "mariadb_ctype.h" typedef struct st_ma_const_string { const char *str; size_t length; } MARIADB_CONST_STRING; typedef struct st_ma_const_data { const unsigned char *data; size_t length; } MARIADB_CONST_DATA; #ifndef ST_MA_USED_MEM_DEFINED #define ST_MA_USED_MEM_DEFINED typedef struct st_ma_used_mem { /* struct for once_alloc */ struct st_ma_used_mem *next; /* Next block in use */ size_t left; /* memory left in block */ size_t size; /* Size of block */ } MA_USED_MEM; typedef struct st_ma_mem_root { MA_USED_MEM *free; MA_USED_MEM *used; MA_USED_MEM *pre_alloc; size_t min_malloc; size_t block_size; unsigned int block_num; unsigned int first_block_usage; void (*error_handler)(void); } MA_MEM_ROOT; #endif extern unsigned int mysql_port; extern char *mysql_unix_port; extern unsigned int mariadb_deinitialize_ssl; #define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG) #define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG) #define IS_BLOB(n) ((n) & BLOB_FLAG) #define IS_NUM(t) (((t) <= MYSQL_TYPE_INT24 && (t) != MYSQL_TYPE_TIMESTAMP) || (t) == MYSQL_TYPE_YEAR || (t) == MYSQL_TYPE_NEWDECIMAL) #define IS_NUM_FIELD(f) ((f)->flags & NUM_FLAG) #define INTERNAL_NUM_FIELD(f) (((f)->type <= MYSQL_TYPE_INT24 && ((f)->type != MYSQL_TYPE_TIMESTAMP || (f)->length == 14 || (f)->length == 8)) || (f)->type == MYSQL_TYPE_YEAR || (f)->type == MYSQL_TYPE_NEWDECIMAL || (f)->type == MYSQL_TYPE_DECIMAL) typedef struct st_mysql_field { char *name; /* Name of column */ char *org_name; /* Name of original column (added after 3.23.58) */ char *table; /* Table of column if column was a field */ char *org_table; /* Name of original table (added after 3.23.58 */ char *db; /* table schema (added after 3.23.58) */ char *catalog; /* table catalog (added after 3.23.58) */ char *def; /* Default value (set by mysql_list_fields) */ unsigned long length; /* Width of column */ unsigned long max_length; /* Max width of selected set */ /* added after 3.23.58 */ unsigned int name_length; unsigned int org_name_length; unsigned int table_length; unsigned int org_table_length; unsigned int db_length; unsigned int catalog_length; unsigned int def_length; /***********************/ unsigned int flags; /* Div flags */ unsigned int decimals; /* Number of decimals in field */ unsigned int charsetnr; /* char set number (added in 4.1) */ enum enum_field_types type; /* Type of field. Se mysql_com.h for types */ void *extension; /* added in 4.1 */ } MYSQL_FIELD; typedef char **MYSQL_ROW; /* return data as array of strings */ typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */ #define SET_CLIENT_ERROR(a, b, c, d) \ do { \ (a)->net.last_errno= (b);\ strncpy((a)->net.sqlstate, (c), SQLSTATE_LENGTH);\ (a)->net.sqlstate[SQLSTATE_LENGTH]= 0;\ strncpy((a)->net.last_error, (d) ? (d) : ER((b)), MYSQL_ERRMSG_SIZE - 1);\ (a)->net.last_error[MYSQL_ERRMSG_SIZE - 1]= 0;\ } while(0) /* For mysql_async.c */ #define set_mariadb_error(A,B,C) SET_CLIENT_ERROR((A),(B),(C),0) extern const char *SQLSTATE_UNKNOWN; #define unknown_sqlstate SQLSTATE_UNKNOWN #define CLEAR_CLIENT_ERROR(a) \ do { \ (a)->net.last_errno= 0;\ strcpy((a)->net.sqlstate, "00000");\ (a)->net.last_error[0]= '\0';\ if ((a)->net.extension)\ (a)->net.extension->extended_errno= 0;\ } while (0) #define MYSQL_COUNT_ERROR (~(unsigned long long) 0) typedef struct st_mysql_rows { struct st_mysql_rows *next; /* list of rows */ MYSQL_ROW data; unsigned long length; } MYSQL_ROWS; typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */ typedef struct st_mysql_data { MYSQL_ROWS *data; void *embedded_info; MA_MEM_ROOT alloc; unsigned long long rows; unsigned int fields; void *extension; } MYSQL_DATA; enum mysql_option { MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE, MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE, MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT, MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, MYSQL_OPT_BIND, MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT, MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER, MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH, /* Connection attribute options */ MYSQL_OPT_CONNECT_ATTR_RESET, MYSQL_OPT_CONNECT_ATTR_ADD, MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_SERVER_PUBLIC_KEY, MYSQL_ENABLE_CLEARTEXT_PLUGIN, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, MYSQL_OPT_SSL_ENFORCE, MYSQL_OPT_MAX_ALLOWED_PACKET, MYSQL_OPT_NET_BUFFER_LENGTH, MYSQL_OPT_TLS_VERSION, MYSQL_OPT_ZSTD_COMPRESSION_LEVEL, /* MariaDB-specific */ MYSQL_PROGRESS_CALLBACK=5999, MYSQL_OPT_NONBLOCK, /* MariaDB Connector/C specific */ MYSQL_DATABASE_DRIVER=7000, MARIADB_OPT_SSL_FP, /* deprecated, use MARIADB_OPT_TLS_PEER_FP instead */ MARIADB_OPT_SSL_FP_LIST, /* deprecated, use MARIADB_OPT_TLS_PEER_FP_LIST instead */ MARIADB_OPT_TLS_PASSPHRASE, /* passphrase for encrypted certificates */ MARIADB_OPT_TLS_CIPHER_STRENGTH, MARIADB_OPT_TLS_VERSION, MARIADB_OPT_TLS_PEER_FP, /* single finger print for server certificate verification */ MARIADB_OPT_TLS_PEER_FP_LIST, /* finger print white list for server certificate verification */ MARIADB_OPT_CONNECTION_READ_ONLY, MYSQL_OPT_CONNECT_ATTRS, /* for mysql_get_optionv */ MARIADB_OPT_USERDATA, MARIADB_OPT_CONNECTION_HANDLER, MARIADB_OPT_PORT, MARIADB_OPT_UNIXSOCKET, MARIADB_OPT_PASSWORD, MARIADB_OPT_HOST, MARIADB_OPT_USER, MARIADB_OPT_SCHEMA, MARIADB_OPT_DEBUG, MARIADB_OPT_FOUND_ROWS, MARIADB_OPT_MULTI_RESULTS, MARIADB_OPT_MULTI_STATEMENTS, MARIADB_OPT_INTERACTIVE, MARIADB_OPT_PROXY_HEADER, MARIADB_OPT_IO_WAIT, MARIADB_OPT_SKIP_READ_RESPONSE, MARIADB_OPT_RESTRICTED_AUTH, MARIADB_OPT_RPL_REGISTER_REPLICA, MARIADB_OPT_STATUS_CALLBACK, MARIADB_OPT_SERVER_PLUGINS }; enum mariadb_value { MARIADB_CHARSET_ID, MARIADB_CHARSET_NAME, MARIADB_CLIENT_ERRORS, MARIADB_CLIENT_VERSION, MARIADB_CLIENT_VERSION_ID, MARIADB_CONNECTION_ASYNC_TIMEOUT, MARIADB_CONNECTION_ASYNC_TIMEOUT_MS, MARIADB_CONNECTION_MARIADB_CHARSET_INFO, MARIADB_CONNECTION_ERROR, MARIADB_CONNECTION_ERROR_ID, MARIADB_CONNECTION_HOST, MARIADB_CONNECTION_INFO, MARIADB_CONNECTION_PORT, MARIADB_CONNECTION_PROTOCOL_VERSION_ID, MARIADB_CONNECTION_PVIO_TYPE, MARIADB_CONNECTION_SCHEMA, MARIADB_CONNECTION_SERVER_TYPE, MARIADB_CONNECTION_SERVER_VERSION, MARIADB_CONNECTION_SERVER_VERSION_ID, MARIADB_CONNECTION_SOCKET, MARIADB_CONNECTION_SQLSTATE, MARIADB_CONNECTION_SSL_CIPHER, MARIADB_TLS_LIBRARY, MARIADB_CONNECTION_TLS_VERSION, MARIADB_CONNECTION_TLS_VERSION_ID, MARIADB_CONNECTION_TYPE, MARIADB_CONNECTION_UNIX_SOCKET, MARIADB_CONNECTION_USER, MARIADB_MAX_ALLOWED_PACKET, MARIADB_NET_BUFFER_LENGTH, MARIADB_CONNECTION_SERVER_STATUS, MARIADB_CONNECTION_SERVER_CAPABILITIES, MARIADB_CONNECTION_EXTENDED_SERVER_CAPABILITIES, MARIADB_CONNECTION_CLIENT_CAPABILITIES, MARIADB_CONNECTION_BYTES_READ, MARIADB_CONNECTION_BYTES_SENT }; enum mysql_status { MYSQL_STATUS_READY, MYSQL_STATUS_GET_RESULT, MYSQL_STATUS_USE_RESULT, MYSQL_STATUS_QUERY_SENT, MYSQL_STATUS_SENDING_LOAD_DATA, MYSQL_STATUS_FETCHING_DATA, MYSQL_STATUS_NEXT_RESULT_PENDING, MYSQL_STATUS_QUIT_SENT, /* object is "destroyed" at this stage */ MYSQL_STATUS_STMT_RESULT }; enum mysql_protocol_type { MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET, MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY }; struct st_mysql_options { unsigned int connect_timeout, read_timeout, write_timeout; unsigned int port, protocol; unsigned long client_flag; char *host,*user,*password,*unix_socket,*db; struct st_dynamic_array *init_command; char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name; char *ssl_key; /* PEM key file */ char *ssl_cert; /* PEM cert file */ char *ssl_ca; /* PEM CA file */ char *ssl_capath; /* PEM directory of CA-s? */ char *ssl_cipher; char *shared_memory_base_name; unsigned long max_allowed_packet; my_bool use_ssl; /* if to use SSL or not */ my_bool compress,named_pipe; my_bool reconnect, unused_1, unused_2, unused_3; enum mysql_option methods_to_use; char *bind_address; my_bool secure_auth; my_bool report_data_truncation; /* function pointers for local infile support */ int (*local_infile_init)(void **, const char *, void *); int (*local_infile_read)(void *, char *, unsigned int); void (*local_infile_end)(void *); int (*local_infile_error)(void *, char *, unsigned int); void *local_infile_userdata; struct st_mysql_options_extension *extension; }; typedef struct st_mysql { NET net; /* Communication parameters */ void *unused_0; char *host,*user,*passwd,*unix_socket,*server_version,*host_info; char *info,*db; const struct ma_charset_info_st *charset; /* character set */ MYSQL_FIELD *fields; MA_MEM_ROOT field_alloc; unsigned long long affected_rows; unsigned long long insert_id; /* id if insert on table with NEXTNR */ unsigned long long extra_info; /* Used by mysqlshow */ unsigned long thread_id; /* Id for connection in server */ unsigned long packet_length; unsigned int port; unsigned long client_flag; unsigned long server_capabilities; unsigned int protocol_version; unsigned int field_count; unsigned int server_status; unsigned int server_language; unsigned int warning_count; /* warning count, added in 4.1 protocol */ struct st_mysql_options options; enum mysql_status status; my_bool free_me; /* If free in mysql_close */ my_bool unused_1; char scramble_buff[20+ 1]; /* madded after 3.23.58 */ my_bool unused_2; void *unused_3, *unused_4, *unused_5, *unused_6; LIST *stmts; const struct st_mariadb_methods *methods; void *thd; my_bool *unbuffered_fetch_owner; char *info_buffer; struct st_mariadb_extension *extension; } MYSQL; typedef struct st_mysql_res { unsigned long long row_count; unsigned int field_count, current_field; MYSQL_FIELD *fields; MYSQL_DATA *data; MYSQL_ROWS *data_cursor; MA_MEM_ROOT field_alloc; MYSQL_ROW row; /* If unbuffered read */ MYSQL_ROW current_row; /* buffer to current row */ unsigned long *lengths; /* column lengths of current row */ MYSQL *handle; /* for unbuffered reads */ my_bool eof; /* Used my mysql_fetch_row */ my_bool is_ps; } MYSQL_RES; typedef struct { unsigned long *p_max_allowed_packet; unsigned long *p_net_buffer_length; void *extension; } MYSQL_PARAMETERS; enum mariadb_field_attr_t { MARIADB_FIELD_ATTR_DATA_TYPE_NAME= 0, MARIADB_FIELD_ATTR_FORMAT_NAME= 1 }; #define MARIADB_FIELD_ATTR_LAST MARIADB_FIELD_ATTR_FORMAT_NAME int STDCALL mariadb_field_attr(MARIADB_CONST_STRING *attr, const MYSQL_FIELD *field, enum mariadb_field_attr_t type); #ifndef _mysql_time_h_ enum enum_mysql_timestamp_type { MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1, MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2 }; typedef struct st_mysql_time { unsigned int year, month, day, hour, minute, second; unsigned long second_part; my_bool neg; enum enum_mysql_timestamp_type time_type; } MYSQL_TIME; #define AUTO_SEC_PART_DIGITS 39 #endif #define SEC_PART_DIGITS 6 #define MARIADB_INVALID_SOCKET -1 /* Asynchronous API constants */ #define MYSQL_WAIT_READ 1 #define MYSQL_WAIT_WRITE 2 #define MYSQL_WAIT_EXCEPT 4 #define MYSQL_WAIT_TIMEOUT 8 typedef struct character_set { unsigned int number; /* character set number */ unsigned int state; /* character set state */ const char *csname; /* character set name */ const char *name; /* collation name */ const char *comment; /* comment */ const char *dir; /* character set directory */ unsigned int mbminlen; /* min. length for multibyte strings */ unsigned int mbmaxlen; /* max. length for multibyte strings */ } MY_CHARSET_INFO; /* Local infile support functions */ #define LOCAL_INFILE_ERROR_LEN 512 #include "mariadb_stmt.h" #ifndef MYSQL_CLIENT_PLUGIN_HEADER #define MYSQL_CLIENT_PLUGIN_HEADER \ int type; \ unsigned int interface_version; \ const char *name; \ const char *author; \ const char *desc; \ unsigned int version[3]; \ const char *license; \ void *mysql_api; \ int (*init)(char *, size_t, int, va_list); \ int (*deinit)(void); \ int (*options)(const char *option, const void *); struct st_mysql_client_plugin { MYSQL_CLIENT_PLUGIN_HEADER }; struct st_mysql_client_plugin * mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, int argc, ...); struct st_mysql_client_plugin * STDCALL mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type, int argc, va_list args); struct st_mysql_client_plugin * STDCALL mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type); struct st_mysql_client_plugin * STDCALL mysql_client_register_plugin(struct st_mysql *mysql, struct st_mysql_client_plugin *plugin); #endif void STDCALL mysql_set_local_infile_handler(MYSQL *mysql, int (*local_infile_init)(void **, const char *, void *), int (*local_infile_read)(void *, char *, unsigned int), void (*local_infile_end)(void *), int (*local_infile_error)(void *, char*, unsigned int), void *); void mysql_set_local_infile_default(MYSQL *mysql); void my_set_error(MYSQL *mysql, unsigned int error_nr, const char *sqlstate, const char *format, ...); /* Functions to get information from the MYSQL and MYSQL_RES structures */ /* Should definitely be used if one uses shared libraries */ my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res); unsigned int STDCALL mysql_num_fields(MYSQL_RES *res); my_bool STDCALL mysql_eof(MYSQL_RES *res); MYSQL_FIELD *STDCALL mysql_fetch_field_direct(MYSQL_RES *res, unsigned int fieldnr); MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res); MYSQL_ROWS * STDCALL mysql_row_tell(MYSQL_RES *res); unsigned int STDCALL mysql_field_tell(MYSQL_RES *res); unsigned int STDCALL mysql_field_count(MYSQL *mysql); my_bool STDCALL mysql_more_results(MYSQL *mysql); int STDCALL mysql_next_result(MYSQL *mysql); my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql); my_bool STDCALL mysql_autocommit(MYSQL *mysql, my_bool mode); my_bool STDCALL mysql_commit(MYSQL *mysql); my_bool STDCALL mysql_rollback(MYSQL *mysql); my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql); unsigned int STDCALL mysql_errno(MYSQL *mysql); const char * STDCALL mysql_error(MYSQL *mysql); const char * STDCALL mysql_info(MYSQL *mysql); unsigned long STDCALL mysql_thread_id(MYSQL *mysql); const char * STDCALL mysql_character_set_name(MYSQL *mysql); void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs); int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname); my_bool mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void *arg, ...); my_bool STDCALL mariadb_get_info(MYSQL *mysql, enum mariadb_value value, void *arg); MYSQL * STDCALL mysql_init(MYSQL *mysql); int STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); const char * STDCALL mysql_get_ssl_cipher(MYSQL *mysql); my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, const char *passwd, const char *db); MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); void STDCALL mysql_close(MYSQL *sock); int STDCALL mysql_select_db(MYSQL *mysql, const char *db); int STDCALL mysql_query(MYSQL *mysql, const char *q); int STDCALL mysql_send_query(MYSQL *mysql, const char *q, unsigned long length); my_bool STDCALL mysql_read_query_result(MYSQL *mysql); int STDCALL mysql_real_query(MYSQL *mysql, const char *q, unsigned long length); int STDCALL mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level); int STDCALL mysql_dump_debug_info(MYSQL *mysql); int STDCALL mysql_refresh(MYSQL *mysql, unsigned int refresh_options); int STDCALL mysql_kill(MYSQL *mysql,unsigned long pid); int STDCALL mysql_ping(MYSQL *mysql); char * STDCALL mysql_stat(MYSQL *mysql); char * STDCALL mysql_get_server_info(MYSQL *mysql); unsigned long STDCALL mysql_get_server_version(MYSQL *mysql); char * STDCALL mysql_get_host_info(MYSQL *mysql); unsigned int STDCALL mysql_get_proto_info(MYSQL *mysql); MYSQL_RES * STDCALL mysql_list_dbs(MYSQL *mysql,const char *wild); MYSQL_RES * STDCALL mysql_list_tables(MYSQL *mysql,const char *wild); MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table, const char *wild); MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql); MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql); MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql); int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg); int STDCALL mysql_options4(MYSQL *mysql,enum mysql_option option, const void *arg1, const void *arg2); void STDCALL mysql_free_result(MYSQL_RES *result); void STDCALL mysql_data_seek(MYSQL_RES *result, unsigned long long offset); MYSQL_ROW_OFFSET STDCALL mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET); MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset); MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result); unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result); MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result); unsigned long STDCALL mysql_escape_string(char *to,const char *from, unsigned long from_length); unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); unsigned int STDCALL mysql_thread_safe(void); unsigned int STDCALL mysql_warning_count(MYSQL *mysql); const char * STDCALL mysql_sqlstate(MYSQL *mysql); int STDCALL mysql_server_init(int argc, char **argv, char **groups); void STDCALL mysql_server_end(void); void STDCALL mysql_thread_end(void); my_bool STDCALL mysql_thread_init(void); int STDCALL mysql_set_server_option(MYSQL *mysql, enum enum_mysql_set_option option); const char * STDCALL mysql_get_client_info(void); unsigned long STDCALL mysql_get_client_version(void); my_bool STDCALL mariadb_connection(MYSQL *mysql); const char * STDCALL mysql_get_server_name(MYSQL *mysql); MARIADB_CHARSET_INFO * STDCALL mariadb_get_charset_by_name(const char *csname); MARIADB_CHARSET_INFO * STDCALL mariadb_get_charset_by_nr(unsigned int csnr); size_t STDCALL mariadb_convert_string(const char *from, size_t *from_len, MARIADB_CHARSET_INFO *from_cs, char *to, size_t *to_len, MARIADB_CHARSET_INFO *to_cs, int *errorcode); int mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...); int mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...); int STDCALL mysql_get_option(MYSQL *mysql, enum mysql_option option, void *arg); unsigned long STDCALL mysql_hex_string(char *to, const char *from, unsigned long len); my_socket STDCALL mysql_get_socket(MYSQL *mysql); unsigned int STDCALL mysql_get_timeout_value(const MYSQL *mysql); unsigned int STDCALL mysql_get_timeout_value_ms(const MYSQL *mysql); my_bool STDCALL mariadb_reconnect(MYSQL *mysql); int STDCALL mariadb_cancel(MYSQL *mysql); void STDCALL mysql_debug(const char *debug); unsigned long STDCALL mysql_net_read_packet(MYSQL *mysql); unsigned long STDCALL mysql_net_field_length(unsigned char **packet); my_bool STDCALL mysql_embedded(void); MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void); /* Async API */ int STDCALL mysql_close_start(MYSQL *sock); int STDCALL mysql_close_cont(MYSQL *sock, int status); int STDCALL mysql_commit_start(my_bool *ret, MYSQL * mysql); int STDCALL mysql_commit_cont(my_bool *ret, MYSQL * mysql, int status); int STDCALL mysql_dump_debug_info_cont(int *ret, MYSQL *mysql, int ready_status); int STDCALL mysql_dump_debug_info_start(int *ret, MYSQL *mysql); int STDCALL mysql_rollback_start(my_bool *ret, MYSQL * mysql); int STDCALL mysql_rollback_cont(my_bool *ret, MYSQL * mysql, int status); int STDCALL mysql_autocommit_start(my_bool *ret, MYSQL * mysql, my_bool auto_mode); int STDCALL mysql_list_fields_cont(MYSQL_RES **ret, MYSQL *mysql, int ready_status); int STDCALL mysql_list_fields_start(MYSQL_RES **ret, MYSQL *mysql, const char *table, const char *wild); int STDCALL mysql_autocommit_cont(my_bool *ret, MYSQL * mysql, int status); int STDCALL mysql_next_result_start(int *ret, MYSQL *mysql); int STDCALL mysql_next_result_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_select_db_start(int *ret, MYSQL *mysql, const char *db); int STDCALL mysql_select_db_cont(int *ret, MYSQL *mysql, int ready_status); int STDCALL mysql_stmt_warning_count(MYSQL_STMT *stmt); int STDCALL mysql_stmt_next_result_start(int *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_next_result_cont(int *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_set_character_set_start(int *ret, MYSQL *mysql, const char *csname); int STDCALL mysql_set_character_set_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_change_user_start(my_bool *ret, MYSQL *mysql, const char *user, const char *passwd, const char *db); int STDCALL mysql_change_user_cont(my_bool *ret, MYSQL *mysql, int status); int STDCALL mysql_real_connect_start(MYSQL **ret, MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); int STDCALL mysql_real_connect_cont(MYSQL **ret, MYSQL *mysql, int status); int STDCALL mysql_query_start(int *ret, MYSQL *mysql, const char *q); int STDCALL mysql_query_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_send_query_start(int *ret, MYSQL *mysql, const char *q, unsigned long length); int STDCALL mysql_send_query_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_real_query_start(int *ret, MYSQL *mysql, const char *q, unsigned long length); int STDCALL mysql_real_query_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_store_result_start(MYSQL_RES **ret, MYSQL *mysql); int STDCALL mysql_store_result_cont(MYSQL_RES **ret, MYSQL *mysql, int status); int STDCALL mysql_shutdown_start(int *ret, MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level); int STDCALL mysql_shutdown_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_refresh_start(int *ret, MYSQL *mysql, unsigned int refresh_options); int STDCALL mysql_refresh_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_kill_start(int *ret, MYSQL *mysql, unsigned long pid); int STDCALL mysql_kill_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_set_server_option_start(int *ret, MYSQL *mysql, enum enum_mysql_set_option option); int STDCALL mysql_set_server_option_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_ping_start(int *ret, MYSQL *mysql); int STDCALL mysql_ping_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_stat_start(const char **ret, MYSQL *mysql); int STDCALL mysql_stat_cont(const char **ret, MYSQL *mysql, int status); int STDCALL mysql_free_result_start(MYSQL_RES *result); int STDCALL mysql_free_result_cont(MYSQL_RES *result, int status); int STDCALL mysql_fetch_row_start(MYSQL_ROW *ret, MYSQL_RES *result); int STDCALL mysql_fetch_row_cont(MYSQL_ROW *ret, MYSQL_RES *result, int status); int STDCALL mysql_read_query_result_start(my_bool *ret, MYSQL *mysql); int STDCALL mysql_read_query_result_cont(my_bool *ret, MYSQL *mysql, int status); int STDCALL mysql_reset_connection_start(int *ret, MYSQL *mysql); int STDCALL mysql_reset_connection_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_session_track_get_next(MYSQL *mysql, enum enum_session_state_type type, const char **data, size_t *length); int STDCALL mysql_session_track_get_first(MYSQL *mysql, enum enum_session_state_type type, const char **data, size_t *length); int STDCALL mysql_stmt_prepare_start(int *ret, MYSQL_STMT *stmt,const char *query, unsigned long length); int STDCALL mysql_stmt_prepare_cont(int *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_stmt_execute_start(int *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_execute_cont(int *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_stmt_fetch_start(int *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_fetch_cont(int *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_stmt_store_result_start(int *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_store_result_cont(int *ret, MYSQL_STMT *stmt,int status); int STDCALL mysql_stmt_close_start(my_bool *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_close_cont(my_bool *ret, MYSQL_STMT * stmt, int status); int STDCALL mysql_stmt_reset_start(my_bool *ret, MYSQL_STMT * stmt); int STDCALL mysql_stmt_reset_cont(my_bool *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_stmt_free_result_start(my_bool *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_free_result_cont(my_bool *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_stmt_send_long_data_start(my_bool *ret, MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long len); int STDCALL mysql_stmt_send_long_data_cont(my_bool *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_reset_connection(MYSQL *mysql); /* API function calls (used by dynamic plugins) */ struct st_mariadb_api { unsigned long long (STDCALL *mysql_num_rows)(MYSQL_RES *res); unsigned int (STDCALL *mysql_num_fields)(MYSQL_RES *res); my_bool (STDCALL *mysql_eof)(MYSQL_RES *res); MYSQL_FIELD *(STDCALL *mysql_fetch_field_direct)(MYSQL_RES *res, unsigned int fieldnr); MYSQL_FIELD * (STDCALL *mysql_fetch_fields)(MYSQL_RES *res); MYSQL_ROWS * (STDCALL *mysql_row_tell)(MYSQL_RES *res); unsigned int (STDCALL *mysql_field_tell)(MYSQL_RES *res); unsigned int (STDCALL *mysql_field_count)(MYSQL *mysql); my_bool (STDCALL *mysql_more_results)(MYSQL *mysql); int (STDCALL *mysql_next_result)(MYSQL *mysql); unsigned long long (STDCALL *mysql_affected_rows)(MYSQL *mysql); my_bool (STDCALL *mysql_autocommit)(MYSQL *mysql, my_bool mode); my_bool (STDCALL *mysql_commit)(MYSQL *mysql); my_bool (STDCALL *mysql_rollback)(MYSQL *mysql); unsigned long long (STDCALL *mysql_insert_id)(MYSQL *mysql); unsigned int (STDCALL *mysql_errno)(MYSQL *mysql); const char * (STDCALL *mysql_error)(MYSQL *mysql); const char * (STDCALL *mysql_info)(MYSQL *mysql); unsigned long (STDCALL *mysql_thread_id)(MYSQL *mysql); const char * (STDCALL *mysql_character_set_name)(MYSQL *mysql); void (STDCALL *mysql_get_character_set_info)(MYSQL *mysql, MY_CHARSET_INFO *cs); int (STDCALL *mysql_set_character_set)(MYSQL *mysql, const char *csname); my_bool (*mariadb_get_infov)(MYSQL *mysql, enum mariadb_value value, void *arg, ...); my_bool (STDCALL *mariadb_get_info)(MYSQL *mysql, enum mariadb_value value, void *arg); MYSQL * (STDCALL *mysql_init)(MYSQL *mysql); int (STDCALL *mysql_ssl_set)(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); const char * (STDCALL *mysql_get_ssl_cipher)(MYSQL *mysql); my_bool (STDCALL *mysql_change_user)(MYSQL *mysql, const char *user, const char *passwd, const char *db); MYSQL * (STDCALL *mysql_real_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); void (STDCALL *mysql_close)(MYSQL *sock); int (STDCALL *mysql_select_db)(MYSQL *mysql, const char *db); int (STDCALL *mysql_query)(MYSQL *mysql, const char *q); int (STDCALL *mysql_send_query)(MYSQL *mysql, const char *q, unsigned long length); my_bool (STDCALL *mysql_read_query_result)(MYSQL *mysql); int (STDCALL *mysql_real_query)(MYSQL *mysql, const char *q, unsigned long length); int (STDCALL *mysql_shutdown)(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level); int (STDCALL *mysql_dump_debug_info)(MYSQL *mysql); int (STDCALL *mysql_refresh)(MYSQL *mysql, unsigned int refresh_options); int (STDCALL *mysql_kill)(MYSQL *mysql,unsigned long pid); int (STDCALL *mysql_ping)(MYSQL *mysql); char * (STDCALL *mysql_stat)(MYSQL *mysql); char * (STDCALL *mysql_get_server_info)(MYSQL *mysql); unsigned long (STDCALL *mysql_get_server_version)(MYSQL *mysql); char * (STDCALL *mysql_get_host_info)(MYSQL *mysql); unsigned int (STDCALL *mysql_get_proto_info)(MYSQL *mysql); MYSQL_RES * (STDCALL *mysql_list_dbs)(MYSQL *mysql,const char *wild); MYSQL_RES * (STDCALL *mysql_list_tables)(MYSQL *mysql,const char *wild); MYSQL_RES * (STDCALL *mysql_list_fields)(MYSQL *mysql, const char *table, const char *wild); MYSQL_RES * (STDCALL *mysql_list_processes)(MYSQL *mysql); MYSQL_RES * (STDCALL *mysql_store_result)(MYSQL *mysql); MYSQL_RES * (STDCALL *mysql_use_result)(MYSQL *mysql); int (STDCALL *mysql_options)(MYSQL *mysql,enum mysql_option option, const void *arg); void (STDCALL *mysql_free_result)(MYSQL_RES *result); void (STDCALL *mysql_data_seek)(MYSQL_RES *result, unsigned long long offset); MYSQL_ROW_OFFSET (STDCALL *mysql_row_seek)(MYSQL_RES *result, MYSQL_ROW_OFFSET); MYSQL_FIELD_OFFSET (STDCALL *mysql_field_seek)(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset); MYSQL_ROW (STDCALL *mysql_fetch_row)(MYSQL_RES *result); unsigned long * (STDCALL *mysql_fetch_lengths)(MYSQL_RES *result); MYSQL_FIELD * (STDCALL *mysql_fetch_field)(MYSQL_RES *result); unsigned long (STDCALL *mysql_escape_string)(char *to,const char *from, unsigned long from_length); unsigned long (STDCALL *mysql_real_escape_string)(MYSQL *mysql, char *to,const char *from, unsigned long length); unsigned int (STDCALL *mysql_thread_safe)(void); unsigned int (STDCALL *mysql_warning_count)(MYSQL *mysql); const char * (STDCALL *mysql_sqlstate)(MYSQL *mysql); int (STDCALL *mysql_server_init)(int argc, char **argv, char **groups); void (STDCALL *mysql_server_end)(void); void (STDCALL *mysql_thread_end)(void); my_bool (STDCALL *mysql_thread_init)(void); int (STDCALL *mysql_set_server_option)(MYSQL *mysql, enum enum_mysql_set_option option); const char * (STDCALL *mysql_get_client_info)(void); unsigned long (STDCALL *mysql_get_client_version)(void); my_bool (STDCALL *mariadb_connection)(MYSQL *mysql); const char * (STDCALL *mysql_get_server_name)(MYSQL *mysql); MARIADB_CHARSET_INFO * (STDCALL *mariadb_get_charset_by_name)(const char *csname); MARIADB_CHARSET_INFO * (STDCALL *mariadb_get_charset_by_nr)(unsigned int csnr); size_t (STDCALL *mariadb_convert_string)(const char *from, size_t *from_len, MARIADB_CHARSET_INFO *from_cs, char *to, size_t *to_len, MARIADB_CHARSET_INFO *to_cs, int *errorcode); int (*mysql_optionsv)(MYSQL *mysql,enum mysql_option option, ...); int (*mysql_get_optionv)(MYSQL *mysql, enum mysql_option option, void *arg, ...); int (STDCALL *mysql_get_option)(MYSQL *mysql, enum mysql_option option, void *arg); unsigned long (STDCALL *mysql_hex_string)(char *to, const char *from, unsigned long len); my_socket (STDCALL *mysql_get_socket)(MYSQL *mysql); unsigned int (STDCALL *mysql_get_timeout_value)(const MYSQL *mysql); unsigned int (STDCALL *mysql_get_timeout_value_ms)(const MYSQL *mysql); my_bool (STDCALL *mariadb_reconnect)(MYSQL *mysql); MYSQL_STMT * (STDCALL *mysql_stmt_init)(MYSQL *mysql); int (STDCALL *mysql_stmt_prepare)(MYSQL_STMT *stmt, const char *query, unsigned long length); int (STDCALL *mysql_stmt_execute)(MYSQL_STMT *stmt); int (STDCALL *mysql_stmt_fetch)(MYSQL_STMT *stmt); int (STDCALL *mysql_stmt_fetch_column)(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg, unsigned int column, unsigned long offset); int (STDCALL *mysql_stmt_store_result)(MYSQL_STMT *stmt); unsigned long (STDCALL *mysql_stmt_param_count)(MYSQL_STMT * stmt); my_bool (STDCALL *mysql_stmt_attr_set)(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *attr); my_bool (STDCALL *mysql_stmt_attr_get)(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *attr); my_bool (STDCALL *mysql_stmt_bind_param)(MYSQL_STMT * stmt, MYSQL_BIND * bnd); my_bool (STDCALL *mysql_stmt_bind_result)(MYSQL_STMT * stmt, MYSQL_BIND * bnd); my_bool (STDCALL *mysql_stmt_close)(MYSQL_STMT * stmt); my_bool (STDCALL *mysql_stmt_reset)(MYSQL_STMT * stmt); my_bool (STDCALL *mysql_stmt_free_result)(MYSQL_STMT *stmt); my_bool (STDCALL *mysql_stmt_send_long_data)(MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length); MYSQL_RES *(STDCALL *mysql_stmt_result_metadata)(MYSQL_STMT *stmt); MYSQL_RES *(STDCALL *mysql_stmt_param_metadata)(MYSQL_STMT *stmt); unsigned int (STDCALL *mysql_stmt_errno)(MYSQL_STMT * stmt); const char *(STDCALL *mysql_stmt_error)(MYSQL_STMT * stmt); const char *(STDCALL *mysql_stmt_sqlstate)(MYSQL_STMT * stmt); MYSQL_ROW_OFFSET (STDCALL *mysql_stmt_row_seek)(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET offset); MYSQL_ROW_OFFSET (STDCALL *mysql_stmt_row_tell)(MYSQL_STMT *stmt); void (STDCALL *mysql_stmt_data_seek)(MYSQL_STMT *stmt, unsigned long long offset); unsigned long long (STDCALL *mysql_stmt_num_rows)(MYSQL_STMT *stmt); unsigned long long (STDCALL *mysql_stmt_affected_rows)(MYSQL_STMT *stmt); unsigned long long (STDCALL *mysql_stmt_insert_id)(MYSQL_STMT *stmt); unsigned int (STDCALL *mysql_stmt_field_count)(MYSQL_STMT *stmt); int (STDCALL *mysql_stmt_next_result)(MYSQL_STMT *stmt); my_bool (STDCALL *mysql_stmt_more_results)(MYSQL_STMT *stmt); int (STDCALL *mariadb_stmt_execute_direct)(MYSQL_STMT *stmt, const char *stmtstr, size_t length); int (STDCALL *mysql_reset_connection)(MYSQL *mysql); }; /* these methods can be overwritten by db plugins */ struct st_mariadb_methods { MYSQL *(*db_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); void (*db_close)(MYSQL *mysql); int (*db_command)(MYSQL *mysql,enum enum_server_command command, const char *arg, size_t length, my_bool skip_check, void *opt_arg); void (*db_skip_result)(MYSQL *mysql); int (*db_read_query_result)(MYSQL *mysql); MYSQL_DATA *(*db_read_rows)(MYSQL *mysql,MYSQL_FIELD *fields, unsigned int field_count); int (*db_read_one_row)(MYSQL *mysql,unsigned int fields,MYSQL_ROW row, unsigned long *lengths); /* prepared statements */ my_bool (*db_supported_buffer_type)(enum enum_field_types type); my_bool (*db_read_prepare_response)(MYSQL_STMT *stmt); int (*db_read_stmt_result)(MYSQL *mysql); my_bool (*db_stmt_get_result_metadata)(MYSQL_STMT *stmt); my_bool (*db_stmt_get_param_metadata)(MYSQL_STMT *stmt); int (*db_stmt_read_all_rows)(MYSQL_STMT *stmt); int (*db_stmt_fetch)(MYSQL_STMT *stmt, unsigned char **row); int (*db_stmt_fetch_to_bind)(MYSQL_STMT *stmt, unsigned char *row); void (*db_stmt_flush_unbuffered)(MYSQL_STMT *stmt); void (*set_error)(MYSQL *mysql, unsigned int error_nr, const char *sqlstate, const char *format, ...); void (*invalidate_stmts)(MYSQL *mysql, const char *function_name); struct st_mariadb_api *api; int (*db_read_execute_response)(MYSQL_STMT *stmt); unsigned char* (*db_execute_generate_request)(MYSQL_STMT *stmt, size_t *request_len, my_bool internal); }; /* synonyms/aliases functions */ #define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT) #define mysql_library_init mysql_server_init #define mysql_library_end mysql_server_end #define mariadb_connect(hdl, conn_str) mysql_real_connect((hdl),(conn_str), NULL, NULL, NULL, 0, NULL, 0) /* new api functions */ #define HAVE_MYSQL_REAL_CONNECT #ifdef __cplusplus } #endif #endif mysql_com.h000064400000000256151031265040006720 0ustar00/* Do not edit this file directly, it was auto-generated by cmake */ #warning This file should not be included by clients, include only #include mariadb_dyncol.h000064400000020116151031265040007661 0ustar00/* Copyright (c) 2011, Monty Program Ab Copyright (c) 2011, Oleksandr Byelkin Copyright (c) 2012, 2022 MariaDB Corporation AB Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ma_dyncol_h #define ma_dyncol_h #ifdef __cplusplus extern "C" { #endif #ifndef LIBMARIADB #include #include #endif #include #ifndef longlong_defined #if defined(HAVE_LONG_LONG) && SIZEOF_LONG != 8 typedef unsigned long long int ulonglong; /* ulong or unsigned long long */ typedef long long int longlong; #else typedef unsigned long ulonglong; /* ulong or unsigned long long */ typedef long longlong; #endif #define longlong_defined #endif #ifndef _my_sys_h typedef struct st_dynamic_string { char *str; size_t length,max_length,alloc_increment; } DYNAMIC_STRING; #endif struct st_mysql_lex_string { char *str; size_t length; }; typedef struct st_mysql_lex_string MYSQL_LEX_STRING; typedef struct st_mysql_lex_string LEX_STRING; /* Limits of implementation */ #define MAX_TOTAL_NAME_LENGTH 65535 #define MAX_NAME_LENGTH (MAX_TOTAL_NAME_LENGTH/4) /* NO and OK is the same used just to show semantics */ #define ER_DYNCOL_NO ER_DYNCOL_OK enum enum_dyncol_func_result { ER_DYNCOL_OK= 0, ER_DYNCOL_YES= 1, /* For functions returning 0/1 */ ER_DYNCOL_FORMAT= -1, /* Wrong format of the encoded string */ ER_DYNCOL_LIMIT= -2, /* Some limit reached */ ER_DYNCOL_RESOURCE= -3, /* Out of resources */ ER_DYNCOL_DATA= -4, /* Incorrect input data */ ER_DYNCOL_UNKNOWN_CHARSET= -5, /* Unknown character set */ ER_DYNCOL_TRUNCATED= 2 /* OK, but data was truncated */ }; typedef DYNAMIC_STRING DYNAMIC_COLUMN; enum enum_dynamic_column_type { DYN_COL_NULL= 0, DYN_COL_INT, DYN_COL_UINT, DYN_COL_DOUBLE, DYN_COL_STRING, DYN_COL_DECIMAL, DYN_COL_DATETIME, DYN_COL_DATE, DYN_COL_TIME, DYN_COL_DYNCOL }; typedef enum enum_dynamic_column_type DYNAMIC_COLUMN_TYPE; struct st_dynamic_column_value { DYNAMIC_COLUMN_TYPE type; union { long long long_value; unsigned long long ulong_value; double double_value; struct { MYSQL_LEX_STRING value; MARIADB_CHARSET_INFO *charset; } string; #ifndef LIBMARIADB struct { decimal_digit_t buffer[DECIMAL_BUFF_LENGTH]; decimal_t value; } decimal; #endif MYSQL_TIME time_value; } x; }; typedef struct st_dynamic_column_value DYNAMIC_COLUMN_VALUE; #ifdef MADYNCOL_DEPRECATED enum enum_dyncol_func_result dynamic_column_create(DYNAMIC_COLUMN *str, uint column_nr, DYNAMIC_COLUMN_VALUE *value); enum enum_dyncol_func_result dynamic_column_create_many(DYNAMIC_COLUMN *str, uint column_count, uint *column_numbers, DYNAMIC_COLUMN_VALUE *values); enum enum_dyncol_func_result dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr, DYNAMIC_COLUMN_VALUE *value); enum enum_dyncol_func_result dynamic_column_update_many(DYNAMIC_COLUMN *str, uint add_column_count, uint *column_numbers, DYNAMIC_COLUMN_VALUE *values); enum enum_dyncol_func_result dynamic_column_exists(DYNAMIC_COLUMN *org, uint column_nr); enum enum_dyncol_func_result dynamic_column_list(DYNAMIC_COLUMN *org, DYNAMIC_ARRAY *array_of_uint); enum enum_dyncol_func_result dynamic_column_get(DYNAMIC_COLUMN *org, uint column_nr, DYNAMIC_COLUMN_VALUE *store_it_here); #endif /* new functions */ enum enum_dyncol_func_result mariadb_dyncol_create_many_num(DYNAMIC_COLUMN *str, uint column_count, uint *column_numbers, DYNAMIC_COLUMN_VALUE *values, my_bool new_string); enum enum_dyncol_func_result mariadb_dyncol_create_many_named(DYNAMIC_COLUMN *str, uint column_count, MYSQL_LEX_STRING *column_keys, DYNAMIC_COLUMN_VALUE *values, my_bool new_string); enum enum_dyncol_func_result mariadb_dyncol_update_many_num(DYNAMIC_COLUMN *str, uint add_column_count, uint *column_keys, DYNAMIC_COLUMN_VALUE *values); enum enum_dyncol_func_result mariadb_dyncol_update_many_named(DYNAMIC_COLUMN *str, uint add_column_count, MYSQL_LEX_STRING *column_keys, DYNAMIC_COLUMN_VALUE *values); enum enum_dyncol_func_result mariadb_dyncol_exists_num(DYNAMIC_COLUMN *org, uint column_nr); enum enum_dyncol_func_result mariadb_dyncol_exists_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *name); /* List of not NULL columns */ enum enum_dyncol_func_result mariadb_dyncol_list_num(DYNAMIC_COLUMN *str, uint *count, uint **nums); enum enum_dyncol_func_result mariadb_dyncol_list_named(DYNAMIC_COLUMN *str, uint *count, MYSQL_LEX_STRING **names); /* if the column do not exists it is NULL */ enum enum_dyncol_func_result mariadb_dyncol_get_num(DYNAMIC_COLUMN *org, uint column_nr, DYNAMIC_COLUMN_VALUE *store_it_here); enum enum_dyncol_func_result mariadb_dyncol_get_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *name, DYNAMIC_COLUMN_VALUE *store_it_here); my_bool mariadb_dyncol_has_names(DYNAMIC_COLUMN *str); enum enum_dyncol_func_result mariadb_dyncol_check(DYNAMIC_COLUMN *str); enum enum_dyncol_func_result mariadb_dyncol_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json); void mariadb_dyncol_free(DYNAMIC_COLUMN *str); #define mariadb_dyncol_init(A) memset((A), 0, sizeof(DYNAMIC_COLUMN)) #define dynamic_column_initialize(A) mariadb_dyncol_init((A)) #define dynamic_column_column_free(A) mariadb_dyncol_free((A)) /* conversion of values to 3 base types */ enum enum_dyncol_func_result mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val, MARIADB_CHARSET_INFO *cs, char quote); enum enum_dyncol_func_result mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val); enum enum_dyncol_func_result mariadb_dyncol_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val); enum enum_dyncol_func_result mariadb_dyncol_unpack(DYNAMIC_COLUMN *str, uint *count, MYSQL_LEX_STRING **names, DYNAMIC_COLUMN_VALUE **vals); int mariadb_dyncol_column_cmp_named(const MYSQL_LEX_STRING *s1, const MYSQL_LEX_STRING *s2); enum enum_dyncol_func_result mariadb_dyncol_column_count(DYNAMIC_COLUMN *str, uint *column_count); #define mariadb_dyncol_value_init(V) \ do {\ (V)->type= DYN_COL_NULL;\ } while(0) /* Prepare value for using as decimal */ void mariadb_dyncol_prepare_decimal(DYNAMIC_COLUMN_VALUE *value); #ifdef __cplusplus } #endif #endif my_global.h000064400000000224151031265040006655 0ustar00/* Do not edit this file directly, it was auto-generated by cmake */ #warning This file should not be included by clients, include only mariadb_version.h000064400000002275151031265040010064 0ustar00/* Copyright Abandoned 1996, 1999, 2001 MySQL AB This file is public domain and comes with NO WARRANTY of any kind */ /* Version numbers for protocol & mysqld */ #ifndef _mariadb_version_h_ #define _mariadb_version_h_ #ifdef _CUSTOMCONFIG_ #include #else #define PROTOCOL_VERSION 10 #define MARIADB_CLIENT_VERSION_STR "10.6.23" #define MARIADB_BASE_VERSION "mariadb-10.6" #define MARIADB_VERSION_ID 100623 #define MARIADB_PORT 3306 #define MARIADB_UNIX_ADDR "/var/lib/mysql/mysql.sock" #ifndef MYSQL_UNIX_ADDR #define MYSQL_UNIX_ADDR MARIADB_UNIX_ADDR #endif #ifndef MYSQL_PORT #define MYSQL_PORT MARIADB_PORT #endif #define MYSQL_CONFIG_NAME "my" #define MYSQL_VERSION_ID 100623 #define MYSQL_SERVER_VERSION "10.6.23-MariaDB" #define MARIADB_PACKAGE_VERSION "3.3.17" #define MARIADB_PACKAGE_VERSION_ID 30317 #define MARIADB_SYSTEM_TYPE "Linux" #define MARIADB_MACHINE_TYPE "x86_64" #define MARIADB_PLUGINDIR "/usr/lib64/mysql/plugin" /* mysqld compile time options */ #ifndef MYSQL_CHARSET #define MYSQL_CHARSET "" #endif #endif /* Source information */ #define CC_SOURCE_REVISION "" #endif /* _mariadb_version_h_ */ server/mysqld_error.h000064400000135573151031265040010760 0ustar00/* Autogenerated file, please don't edit */ #ifndef ER_ERROR_FIRST #define ER_ERROR_FIRST 1000 #define ER_HASHCHK 1000 #define ER_NISAMCHK 1001 #define ER_NO 1002 #define ER_YES 1003 #define ER_CANT_CREATE_FILE 1004 #define ER_CANT_CREATE_TABLE 1005 #define ER_CANT_CREATE_DB 1006 #define ER_DB_CREATE_EXISTS 1007 #define ER_DB_DROP_EXISTS 1008 #define ER_DB_DROP_DELETE 1009 #define ER_DB_DROP_RMDIR 1010 #define ER_CANT_DELETE_FILE 1011 #define ER_CANT_FIND_SYSTEM_REC 1012 #define ER_CANT_GET_STAT 1013 #define ER_CANT_GET_WD 1014 #define ER_CANT_LOCK 1015 #define ER_CANT_OPEN_FILE 1016 #define ER_FILE_NOT_FOUND 1017 #define ER_CANT_READ_DIR 1018 #define ER_CANT_SET_WD 1019 #define ER_CHECKREAD 1020 #define ER_DISK_FULL 1021 #define ER_DUP_KEY 1022 #define ER_ERROR_ON_CLOSE 1023 #define ER_ERROR_ON_READ 1024 #define ER_ERROR_ON_RENAME 1025 #define ER_ERROR_ON_WRITE 1026 #define ER_FILE_USED 1027 #define ER_FILSORT_ABORT 1028 #define ER_FORM_NOT_FOUND 1029 #define ER_GET_ERRNO 1030 #define ER_ILLEGAL_HA 1031 #define ER_KEY_NOT_FOUND 1032 #define ER_NOT_FORM_FILE 1033 #define ER_NOT_KEYFILE 1034 #define ER_OLD_KEYFILE 1035 #define ER_OPEN_AS_READONLY 1036 #define ER_OUTOFMEMORY 1037 #define ER_OUT_OF_SORTMEMORY 1038 #define ER_UNEXPECTED_EOF 1039 #define ER_CON_COUNT_ERROR 1040 #define ER_OUT_OF_RESOURCES 1041 #define ER_BAD_HOST_ERROR 1042 #define ER_HANDSHAKE_ERROR 1043 #define ER_DBACCESS_DENIED_ERROR 1044 #define ER_ACCESS_DENIED_ERROR 1045 #define ER_NO_DB_ERROR 1046 #define ER_UNKNOWN_COM_ERROR 1047 #define ER_BAD_NULL_ERROR 1048 #define ER_BAD_DB_ERROR 1049 #define ER_TABLE_EXISTS_ERROR 1050 #define ER_BAD_TABLE_ERROR 1051 #define ER_NON_UNIQ_ERROR 1052 #define ER_SERVER_SHUTDOWN 1053 #define ER_BAD_FIELD_ERROR 1054 #define ER_WRONG_FIELD_WITH_GROUP 1055 #define ER_WRONG_GROUP_FIELD 1056 #define ER_WRONG_SUM_SELECT 1057 #define ER_WRONG_VALUE_COUNT 1058 #define ER_TOO_LONG_IDENT 1059 #define ER_DUP_FIELDNAME 1060 #define ER_DUP_KEYNAME 1061 #define ER_DUP_ENTRY 1062 #define ER_WRONG_FIELD_SPEC 1063 #define ER_PARSE_ERROR 1064 #define ER_EMPTY_QUERY 1065 #define ER_NONUNIQ_TABLE 1066 #define ER_INVALID_DEFAULT 1067 #define ER_MULTIPLE_PRI_KEY 1068 #define ER_TOO_MANY_KEYS 1069 #define ER_TOO_MANY_KEY_PARTS 1070 #define ER_TOO_LONG_KEY 1071 #define ER_KEY_COLUMN_DOES_NOT_EXITS 1072 #define ER_BLOB_USED_AS_KEY 1073 #define ER_TOO_BIG_FIELDLENGTH 1074 #define ER_WRONG_AUTO_KEY 1075 #define ER_BINLOG_CANT_DELETE_GTID_DOMAIN 1076 #define ER_NORMAL_SHUTDOWN 1077 #define ER_GOT_SIGNAL 1078 #define ER_SHUTDOWN_COMPLETE 1079 #define ER_FORCING_CLOSE 1080 #define ER_IPSOCK_ERROR 1081 #define ER_NO_SUCH_INDEX 1082 #define ER_WRONG_FIELD_TERMINATORS 1083 #define ER_BLOBS_AND_NO_TERMINATED 1084 #define ER_TEXTFILE_NOT_READABLE 1085 #define ER_FILE_EXISTS_ERROR 1086 #define ER_LOAD_INFO 1087 #define ER_ALTER_INFO 1088 #define ER_WRONG_SUB_KEY 1089 #define ER_CANT_REMOVE_ALL_FIELDS 1090 #define ER_CANT_DROP_FIELD_OR_KEY 1091 #define ER_INSERT_INFO 1092 #define ER_UPDATE_TABLE_USED 1093 #define ER_NO_SUCH_THREAD 1094 #define ER_KILL_DENIED_ERROR 1095 #define ER_NO_TABLES_USED 1096 #define ER_TOO_BIG_SET 1097 #define ER_NO_UNIQUE_LOGFILE 1098 #define ER_TABLE_NOT_LOCKED_FOR_WRITE 1099 #define ER_TABLE_NOT_LOCKED 1100 #define ER_UNUSED_17 1101 #define ER_WRONG_DB_NAME 1102 #define ER_WRONG_TABLE_NAME 1103 #define ER_TOO_BIG_SELECT 1104 #define ER_UNKNOWN_ERROR 1105 #define ER_UNKNOWN_PROCEDURE 1106 #define ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107 #define ER_WRONG_PARAMETERS_TO_PROCEDURE 1108 #define ER_UNKNOWN_TABLE 1109 #define ER_FIELD_SPECIFIED_TWICE 1110 #define ER_INVALID_GROUP_FUNC_USE 1111 #define ER_UNSUPPORTED_EXTENSION 1112 #define ER_TABLE_MUST_HAVE_COLUMNS 1113 #define ER_RECORD_FILE_FULL 1114 #define ER_UNKNOWN_CHARACTER_SET 1115 #define ER_TOO_MANY_TABLES 1116 #define ER_TOO_MANY_FIELDS 1117 #define ER_TOO_BIG_ROWSIZE 1118 #define ER_STACK_OVERRUN 1119 #define ER_WRONG_OUTER_JOIN 1120 #define ER_NULL_COLUMN_IN_INDEX 1121 #define ER_CANT_FIND_UDF 1122 #define ER_CANT_INITIALIZE_UDF 1123 #define ER_UDF_NO_PATHS 1124 #define ER_UDF_EXISTS 1125 #define ER_CANT_OPEN_LIBRARY 1126 #define ER_CANT_FIND_DL_ENTRY 1127 #define ER_FUNCTION_NOT_DEFINED 1128 #define ER_HOST_IS_BLOCKED 1129 #define ER_HOST_NOT_PRIVILEGED 1130 #define ER_PASSWORD_ANONYMOUS_USER 1131 #define ER_PASSWORD_NOT_ALLOWED 1132 #define ER_PASSWORD_NO_MATCH 1133 #define ER_UPDATE_INFO 1134 #define ER_CANT_CREATE_THREAD 1135 #define ER_WRONG_VALUE_COUNT_ON_ROW 1136 #define ER_CANT_REOPEN_TABLE 1137 #define ER_INVALID_USE_OF_NULL 1138 #define ER_REGEXP_ERROR 1139 #define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140 #define ER_NONEXISTING_GRANT 1141 #define ER_TABLEACCESS_DENIED_ERROR 1142 #define ER_COLUMNACCESS_DENIED_ERROR 1143 #define ER_ILLEGAL_GRANT_FOR_TABLE 1144 #define ER_GRANT_WRONG_HOST_OR_USER 1145 #define ER_NO_SUCH_TABLE 1146 #define ER_NONEXISTING_TABLE_GRANT 1147 #define ER_NOT_ALLOWED_COMMAND 1148 #define ER_SYNTAX_ERROR 1149 #define ER_DELAYED_CANT_CHANGE_LOCK 1150 #define ER_TOO_MANY_DELAYED_THREADS 1151 #define ER_ABORTING_CONNECTION 1152 #define ER_NET_PACKET_TOO_LARGE 1153 #define ER_NET_READ_ERROR_FROM_PIPE 1154 #define ER_NET_FCNTL_ERROR 1155 #define ER_NET_PACKETS_OUT_OF_ORDER 1156 #define ER_NET_UNCOMPRESS_ERROR 1157 #define ER_NET_READ_ERROR 1158 #define ER_NET_READ_INTERRUPTED 1159 #define ER_NET_ERROR_ON_WRITE 1160 #define ER_NET_WRITE_INTERRUPTED 1161 #define ER_TOO_LONG_STRING 1162 #define ER_TABLE_CANT_HANDLE_BLOB 1163 #define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164 #define ER_DELAYED_INSERT_TABLE_LOCKED 1165 #define ER_WRONG_COLUMN_NAME 1166 #define ER_WRONG_KEY_COLUMN 1167 #define ER_WRONG_MRG_TABLE 1168 #define ER_DUP_UNIQUE 1169 #define ER_BLOB_KEY_WITHOUT_LENGTH 1170 #define ER_PRIMARY_CANT_HAVE_NULL 1171 #define ER_TOO_MANY_ROWS 1172 #define ER_REQUIRES_PRIMARY_KEY 1173 #define ER_NO_RAID_COMPILED 1174 #define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175 #define ER_KEY_DOES_NOT_EXISTS 1176 #define ER_CHECK_NO_SUCH_TABLE 1177 #define ER_CHECK_NOT_IMPLEMENTED 1178 #define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179 #define ER_ERROR_DURING_COMMIT 1180 #define ER_ERROR_DURING_ROLLBACK 1181 #define ER_ERROR_DURING_FLUSH_LOGS 1182 #define ER_ERROR_DURING_CHECKPOINT 1183 #define ER_NEW_ABORTING_CONNECTION 1184 #define ER_UNUSED_10 1185 #define ER_FLUSH_MASTER_BINLOG_CLOSED 1186 #define ER_INDEX_REBUILD 1187 #define ER_MASTER 1188 #define ER_MASTER_NET_READ 1189 #define ER_MASTER_NET_WRITE 1190 #define ER_FT_MATCHING_KEY_NOT_FOUND 1191 #define ER_LOCK_OR_ACTIVE_TRANSACTION 1192 #define ER_UNKNOWN_SYSTEM_VARIABLE 1193 #define ER_CRASHED_ON_USAGE 1194 #define ER_CRASHED_ON_REPAIR 1195 #define ER_WARNING_NOT_COMPLETE_ROLLBACK 1196 #define ER_TRANS_CACHE_FULL 1197 #define ER_SLAVE_MUST_STOP 1198 #define ER_SLAVE_NOT_RUNNING 1199 #define ER_BAD_SLAVE 1200 #define ER_MASTER_INFO 1201 #define ER_SLAVE_THREAD 1202 #define ER_TOO_MANY_USER_CONNECTIONS 1203 #define ER_SET_CONSTANTS_ONLY 1204 #define ER_LOCK_WAIT_TIMEOUT 1205 #define ER_LOCK_TABLE_FULL 1206 #define ER_READ_ONLY_TRANSACTION 1207 #define ER_DROP_DB_WITH_READ_LOCK 1208 #define ER_CREATE_DB_WITH_READ_LOCK 1209 #define ER_WRONG_ARGUMENTS 1210 #define ER_NO_PERMISSION_TO_CREATE_USER 1211 #define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 #define ER_LOCK_DEADLOCK 1213 #define ER_TABLE_CANT_HANDLE_FT 1214 #define ER_CANNOT_ADD_FOREIGN 1215 #define ER_NO_REFERENCED_ROW 1216 #define ER_ROW_IS_REFERENCED 1217 #define ER_CONNECT_TO_MASTER 1218 #define ER_QUERY_ON_MASTER 1219 #define ER_ERROR_WHEN_EXECUTING_COMMAND 1220 #define ER_WRONG_USAGE 1221 #define ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1222 #define ER_CANT_UPDATE_WITH_READLOCK 1223 #define ER_MIXING_NOT_ALLOWED 1224 #define ER_DUP_ARGUMENT 1225 #define ER_USER_LIMIT_REACHED 1226 #define ER_SPECIFIC_ACCESS_DENIED_ERROR 1227 #define ER_LOCAL_VARIABLE 1228 #define ER_GLOBAL_VARIABLE 1229 #define ER_NO_DEFAULT 1230 #define ER_WRONG_VALUE_FOR_VAR 1231 #define ER_WRONG_TYPE_FOR_VAR 1232 #define ER_VAR_CANT_BE_READ 1233 #define ER_CANT_USE_OPTION_HERE 1234 #define ER_NOT_SUPPORTED_YET 1235 #define ER_MASTER_FATAL_ERROR_READING_BINLOG 1236 #define ER_SLAVE_IGNORED_TABLE 1237 #define ER_INCORRECT_GLOBAL_LOCAL_VAR 1238 #define ER_WRONG_FK_DEF 1239 #define ER_KEY_REF_DO_NOT_MATCH_TABLE_REF 1240 #define ER_OPERAND_COLUMNS 1241 #define ER_SUBQUERY_NO_1_ROW 1242 #define ER_UNKNOWN_STMT_HANDLER 1243 #define ER_CORRUPT_HELP_DB 1244 #define ER_CYCLIC_REFERENCE 1245 #define ER_AUTO_CONVERT 1246 #define ER_ILLEGAL_REFERENCE 1247 #define ER_DERIVED_MUST_HAVE_ALIAS 1248 #define ER_SELECT_REDUCED 1249 #define ER_TABLENAME_NOT_ALLOWED_HERE 1250 #define ER_NOT_SUPPORTED_AUTH_MODE 1251 #define ER_SPATIAL_CANT_HAVE_NULL 1252 #define ER_COLLATION_CHARSET_MISMATCH 1253 #define ER_SLAVE_WAS_RUNNING 1254 #define ER_SLAVE_WAS_NOT_RUNNING 1255 #define ER_TOO_BIG_FOR_UNCOMPRESS 1256 #define ER_ZLIB_Z_MEM_ERROR 1257 #define ER_ZLIB_Z_BUF_ERROR 1258 #define ER_ZLIB_Z_DATA_ERROR 1259 #define ER_CUT_VALUE_GROUP_CONCAT 1260 #define ER_WARN_TOO_FEW_RECORDS 1261 #define ER_WARN_TOO_MANY_RECORDS 1262 #define ER_WARN_NULL_TO_NOTNULL 1263 #define ER_WARN_DATA_OUT_OF_RANGE 1264 #define WARN_DATA_TRUNCATED 1265 #define ER_WARN_USING_OTHER_HANDLER 1266 #define ER_CANT_AGGREGATE_2COLLATIONS 1267 #define ER_DROP_USER 1268 #define ER_REVOKE_GRANTS 1269 #define ER_CANT_AGGREGATE_3COLLATIONS 1270 #define ER_CANT_AGGREGATE_NCOLLATIONS 1271 #define ER_VARIABLE_IS_NOT_STRUCT 1272 #define ER_UNKNOWN_COLLATION 1273 #define ER_SLAVE_IGNORED_SSL_PARAMS 1274 #define ER_SERVER_IS_IN_SECURE_AUTH_MODE 1275 #define ER_WARN_FIELD_RESOLVED 1276 #define ER_BAD_SLAVE_UNTIL_COND 1277 #define ER_MISSING_SKIP_SLAVE 1278 #define ER_UNTIL_COND_IGNORED 1279 #define ER_WRONG_NAME_FOR_INDEX 1280 #define ER_WRONG_NAME_FOR_CATALOG 1281 #define ER_WARN_QC_RESIZE 1282 #define ER_BAD_FT_COLUMN 1283 #define ER_UNKNOWN_KEY_CACHE 1284 #define ER_WARN_HOSTNAME_WONT_WORK 1285 #define ER_UNKNOWN_STORAGE_ENGINE 1286 #define ER_WARN_DEPRECATED_SYNTAX 1287 #define ER_NON_UPDATABLE_TABLE 1288 #define ER_FEATURE_DISABLED 1289 #define ER_OPTION_PREVENTS_STATEMENT 1290 #define ER_DUPLICATED_VALUE_IN_TYPE 1291 #define ER_TRUNCATED_WRONG_VALUE 1292 #define ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293 #define ER_INVALID_ON_UPDATE 1294 #define ER_UNSUPPORTED_PS 1295 #define ER_GET_ERRMSG 1296 #define ER_GET_TEMPORARY_ERRMSG 1297 #define ER_UNKNOWN_TIME_ZONE 1298 #define ER_WARN_INVALID_TIMESTAMP 1299 #define ER_INVALID_CHARACTER_STRING 1300 #define ER_WARN_ALLOWED_PACKET_OVERFLOWED 1301 #define ER_CONFLICTING_DECLARATIONS 1302 #define ER_SP_NO_RECURSIVE_CREATE 1303 #define ER_SP_ALREADY_EXISTS 1304 #define ER_SP_DOES_NOT_EXIST 1305 #define ER_SP_DROP_FAILED 1306 #define ER_SP_STORE_FAILED 1307 #define ER_SP_LILABEL_MISMATCH 1308 #define ER_SP_LABEL_REDEFINE 1309 #define ER_SP_LABEL_MISMATCH 1310 #define ER_SP_UNINIT_VAR 1311 #define ER_SP_BADSELECT 1312 #define ER_SP_BADRETURN 1313 #define ER_SP_BADSTATEMENT 1314 #define ER_UPDATE_LOG_DEPRECATED_IGNORED 1315 #define ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1316 #define ER_QUERY_INTERRUPTED 1317 #define ER_SP_WRONG_NO_OF_ARGS 1318 #define ER_SP_COND_MISMATCH 1319 #define ER_SP_NORETURN 1320 #define ER_SP_NORETURNEND 1321 #define ER_SP_BAD_CURSOR_QUERY 1322 #define ER_SP_BAD_CURSOR_SELECT 1323 #define ER_SP_CURSOR_MISMATCH 1324 #define ER_SP_CURSOR_ALREADY_OPEN 1325 #define ER_SP_CURSOR_NOT_OPEN 1326 #define ER_SP_UNDECLARED_VAR 1327 #define ER_SP_WRONG_NO_OF_FETCH_ARGS 1328 #define ER_SP_FETCH_NO_DATA 1329 #define ER_SP_DUP_PARAM 1330 #define ER_SP_DUP_VAR 1331 #define ER_SP_DUP_COND 1332 #define ER_SP_DUP_CURS 1333 #define ER_SP_CANT_ALTER 1334 #define ER_SP_SUBSELECT_NYI 1335 #define ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 1336 #define ER_SP_VARCOND_AFTER_CURSHNDLR 1337 #define ER_SP_CURSOR_AFTER_HANDLER 1338 #define ER_SP_CASE_NOT_FOUND 1339 #define ER_FPARSER_TOO_BIG_FILE 1340 #define ER_FPARSER_BAD_HEADER 1341 #define ER_FPARSER_EOF_IN_COMMENT 1342 #define ER_FPARSER_ERROR_IN_PARAMETER 1343 #define ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER 1344 #define ER_VIEW_NO_EXPLAIN 1345 #define ER_FRM_UNKNOWN_TYPE 1346 #define ER_WRONG_OBJECT 1347 #define ER_NONUPDATEABLE_COLUMN 1348 #define ER_VIEW_SELECT_DERIVED 1349 #define ER_VIEW_SELECT_CLAUSE 1350 #define ER_VIEW_SELECT_VARIABLE 1351 #define ER_VIEW_SELECT_TMPTABLE 1352 #define ER_VIEW_WRONG_LIST 1353 #define ER_WARN_VIEW_MERGE 1354 #define ER_WARN_VIEW_WITHOUT_KEY 1355 #define ER_VIEW_INVALID 1356 #define ER_SP_NO_DROP_SP 1357 #define ER_SP_GOTO_IN_HNDLR 1358 #define ER_TRG_ALREADY_EXISTS 1359 #define ER_TRG_DOES_NOT_EXIST 1360 #define ER_TRG_ON_VIEW_OR_TEMP_TABLE 1361 #define ER_TRG_CANT_CHANGE_ROW 1362 #define ER_TRG_NO_SUCH_ROW_IN_TRG 1363 #define ER_NO_DEFAULT_FOR_FIELD 1364 #define ER_DIVISION_BY_ZERO 1365 #define ER_TRUNCATED_WRONG_VALUE_FOR_FIELD 1366 #define ER_ILLEGAL_VALUE_FOR_TYPE 1367 #define ER_VIEW_NONUPD_CHECK 1368 #define ER_VIEW_CHECK_FAILED 1369 #define ER_PROCACCESS_DENIED_ERROR 1370 #define ER_RELAY_LOG_FAIL 1371 #define ER_PASSWD_LENGTH 1372 #define ER_UNKNOWN_TARGET_BINLOG 1373 #define ER_IO_ERR_LOG_INDEX_READ 1374 #define ER_BINLOG_PURGE_PROHIBITED 1375 #define ER_FSEEK_FAIL 1376 #define ER_BINLOG_PURGE_FATAL_ERR 1377 #define ER_LOG_IN_USE 1378 #define ER_LOG_PURGE_UNKNOWN_ERR 1379 #define ER_RELAY_LOG_INIT 1380 #define ER_NO_BINARY_LOGGING 1381 #define ER_RESERVED_SYNTAX 1382 #define ER_WSAS_FAILED 1383 #define ER_DIFF_GROUPS_PROC 1384 #define ER_NO_GROUP_FOR_PROC 1385 #define ER_ORDER_WITH_PROC 1386 #define ER_LOGGING_PROHIBIT_CHANGING_OF 1387 #define ER_NO_FILE_MAPPING 1388 #define ER_WRONG_MAGIC 1389 #define ER_PS_MANY_PARAM 1390 #define ER_KEY_PART_0 1391 #define ER_VIEW_CHECKSUM 1392 #define ER_VIEW_MULTIUPDATE 1393 #define ER_VIEW_NO_INSERT_FIELD_LIST 1394 #define ER_VIEW_DELETE_MERGE_VIEW 1395 #define ER_CANNOT_USER 1396 #define ER_XAER_NOTA 1397 #define ER_XAER_INVAL 1398 #define ER_XAER_RMFAIL 1399 #define ER_XAER_OUTSIDE 1400 #define ER_XAER_RMERR 1401 #define ER_XA_RBROLLBACK 1402 #define ER_NONEXISTING_PROC_GRANT 1403 #define ER_PROC_AUTO_GRANT_FAIL 1404 #define ER_PROC_AUTO_REVOKE_FAIL 1405 #define ER_DATA_TOO_LONG 1406 #define ER_SP_BAD_SQLSTATE 1407 #define ER_STARTUP 1408 #define ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR 1409 #define ER_CANT_CREATE_USER_WITH_GRANT 1410 #define ER_WRONG_VALUE_FOR_TYPE 1411 #define ER_TABLE_DEF_CHANGED 1412 #define ER_SP_DUP_HANDLER 1413 #define ER_SP_NOT_VAR_ARG 1414 #define ER_SP_NO_RETSET 1415 #define ER_CANT_CREATE_GEOMETRY_OBJECT 1416 #define ER_FAILED_ROUTINE_BREAK_BINLOG 1417 #define ER_BINLOG_UNSAFE_ROUTINE 1418 #define ER_BINLOG_CREATE_ROUTINE_NEED_SUPER 1419 #define ER_EXEC_STMT_WITH_OPEN_CURSOR 1420 #define ER_STMT_HAS_NO_OPEN_CURSOR 1421 #define ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG 1422 #define ER_NO_DEFAULT_FOR_VIEW_FIELD 1423 #define ER_SP_NO_RECURSION 1424 #define ER_TOO_BIG_SCALE 1425 #define ER_TOO_BIG_PRECISION 1426 #define ER_M_BIGGER_THAN_D 1427 #define ER_WRONG_LOCK_OF_SYSTEM_TABLE 1428 #define ER_CONNECT_TO_FOREIGN_DATA_SOURCE 1429 #define ER_QUERY_ON_FOREIGN_DATA_SOURCE 1430 #define ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST 1431 #define ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE 1432 #define ER_FOREIGN_DATA_STRING_INVALID 1433 #define ER_CANT_CREATE_FEDERATED_TABLE 1434 #define ER_TRG_IN_WRONG_SCHEMA 1435 #define ER_STACK_OVERRUN_NEED_MORE 1436 #define ER_TOO_LONG_BODY 1437 #define ER_WARN_CANT_DROP_DEFAULT_KEYCACHE 1438 #define ER_TOO_BIG_DISPLAYWIDTH 1439 #define ER_XAER_DUPID 1440 #define ER_DATETIME_FUNCTION_OVERFLOW 1441 #define ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG 1442 #define ER_VIEW_PREVENT_UPDATE 1443 #define ER_PS_NO_RECURSION 1444 #define ER_SP_CANT_SET_AUTOCOMMIT 1445 #define ER_MALFORMED_DEFINER 1446 #define ER_VIEW_FRM_NO_USER 1447 #define ER_VIEW_OTHER_USER 1448 #define ER_NO_SUCH_USER 1449 #define ER_FORBID_SCHEMA_CHANGE 1450 #define ER_ROW_IS_REFERENCED_2 1451 #define ER_NO_REFERENCED_ROW_2 1452 #define ER_SP_BAD_VAR_SHADOW 1453 #define ER_TRG_NO_DEFINER 1454 #define ER_OLD_FILE_FORMAT 1455 #define ER_SP_RECURSION_LIMIT 1456 #define ER_SP_PROC_TABLE_CORRUPT 1457 #define ER_SP_WRONG_NAME 1458 #define ER_TABLE_NEEDS_UPGRADE 1459 #define ER_SP_NO_AGGREGATE 1460 #define ER_MAX_PREPARED_STMT_COUNT_REACHED 1461 #define ER_VIEW_RECURSIVE 1462 #define ER_NON_GROUPING_FIELD_USED 1463 #define ER_TABLE_CANT_HANDLE_SPKEYS 1464 #define ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA 1465 #define ER_REMOVED_SPACES 1466 #define ER_AUTOINC_READ_FAILED 1467 #define ER_USERNAME 1468 #define ER_HOSTNAME 1469 #define ER_WRONG_STRING_LENGTH 1470 #define ER_NON_INSERTABLE_TABLE 1471 #define ER_ADMIN_WRONG_MRG_TABLE 1472 #define ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT 1473 #define ER_NAME_BECOMES_EMPTY 1474 #define ER_AMBIGUOUS_FIELD_TERM 1475 #define ER_FOREIGN_SERVER_EXISTS 1476 #define ER_FOREIGN_SERVER_DOESNT_EXIST 1477 #define ER_ILLEGAL_HA_CREATE_OPTION 1478 #define ER_PARTITION_REQUIRES_VALUES_ERROR 1479 #define ER_PARTITION_WRONG_VALUES_ERROR 1480 #define ER_PARTITION_MAXVALUE_ERROR 1481 #define ER_PARTITION_SUBPARTITION_ERROR 1482 #define ER_PARTITION_SUBPART_MIX_ERROR 1483 #define ER_PARTITION_WRONG_NO_PART_ERROR 1484 #define ER_PARTITION_WRONG_NO_SUBPART_ERROR 1485 #define ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR 1486 #define ER_NOT_CONSTANT_EXPRESSION 1487 #define ER_FIELD_NOT_FOUND_PART_ERROR 1488 #define ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR 1489 #define ER_INCONSISTENT_PARTITION_INFO_ERROR 1490 #define ER_PARTITION_FUNC_NOT_ALLOWED_ERROR 1491 #define ER_PARTITIONS_MUST_BE_DEFINED_ERROR 1492 #define ER_RANGE_NOT_INCREASING_ERROR 1493 #define ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR 1494 #define ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR 1495 #define ER_PARTITION_ENTRY_ERROR 1496 #define ER_MIX_HANDLER_ERROR 1497 #define ER_PARTITION_NOT_DEFINED_ERROR 1498 #define ER_TOO_MANY_PARTITIONS_ERROR 1499 #define ER_SUBPARTITION_ERROR 1500 #define ER_CANT_CREATE_HANDLER_FILE 1501 #define ER_BLOB_FIELD_IN_PART_FUNC_ERROR 1502 #define ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF 1503 #define ER_NO_PARTS_ERROR 1504 #define ER_PARTITION_MGMT_ON_NONPARTITIONED 1505 #define ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING 1506 #define ER_DROP_PARTITION_NON_EXISTENT 1507 #define ER_DROP_LAST_PARTITION 1508 #define ER_COALESCE_ONLY_ON_HASH_PARTITION 1509 #define ER_REORG_HASH_ONLY_ON_SAME_NO 1510 #define ER_REORG_NO_PARAM_ERROR 1511 #define ER_ONLY_ON_RANGE_LIST_PARTITION 1512 #define ER_ADD_PARTITION_SUBPART_ERROR 1513 #define ER_ADD_PARTITION_NO_NEW_PARTITION 1514 #define ER_COALESCE_PARTITION_NO_PARTITION 1515 #define ER_REORG_PARTITION_NOT_EXIST 1516 #define ER_SAME_NAME_PARTITION 1517 #define ER_NO_BINLOG_ERROR 1518 #define ER_CONSECUTIVE_REORG_PARTITIONS 1519 #define ER_REORG_OUTSIDE_RANGE 1520 #define ER_PARTITION_FUNCTION_FAILURE 1521 #define ER_PART_STATE_ERROR 1522 #define ER_LIMITED_PART_RANGE 1523 #define ER_PLUGIN_IS_NOT_LOADED 1524 #define ER_WRONG_VALUE 1525 #define ER_NO_PARTITION_FOR_GIVEN_VALUE 1526 #define ER_FILEGROUP_OPTION_ONLY_ONCE 1527 #define ER_CREATE_FILEGROUP_FAILED 1528 #define ER_DROP_FILEGROUP_FAILED 1529 #define ER_TABLESPACE_AUTO_EXTEND_ERROR 1530 #define ER_WRONG_SIZE_NUMBER 1531 #define ER_SIZE_OVERFLOW_ERROR 1532 #define ER_ALTER_FILEGROUP_FAILED 1533 #define ER_BINLOG_ROW_LOGGING_FAILED 1534 #define ER_BINLOG_ROW_WRONG_TABLE_DEF 1535 #define ER_BINLOG_ROW_RBR_TO_SBR 1536 #define ER_EVENT_ALREADY_EXISTS 1537 #define ER_EVENT_STORE_FAILED 1538 #define ER_EVENT_DOES_NOT_EXIST 1539 #define ER_EVENT_CANT_ALTER 1540 #define ER_EVENT_DROP_FAILED 1541 #define ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG 1542 #define ER_EVENT_ENDS_BEFORE_STARTS 1543 #define ER_EVENT_EXEC_TIME_IN_THE_PAST 1544 #define ER_EVENT_OPEN_TABLE_FAILED 1545 #define ER_EVENT_NEITHER_M_EXPR_NOR_M_AT 1546 #define ER_UNUSED_2 1547 #define ER_UNUSED_3 1548 #define ER_EVENT_CANNOT_DELETE 1549 #define ER_EVENT_COMPILE_ERROR 1550 #define ER_EVENT_SAME_NAME 1551 #define ER_EVENT_DATA_TOO_LONG 1552 #define ER_DROP_INDEX_FK 1553 #define ER_WARN_DEPRECATED_SYNTAX_WITH_VER 1554 #define ER_CANT_WRITE_LOCK_LOG_TABLE 1555 #define ER_CANT_LOCK_LOG_TABLE 1556 #define ER_UNUSED_4 1557 #define ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE 1558 #define ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR 1559 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT 1560 #define ER_UNUSED_13 1561 #define ER_PARTITION_NO_TEMPORARY 1562 #define ER_PARTITION_CONST_DOMAIN_ERROR 1563 #define ER_PARTITION_FUNCTION_IS_NOT_ALLOWED 1564 #define ER_DDL_LOG_ERROR 1565 #define ER_NULL_IN_VALUES_LESS_THAN 1566 #define ER_WRONG_PARTITION_NAME 1567 #define ER_CANT_CHANGE_TX_CHARACTERISTICS 1568 #define ER_DUP_ENTRY_AUTOINCREMENT_CASE 1569 #define ER_EVENT_MODIFY_QUEUE_ERROR 1570 #define ER_EVENT_SET_VAR_ERROR 1571 #define ER_PARTITION_MERGE_ERROR 1572 #define ER_CANT_ACTIVATE_LOG 1573 #define ER_RBR_NOT_AVAILABLE 1574 #define ER_BASE64_DECODE_ERROR 1575 #define ER_EVENT_RECURSION_FORBIDDEN 1576 #define ER_EVENTS_DB_ERROR 1577 #define ER_ONLY_INTEGERS_ALLOWED 1578 #define ER_UNSUPORTED_LOG_ENGINE 1579 #define ER_BAD_LOG_STATEMENT 1580 #define ER_CANT_RENAME_LOG_TABLE 1581 #define ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 1582 #define ER_WRONG_PARAMETERS_TO_NATIVE_FCT 1583 #define ER_WRONG_PARAMETERS_TO_STORED_FCT 1584 #define ER_NATIVE_FCT_NAME_COLLISION 1585 #define ER_DUP_ENTRY_WITH_KEY_NAME 1586 #define ER_BINLOG_PURGE_EMFILE 1587 #define ER_EVENT_CANNOT_CREATE_IN_THE_PAST 1588 #define ER_EVENT_CANNOT_ALTER_IN_THE_PAST 1589 #define ER_SLAVE_INCIDENT 1590 #define ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT 1591 #define ER_BINLOG_UNSAFE_STATEMENT 1592 #define ER_SLAVE_FATAL_ERROR 1593 #define ER_SLAVE_RELAY_LOG_READ_FAILURE 1594 #define ER_SLAVE_RELAY_LOG_WRITE_FAILURE 1595 #define ER_SLAVE_CREATE_EVENT_FAILURE 1596 #define ER_SLAVE_MASTER_COM_FAILURE 1597 #define ER_BINLOG_LOGGING_IMPOSSIBLE 1598 #define ER_VIEW_NO_CREATION_CTX 1599 #define ER_VIEW_INVALID_CREATION_CTX 1600 #define ER_SR_INVALID_CREATION_CTX 1601 #define ER_TRG_CORRUPTED_FILE 1602 #define ER_TRG_NO_CREATION_CTX 1603 #define ER_TRG_INVALID_CREATION_CTX 1604 #define ER_EVENT_INVALID_CREATION_CTX 1605 #define ER_TRG_CANT_OPEN_TABLE 1606 #define ER_CANT_CREATE_SROUTINE 1607 #define ER_UNUSED_11 1608 #define ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT 1609 #define ER_SLAVE_CORRUPT_EVENT 1610 #define ER_LOAD_DATA_INVALID_COLUMN 1611 #define ER_LOG_PURGE_NO_FILE 1612 #define ER_XA_RBTIMEOUT 1613 #define ER_XA_RBDEADLOCK 1614 #define ER_NEED_REPREPARE 1615 #define ER_DELAYED_NOT_SUPPORTED 1616 #define WARN_NO_MASTER_INFO 1617 #define WARN_OPTION_IGNORED 1618 #define ER_PLUGIN_DELETE_BUILTIN 1619 #define WARN_PLUGIN_BUSY 1620 #define ER_VARIABLE_IS_READONLY 1621 #define ER_WARN_ENGINE_TRANSACTION_ROLLBACK 1622 #define ER_SLAVE_HEARTBEAT_FAILURE 1623 #define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE 1624 #define ER_UNUSED_14 1625 #define ER_CONFLICT_FN_PARSE_ERROR 1626 #define ER_EXCEPTIONS_WRITE_ERROR 1627 #define ER_TOO_LONG_TABLE_COMMENT 1628 #define ER_TOO_LONG_FIELD_COMMENT 1629 #define ER_FUNC_INEXISTENT_NAME_COLLISION 1630 #define ER_DATABASE_NAME 1631 #define ER_TABLE_NAME 1632 #define ER_PARTITION_NAME 1633 #define ER_SUBPARTITION_NAME 1634 #define ER_TEMPORARY_NAME 1635 #define ER_RENAMED_NAME 1636 #define ER_TOO_MANY_CONCURRENT_TRXS 1637 #define WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED 1638 #define ER_DEBUG_SYNC_TIMEOUT 1639 #define ER_DEBUG_SYNC_HIT_LIMIT 1640 #define ER_DUP_SIGNAL_SET 1641 #define ER_SIGNAL_WARN 1642 #define ER_SIGNAL_NOT_FOUND 1643 #define ER_SIGNAL_EXCEPTION 1644 #define ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER 1645 #define ER_SIGNAL_BAD_CONDITION_TYPE 1646 #define WARN_COND_ITEM_TRUNCATED 1647 #define ER_COND_ITEM_TOO_LONG 1648 #define ER_UNKNOWN_LOCALE 1649 #define ER_SLAVE_IGNORE_SERVER_IDS 1650 #define ER_QUERY_CACHE_DISABLED 1651 #define ER_SAME_NAME_PARTITION_FIELD 1652 #define ER_PARTITION_COLUMN_LIST_ERROR 1653 #define ER_WRONG_TYPE_COLUMN_VALUE_ERROR 1654 #define ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR 1655 #define ER_MAXVALUE_IN_VALUES_IN 1656 #define ER_TOO_MANY_VALUES_ERROR 1657 #define ER_ROW_SINGLE_PARTITION_FIELD_ERROR 1658 #define ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD 1659 #define ER_PARTITION_FIELDS_TOO_LONG 1660 #define ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE 1661 #define ER_BINLOG_ROW_MODE_AND_STMT_ENGINE 1662 #define ER_BINLOG_UNSAFE_AND_STMT_ENGINE 1663 #define ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE 1664 #define ER_BINLOG_STMT_MODE_AND_ROW_ENGINE 1665 #define ER_BINLOG_ROW_INJECTION_AND_STMT_MODE 1666 #define ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1667 #define ER_BINLOG_UNSAFE_LIMIT 1668 #define ER_BINLOG_UNSAFE_INSERT_DELAYED 1669 #define ER_BINLOG_UNSAFE_SYSTEM_TABLE 1670 #define ER_BINLOG_UNSAFE_AUTOINC_COLUMNS 1671 #define ER_BINLOG_UNSAFE_UDF 1672 #define ER_BINLOG_UNSAFE_SYSTEM_VARIABLE 1673 #define ER_BINLOG_UNSAFE_SYSTEM_FUNCTION 1674 #define ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS 1675 #define ER_MESSAGE_AND_STATEMENT 1676 #define ER_SLAVE_CONVERSION_FAILED 1677 #define ER_SLAVE_CANT_CREATE_CONVERSION 1678 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT 1679 #define ER_PATH_LENGTH 1680 #define ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT 1681 #define ER_WRONG_NATIVE_TABLE_STRUCTURE 1682 #define ER_WRONG_PERFSCHEMA_USAGE 1683 #define ER_WARN_I_S_SKIPPED_TABLE 1684 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT 1685 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT 1686 #define ER_SPATIAL_MUST_HAVE_GEOM_COL 1687 #define ER_TOO_LONG_INDEX_COMMENT 1688 #define ER_LOCK_ABORTED 1689 #define ER_DATA_OUT_OF_RANGE 1690 #define ER_WRONG_SPVAR_TYPE_IN_LIMIT 1691 #define ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1692 #define ER_BINLOG_UNSAFE_MIXED_STATEMENT 1693 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN 1694 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN 1695 #define ER_FAILED_READ_FROM_PAR_FILE 1696 #define ER_VALUES_IS_NOT_INT_TYPE_ERROR 1697 #define ER_ACCESS_DENIED_NO_PASSWORD_ERROR 1698 #define ER_SET_PASSWORD_AUTH_PLUGIN 1699 #define ER_GRANT_PLUGIN_USER_EXISTS 1700 #define ER_TRUNCATE_ILLEGAL_FK 1701 #define ER_PLUGIN_IS_PERMANENT 1702 #define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN 1703 #define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX 1704 #define ER_STMT_CACHE_FULL 1705 #define ER_MULTI_UPDATE_KEY_CONFLICT 1706 #define ER_TABLE_NEEDS_REBUILD 1707 #define WARN_OPTION_BELOW_LIMIT 1708 #define ER_INDEX_COLUMN_TOO_LONG 1709 #define ER_ERROR_IN_TRIGGER_BODY 1710 #define ER_ERROR_IN_UNKNOWN_TRIGGER_BODY 1711 #define ER_INDEX_CORRUPT 1712 #define ER_UNDO_RECORD_TOO_BIG 1713 #define ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT 1714 #define ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE 1715 #define ER_BINLOG_UNSAFE_REPLACE_SELECT 1716 #define ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT 1717 #define ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT 1718 #define ER_BINLOG_UNSAFE_UPDATE_IGNORE 1719 #define ER_UNUSED_15 1720 #define ER_UNUSED_16 1721 #define ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT 1722 #define ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC 1723 #define ER_BINLOG_UNSAFE_INSERT_TWO_KEYS 1724 #define ER_UNUSED_28 1725 #define ER_VERS_NOT_ALLOWED 1726 #define ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST 1727 #define ER_CANNOT_LOAD_FROM_TABLE_V2 1728 #define ER_MASTER_DELAY_VALUE_OUT_OF_RANGE 1729 #define ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT 1730 #define ER_PARTITION_EXCHANGE_DIFFERENT_OPTION 1731 #define ER_PARTITION_EXCHANGE_PART_TABLE 1732 #define ER_PARTITION_EXCHANGE_TEMP_TABLE 1733 #define ER_PARTITION_INSTEAD_OF_SUBPARTITION 1734 #define ER_UNKNOWN_PARTITION 1735 #define ER_TABLES_DIFFERENT_METADATA 1736 #define ER_ROW_DOES_NOT_MATCH_PARTITION 1737 #define ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX 1738 #define ER_WARN_INDEX_NOT_APPLICABLE 1739 #define ER_PARTITION_EXCHANGE_FOREIGN_KEY 1740 #define ER_NO_SUCH_KEY_VALUE 1741 #define ER_VALUE_TOO_LONG 1742 #define ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE 1743 #define ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE 1744 #define ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX 1745 #define ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT 1746 #define ER_PARTITION_CLAUSE_ON_NONPARTITIONED 1747 #define ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET 1748 #define ER_UNUSED_5 1749 #define ER_CHANGE_RPL_INFO_REPOSITORY_FAILURE 1750 #define ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE 1751 #define ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE 1752 #define ER_MTS_FEATURE_IS_NOT_SUPPORTED 1753 #define ER_MTS_UPDATED_DBS_GREATER_MAX 1754 #define ER_MTS_CANT_PARALLEL 1755 #define ER_MTS_INCONSISTENT_DATA 1756 #define ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING 1757 #define ER_DA_INVALID_CONDITION_NUMBER 1758 #define ER_INSECURE_PLAIN_TEXT 1759 #define ER_INSECURE_CHANGE_MASTER 1760 #define ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO 1761 #define ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO 1762 #define ER_SQLTHREAD_WITH_SECURE_SLAVE 1763 #define ER_TABLE_HAS_NO_FT 1764 #define ER_VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER 1765 #define ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION 1766 #define ER_GTID_NEXT_IS_NOT_IN_GTID_NEXT_LIST 1767 #define ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION_WHEN_GTID_NEXT_LIST_IS_NULL 1768 #define ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION 1769 #define ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL 1770 #define ER_SKIPPING_LOGGED_TRANSACTION 1771 #define ER_MALFORMED_GTID_SET_SPECIFICATION 1772 #define ER_MALFORMED_GTID_SET_ENCODING 1773 #define ER_MALFORMED_GTID_SPECIFICATION 1774 #define ER_GNO_EXHAUSTED 1775 #define ER_BAD_SLAVE_AUTO_POSITION 1776 #define ER_AUTO_POSITION_REQUIRES_GTID_MODE_ON 1777 #define ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET 1778 #define ER_GTID_MODE_2_OR_3_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON 1779 #define ER_GTID_MODE_REQUIRES_BINLOG 1780 #define ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF 1781 #define ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON 1782 #define ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF 1783 #define ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF 1784 #define ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE 1785 #define ER_GTID_UNSAFE_CREATE_SELECT 1786 #define ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION 1787 #define ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME 1788 #define ER_MASTER_HAS_PURGED_REQUIRED_GTIDS 1789 #define ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID 1790 #define ER_UNKNOWN_EXPLAIN_FORMAT 1791 #define ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION 1792 #define ER_TOO_LONG_TABLE_PARTITION_COMMENT 1793 #define ER_SLAVE_CONFIGURATION 1794 #define ER_INNODB_FT_LIMIT 1795 #define ER_INNODB_NO_FT_TEMP_TABLE 1796 #define ER_INNODB_FT_WRONG_DOCID_COLUMN 1797 #define ER_INNODB_FT_WRONG_DOCID_INDEX 1798 #define ER_INNODB_ONLINE_LOG_TOO_BIG 1799 #define ER_UNKNOWN_ALTER_ALGORITHM 1800 #define ER_UNKNOWN_ALTER_LOCK 1801 #define ER_MTS_CHANGE_MASTER_CANT_RUN_WITH_GAPS 1802 #define ER_MTS_RECOVERY_FAILURE 1803 #define ER_MTS_RESET_WORKERS 1804 #define ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2 1805 #define ER_SLAVE_SILENT_RETRY_TRANSACTION 1806 #define ER_UNUSED_22 1807 #define ER_TABLE_SCHEMA_MISMATCH 1808 #define ER_TABLE_IN_SYSTEM_TABLESPACE 1809 #define ER_IO_READ_ERROR 1810 #define ER_IO_WRITE_ERROR 1811 #define ER_TABLESPACE_MISSING 1812 #define ER_TABLESPACE_EXISTS 1813 #define ER_TABLESPACE_DISCARDED 1814 #define ER_INTERNAL_ERROR 1815 #define ER_INNODB_IMPORT_ERROR 1816 #define ER_INNODB_INDEX_CORRUPT 1817 #define ER_INVALID_YEAR_COLUMN_LENGTH 1818 #define ER_NOT_VALID_PASSWORD 1819 #define ER_MUST_CHANGE_PASSWORD 1820 #define ER_FK_NO_INDEX_CHILD 1821 #define ER_FK_NO_INDEX_PARENT 1822 #define ER_FK_FAIL_ADD_SYSTEM 1823 #define ER_FK_CANNOT_OPEN_PARENT 1824 #define ER_FK_INCORRECT_OPTION 1825 #define ER_DUP_CONSTRAINT_NAME 1826 #define ER_PASSWORD_FORMAT 1827 #define ER_FK_COLUMN_CANNOT_DROP 1828 #define ER_FK_COLUMN_CANNOT_DROP_CHILD 1829 #define ER_FK_COLUMN_NOT_NULL 1830 #define ER_DUP_INDEX 1831 #define ER_FK_COLUMN_CANNOT_CHANGE 1832 #define ER_FK_COLUMN_CANNOT_CHANGE_CHILD 1833 #define ER_FK_CANNOT_DELETE_PARENT 1834 #define ER_MALFORMED_PACKET 1835 #define ER_READ_ONLY_MODE 1836 #define ER_GTID_NEXT_TYPE_UNDEFINED_GROUP 1837 #define ER_VARIABLE_NOT_SETTABLE_IN_SP 1838 #define ER_CANT_SET_GTID_PURGED_WHEN_GTID_MODE_IS_OFF 1839 #define ER_CANT_SET_GTID_PURGED_WHEN_GTID_EXECUTED_IS_NOT_EMPTY 1840 #define ER_CANT_SET_GTID_PURGED_WHEN_OWNED_GTIDS_IS_NOT_EMPTY 1841 #define ER_GTID_PURGED_WAS_CHANGED 1842 #define ER_GTID_EXECUTED_WAS_CHANGED 1843 #define ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES 1844 #define ER_ALTER_OPERATION_NOT_SUPPORTED 1845 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON 1846 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY 1847 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION 1848 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME 1849 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE 1850 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_CHECK 1851 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_IGNORE 1852 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOPK 1853 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_AUTOINC 1854 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_HIDDEN_FTS 1855 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_CHANGE_FTS 1856 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS 1857 #define ER_SQL_SLAVE_SKIP_COUNTER_NOT_SETTABLE_IN_GTID_MODE 1858 #define ER_DUP_UNKNOWN_IN_INDEX 1859 #define ER_IDENT_CAUSES_TOO_LONG_PATH 1860 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL 1861 #define ER_MUST_CHANGE_PASSWORD_LOGIN 1862 #define ER_ROW_IN_WRONG_PARTITION 1863 #define ER_MTS_EVENT_BIGGER_PENDING_JOBS_SIZE_MAX 1864 #define ER_INNODB_NO_FT_USES_PARSER 1865 #define ER_BINLOG_LOGICAL_CORRUPTION 1866 #define ER_WARN_PURGE_LOG_IN_USE 1867 #define ER_WARN_PURGE_LOG_IS_ACTIVE 1868 #define ER_AUTO_INCREMENT_CONFLICT 1869 #define WARN_ON_BLOCKHOLE_IN_RBR 1870 #define ER_SLAVE_MI_INIT_REPOSITORY 1871 #define ER_SLAVE_RLI_INIT_REPOSITORY 1872 #define ER_ACCESS_DENIED_CHANGE_USER_ERROR 1873 #define ER_INNODB_READ_ONLY 1874 #define ER_STOP_SLAVE_SQL_THREAD_TIMEOUT 1875 #define ER_STOP_SLAVE_IO_THREAD_TIMEOUT 1876 #define ER_TABLE_CORRUPT 1877 #define ER_TEMP_FILE_WRITE_FAILURE 1878 #define ER_INNODB_FT_AUX_NOT_HEX_ID 1879 #define ER_LAST_MYSQL_ERROR_MESSAGE 1880 #define ER_ERROR_LAST_SECTION_1 1880 /* New section */ #define ER_ERROR_FIRST_SECTION_2 1900 #define ER_UNUSED_18 1900 #define ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED 1901 #define ER_UNUSED_19 1902 #define ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN 1903 #define ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN 1904 #define ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN 1905 #define ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN 1906 #define ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN 1907 #define ER_UNUSED_20 1908 #define ER_UNUSED_21 1909 #define ER_UNSUPPORTED_ENGINE_FOR_GENERATED_COLUMNS 1910 #define ER_UNKNOWN_OPTION 1911 #define ER_BAD_OPTION_VALUE 1912 #define ER_UNUSED_6 1913 #define ER_UNUSED_7 1914 #define ER_UNUSED_8 1915 #define ER_DATA_OVERFLOW 1916 #define ER_DATA_TRUNCATED 1917 #define ER_BAD_DATA 1918 #define ER_DYN_COL_WRONG_FORMAT 1919 #define ER_DYN_COL_IMPLEMENTATION_LIMIT 1920 #define ER_DYN_COL_DATA 1921 #define ER_DYN_COL_WRONG_CHARSET 1922 #define ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES 1923 #define ER_QUERY_CACHE_IS_DISABLED 1924 #define ER_QUERY_CACHE_IS_GLOBALY_DISABLED 1925 #define ER_VIEW_ORDERBY_IGNORED 1926 #define ER_CONNECTION_KILLED 1927 #define ER_UNUSED_12 1928 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION 1929 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION 1930 #define ER_QUERY_RESULT_INCOMPLETE 1931 #define ER_NO_SUCH_TABLE_IN_ENGINE 1932 #define ER_TARGET_NOT_EXPLAINABLE 1933 #define ER_CONNECTION_ALREADY_EXISTS 1934 #define ER_MASTER_LOG_PREFIX 1935 #define ER_CANT_START_STOP_SLAVE 1936 #define ER_SLAVE_STARTED 1937 #define ER_SLAVE_STOPPED 1938 #define ER_SQL_DISCOVER_ERROR 1939 #define ER_FAILED_GTID_STATE_INIT 1940 #define ER_INCORRECT_GTID_STATE 1941 #define ER_CANNOT_UPDATE_GTID_STATE 1942 #define ER_DUPLICATE_GTID_DOMAIN 1943 #define ER_GTID_OPEN_TABLE_FAILED 1944 #define ER_GTID_POSITION_NOT_FOUND_IN_BINLOG 1945 #define ER_CANNOT_LOAD_SLAVE_GTID_STATE 1946 #define ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG 1947 #define ER_MASTER_GTID_POS_MISSING_DOMAIN 1948 #define ER_UNTIL_REQUIRES_USING_GTID 1949 #define ER_GTID_STRICT_OUT_OF_ORDER 1950 #define ER_GTID_START_FROM_BINLOG_HOLE 1951 #define ER_SLAVE_UNEXPECTED_MASTER_SWITCH 1952 #define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO 1953 #define ER_STORED_FUNCTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO 1954 #define ER_GTID_POSITION_NOT_FOUND_IN_BINLOG2 1955 #define ER_BINLOG_MUST_BE_EMPTY 1956 #define ER_NO_SUCH_QUERY 1957 #define ER_BAD_BASE64_DATA 1958 #define ER_INVALID_ROLE 1959 #define ER_INVALID_CURRENT_USER 1960 #define ER_CANNOT_GRANT_ROLE 1961 #define ER_CANNOT_REVOKE_ROLE 1962 #define ER_CHANGE_SLAVE_PARALLEL_THREADS_ACTIVE 1963 #define ER_PRIOR_COMMIT_FAILED 1964 #define ER_IT_IS_A_VIEW 1965 #define ER_SLAVE_SKIP_NOT_IN_GTID 1966 #define ER_TABLE_DEFINITION_TOO_BIG 1967 #define ER_PLUGIN_INSTALLED 1968 #define ER_STATEMENT_TIMEOUT 1969 #define ER_SUBQUERIES_NOT_SUPPORTED 1970 #define ER_SET_STATEMENT_NOT_SUPPORTED 1971 #define ER_UNUSED_9 1972 #define ER_USER_CREATE_EXISTS 1973 #define ER_USER_DROP_EXISTS 1974 #define ER_ROLE_CREATE_EXISTS 1975 #define ER_ROLE_DROP_EXISTS 1976 #define ER_CANNOT_CONVERT_CHARACTER 1977 #define ER_INVALID_DEFAULT_VALUE_FOR_FIELD 1978 #define ER_KILL_QUERY_DENIED_ERROR 1979 #define ER_NO_EIS_FOR_FIELD 1980 #define ER_WARN_AGGFUNC_DEPENDENCE 1981 #define WARN_INNODB_PARTITION_OPTION_IGNORED 1982 #define ER_ERROR_LAST_SECTION_2 1982 /* New section */ #define ER_ERROR_FIRST_SECTION_3 2000 #define ER_ERROR_LAST_SECTION_3 2000 /* New section */ #define ER_ERROR_FIRST_SECTION_4 3000 #define ER_FILE_CORRUPT 3000 #define ER_ERROR_ON_MASTER 3001 #define ER_INCONSISTENT_ERROR 3002 #define ER_STORAGE_ENGINE_NOT_LOADED 3003 #define ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER 3004 #define ER_WARN_LEGACY_SYNTAX_CONVERTED 3005 #define ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN 3006 #define ER_CANNOT_DISCARD_TEMPORARY_TABLE 3007 #define ER_FK_DEPTH_EXCEEDED 3008 #define ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2 3009 #define ER_WARN_TRIGGER_DOESNT_HAVE_CREATED 3010 #define ER_REFERENCED_TRG_DOES_NOT_EXIST_MYSQL 3011 #define ER_EXPLAIN_NOT_SUPPORTED 3012 #define ER_INVALID_FIELD_SIZE 3013 #define ER_MISSING_HA_CREATE_OPTION 3014 #define ER_ENGINE_OUT_OF_MEMORY 3015 #define ER_PASSWORD_EXPIRE_ANONYMOUS_USER 3016 #define ER_SLAVE_SQL_THREAD_MUST_STOP 3017 #define ER_NO_FT_MATERIALIZED_SUBQUERY 3018 #define ER_INNODB_UNDO_LOG_FULL 3019 #define ER_INVALID_ARGUMENT_FOR_LOGARITHM 3020 #define ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP 3021 #define ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO 3022 #define ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS 3023 #define ER_UNUSED_1 3024 #define ER_NON_RO_SELECT_DISABLE_TIMER 3025 #define ER_DUP_LIST_ENTRY 3026 #define ER_SQL_MODE_NO_EFFECT 3027 #define ER_AGGREGATE_ORDER_FOR_UNION 3028 #define ER_AGGREGATE_ORDER_NON_AGG_QUERY 3029 #define ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR 3030 #define ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER 3031 #define ER_SERVER_OFFLINE_MODE 3032 #define ER_GIS_DIFFERENT_SRIDS 3033 #define ER_GIS_UNSUPPORTED_ARGUMENT 3034 #define ER_GIS_UNKNOWN_ERROR 3035 #define ER_GIS_UNKNOWN_EXCEPTION 3036 #define ER_GIS_INVALID_DATA 3037 #define ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION 3038 #define ER_BOOST_GEOMETRY_CENTROID_EXCEPTION 3039 #define ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION 3040 #define ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION 3041 #define ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION 3042 #define ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION 3043 #define ER_STD_BAD_ALLOC_ERROR 3044 #define ER_STD_DOMAIN_ERROR 3045 #define ER_STD_LENGTH_ERROR 3046 #define ER_STD_INVALID_ARGUMENT 3047 #define ER_STD_OUT_OF_RANGE_ERROR 3048 #define ER_STD_OVERFLOW_ERROR 3049 #define ER_STD_RANGE_ERROR 3050 #define ER_STD_UNDERFLOW_ERROR 3051 #define ER_STD_LOGIC_ERROR 3052 #define ER_STD_RUNTIME_ERROR 3053 #define ER_STD_UNKNOWN_EXCEPTION 3054 #define ER_GIS_DATA_WRONG_ENDIANESS 3055 #define ER_CHANGE_MASTER_PASSWORD_LENGTH 3056 #define ER_USER_LOCK_WRONG_NAME 3057 #define ER_USER_LOCK_DEADLOCK 3058 #define ER_REPLACE_INACCESSIBLE_ROWS 3059 #define ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS 3060 #define ER_ERROR_LAST_SECTION_4 3060 /* New section */ #define ER_ERROR_FIRST_SECTION_5 4000 #define ER_UNUSED_26 4000 #define ER_UNUSED_27 4001 #define ER_WITH_COL_WRONG_LIST 4002 #define ER_TOO_MANY_DEFINITIONS_IN_WITH_CLAUSE 4003 #define ER_DUP_QUERY_NAME 4004 #define ER_RECURSIVE_WITHOUT_ANCHORS 4005 #define ER_UNACCEPTABLE_MUTUAL_RECURSION 4006 #define ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED 4007 #define ER_NOT_STANDARD_COMPLIANT_RECURSIVE 4008 #define ER_WRONG_WINDOW_SPEC_NAME 4009 #define ER_DUP_WINDOW_NAME 4010 #define ER_PARTITION_LIST_IN_REFERENCING_WINDOW_SPEC 4011 #define ER_ORDER_LIST_IN_REFERENCING_WINDOW_SPEC 4012 #define ER_WINDOW_FRAME_IN_REFERENCED_WINDOW_SPEC 4013 #define ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS 4014 #define ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION 4015 #define ER_WINDOW_FUNCTION_IN_WINDOW_SPEC 4016 #define ER_NOT_ALLOWED_WINDOW_FRAME 4017 #define ER_NO_ORDER_LIST_IN_WINDOW_SPEC 4018 #define ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY 4019 #define ER_WRONG_TYPE_FOR_ROWS_FRAME 4020 #define ER_WRONG_TYPE_FOR_RANGE_FRAME 4021 #define ER_FRAME_EXCLUSION_NOT_SUPPORTED 4022 #define ER_WINDOW_FUNCTION_DONT_HAVE_FRAME 4023 #define ER_INVALID_NTILE_ARGUMENT 4024 #define ER_CONSTRAINT_FAILED 4025 #define ER_EXPRESSION_IS_TOO_BIG 4026 #define ER_ERROR_EVALUATING_EXPRESSION 4027 #define ER_CALCULATING_DEFAULT_VALUE 4028 #define ER_EXPRESSION_REFERS_TO_UNINIT_FIELD 4029 #define ER_PARTITION_DEFAULT_ERROR 4030 #define ER_REFERENCED_TRG_DOES_NOT_EXIST 4031 #define ER_INVALID_DEFAULT_PARAM 4032 #define ER_BINLOG_NON_SUPPORTED_BULK 4033 #define ER_BINLOG_UNCOMPRESS_ERROR 4034 #define ER_JSON_BAD_CHR 4035 #define ER_JSON_NOT_JSON_CHR 4036 #define ER_JSON_EOS 4037 #define ER_JSON_SYNTAX 4038 #define ER_JSON_ESCAPING 4039 #define ER_JSON_DEPTH 4040 #define ER_JSON_PATH_EOS 4041 #define ER_JSON_PATH_SYNTAX 4042 #define ER_JSON_PATH_DEPTH 4043 #define ER_JSON_PATH_NO_WILDCARD 4044 #define ER_JSON_PATH_ARRAY 4045 #define ER_JSON_ONE_OR_ALL 4046 #define ER_UNSUPPORTED_COMPRESSED_TABLE 4047 #define ER_GEOJSON_INCORRECT 4048 #define ER_GEOJSON_TOO_FEW_POINTS 4049 #define ER_GEOJSON_NOT_CLOSED 4050 #define ER_JSON_PATH_EMPTY 4051 #define ER_SLAVE_SAME_ID 4052 #define ER_FLASHBACK_NOT_SUPPORTED 4053 #define ER_KEYS_OUT_OF_ORDER 4054 #define ER_OVERLAPPING_KEYS 4055 #define ER_REQUIRE_ROW_BINLOG_FORMAT 4056 #define ER_ISOLATION_MODE_NOT_SUPPORTED 4057 #define ER_ON_DUPLICATE_DISABLED 4058 #define ER_UPDATES_WITH_CONSISTENT_SNAPSHOT 4059 #define ER_ROLLBACK_ONLY 4060 #define ER_ROLLBACK_TO_SAVEPOINT 4061 #define ER_ISOLATION_LEVEL_WITH_CONSISTENT_SNAPSHOT 4062 #define ER_UNSUPPORTED_COLLATION 4063 #define ER_METADATA_INCONSISTENCY 4064 #define ER_CF_DIFFERENT 4065 #define ER_RDB_TTL_DURATION_FORMAT 4066 #define ER_RDB_STATUS_GENERAL 4067 #define ER_RDB_STATUS_MSG 4068 #define ER_RDB_TTL_UNSUPPORTED 4069 #define ER_RDB_TTL_COL_FORMAT 4070 #define ER_PER_INDEX_CF_DEPRECATED 4071 #define ER_KEY_CREATE_DURING_ALTER 4072 #define ER_SK_POPULATE_DURING_ALTER 4073 #define ER_SUM_FUNC_WITH_WINDOW_FUNC_AS_ARG 4074 #define ER_NET_OK_PACKET_TOO_LARGE 4075 #define ER_GEOJSON_EMPTY_COORDINATES 4076 #define ER_MYROCKS_CANT_NOPAD_COLLATION 4077 #define ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION 4078 #define ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION 4079 #define ER_WRONG_PARAMCOUNT_TO_CURSOR 4080 #define ER_UNKNOWN_STRUCTURED_VARIABLE 4081 #define ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD 4082 #define ER_END_IDENTIFIER_DOES_NOT_MATCH 4083 #define ER_SEQUENCE_RUN_OUT 4084 #define ER_SEQUENCE_INVALID_DATA 4085 #define ER_SEQUENCE_INVALID_TABLE_STRUCTURE 4086 #define ER_SEQUENCE_ACCESS_ERROR 4087 #define ER_SEQUENCE_BINLOG_FORMAT 4088 #define ER_NOT_SEQUENCE 4089 #define ER_NOT_SEQUENCE2 4090 #define ER_UNKNOWN_SEQUENCES 4091 #define ER_UNKNOWN_VIEW 4092 #define ER_WRONG_INSERT_INTO_SEQUENCE 4093 #define ER_SP_STACK_TRACE 4094 #define ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY 4095 #define ER_PACKAGE_ROUTINE_FORWARD_DECLARATION_NOT_DEFINED 4096 #define ER_COMPRESSED_COLUMN_USED_AS_KEY 4097 #define ER_UNKNOWN_COMPRESSION_METHOD 4098 #define ER_WRONG_NUMBER_OF_VALUES_IN_TVC 4099 #define ER_FIELD_REFERENCE_IN_TVC 4100 #define ER_WRONG_TYPE_FOR_PERCENTILE_FUNC 4101 #define ER_ARGUMENT_NOT_CONSTANT 4102 #define ER_ARGUMENT_OUT_OF_RANGE 4103 #define ER_WRONG_TYPE_OF_ARGUMENT 4104 #define ER_NOT_AGGREGATE_FUNCTION 4105 #define ER_INVALID_AGGREGATE_FUNCTION 4106 #define ER_INVALID_VALUE_TO_LIMIT 4107 #define ER_INVISIBLE_NOT_NULL_WITHOUT_DEFAULT 4108 #define ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING 4109 #define ER_VERS_FIELD_WRONG_TYPE 4110 #define ER_VERS_ENGINE_UNSUPPORTED 4111 #define ER_UNUSED_23 4112 #define ER_PARTITION_WRONG_TYPE 4113 #define WARN_VERS_PART_FULL 4114 #define WARN_VERS_PARAMETERS 4115 #define ER_VERS_DROP_PARTITION_INTERVAL 4116 #define ER_UNUSED_25 4117 #define WARN_VERS_PART_NON_HISTORICAL 4118 #define ER_VERS_ALTER_NOT_ALLOWED 4119 #define ER_VERS_ALTER_ENGINE_PROHIBITED 4120 #define ER_VERS_RANGE_PROHIBITED 4121 #define ER_CONFLICTING_FOR_SYSTEM_TIME 4122 #define ER_VERS_TABLE_MUST_HAVE_COLUMNS 4123 #define ER_VERS_NOT_VERSIONED 4124 #define ER_MISSING 4125 #define ER_VERS_PERIOD_COLUMNS 4126 #define ER_PART_WRONG_VALUE 4127 #define ER_VERS_WRONG_PARTS 4128 #define ER_VERS_NO_TRX_ID 4129 #define ER_VERS_ALTER_SYSTEM_FIELD 4130 #define ER_DROP_VERSIONING_SYSTEM_TIME_PARTITION 4131 #define ER_VERS_DB_NOT_SUPPORTED 4132 #define ER_VERS_TRT_IS_DISABLED 4133 #define ER_VERS_DUPLICATE_ROW_START_END 4134 #define ER_VERS_ALREADY_VERSIONED 4135 #define ER_UNUSED_24 4136 #define ER_VERS_NOT_SUPPORTED 4137 #define ER_VERS_TRX_PART_HISTORIC_ROW_NOT_SUPPORTED 4138 #define ER_INDEX_FILE_FULL 4139 #define ER_UPDATED_COLUMN_ONLY_ONCE 4140 #define ER_EMPTY_ROW_IN_TVC 4141 #define ER_VERS_QUERY_IN_PARTITION 4142 #define ER_KEY_DOESNT_SUPPORT 4143 #define ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD 4144 #define ER_BACKUP_LOCK_IS_ACTIVE 4145 #define ER_BACKUP_NOT_RUNNING 4146 #define ER_BACKUP_WRONG_STAGE 4147 #define ER_BACKUP_STAGE_FAILED 4148 #define ER_BACKUP_UNKNOWN_STAGE 4149 #define ER_USER_IS_BLOCKED 4150 #define ER_ACCOUNT_HAS_BEEN_LOCKED 4151 #define ER_PERIOD_TEMPORARY_NOT_ALLOWED 4152 #define ER_PERIOD_TYPES_MISMATCH 4153 #define ER_MORE_THAN_ONE_PERIOD 4154 #define ER_PERIOD_FIELD_WRONG_ATTRIBUTES 4155 #define ER_PERIOD_NOT_FOUND 4156 #define ER_PERIOD_COLUMNS_UPDATED 4157 #define ER_PERIOD_CONSTRAINT_DROP 4158 #define ER_TOO_LONG_KEYPART 4159 #define ER_TOO_LONG_DATABASE_COMMENT 4160 #define ER_UNKNOWN_DATA_TYPE 4161 #define ER_UNKNOWN_OPERATOR 4162 #define ER_WARN_HISTORY_ROW_START_TIME 4163 #define ER_PART_STARTS_BEYOND_INTERVAL 4164 #define ER_GALERA_REPLICATION_NOT_SUPPORTED 4165 #define ER_LOAD_INFILE_CAPABILITY_DISABLED 4166 #define ER_NO_SECURE_TRANSPORTS_CONFIGURED 4167 #define ER_SLAVE_IGNORED_SHARED_TABLE 4168 #define ER_NO_AUTOINCREMENT_WITH_UNIQUE 4169 #define ER_KEY_CONTAINS_PERIOD_FIELDS 4170 #define ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS 4171 #define ER_NOT_ALLOWED_IN_THIS_CONTEXT 4172 #define ER_DATA_WAS_COMMITED_UNDER_ROLLBACK 4173 #define ER_PK_INDEX_CANT_BE_IGNORED 4174 #define ER_BINLOG_UNSAFE_SKIP_LOCKED 4175 #define ER_JSON_TABLE_ERROR_ON_FIELD 4176 #define ER_JSON_TABLE_ALIAS_REQUIRED 4177 #define ER_JSON_TABLE_SCALAR_EXPECTED 4178 #define ER_JSON_TABLE_MULTIPLE_MATCHES 4179 #define ER_WITH_TIES_NEEDS_ORDER 4180 #define ER_REMOVED_ORPHAN_TRIGGER 4181 #define ER_STORAGE_ENGINE_DISABLED 4182 #define ER_ERROR_LAST 4182 #endif /* ER_ERROR_FIRST */ server/json_lib.h000064400000032713151031265040010025 0ustar00#ifndef JSON_LIB_INCLUDED #define JSON_LIB_INCLUDED #ifdef __cplusplus extern "C" { #endif #define JSON_DEPTH_LIMIT 32 /* When error happens, the c_next of the JSON engine contains the character that caused the error, and the c_str is the position in string where the error occurs. */ enum json_errors { JE_BAD_CHR= -1, /* Invalid character, charset handler cannot read it. */ JE_NOT_JSON_CHR= -2, /* Character met not used in JSON. */ /* ASCII 00-08 for instance. */ JE_EOS= -3, /* Unexpected end of string. */ JE_SYN= -4, /* The next character breaks the JSON syntax. */ JE_STRING_CONST= -5, /* Character disallowed in string constant. */ JE_ESCAPING= -6, /* Error in the escaping. */ JE_DEPTH= -7, /* The limit on the JSON depth was overrun. */ }; typedef struct st_json_string_t { const uchar *c_str; /* Current position in JSON string */ const uchar *str_end; /* The end on the string. */ my_wc_t c_next; /* UNICODE of the last read character */ int c_next_len; /* character lenght of the last read character. */ int error; /* error code. */ CHARSET_INFO *cs; /* Character set of the JSON string. */ my_charset_conv_mb_wc wc; /* UNICODE conversion function. */ /* It's taken out of the cs just to speed calls. */ } json_string_t; void json_string_set_cs(json_string_t *s, CHARSET_INFO *i_cs); void json_string_set_str(json_string_t *s, const uchar *str, const uchar *end); #define json_next_char(j) \ ((j)->c_next_len= (j)->wc((j)->cs, &(j)->c_next, (j)->c_str, (j)->str_end)) #define json_eos(j) ((j)->c_str >= (j)->str_end) /* read_string_const_chr() reads the next character of the string constant and saves it to the js->c_next. It takes into account possible escapings, so if for instance the string is '\b', the read_string_const_chr() sets 8. */ int json_read_string_const_chr(json_string_t *js); /* Various JSON-related operations expect JSON path as a parameter. The path is a string like this "$.keyA[2].*" The path itself is a number of steps specifying either a key or a position in an array. Some of them can be wildcards. So the representation of the JSON path is the json_path_t class containing an array of json_path_step_t objects. */ /* Path step types - actually bitmasks to let '&' or '|' operations. */ enum json_path_step_types { JSON_PATH_KEY_NULL=0, JSON_PATH_KEY=1, /* Must be equal to JSON_VALUE_OBJECT. */ JSON_PATH_ARRAY=2, /* Must be equal to JSON_VALUE_ARRAY. */ JSON_PATH_KEY_OR_ARRAY=3, JSON_PATH_WILD=4, /* Step like .* or [*] */ JSON_PATH_DOUBLE_WILD=8, /* Step like **.k or **[1] */ JSON_PATH_KEY_WILD= 1+4, JSON_PATH_KEY_DOUBLEWILD= 1+8, JSON_PATH_ARRAY_WILD= 2+4, JSON_PATH_ARRAY_DOUBLEWILD= 2+8 }; typedef struct st_json_path_step_t { enum json_path_step_types type; /* The type of the step - */ /* see json_path_step_types */ const uchar *key; /* Pointer to the beginning of the key. */ const uchar *key_end; /* Pointer to the end of the key. */ uint n_item; /* Item number in an array. No meaning for the key step. */ } json_path_step_t; typedef struct st_json_path_t { json_string_t s; /* The string to be parsed. */ json_path_step_t steps[JSON_DEPTH_LIMIT]; /* Steps of the path. */ json_path_step_t *last_step; /* Points to the last step. */ int mode_strict; /* TRUE if the path specified as 'strict' */ enum json_path_step_types types_used; /* The '|' of all step's 'type'-s */ } json_path_t; int json_path_setup(json_path_t *p, CHARSET_INFO *i_cs, const uchar *str, const uchar *end); /* The set of functions and structures below provides interface to the JSON text parser. Running the parser normally goes like this: json_engine_t j_eng; // structure keeps parser's data json_scan_start(j_eng) // begin the parsing do { // The parser has read next piece of JSON // and set fields of j_eng structure accordingly. // So let's see what we have: switch (j_eng.state) { case JST_KEY: // Handle key name. See the json_read_keyname_chr() // Probably compare it with the keyname we're looking for case JST_VALUE: // Handle value. It is either value of the key or an array item. // see the json_read_value() case JST_OBJ_START: // parser found an object (the '{' in JSON) case JST_OBJ_END: // parser found the end of the object (the '}' in JSON) case JST_ARRAY_START: // parser found an array (the '[' in JSON) case JST_ARRAY_END: // parser found the end of the array (the ']' in JSON) }; } while (json_scan_next() == 0); // parse next structure if (j_eng.s.error) // we need to check why the loop ended. // Did we get to the end of JSON, or came upon error. { signal_error_in_JSON() } Parts of JSON can be quickly skipped. If we are not interested in a particular key, we can just skip it with json_skip_key() call. Similarly json_skip_level() goes right to the end of an object or an array. */ /* These are JSON parser states that user can expect and handle. */ enum json_states { JST_VALUE, /* value found */ JST_KEY, /* key found */ JST_OBJ_START, /* object */ JST_OBJ_END, /* object ended */ JST_ARRAY_START, /* array */ JST_ARRAY_END, /* array ended */ NR_JSON_USER_STATES }; enum json_value_types { JSON_VALUE_UNINITALIZED=0, JSON_VALUE_OBJECT=1, JSON_VALUE_ARRAY=2, JSON_VALUE_STRING=3, JSON_VALUE_NUMBER=4, JSON_VALUE_TRUE=5, JSON_VALUE_FALSE=6, JSON_VALUE_NULL=7 }; enum json_num_flags { JSON_NUM_NEG=1, /* Number is negative. */ JSON_NUM_FRAC_PART=2, /* The fractional part is not empty. */ JSON_NUM_EXP=4, /* The number has the 'e' part. */ }; typedef struct st_json_engine_t { json_string_t s; /* String to parse. */ int sav_c_len; /* Length of the current character. Can be more than 1 for multibyte charsets */ int state; /* The state of the parser. One of 'enum json_states'. It tells us what construction of JSON we've just read. */ /* These values are only set after the json_read_value() call. */ enum json_value_types value_type; /* type of the value.*/ const uchar *value; /* Points to the value. */ const uchar *value_begin;/* Points to where the value starts in the JSON. */ int value_escaped; /* Flag telling if the string value has escaping.*/ uint num_flags; /* the details of the JSON_VALUE_NUMBER, is it negative, or if it has the fractional part. See the enum json_num_flags. */ /* In most cases the 'value' and 'value_begin' are equal. They only differ if the value is a string constants. Then 'value_begin' points to the starting quotation mark, while the 'value' - to the first character of the string. */ const uchar *value_end; /* Points to the next character after the value. */ int value_len; /* The length of the value. Does not count quotations for */ /* string constants. */ int stack[JSON_DEPTH_LIMIT]; /* Keeps the stack of nested JSON structures. */ int stack_p; /* The 'stack' pointer. */ volatile uchar *killed_ptr; } json_engine_t; int json_scan_start(json_engine_t *je, CHARSET_INFO *i_cs, const uchar *str, const uchar *end); int json_scan_next(json_engine_t *j); /* json_read_keyname_chr() function assists parsing the name of an JSON key. It only can be called when the json_engine is in JST_KEY. The json_read_keyname_chr() reads one character of the name of the key, and puts it in j_eng.s.next_c. Typical usage is like this: if (j_eng.state == JST_KEY) { while (json_read_keyname_chr(&j) == 0) { //handle next character i.e. match it against the pattern } } */ int json_read_keyname_chr(json_engine_t *j); /* Check if the name of the current JSON key matches the step of the path. */ int json_key_matches(json_engine_t *je, json_string_t *k); /* json_read_value() function parses the JSON value syntax, so that we can handle the value of a key or an array item. It only returns meaningful result when the engine is in the JST_VALUE state. Typical usage is like this: if (j_eng.state == JST_VALUE) { json_read_value(&j_eng); switch(j_eng.value_type) { case JSON_VALUE_STRING: // get the string str= j_eng.value; str_length= j_eng.value_len; case JSON_VALUE_NUMBER: // get the number ... etc } */ int json_read_value(json_engine_t *j); /* json_skip_key() makes parser skip the content of the current JSON key quickly. It can be called only when the json_engine state is JST_KEY. Typical usage is: if (j_eng.state == JST_KEY) { if (key_does_not_match(j_eng)) json_skip_key(j_eng); } */ int json_skip_key(json_engine_t *j); typedef const int *json_level_t; /* json_skip_to_level() makes parser quickly get out of nested loops and arrays. It is used when we're not interested in what is there in the rest of these structures. The 'level' should be remembered in advance. json_level_t level= json_get_level(j); .... // getting into the nested JSON structures json_skip_to_level(j, level); */ #define json_get_level(j) (j->stack_p) int json_skip_to_level(json_engine_t *j, int level); /* json_skip_level() works as above with just current structure. So it gets to the end of the current JSON array or object. */ #define json_skip_level(json_engine) \ json_skip_to_level((json_engine), (json_engine)->stack_p) /* works as json_skip_level() but also counts items on the current level skipped. */ int json_skip_level_and_count(json_engine_t *j, int *n_items_skipped); #define json_skip_array_item json_skip_key /* Checks if the current value is of scalar type - not an OBJECT nor ARRAY. */ #define json_value_scalar(je) ((je)->value_type > JSON_VALUE_ARRAY) /* Look for the JSON PATH in the json string. Function can be called several times with same JSON/PATH to find multiple matches. On the first call, the json_engine_t parameter should be initialized with the JSON string, and the json_path_t with the JSON path appropriately. The 'p_cur_step' should point at the first step of the path. The 'array_counters' is the array of JSON_DEPTH_LIMIT size. It stores the array counters of the parsed JSON. If function returns 0, it means it found the match. The position of the match is je->s.c_str. Then we can call the json_find_path() with same engine/path/p_cur_step to get the next match. Non-zero return means no matches found. Check je->s.error to see if there was an error in JSON. */ int json_find_path(json_engine_t *je, json_path_t *p, json_path_step_t **p_cur_step, uint *array_counters); typedef struct st_json_find_paths_t { uint n_paths; json_path_t *paths; uint cur_depth; uint *path_depths; uint array_counters[JSON_DEPTH_LIMIT]; } json_find_paths_t; int json_find_paths_first(json_engine_t *je, json_find_paths_t *state, uint n_paths, json_path_t *paths, uint *path_depths); int json_find_paths_next(json_engine_t *je, json_find_paths_t *state); /* Convert JSON string constant into ordinary string constant which can involve unpacking json escapes and changing character set. Returns negative integer in the case of an error, the length of the result otherwise. */ int json_unescape(CHARSET_INFO *json_cs, const uchar *json_str, const uchar *json_end, CHARSET_INFO *res_cs, uchar *res, uchar *res_end); /* Convert ordinary string constant into JSON string constant. which can involve appropriate escaping and changing character set. Returns negative integer in the case of an error, the length of the result otherwise. */ int json_escape(CHARSET_INFO *str_cs, const uchar *str, const uchar *str_end, CHARSET_INFO *json_cs, uchar *json, uchar *json_end); /* Appends the ASCII string to the json with the charset conversion. */ int json_append_ascii(CHARSET_INFO *json_cs, uchar *json, uchar *json_end, const uchar *ascii, const uchar *ascii_end); /* Scan the JSON and return paths met one-by-one. json_get_path_start(&p) while (json_get_path_next(&p)) { handle_the_next_path(); } */ int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs, const uchar *str, const uchar *end, json_path_t *p); int json_get_path_next(json_engine_t *je, json_path_t *p); int json_path_parts_compare( const json_path_step_t *a, const json_path_step_t *a_end, const json_path_step_t *b, const json_path_step_t *b_end, enum json_value_types vt); int json_path_compare(const json_path_t *a, const json_path_t *b, enum json_value_types vt); int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs); int json_locate_key(const char *js, const char *js_end, const char *kname, const char **key_start, const char **key_end, int *comma_pos); #ifdef __cplusplus } #endif #endif /* JSON_LIB_INCLUDED */ server/m_string.h000064400000024112151031265040010042 0ustar00/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. Copyright (c) 2019, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* There may be problems included in all of these. Try to test in configure which ones are needed? */ /* This is needed for the definitions of strchr... on solaris */ #ifndef _m_string_h #define _m_string_h #include "my_decimal_limits.h" #ifndef __USE_GNU #define __USE_GNU /* We want to use stpcpy */ #endif #if defined(HAVE_STRINGS_H) #include #endif #if defined(HAVE_STRING_H) #include #endif /* This is needed for the definitions of memcpy... on solaris */ #if defined(HAVE_MEMORY_H) && !defined(__cplusplus) #include #endif #if !defined(HAVE_MEMCPY) && !defined(HAVE_MEMMOVE) # define memcpy(d, s, n) bcopy ((s), (d), (n)) # define memset(A,C,B) bfill((A),(B),(C)) # define memmove(d, s, n) bmove ((d), (s), (n)) #elif defined(HAVE_MEMMOVE) # define bmove(d, s, n) memmove((d), (s), (n)) #endif /* Unixware 7 */ #if !defined(HAVE_BFILL) # define bfill(A,B,C) memset((A),(C),(B)) #endif # define bmove_align(A,B,C) memcpy((A),(B),(C)) # define bcmp(A,B,C) memcmp((A),(B),(C)) #if !defined(bzero) # define bzero(A,B) memset((A),0,(B)) #endif #if defined(__cplusplus) extern "C" { #endif #ifdef DBUG_OFF #if defined(HAVE_STPCPY) && defined(__GNUC__) && !defined(__INTEL_COMPILER) #define strmov(A,B) __builtin_stpcpy((A),(B)) #elif defined(HAVE_STPCPY) #define strmov(A,B) stpcpy((A),(B)) #endif #endif /* Declared in int2str() */ extern const char _dig_vec_upper[]; extern const char _dig_vec_lower[]; extern char *strmov_overlapp(char *dest, const char *src); #if defined(_lint) || defined(FORCE_INIT_OF_VARS) #define LINT_INIT_STRUCT(var) bzero(&var, sizeof(var)) /* No uninitialize-warning */ #else #define LINT_INIT_STRUCT(var) #endif /* Prototypes for string functions */ extern void bmove_upp(uchar *dst,const uchar *src,size_t len); extern void bchange(uchar *dst,size_t old_len,const uchar *src, size_t new_len,size_t tot_len); extern void strappend(char *s,size_t len,pchar fill); extern char *strend(const char *s); extern char *strcend(const char *, pchar); extern char *strfill(char * s,size_t len,pchar fill); extern char *strmake(char *dst,const char *src,size_t length); #if !defined(__GNUC__) || (__GNUC__ < 4) #define strmake_buf(D,S) strmake(D, S, sizeof(D) - 1) #else #define strmake_buf(D,S) ({ \ __typeof__ (D) __x __attribute__((unused)) = { 2 }; \ strmake(D, S, sizeof(D) - 1); \ }) #endif #ifndef strmov extern char *strmov(char *dst,const char *src); #endif extern char *strnmov(char *dst, const char *src, size_t n); extern char *strcont(const char *src, const char *set); extern char *strxmov(char *dst, const char *src, ...); extern char *strxnmov(char *dst, size_t len, const char *src, ...); /* Prototypes of normal stringfunctions (with may ours) */ #ifndef HAVE_STRNLEN extern size_t strnlen(const char *s, size_t n); #endif extern int is_prefix(const char *, const char *); /* Conversion routines */ typedef enum { MY_GCVT_ARG_FLOAT, MY_GCVT_ARG_DOUBLE } my_gcvt_arg_type; double my_strtod(const char *str, char **end, int *error); double my_atof(const char *nptr); size_t my_fcvt(double x, int precision, char *to, my_bool *error); size_t my_gcvt(double x, my_gcvt_arg_type type, int width, char *to, my_bool *error); /* The longest string my_fcvt can return is 311 + "precision" bytes. Here we assume that we never cal my_fcvt() with precision >= DECIMAL_NOT_SPECIFIED (+ 1 byte for the terminating '\0'). */ #define FLOATING_POINT_BUFFER (311 + DECIMAL_NOT_SPECIFIED) /* We want to use the 'e' format in some cases even if we have enough space for the 'f' one just to mimic sprintf("%.15g") behavior for large integers, and to improve it for numbers < 10^(-4). That is, for |x| < 1 we require |x| >= 10^(-15), and for |x| > 1 we require it to be integer and be <= 10^DBL_DIG for the 'f' format to be used. We don't lose precision, but make cases like "1e200" or "0.00001" look nicer. */ #define MAX_DECPT_FOR_F_FORMAT DBL_DIG /* The maximum possible field width for my_gcvt() conversion. (DBL_DIG + 2) significant digits + sign + "." + ("e-NNN" or MAX_DECPT_FOR_F_FORMAT zeros for cases when |x|<1 and the 'f' format is used). */ #define MY_GCVT_MAX_FIELD_WIDTH (DBL_DIG + 4 + MY_MAX(5, MAX_DECPT_FOR_F_FORMAT)) \ extern char *llstr(longlong value,char *buff); extern char *ullstr(longlong value,char *buff); #ifndef HAVE_STRTOUL extern long strtol(const char *str, char **ptr, int base); extern ulong strtoul(const char *str, char **ptr, int base); #endif extern char *int2str(long val, char *dst, int radix, int upcase); extern char *int10_to_str(long val,char *dst,int radix); extern char *str2int(const char *src,int radix,long lower,long upper, long *val); longlong my_strtoll10(const char *nptr, char **endptr, int *error); #if SIZEOF_LONG == SIZEOF_LONG_LONG #define ll2str(A,B,C,D) int2str((A),(B),(C),(D)) #define longlong10_to_str(A,B,C) int10_to_str((A),(B),(C)) #undef strtoll #define strtoll(A,B,C) strtol((A),(B),(C)) #define strtoull(A,B,C) strtoul((A),(B),(C)) #ifndef HAVE_STRTOULL #define HAVE_STRTOULL #endif #ifndef HAVE_STRTOLL #define HAVE_STRTOLL #endif #else #ifdef HAVE_LONG_LONG extern char *ll2str(longlong val,char *dst,int radix, int upcase); extern char *longlong10_to_str(longlong val,char *dst,int radix); #if (!defined(HAVE_STRTOULL) || defined(NO_STRTOLL_PROTO)) extern longlong strtoll(const char *str, char **ptr, int base); extern ulonglong strtoull(const char *str, char **ptr, int base); #endif #endif #endif #define longlong2str(A,B,C) ll2str((A),(B),(C),1) #if defined(__cplusplus) } #endif #include #ifdef __cplusplus #include template inline const char *_swl_check(T s) { static_assert(std::is_same::value || std::is_same::value, "Wrong argument for STRING_WITH_LEN()"); return s; } #define STRING_WITH_LEN(X) _swl_check(X), ((size_t) (sizeof(X) - 1)) #else #define STRING_WITH_LEN(X) (X ""), ((size_t) (sizeof(X) - 1)) #endif #define USTRING_WITH_LEN(X) (uchar*) STRING_WITH_LEN(X) #define C_STRING_WITH_LEN(X) (char *) STRING_WITH_LEN(X) #define LEX_STRING_WITH_LEN(X) (X).str, (X).length typedef struct st_mysql_const_lex_string LEX_CSTRING; /* A variant with const and unsigned */ struct st_mysql_const_unsigned_lex_string { const uchar *str; size_t length; }; typedef struct st_mysql_const_unsigned_lex_string LEX_CUSTRING; static inline void lex_string_set(LEX_CSTRING *lex_str, const char *c_str) { lex_str->str= c_str; lex_str->length= strlen(c_str); } static inline void lex_string_set3(LEX_CSTRING *lex_str, const char *c_str, size_t len) { lex_str->str= c_str; lex_str->length= len; } /** Copies a string. @param dst destination buffer, will be NUL padded. @param dst_size size of dst buffer, must be > 0 @param src NUL terminated source string */ static inline void safe_strcpy(char *dst, size_t dst_size, const char *src) { DBUG_ASSERT(dst_size > 0); /* 1) IF there is a 0 byte in the first dst_size bytes of src, strncpy will * 0-terminate dst, and pad dst with additional 0 bytes out to dst_size. * * 2) IF there is no 0 byte in the first dst_size bytes of src, strncpy will * copy dst_size bytes, and the final byte won't be 0. * * In GCC 8+, the `-Wstringop-truncation` warning may object to strncpy() * being used in this way, so we need to disable this warning for this * single statement. */ #if defined __GNUC__ && __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-truncation" #endif strncpy(dst, src, dst_size); #if defined __GNUC__ && __GNUC__ >= 8 #pragma GCC diagnostic pop #endif dst[dst_size - 1]= 0; } /** Copies a string, checking for truncation. @param dst destination buffer, will be NUL padded. @param dst_size size of dst buffer, must be > 0 @param src NUL terminated source string @retval 1 if the src string was truncated due to too small size of dst. @retval 0 if src completely fit within dst, */ static inline int safe_strcpy_truncated(char *dst, size_t dst_size, const char *src) { DBUG_ASSERT(dst_size > 0); if (dst_size == 0) return 1; /* We do not want to use strncpy() as we do not want to rely on strncpy() filling the unused dst with 0. We cannot use strmake() here as it in debug mode fills the buffers with 'Z'. */ if (strnmov(dst, src, dst_size) == dst+dst_size) { dst[dst_size-1]= 0; return 1; } return 0; } /** Appends src to dst and ensures dst is a NUL terminated C string. @retval 1 if the src string was truncated due to too small size of dst. @retval 0 if src completely fit within the remaining dst space, including NUL termination. */ static inline int safe_strcat(char *dst, size_t dst_size, const char *src) { size_t init_len= strlen(dst); if (init_len >= dst_size) return 1; return safe_strcpy_truncated(dst + init_len, dst_size - init_len, src); } #ifdef __cplusplus static inline char *safe_str(char *str) { return str ? str : const_cast(""); } #endif static inline const char *safe_str(const char *str) { return str ? str : ""; } static inline size_t safe_strlen(const char *str) { return str ? strlen(str) : 0; } #endif server/my_decimal_limits.h000064400000004032151031265040011703 0ustar00#ifndef MY_DECIMAL_LIMITS_INCLUDED #define MY_DECIMAL_LIMITS_INCLUDED /* Copyright (c) 2011 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #define DECIMAL_LONGLONG_DIGITS 22 #define DECIMAL_LONG_DIGITS 10 #define DECIMAL_LONG3_DIGITS 8 /** maximum length of buffer in our big digits (uint32). */ #define DECIMAL_BUFF_LENGTH 9 /* the number of digits that my_decimal can possibly contain */ #define DECIMAL_MAX_POSSIBLE_PRECISION (DECIMAL_BUFF_LENGTH * 9) /** maximum guaranteed precision of number in decimal digits (number of our digits * number of decimal digits in one our big digit - number of decimal digits in one our big digit decreased by 1 (because we always put decimal point on the border of our big digits)) With normal precision we can handle 65 digits. MariaDB can store in the .frm up to 63 digits. By default we use DECIMAL_NOT_SPECIFIED digits when converting strings to decimal, so we don't want to set this too high. To not use up all digits for the scale we limit the number of decimals to 38. */ #define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2) #define DECIMAL_MAX_SCALE 38 #define DECIMAL_NOT_SPECIFIED 39 /** maximum length of string representation (number of maximum decimal digits + 1 position for sign + 1 position for decimal point, no terminator) */ #define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2) #endif /* MY_DECIMAL_LIMITS_INCLUDED */ server/pack.h000064400000002121151031265040007132 0ustar00/* Copyright (c) 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef __cplusplus extern "C" { #endif ulong net_field_length(uchar **packet); my_ulonglong net_field_length_ll(uchar **packet); my_ulonglong safe_net_field_length_ll(uchar **packet, size_t packet_len); uchar *net_store_length(uchar *pkg, ulonglong length); uchar *safe_net_store_length(uchar *pkg, size_t pkg_len, ulonglong length); unsigned int net_length_size(ulonglong num); #ifdef __cplusplus } #endif server/mariadb_capi_rename.h000064400000006532151031265040012150 0ustar00/* Copyright (c) 2022, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Renaming C API symbols inside server * client.c defines a number of functions from the C API, that are used in replication, in number of storage engine plugins, mariadb-backup. * That can cause a problem if a plugin loads libmariadb/libmysql or a library, that has dependency on them. The known case is ODBC driver. * Thus the header re-names those functions for internal use. */ #ifndef MARIADB_CAPI_RENAME_INCLUDED #define MARIADB_CAPI_RENAME_INCLUDED #if !defined(EMBEDDED_LIBRARY) && !defined(MYSQL_DYNAMIC_PLUGIN) #define MARIADB_ADD_PREFIX(_SYMBOL) server_##_SYMBOL #define mysql_real_connect MARIADB_ADD_PREFIX(mysql_real_connect) #define mysql_init MARIADB_ADD_PREFIX(mysql_init) #define mysql_close MARIADB_ADD_PREFIX(mysql_close) #define mysql_options MARIADB_ADD_PREFIX(mysql_options) #define mysql_load_plugin MARIADB_ADD_PREFIX(mysql_load_plugin) #define mysql_load_plugin_v MARIADB_ADD_PREFIX(mysql_load_plugin_v) #define mysql_client_find_plugin MARIADB_ADD_PREFIX(mysql_client_find_plugin) #define mysql_real_query MARIADB_ADD_PREFIX(mysql_real_query) #define mysql_send_query MARIADB_ADD_PREFIX(mysql_send_query) #define mysql_free_result MARIADB_ADD_PREFIX(mysql_free_result) #define mysql_get_socket MARIADB_ADD_PREFIX(mysql_get_socket) #define mysql_set_character_set MARIADB_ADD_PREFIX(mysql_set_character_set) #define mysql_real_escape_string MARIADB_ADD_PREFIX(mysql_real_escape_string) #define mysql_get_server_version MARIADB_ADD_PREFIX(mysql_get_server_version) #define mysql_error MARIADB_ADD_PREFIX(mysql_error) #define mysql_errno MARIADB_ADD_PREFIX(mysql_errno) #define mysql_num_fields MARIADB_ADD_PREFIX(mysql_num_fields) #define mysql_num_rows MARIADB_ADD_PREFIX(mysql_num_rows) #define mysql_options4 MARIADB_ADD_PREFIX(mysql_options4) #define mysql_fetch_fields MARIADB_ADD_PREFIX(mysql_fetch_fields) #define mysql_fetch_lengths MARIADB_ADD_PREFIX(mysql_fetch_lengths) #define mysql_fetch_row MARIADB_ADD_PREFIX(mysql_fetch_row) #define mysql_affected_rows MARIADB_ADD_PREFIX(mysql_affected_rows) #define mysql_store_result MARIADB_ADD_PREFIX(mysql_store_result) #define mysql_use_result MARIADB_ADD_PREFIX(mysql_use_result) #define mysql_select_db MARIADB_ADD_PREFIX(mysql_select_db) #define mysql_get_ssl_cipher MARIADB_ADD_PREFIX(mysql_get_ssl_cipher) #define mysql_ssl_set MARIADB_ADD_PREFIX(mysql_ssl_set) #define mysql_client_register_plugin MARIADB_ADD_PREFIX(mysql_client_register_plugin) #endif // !EMBEDDED_LIBRARY && !MYSQL_DYNAMIC_PLUGIN #endif // !MARIADB_CAPI_RENAME_INCLUDED server/my_attribute.h000064400000006772151031265040010744 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Helper macros used for setting different __attributes__ on functions in a portable fashion */ #ifndef _my_attribute_h #define _my_attribute_h #if defined(__GNUC__) # ifndef GCC_VERSION # define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) # endif #endif /* Disable __attribute__() on gcc < 2.7, g++ < 3.4, and non-gcc compilers. Some forms of __attribute__ are actually supported in earlier versions of g++, but we just disable them all because we only use them to generate compilation warnings. */ #ifndef __attribute__ # if !defined(__GNUC__) && !defined(__clang__) # define __attribute__(A) # elif defined(__GNUC__) # ifndef GCC_VERSION # define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) # endif # if GCC_VERSION < 2008 # define __attribute__(A) # elif defined(__cplusplus) && GCC_VERSION < 3004 # define __attribute__(A) # endif # endif #endif /* __attribute__((format(...))) is only supported in gcc >= 2.8 and g++ >= 3.4 But that's already covered by the __attribute__ tests above, so this is just a convenience macro. */ #ifndef ATTRIBUTE_FORMAT # define ATTRIBUTE_FORMAT(style, m, n) __attribute__((format(style, m, n))) #endif /* __attribute__((format(...))) on a function pointer is not supported until gcc 3.1 */ #ifndef ATTRIBUTE_FORMAT_FPTR # if (GCC_VERSION >= 3001) # define ATTRIBUTE_FORMAT_FPTR(style, m, n) ATTRIBUTE_FORMAT(style, m, n) # else # define ATTRIBUTE_FORMAT_FPTR(style, m, n) # endif /* GNUC >= 3.1 */ #endif /* gcc 7.5.0 does not support __attribute__((no_sanitize("undefined")) */ #ifndef ATTRIBUTE_NO_UBSAN # if (GCC_VERSION >= 8000) || defined(__clang__) # define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined"))) # elif (GCC_VERSION >= 6001) # define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize_undefined)) # else # define ATTRIBUTE_NO_UBSAN # endif #endif /* Define pragmas to disable warnings for stack frame checking */ #ifdef __GNUC__ #define PRAGMA_DISABLE_CHECK_STACK_FRAME \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wframe-larger-than=\"") #define PRAGMA_REENABLE_CHECK_STACK_FRAME \ _Pragma("GCC diagnostic pop") /* The following check is for older gcc version that allocates a lot of stack during startup that does not need to be checked */ #if !defined(__clang__) && __GNUC__ < 13 #define PRAGMA_DISABLE_CHECK_STACK_FRAME_EXTRA PRAGMA_DISABLE_CHECK_STACK_FRAME #else #define PRAGMA_DISABLE_CHECK_STACK_FRAME_EXTRA #endif /* !defined(__clang__) && __GNUC__ < 13 */ #else /*! __GNUC__ */ #define PRAGMA_DISABLE_CHECK_STACK_FRAME #define PRAGMA_REENABLE_CHECK_STACK_FRAME #define PRAGMA_DISABLE_CHECK_STACK_FRAME #define PRAGMA_DISABLE_CHECK_STACK_FRAME_EXTRA #endif /* __GNUC__ */ #endif /* _my_attribute_h */ server/sslopt-vars.h000064400000002575151031265040010526 0ustar00#ifndef SSLOPT_VARS_INCLUDED #define SSLOPT_VARS_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) #ifdef SSL_VARS_NOT_STATIC #define SSL_STATIC #else #define SSL_STATIC static #endif SSL_STATIC my_bool opt_use_ssl = 0; SSL_STATIC char *opt_ssl_ca = 0; SSL_STATIC char *opt_ssl_capath = 0; SSL_STATIC char *opt_ssl_cert = 0; SSL_STATIC char *opt_ssl_cipher = 0; SSL_STATIC char *opt_ssl_key = 0; SSL_STATIC char *opt_ssl_crl = 0; SSL_STATIC char *opt_ssl_crlpath = 0; SSL_STATIC char *opt_tls_version = 0; #ifdef MYSQL_CLIENT SSL_STATIC my_bool opt_ssl_verify_server_cert= 0; #endif #endif #endif /* SSLOPT_VARS_INCLUDED */ server/mysql_com_server.h000064400000002441151031265040011612 0ustar00/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Definitions private to the server, used in the networking layer to notify specific events. */ #ifndef _mysql_com_server_h #define _mysql_com_server_h struct st_net_server; typedef void (*before_header_callback_fn) (struct st_net *net, void *user_data, size_t count); typedef void (*after_header_callback_fn) (struct st_net *net, void *user_data, size_t count, my_bool rc); struct st_net_server { before_header_callback_fn m_before_header; after_header_callback_fn m_after_header; void *m_user_data; }; typedef struct st_net_server NET_SERVER; #endif server/my_net.h000064400000003755151031265040007525 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file is also used to make handling of sockets and ioctl() portable across systems. */ #ifndef _my_net_h #define _my_net_h C_MODE_START #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #if defined(HAVE_POLL_H) #include #elif defined(HAVE_SYS_POLL_H) #include #endif /* defined(HAVE_POLL_H) */ #ifdef HAVE_SYS_IOCTL_H #include #endif #if !defined(_WIN32) #include #include #include #if !defined(alpha_linux_port) #include #endif #endif #if defined(_WIN32) #define O_NONBLOCK 1 /* For emulation of fcntl() */ /* SHUT_RDWR is called SD_BOTH in windows and is defined to 2 in winsock2.h #define SD_BOTH 0x02 */ #define SHUT_RDWR 0x02 #else #include /* getaddrinfo() & co */ #endif /* On OSes which don't have the in_addr_t, we guess that using uint32 is the best possible choice. We guess this from the fact that on HP-UX64bit & FreeBSD64bit & Solaris64bit, in_addr_t is equivalent to uint32. And on Linux32bit too. */ #ifndef HAVE_IN_ADDR_T #define in_addr_t uint32 #endif C_MODE_END #endif server/errmsg.h000064400000010471151031265040007522 0ustar00#ifndef ERRMSG_INCLUDED #define ERRMSG_INCLUDED /* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Error messages numbers for MySQL clients. The error messages itself are in libmysql/errmsg.c Error messages for the mysqld daemon are in sql/share/errmsg.txt */ #ifdef __cplusplus extern "C" { #endif void init_client_errs(void); void finish_client_errs(void); extern const char *client_errors[]; /* Error messages */ #ifdef __cplusplus } #endif #define CR_MIN_ERROR 2000 /* For easier client code */ #define CR_MAX_ERROR 2999 #if !defined(ER) #define ER(X) (((X) >= CR_ERROR_FIRST && (X) <= CR_ERROR_LAST) \ ? client_errors[(X)-CR_ERROR_FIRST] \ : client_errors[CR_UNKNOWN_ERROR-CR_ERROR_FIRST]) #endif #define CLIENT_ERRMAP 2 /* Errormap used by my_error() */ /* Do not add error numbers before CR_ERROR_FIRST. */ /* If necessary to add lower numbers, change CR_ERROR_FIRST accordingly. */ #define CR_ERROR_FIRST 2000 /*Copy first error nr.*/ #define CR_UNKNOWN_ERROR 2000 #define CR_SOCKET_CREATE_ERROR 2001 #define CR_CONNECTION_ERROR 2002 #define CR_CONN_HOST_ERROR 2003 #define CR_IPSOCK_ERROR 2004 #define CR_UNKNOWN_HOST 2005 #define CR_SERVER_GONE_ERROR 2006 #define CR_VERSION_ERROR 2007 #define CR_OUT_OF_MEMORY 2008 #define CR_WRONG_HOST_INFO 2009 #define CR_LOCALHOST_CONNECTION 2010 #define CR_TCP_CONNECTION 2011 #define CR_SERVER_HANDSHAKE_ERR 2012 #define CR_SERVER_LOST 2013 #define CR_COMMANDS_OUT_OF_SYNC 2014 #define CR_NAMEDPIPE_CONNECTION 2015 #define CR_NAMEDPIPEWAIT_ERROR 2016 #define CR_NAMEDPIPEOPEN_ERROR 2017 #define CR_NAMEDPIPESETSTATE_ERROR 2018 #define CR_CANT_READ_CHARSET 2019 #define CR_NET_PACKET_TOO_LARGE 2020 #define CR_EMBEDDED_CONNECTION 2021 #define CR_PROBE_SLAVE_STATUS 2022 #define CR_PROBE_SLAVE_HOSTS 2023 #define CR_PROBE_SLAVE_CONNECT 2024 #define CR_PROBE_MASTER_CONNECT 2025 #define CR_SSL_CONNECTION_ERROR 2026 #define CR_MALFORMED_PACKET 2027 #define CR_WRONG_LICENSE 2028 /* new 4.1 error codes */ #define CR_NULL_POINTER 2029 #define CR_NO_PREPARE_STMT 2030 #define CR_PARAMS_NOT_BOUND 2031 #define CR_DATA_TRUNCATED 2032 #define CR_NO_PARAMETERS_EXISTS 2033 #define CR_INVALID_PARAMETER_NO 2034 #define CR_INVALID_BUFFER_USE 2035 #define CR_UNSUPPORTED_PARAM_TYPE 2036 #define CR_SHARED_MEMORY_CONNECTION 2037 #define CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR 2038 #define CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR 2039 #define CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR 2040 #define CR_SHARED_MEMORY_CONNECT_MAP_ERROR 2041 #define CR_SHARED_MEMORY_FILE_MAP_ERROR 2042 #define CR_SHARED_MEMORY_MAP_ERROR 2043 #define CR_SHARED_MEMORY_EVENT_ERROR 2044 #define CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR 2045 #define CR_SHARED_MEMORY_CONNECT_SET_ERROR 2046 #define CR_CONN_UNKNOW_PROTOCOL 2047 #define CR_INVALID_CONN_HANDLE 2048 #define CR_SECURE_AUTH 2049 #define CR_FETCH_CANCELED 2050 #define CR_NO_DATA 2051 #define CR_NO_STMT_METADATA 2052 #define CR_NO_RESULT_SET 2053 #define CR_NOT_IMPLEMENTED 2054 #define CR_SERVER_LOST_EXTENDED 2055 #define CR_STMT_CLOSED 2056 #define CR_NEW_STMT_METADATA 2057 #define CR_ALREADY_CONNECTED 2058 #define CR_AUTH_PLUGIN_CANNOT_LOAD 2059 #define CR_DUPLICATE_CONNECTION_ATTR 2060 #define CR_AUTH_PLUGIN_ERR 2061 #define CR_ERROR_LAST /*Copy last error nr:*/ 2061 /* Add error numbers before CR_ERROR_LAST and change it accordingly. */ #endif /* ERRMSG_INCLUDED */ server/sql_state.h000064400000035061151031265040010224 0ustar00/* Autogenerated file, please don't edit */ { ER_DUP_KEY ,"23000", "" }, { ER_OUTOFMEMORY ,"HY001", "S1001" }, { ER_OUT_OF_SORTMEMORY ,"HY001", "S1001" }, { ER_CON_COUNT_ERROR ,"08004", "" }, { ER_BAD_HOST_ERROR ,"08S01", "" }, { ER_HANDSHAKE_ERROR ,"08S01", "" }, { ER_DBACCESS_DENIED_ERROR ,"42000", "" }, { ER_ACCESS_DENIED_ERROR ,"28000", "" }, { ER_NO_DB_ERROR ,"3D000", "" }, { ER_UNKNOWN_COM_ERROR ,"08S01", "" }, { ER_BAD_NULL_ERROR ,"23000", "" }, { ER_BAD_DB_ERROR ,"42000", "" }, { ER_TABLE_EXISTS_ERROR ,"42S01", "" }, { ER_BAD_TABLE_ERROR ,"42S02", "" }, { ER_NON_UNIQ_ERROR ,"23000", "" }, { ER_SERVER_SHUTDOWN ,"08S01", "" }, { ER_BAD_FIELD_ERROR ,"42S22", "S0022" }, { ER_WRONG_FIELD_WITH_GROUP ,"42000", "S1009" }, { ER_WRONG_GROUP_FIELD ,"42000", "S1009" }, { ER_WRONG_SUM_SELECT ,"42000", "S1009" }, { ER_WRONG_VALUE_COUNT ,"21S01", "" }, { ER_TOO_LONG_IDENT ,"42000", "S1009" }, { ER_DUP_FIELDNAME ,"42S21", "S1009" }, { ER_DUP_KEYNAME ,"42000", "S1009" }, { ER_DUP_ENTRY ,"23000", "S1009" }, { ER_WRONG_FIELD_SPEC ,"42000", "S1009" }, { ER_PARSE_ERROR ,"42000", "s1009" }, { ER_EMPTY_QUERY ,"42000", "" }, { ER_NONUNIQ_TABLE ,"42000", "S1009" }, { ER_INVALID_DEFAULT ,"42000", "S1009" }, { ER_MULTIPLE_PRI_KEY ,"42000", "S1009" }, { ER_TOO_MANY_KEYS ,"42000", "S1009" }, { ER_TOO_MANY_KEY_PARTS ,"42000", "S1009" }, { ER_TOO_LONG_KEY ,"42000", "S1009" }, { ER_KEY_COLUMN_DOES_NOT_EXITS ,"42000", "S1009" }, { ER_BLOB_USED_AS_KEY ,"42000", "S1009" }, { ER_TOO_BIG_FIELDLENGTH ,"42000", "S1009" }, { ER_WRONG_AUTO_KEY ,"42000", "S1009" }, { ER_FORCING_CLOSE ,"08S01", "" }, { ER_IPSOCK_ERROR ,"08S01", "" }, { ER_NO_SUCH_INDEX ,"42S12", "S1009" }, { ER_WRONG_FIELD_TERMINATORS ,"42000", "S1009" }, { ER_BLOBS_AND_NO_TERMINATED ,"42000", "S1009" }, { ER_CANT_REMOVE_ALL_FIELDS ,"42000", "" }, { ER_CANT_DROP_FIELD_OR_KEY ,"42000", "" }, { ER_WRONG_DB_NAME ,"42000", "" }, { ER_WRONG_TABLE_NAME ,"42000", "" }, { ER_TOO_BIG_SELECT ,"42000", "" }, { ER_UNKNOWN_PROCEDURE ,"42000", "" }, { ER_WRONG_PARAMCOUNT_TO_PROCEDURE ,"42000", "" }, { ER_UNKNOWN_TABLE ,"42S02", "" }, { ER_FIELD_SPECIFIED_TWICE ,"42000", "" }, { ER_UNSUPPORTED_EXTENSION ,"42000", "" }, { ER_TABLE_MUST_HAVE_COLUMNS ,"42000", "" }, { ER_UNKNOWN_CHARACTER_SET ,"42000", "" }, { ER_TOO_BIG_ROWSIZE ,"42000", "" }, { ER_WRONG_OUTER_JOIN ,"42000", "" }, { ER_NULL_COLUMN_IN_INDEX ,"42000", "" }, { ER_PASSWORD_ANONYMOUS_USER ,"42000", "" }, { ER_PASSWORD_NOT_ALLOWED ,"42000", "" }, { ER_PASSWORD_NO_MATCH ,"28000", "" }, { ER_WRONG_VALUE_COUNT_ON_ROW ,"21S01", "" }, { ER_INVALID_USE_OF_NULL ,"22004", "" }, { ER_REGEXP_ERROR ,"42000", "" }, { ER_MIX_OF_GROUP_FUNC_AND_FIELDS ,"42000", "" }, { ER_NONEXISTING_GRANT ,"42000", "" }, { ER_TABLEACCESS_DENIED_ERROR ,"42000", "" }, { ER_COLUMNACCESS_DENIED_ERROR ,"42000", "" }, { ER_ILLEGAL_GRANT_FOR_TABLE ,"42000", "" }, { ER_GRANT_WRONG_HOST_OR_USER ,"42000", "" }, { ER_NO_SUCH_TABLE ,"42S02", "" }, { ER_NONEXISTING_TABLE_GRANT ,"42000", "" }, { ER_NOT_ALLOWED_COMMAND ,"42000", "" }, { ER_SYNTAX_ERROR ,"42000", "" }, { ER_ABORTING_CONNECTION ,"08S01", "" }, { ER_NET_PACKET_TOO_LARGE ,"08S01", "" }, { ER_NET_READ_ERROR_FROM_PIPE ,"08S01", "" }, { ER_NET_FCNTL_ERROR ,"08S01", "" }, { ER_NET_PACKETS_OUT_OF_ORDER ,"08S01", "" }, { ER_NET_UNCOMPRESS_ERROR ,"08S01", "" }, { ER_NET_READ_ERROR ,"08S01", "" }, { ER_NET_READ_INTERRUPTED ,"08S01", "" }, { ER_NET_ERROR_ON_WRITE ,"08S01", "" }, { ER_NET_WRITE_INTERRUPTED ,"08S01", "" }, { ER_TOO_LONG_STRING ,"42000", "" }, { ER_TABLE_CANT_HANDLE_BLOB ,"42000", "" }, { ER_TABLE_CANT_HANDLE_AUTO_INCREMENT ,"42000", "" }, { ER_WRONG_COLUMN_NAME ,"42000", "" }, { ER_WRONG_KEY_COLUMN ,"42000", "" }, { ER_DUP_UNIQUE ,"23000", "" }, { ER_BLOB_KEY_WITHOUT_LENGTH ,"42000", "" }, { ER_PRIMARY_CANT_HAVE_NULL ,"42000", "" }, { ER_TOO_MANY_ROWS ,"42000", "" }, { ER_REQUIRES_PRIMARY_KEY ,"42000", "" }, { ER_KEY_DOES_NOT_EXISTS ,"42000", "S1009" }, { ER_CHECK_NO_SUCH_TABLE ,"42000", "" }, { ER_CHECK_NOT_IMPLEMENTED ,"42000", "" }, { ER_CANT_DO_THIS_DURING_AN_TRANSACTION ,"25000", "" }, { ER_NEW_ABORTING_CONNECTION ,"08S01", "" }, { ER_MASTER_NET_READ ,"08S01", "" }, { ER_MASTER_NET_WRITE ,"08S01", "" }, { ER_TOO_MANY_USER_CONNECTIONS ,"42000", "" }, { ER_READ_ONLY_TRANSACTION ,"25000", "" }, { ER_NO_PERMISSION_TO_CREATE_USER ,"42000", "" }, { ER_LOCK_DEADLOCK ,"40001", "" }, { ER_NO_REFERENCED_ROW ,"23000", "" }, { ER_ROW_IS_REFERENCED ,"23000", "" }, { ER_CONNECT_TO_MASTER ,"08S01", "" }, { ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT ,"21000", "" }, { ER_USER_LIMIT_REACHED ,"42000", "" }, { ER_SPECIFIC_ACCESS_DENIED_ERROR ,"42000", "" }, { ER_NO_DEFAULT ,"42000", "" }, { ER_WRONG_VALUE_FOR_VAR ,"42000", "" }, { ER_WRONG_TYPE_FOR_VAR ,"42000", "" }, { ER_CANT_USE_OPTION_HERE ,"42000", "" }, { ER_NOT_SUPPORTED_YET ,"42000", "" }, { ER_WRONG_FK_DEF ,"42000", "" }, { ER_OPERAND_COLUMNS ,"21000", "" }, { ER_SUBQUERY_NO_1_ROW ,"21000", "" }, { ER_ILLEGAL_REFERENCE ,"42S22", "" }, { ER_DERIVED_MUST_HAVE_ALIAS ,"42000", "" }, { ER_SELECT_REDUCED ,"01000", "" }, { ER_TABLENAME_NOT_ALLOWED_HERE ,"42000", "" }, { ER_NOT_SUPPORTED_AUTH_MODE ,"08004", "" }, { ER_SPATIAL_CANT_HAVE_NULL ,"42000", "" }, { ER_COLLATION_CHARSET_MISMATCH ,"42000", "" }, { ER_WARN_TOO_FEW_RECORDS ,"01000", "" }, { ER_WARN_TOO_MANY_RECORDS ,"01000", "" }, { ER_WARN_NULL_TO_NOTNULL ,"22004", "" }, { ER_WARN_DATA_OUT_OF_RANGE ,"22003", "" }, { WARN_DATA_TRUNCATED ,"01000", "" }, { ER_WRONG_NAME_FOR_INDEX ,"42000", "" }, { ER_WRONG_NAME_FOR_CATALOG ,"42000", "" }, { ER_UNKNOWN_STORAGE_ENGINE ,"42000", "" }, { ER_TRUNCATED_WRONG_VALUE ,"22007", "" }, { ER_SP_NO_RECURSIVE_CREATE ,"2F003", "" }, { ER_SP_ALREADY_EXISTS ,"42000", "" }, { ER_SP_DOES_NOT_EXIST ,"42000", "" }, { ER_SP_LILABEL_MISMATCH ,"42000", "" }, { ER_SP_LABEL_REDEFINE ,"42000", "" }, { ER_SP_LABEL_MISMATCH ,"42000", "" }, { ER_SP_UNINIT_VAR ,"01000", "" }, { ER_SP_BADSELECT ,"0A000", "" }, { ER_SP_BADRETURN ,"42000", "" }, { ER_SP_BADSTATEMENT ,"0A000", "" }, { ER_UPDATE_LOG_DEPRECATED_IGNORED ,"42000", "" }, { ER_UPDATE_LOG_DEPRECATED_TRANSLATED ,"42000", "" }, { ER_QUERY_INTERRUPTED ,"70100", "" }, { ER_SP_WRONG_NO_OF_ARGS ,"42000", "" }, { ER_SP_COND_MISMATCH ,"42000", "" }, { ER_SP_NORETURN ,"42000", "" }, { ER_SP_NORETURNEND ,"2F005", "" }, { ER_SP_BAD_CURSOR_QUERY ,"42000", "" }, { ER_SP_BAD_CURSOR_SELECT ,"42000", "" }, { ER_SP_CURSOR_MISMATCH ,"42000", "" }, { ER_SP_CURSOR_ALREADY_OPEN ,"24000", "" }, { ER_SP_CURSOR_NOT_OPEN ,"24000", "" }, { ER_SP_UNDECLARED_VAR ,"42000", "" }, { ER_SP_FETCH_NO_DATA ,"02000", "" }, { ER_SP_DUP_PARAM ,"42000", "" }, { ER_SP_DUP_VAR ,"42000", "" }, { ER_SP_DUP_COND ,"42000", "" }, { ER_SP_DUP_CURS ,"42000", "" }, { ER_SP_SUBSELECT_NYI ,"0A000", "" }, { ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG ,"0A000", "" }, { ER_SP_VARCOND_AFTER_CURSHNDLR ,"42000", "" }, { ER_SP_CURSOR_AFTER_HANDLER ,"42000", "" }, { ER_SP_CASE_NOT_FOUND ,"20000", "" }, { ER_DIVISION_BY_ZERO ,"22012", "" }, { ER_TRUNCATED_WRONG_VALUE_FOR_FIELD ,"22007", "" }, { ER_ILLEGAL_VALUE_FOR_TYPE ,"22007", "" }, { ER_VIEW_CHECK_FAILED ,"44000", "" }, { ER_PROCACCESS_DENIED_ERROR ,"42000", "" }, { ER_XAER_NOTA ,"XAE04", "" }, { ER_XAER_INVAL ,"XAE05", "" }, { ER_XAER_RMFAIL ,"XAE07", "" }, { ER_XAER_OUTSIDE ,"XAE09", "" }, { ER_XAER_RMERR ,"XAE03", "" }, { ER_XA_RBROLLBACK ,"XA100", "" }, { ER_NONEXISTING_PROC_GRANT ,"42000", "" }, { ER_DATA_TOO_LONG ,"22001", "" }, { ER_SP_BAD_SQLSTATE ,"42000", "" }, { ER_CANT_CREATE_USER_WITH_GRANT ,"42000", "" }, { ER_SP_DUP_HANDLER ,"42000", "" }, { ER_SP_NOT_VAR_ARG ,"42000", "" }, { ER_SP_NO_RETSET ,"0A000", "" }, { ER_CANT_CREATE_GEOMETRY_OBJECT ,"22003", "" }, { ER_TOO_BIG_SCALE ,"42000", "S1009" }, { ER_TOO_BIG_PRECISION ,"42000", "S1009" }, { ER_M_BIGGER_THAN_D ,"42000", "S1009" }, { ER_TOO_LONG_BODY ,"42000", "S1009" }, { ER_TOO_BIG_DISPLAYWIDTH ,"42000", "S1009" }, { ER_XAER_DUPID ,"XAE08", "" }, { ER_DATETIME_FUNCTION_OVERFLOW ,"22008", "" }, { ER_MALFORMED_DEFINER ,"0L000", "" }, { ER_ROW_IS_REFERENCED_2 ,"23000", "" }, { ER_NO_REFERENCED_ROW_2 ,"23000", "" }, { ER_SP_BAD_VAR_SHADOW ,"42000", "" }, { ER_SP_WRONG_NAME ,"42000", "" }, { ER_SP_NO_AGGREGATE ,"42000", "" }, { ER_MAX_PREPARED_STMT_COUNT_REACHED ,"42000", "" }, { ER_NON_GROUPING_FIELD_USED ,"42000", "" }, { ER_CANT_CHANGE_TX_CHARACTERISTICS ,"25001", "" }, { ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT ,"42000", "" }, { ER_WRONG_PARAMETERS_TO_NATIVE_FCT ,"42000", "" }, { ER_WRONG_PARAMETERS_TO_STORED_FCT ,"42000", "" }, { ER_DUP_ENTRY_WITH_KEY_NAME ,"23000", "S1009" }, { ER_XA_RBTIMEOUT ,"XA106", "" }, { ER_XA_RBDEADLOCK ,"XA102", "" }, { ER_FUNC_INEXISTENT_NAME_COLLISION ,"42000", "" }, { ER_DUP_SIGNAL_SET ,"42000", "" }, { ER_SIGNAL_WARN ,"01000", "" }, { ER_SIGNAL_NOT_FOUND ,"02000", "" }, { ER_SIGNAL_EXCEPTION ,"HY000", "" }, { ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER ,"0K000", "" }, { ER_SPATIAL_MUST_HAVE_GEOM_COL ,"42000", "" }, { ER_DATA_OUT_OF_RANGE ,"22003", "" }, { ER_ACCESS_DENIED_NO_PASSWORD_ERROR ,"28000", "" }, { ER_TRUNCATE_ILLEGAL_FK ,"42000", "" }, { ER_DA_INVALID_CONDITION_NUMBER ,"35000", "" }, { ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO,"23000", "S1009" }, { ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO,"23000", "S1009" }, { ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION,"25006", "" }, { ER_ALTER_OPERATION_NOT_SUPPORTED ,"0A000", "" }, { ER_ALTER_OPERATION_NOT_SUPPORTED_REASON ,"0A000", "" }, { ER_DUP_UNKNOWN_IN_INDEX ,"23000", "" }, { ER_ACCESS_DENIED_CHANGE_USER_ERROR ,"28000", "" }, { ER_DATA_OVERFLOW ,"22003", "" }, { ER_DATA_TRUNCATED ,"22003", "" }, { ER_BAD_DATA ,"22007", "" }, { ER_DYN_COL_DATA ,"22007", "" }, { ER_CONNECTION_KILLED ,"70100", "" }, { ER_NO_SUCH_TABLE_IN_ENGINE ,"42S02", "" }, { ER_INVALID_ROLE ,"OP000", "" }, { ER_INVALID_CURRENT_USER ,"0L000", "" }, { ER_IT_IS_A_VIEW ,"42S02", "" }, { ER_STATEMENT_TIMEOUT ,"70100", "" }, { ER_SUBQUERIES_NOT_SUPPORTED ,"42000", "" }, { ER_SET_STATEMENT_NOT_SUPPORTED ,"42000", "" }, { ER_INVALID_DEFAULT_VALUE_FOR_FIELD ,"22007", "" }, { ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER,"0Z002", "" }, { ER_INVALID_ARGUMENT_FOR_LOGARITHM ,"2201E", "" }, { ER_GIS_INVALID_DATA ,"22023", "" }, { ER_USER_LOCK_WRONG_NAME ,"42000", "" }, { ER_UNUSED_26 ,"0A000", "" }, { ER_CONSTRAINT_FAILED ,"23000", "" }, { ER_EXPRESSION_REFERS_TO_UNINIT_FIELD ,"01000", "" }, { ER_WRONG_PARAMCOUNT_TO_CURSOR ,"42000", "" }, { ER_NOT_SEQUENCE ,"42S02", "" }, { ER_NOT_SEQUENCE2 ,"42S02", "" }, { ER_UNKNOWN_SEQUENCES ,"42S02", "" }, { ER_UNKNOWN_VIEW ,"42S02", "" }, { ER_TOO_LONG_KEYPART ,"42000", "S1009" }, server/mysql/service_kill_statement.h000064400000004026151031265040014126 0ustar00/* Copyright (c) 2013, 2018, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SERVICE_KILL_STATEMENT_INCLUDED #define MYSQL_SERVICE_KILL_STATEMENT_INCLUDED /** @file This service provides functions that allow plugins to support the KILL statement. In MySQL support for the KILL statement is cooperative. The KILL statement only sets a "killed" flag. This function returns the value of that flag. A thread should check it often, especially inside time-consuming loops, and gracefully abort the operation if it is non-zero. thd_killed(thd) @return 0 - no KILL statement was issued, continue normally @return 1 - there was a KILL statement, abort the execution. thd_kill_level(thd) @return thd_kill_levels_enum values */ #ifdef __cplusplus extern "C" { #endif enum thd_kill_levels { THD_IS_NOT_KILLED=0, THD_ABORT_SOFTLY=50, /**< abort when possible, don't leave tables corrupted */ THD_ABORT_ASAP=100, /**< abort asap */ }; extern struct kill_statement_service_st { enum thd_kill_levels (*thd_kill_level_func)(const MYSQL_THD); } *thd_kill_statement_service; /* backward compatibility helper */ #define thd_killed(THD) (thd_kill_level(THD) == THD_ABORT_ASAP) #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_kill_level(THD) \ thd_kill_statement_service->thd_kill_level_func(THD) #else enum thd_kill_levels thd_kill_level(const MYSQL_THD); #endif #ifdef __cplusplus } #endif #endif server/mysql/service_sha2.h000064400000012263151031265040011746 0ustar00#ifndef MYSQL_SERVICE_SHA2_INCLUDED /* Copyright (c) 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my sha2 service Functions to calculate SHA2 hash from a memory buffer */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #endif extern struct my_sha2_service_st { void (*my_sha224_type)(unsigned char*, const char*, size_t); void (*my_sha224_multi_type)(unsigned char*, ...); size_t (*my_sha224_context_size_type)(); void (*my_sha224_init_type)(void *); void (*my_sha224_input_type)(void *, const unsigned char *, size_t); void (*my_sha224_result_type)(void *, unsigned char *); void (*my_sha256_type)(unsigned char*, const char*, size_t); void (*my_sha256_multi_type)(unsigned char*, ...); size_t (*my_sha256_context_size_type)(); void (*my_sha256_init_type)(void *); void (*my_sha256_input_type)(void *, const unsigned char *, size_t); void (*my_sha256_result_type)(void *, unsigned char *); void (*my_sha384_type)(unsigned char*, const char*, size_t); void (*my_sha384_multi_type)(unsigned char*, ...); size_t (*my_sha384_context_size_type)(); void (*my_sha384_init_type)(void *); void (*my_sha384_input_type)(void *, const unsigned char *, size_t); void (*my_sha384_result_type)(void *, unsigned char *); void (*my_sha512_type)(unsigned char*, const char*, size_t); void (*my_sha512_multi_type)(unsigned char*, ...); size_t (*my_sha512_context_size_type)(); void (*my_sha512_init_type)(void *); void (*my_sha512_input_type)(void *, const unsigned char *, size_t); void (*my_sha512_result_type)(void *, unsigned char *); } *my_sha2_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_sha224(A,B,C) my_sha2_service->my_sha224_type(A,B,C) #define my_sha224_multi my_sha2_service->my_sha224_multi_type #define my_sha224_context_size() my_sha2_service->my_sha224_context_size_type() #define my_sha224_init(A) my_sha2_service->my_sha224_init_type(A) #define my_sha224_input(A,B,C) my_sha2_service->my_sha224_input_type(A,B,C) #define my_sha224_result(A,B) my_sha2_service->my_sha224_result_type(A,B) #define my_sha256(A,B,C) my_sha2_service->my_sha256_type(A,B,C) #define my_sha256_multi my_sha2_service->my_sha256_multi_type #define my_sha256_context_size() my_sha2_service->my_sha256_context_size_type() #define my_sha256_init(A) my_sha2_service->my_sha256_init_type(A) #define my_sha256_input(A,B,C) my_sha2_service->my_sha256_input_type(A,B,C) #define my_sha256_result(A,B) my_sha2_service->my_sha256_result_type(A,B) #define my_sha384(A,B,C) my_sha2_service->my_sha384_type(A,B,C) #define my_sha384_multi my_sha2_service->my_sha384_multi_type #define my_sha384_context_size() my_sha2_service->my_sha384_context_size_type() #define my_sha384_init(A) my_sha2_service->my_sha384_init_type(A) #define my_sha384_input(A,B,C) my_sha2_service->my_sha384_input_type(A,B,C) #define my_sha384_result(A,B) my_sha2_service->my_sha384_result_type(A,B) #define my_sha512(A,B,C) my_sha2_service->my_sha512_type(A,B,C) #define my_sha512_multi my_sha2_service->my_sha512_multi_type #define my_sha512_context_size() my_sha2_service->my_sha512_context_size_type() #define my_sha512_init(A) my_sha2_service->my_sha512_init_type(A) #define my_sha512_input(A,B,C) my_sha2_service->my_sha512_input_type(A,B,C) #define my_sha512_result(A,B) my_sha2_service->my_sha512_result_type(A,B) #else void my_sha224(unsigned char*, const char*, size_t); void my_sha224_multi(unsigned char*, ...); size_t my_sha224_context_size(); void my_sha224_init(void *context); void my_sha224_input(void *context, const unsigned char *buf, size_t len); void my_sha224_result(void *context, unsigned char *digest); void my_sha256(unsigned char*, const char*, size_t); void my_sha256_multi(unsigned char*, ...); size_t my_sha256_context_size(); void my_sha256_init(void *context); void my_sha256_input(void *context, const unsigned char *buf, size_t len); void my_sha256_result(void *context, unsigned char *digest); void my_sha384(unsigned char*, const char*, size_t); void my_sha384_multi(unsigned char*, ...); size_t my_sha384_context_size(); void my_sha384_init(void *context); void my_sha384_input(void *context, const unsigned char *buf, size_t len); void my_sha384_result(void *context, unsigned char *digest); void my_sha512(unsigned char*, const char*, size_t); void my_sha512_multi(unsigned char*, ...); size_t my_sha512_context_size(); void my_sha512_init(void *context); void my_sha512_input(void *context, const unsigned char *buf, size_t len); void my_sha512_result(void *context, unsigned char *digest); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_SHA2_INCLUDED #endif server/mysql/plugin_password_validation.h000064400000003021151031265040015013 0ustar00#ifndef MYSQL_PLUGIN_PASSWORD_VALIDATION_INCLUDED /* Copyright (C) 2014 Sergei Golubchik and MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Password Validation Plugin API. This file defines the API for server password validation plugins. */ #define MYSQL_PLUGIN_PASSWORD_VALIDATION_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #define MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION 0x0100 /** Password validation plugin descriptor */ struct st_mariadb_password_validation { int interface_version; /**< version plugin uses */ /** Function provided by the plugin which should perform password validation and return 0 if the password has passed the validation. */ int (*validate_password)(const MYSQL_CONST_LEX_STRING *username, const MYSQL_CONST_LEX_STRING *password); }; #ifdef __cplusplus } #endif #endif server/mysql/plugin_data_type.h000064400000002424151031265040012717 0ustar00#ifndef MARIADB_PLUGIN_DATA_TYPE_INCLUDED #define MARIADB_PLUGIN_DATA_TYPE_INCLUDED /* Copyright (C) 2019, Alexander Barkov and MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Data Type Plugin API. This file defines the API for server plugins that manage data types. */ #ifdef __cplusplus #include /* API for data type plugins. (MariaDB_DATA_TYPE_PLUGIN) */ #define MariaDB_DATA_TYPE_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) struct st_mariadb_data_type { int interface_version; class Type_handler *type_handler; }; /** Data type plugin descriptor */ #endif /* __cplusplus */ #endif /* MARIADB_PLUGIN_DATA_TYPE_INCLUDED */ server/mysql/service_thd_error_context.h000064400000006540151031265040014646 0ustar00#ifndef MYSQL_SERVICE_THD_STMT_DA_INCLUDED /* Copyright (C) 2013 MariaDB Foundation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service provides access to the statement diagnostics area: - error message - error number - row for warning (e.g. for multi-row INSERT statements) */ #ifdef __cplusplus extern "C" { #endif extern struct thd_error_context_service_st { const char *(*thd_get_error_message_func)(const MYSQL_THD thd); unsigned int (*thd_get_error_number_func)(const MYSQL_THD thd); unsigned long (*thd_get_error_row_func)(const MYSQL_THD thd); void (*thd_inc_error_row_func)(MYSQL_THD thd); char *(*thd_get_error_context_description_func)(MYSQL_THD thd, char *buffer, unsigned int length, unsigned int max_query_length); } *thd_error_context_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_get_error_message(thd) \ (thd_error_context_service->thd_get_error_message_func((thd))) #define thd_get_error_number(thd) \ (thd_error_context_service->thd_get_error_number_func((thd))) #define thd_get_error_row(thd) \ (thd_error_context_service->thd_get_error_row_func((thd))) #define thd_inc_error_row(thd) \ (thd_error_context_service->thd_inc_error_row_func((thd))) #define thd_get_error_context_description(thd, buffer, length, max_query_len) \ (thd_error_context_service->thd_get_error_context_description_func((thd), \ (buffer), \ (length), \ (max_query_len))) #else /** Return error message @param thd user thread connection handle @return error text */ const char *thd_get_error_message(const MYSQL_THD thd); /** Return error number @param thd user thread connection handle @return error number */ unsigned int thd_get_error_number(const MYSQL_THD thd); /** Return the current row number (i.e. in a multiple INSERT statement) @param thd user thread connection handle @return row number */ unsigned long thd_get_error_row(const MYSQL_THD thd); /** Increment the current row number @param thd user thread connection handle */ void thd_inc_error_row(MYSQL_THD thd); /** Return a text description of a thread, its security context (user,host) and the current query. */ char *thd_get_error_context_description(MYSQL_THD thd, char *buffer, unsigned int length, unsigned int max_query_length); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_STMT_DA_INCLUDED #endif server/mysql/service_thd_wait.h000064400000007157151031265040012722 0ustar00/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SERVICE_THD_WAIT_INCLUDED #define MYSQL_SERVICE_THD_WAIT_INCLUDED /** @file include/mysql/service_thd_wait.h This service provides functions for plugins and storage engines to report when they are going to sleep/stall. SYNOPSIS thd_wait_begin() - call just before a wait begins thd Thread object Use NULL if the thd is NOT known. wait_type Type of wait 1 -- short wait (e.g. for mutex) 2 -- medium wait (e.g. for disk io) 3 -- large wait (e.g. for locked row/table) NOTES This is used by the threadpool to have better knowledge of which threads that currently are actively running on CPUs. When a thread reports that it's going to sleep/stall, the threadpool scheduler is free to start another thread in the pool most likely. The expected wait time is simply an indication of how long the wait is expected to become, the real wait time could be very different. thd_wait_end() called immediately after the wait is complete thd_wait_end() MUST be called if thd_wait_begin() was called. Using thd_wait_...() service is optional but recommended. Using it will improve performance as the thread pool will be more active at managing the thread workload. */ #ifdef __cplusplus extern "C" { #endif /* One should only report wait events that could potentially block for a long time. A mutex wait is too short of an event to report. The reason is that an event which is reported leads to a new thread starts executing a query and this has a negative impact of usage of CPU caches and thus the expected gain of starting a new thread must be higher than the expected cost of lost performance due to starting a new thread. Good examples of events that should be reported are waiting for row locks that could easily be for many milliseconds or even seconds and the same holds true for global read locks, table locks and other meta data locks. Another event of interest is going to sleep for an extended time. */ typedef enum _thd_wait_type_e { THD_WAIT_SLEEP= 1, THD_WAIT_DISKIO= 2, THD_WAIT_ROW_LOCK= 3, THD_WAIT_GLOBAL_LOCK= 4, THD_WAIT_META_DATA_LOCK= 5, THD_WAIT_TABLE_LOCK= 6, THD_WAIT_USER_LOCK= 7, THD_WAIT_BINLOG= 8, THD_WAIT_GROUP_COMMIT= 9, THD_WAIT_SYNC= 10, THD_WAIT_NET= 11, THD_WAIT_LAST= 12 } thd_wait_type; extern struct thd_wait_service_st { void (*thd_wait_begin_func)(MYSQL_THD, int); void (*thd_wait_end_func)(MYSQL_THD); } *thd_wait_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_wait_begin(_THD, _WAIT_TYPE) \ thd_wait_service->thd_wait_begin_func(_THD, _WAIT_TYPE) #define thd_wait_end(_THD) thd_wait_service->thd_wait_end_func(_THD) #else void thd_wait_begin(MYSQL_THD thd, int wait_type); void thd_wait_end(MYSQL_THD thd); #endif #ifdef __cplusplus } #endif #endif server/mysql/service_debug_sync.h000064400000032414151031265040013233 0ustar00#ifndef MYSQL_SERVICE_DEBUG_SYNC_INCLUDED /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. Copyright (c) 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file == Debug Sync Facility == The Debug Sync Facility allows placement of synchronization points in the server code by using the DEBUG_SYNC macro: open_tables(...) DEBUG_SYNC(thd, "after_open_tables"); lock_tables(...) When activated, a sync point can - Emit a signal and/or - Wait for a signal Nomenclature: - signal: A value of a global variable that persists until overwritten by a new signal. The global variable can also be seen as a "signal post" or "flag mast". Then the signal is what is attached to the "signal post" or "flag mast". - emit a signal: Assign the value (the signal) to the global variable ("set a flag") and broadcast a global condition to wake those waiting for a signal. - wait for a signal: Loop over waiting for the global condition until the global value matches the wait-for signal. By default, all sync points are inactive. They do nothing (except to burn a couple of CPU cycles for checking if they are active). A sync point becomes active when an action is requested for it. To do so, put a line like this in the test case file: SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed'; This activates the sync point 'after_open_tables'. It requests it to emit the signal 'opened' and wait for another thread to emit the signal 'flushed' when the thread's execution runs through the sync point. For every sync point there can be one action per thread only. Every thread can request multiple actions, but only one per sync point. In other words, a thread can activate multiple sync points. Here is an example how to activate and use the sync points: --connection conn1 SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed'; send INSERT INTO t1 VALUES(1); --connection conn2 SET DEBUG_SYNC= 'now WAIT_FOR opened'; SET DEBUG_SYNC= 'after_abort_locks SIGNAL flushed'; FLUSH TABLE t1; When conn1 runs through the INSERT statement, it hits the sync point 'after_open_tables'. It notices that it is active and executes its action. It emits the signal 'opened' and waits for another thread to emit the signal 'flushed'. conn2 waits immediately at the special sync point 'now' for another thread to emit the 'opened' signal. A signal remains in effect until it is overwritten. If conn1 signals 'opened' before conn2 reaches 'now', conn2 will still find the 'opened' signal. It does not wait in this case. When conn2 reaches 'after_abort_locks', it signals 'flushed', which lets conn1 awake. Normally the activation of a sync point is cleared when it has been executed. Sometimes it is necessary to keep the sync point active for another execution. You can add an execute count to the action: SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 3'; This sets the signal point's activation counter to 3. Each execution decrements the counter. After the third execution the sync point becomes inactive. One of the primary goals of this facility is to eliminate sleeps from the test suite. In most cases it should be possible to rewrite test cases so that they do not need to sleep. (But this facility cannot synchronize multiple processes.) However, to support test development, and as a last resort, sync point waiting times out. There is a default timeout, but it can be overridden: SET DEBUG_SYNC= 'name WAIT_FOR sig TIMEOUT 10 EXECUTE 2'; TIMEOUT 0 is special: If the signal is not present, the wait times out immediately. When a wait timed out (even on TIMEOUT 0), a warning is generated so that it shows up in the test result. You can throw an error message and kill the query when a synchronization point is hit a certain number of times: SET DEBUG_SYNC= 'name HIT_LIMIT 3'; Or combine it with signal and/or wait: SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 2 HIT_LIMIT 3'; Here the first two hits emit the signal, the third hit returns the error message and kills the query. For cases where you are not sure that an action is taken and thus cleared in any case, you can force to clear (deactivate) a sync point: SET DEBUG_SYNC= 'name CLEAR'; If you want to clear all actions and clear the global signal, use: SET DEBUG_SYNC= 'RESET'; This is the only way to reset the global signal to an empty string. For testing of the facility itself you can execute a sync point just as if it had been hit: SET DEBUG_SYNC= 'name TEST'; === Formal Syntax === The string to "assign" to the DEBUG_SYNC variable can contain: {RESET | TEST | CLEAR | {{SIGNAL | WAIT_FOR [TIMEOUT ]} [EXECUTE ] &| HIT_LIMIT } Here '&|' means 'and/or'. This means that one of the sections separated by '&|' must be present or both of them. === Activation/Deactivation === The facility is an optional part of the MySQL server. It is enabled in a debug server by default. ./configure --enable-debug-sync The Debug Sync Facility, when compiled in, is disabled by default. It can be enabled by a mysqld command line option: --debug-sync-timeout[=default_wait_timeout_value_in_seconds] 'default_wait_timeout_value_in_seconds' is the default timeout for the WAIT_FOR action. If set to zero, the facility stays disabled. The facility is enabled by default in the test suite, but can be disabled with: mysql-test-run.pl ... --debug-sync-timeout=0 ... Likewise the default wait timeout can be set: mysql-test-run.pl ... --debug-sync-timeout=10 ... The command line option influences the readable value of the system variable 'debug_sync'. * If the facility is not compiled in, the system variable does not exist. * If --debug-sync-timeout=0 the value of the variable reads as "OFF". * Otherwise the value reads as "ON - current signal: " followed by the current signal string, which can be empty. The readable variable value is the same, regardless if read as global or session value. Setting the 'debug-sync' system variable requires 'SUPER' privilege. You can never read back the string that you assigned to the variable, unless you assign the value that the variable does already have. But that would give a parse error. A syntactically correct string is parsed into a debug sync action and stored apart from the variable value. === Implementation === Pseudo code for a sync point: #define DEBUG_SYNC(thd, sync_point_name) if (unlikely(opt_debug_sync_timeout)) debug_sync(thd, STRING_WITH_LEN(sync_point_name)) The sync point performs a binary search in a sorted array of actions for this thread. The SET DEBUG_SYNC statement adds a requested action to the array or overwrites an existing action for the same sync point. When it adds a new action, the array is sorted again. === A typical synchronization pattern === There are quite a few places in MySQL, where we use a synchronization pattern like this: mysql_mutex_lock(&mutex); thd->enter_cond(&condition_variable, &mutex, new_message); #if defined(ENABLE_DEBUG_SYNC) if (!thd->killed && !end_of_wait_condition) DEBUG_SYNC(thd, "sync_point_name"); #endif while (!thd->killed && !end_of_wait_condition) mysql_cond_wait(&condition_variable, &mutex); thd->exit_cond(old_message); Here some explanations: thd->enter_cond() is used to register the condition variable and the mutex in thd->mysys_var. This is done to allow the thread to be interrupted (killed) from its sleep. Another thread can find the condition variable to signal and mutex to use for synchronization in this thread's THD::mysys_var. thd->enter_cond() requires the mutex to be acquired in advance. thd->exit_cond() unregisters the condition variable and mutex and releases the mutex. If you want to have a Debug Sync point with the wait, please place it behind enter_cond(). Only then you can safely decide, if the wait will be taken. Also you will have THD::proc_info correct when the sync point emits a signal. DEBUG_SYNC sets its own proc_info, but restores the previous one before releasing its internal mutex. As soon as another thread sees the signal, it does also see the proc_info from before entering the sync point. In this case it will be "new_message", which is associated with the wait that is to be synchronized. In the example above, the wait condition is repeated before the sync point. This is done to skip the sync point, if no wait takes place. The sync point is before the loop (not inside the loop) to have it hit once only. It is possible that the condition variable is signaled multiple times without the wait condition to be true. A bit off-topic: At some places, the loop is taken around the whole synchronization pattern: while (!thd->killed && !end_of_wait_condition) { mysql_mutex_lock(&mutex); thd->enter_cond(&condition_variable, &mutex, new_message); if (!thd->killed [&& !end_of_wait_condition]) { [DEBUG_SYNC(thd, "sync_point_name");] mysql_cond_wait(&condition_variable, &mutex); } thd->exit_cond(old_message); } Note that it is important to repeat the test for thd->killed after enter_cond(). Otherwise the killing thread may kill this thread after it tested thd->killed in the loop condition and before it registered the condition variable and mutex in enter_cond(). In this case, the killing thread does not know that this thread is going to wait on a condition variable. It would just set THD::killed. But if we would not test it again, we would go asleep though we are killed. If the killing thread would kill us when we are after the second test, but still before sleeping, we hold the mutex, which is registered in mysys_var. The killing thread would try to acquire the mutex before signaling the condition variable. Since the mutex is only released implicitly in mysql_cond_wait(), the signaling happens at the right place. We have a safe synchronization. === Co-work with the DBUG facility === When running the MySQL test suite with the --debug-dbug command line option, the Debug Sync Facility writes trace messages to the DBUG trace. The following shell commands proved very useful in extracting relevant information: egrep 'query:|debug_sync_exec:' mysql-test/var/log/mysqld.1.trace It shows all executed SQL statements and all actions executed by synchronization points. Sometimes it is also useful to see, which synchronization points have been run through (hit) with or without executing actions. Then add "|debug_sync_point:" to the egrep pattern. === Further reading === For a discussion of other methods to synchronize threads see http://forge.mysql.com/wiki/MySQL_Internals_Test_Synchronization For complete syntax tests, functional tests, and examples see the test case debug_sync.test. See also http://forge.mysql.com/worklog/task.php?id=4259 */ #ifndef MYSQL_ABI_CHECK #include #endif #ifdef __cplusplus extern "C" { #endif #ifdef MYSQL_DYNAMIC_PLUGIN extern void (*debug_sync_service)(MYSQL_THD, const char *, size_t); #else #define debug_sync_service debug_sync_C_callback_ptr extern void (*debug_sync_C_callback_ptr)(MYSQL_THD, const char *, size_t); #endif #ifdef ENABLED_DEBUG_SYNC #define DEBUG_SYNC(thd, name) \ do { \ if (debug_sync_service) \ debug_sync_service(thd, STRING_WITH_LEN(name)); \ } while(0) #define DEBUG_SYNC_C_IF_THD(thd, name) \ do { \ if (debug_sync_service && thd) \ debug_sync_service((MYSQL_THD) thd, STRING_WITH_LEN(name)); \ } while(0) #else #define DEBUG_SYNC(thd,name) do { } while(0) #define DEBUG_SYNC_C_IF_THD(thd, _sync_point_name_) do { } while(0) #endif /* defined(ENABLED_DEBUG_SYNC) */ /* compatibility macro */ #ifdef __cplusplus #define DEBUG_SYNC_C(name) DEBUG_SYNC(nullptr, name) #else #define DEBUG_SYNC_C(name) DEBUG_SYNC(NULL, name) #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_DEBUG_SYNC_INCLUDED #endif server/mysql/service_my_crypt.h000064400000010107151031265040012752 0ustar00#ifndef MYSQL_SERVICE_MY_CRYPT_INCLUDED #define MYSQL_SERVICE_MY_CRYPT_INCLUDED /* Copyright (c) 2014 Google Inc. Copyright (c) 2014, 2015 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my crypt service AES encryption functions, and a function to generate random bytes. Include my_config.h before this file to use CTR and GCM modes (they only work if server was compiled with openssl). */ #ifdef __cplusplus extern "C" { #endif /* return values from my_aes_encrypt/my_aes_decrypt functions */ #define MY_AES_OK 0 #define MY_AES_BAD_DATA -100 #define MY_AES_OPENSSL_ERROR -101 #define MY_AES_BAD_KEYSIZE -102 /* The block size for all supported algorithms */ #define MY_AES_BLOCK_SIZE 16 /* The max key length of all supported algorithms */ #define MY_AES_MAX_KEY_LENGTH 32 #define MY_AES_CTX_SIZE 1040 enum my_aes_mode { MY_AES_ECB, MY_AES_CBC #ifdef HAVE_EncryptAes128Ctr , MY_AES_CTR #endif #ifdef HAVE_EncryptAes128Gcm , MY_AES_GCM #endif }; extern struct my_crypt_service_st { int (*my_aes_crypt_init)(void *ctx, enum my_aes_mode mode, int flags, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen); int (*my_aes_crypt_update)(void *ctx, const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen); int (*my_aes_crypt_finish)(void *ctx, unsigned char *dst, unsigned int *dlen); int (*my_aes_crypt)(enum my_aes_mode mode, int flags, const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen, const unsigned char *key, unsigned int klen, const unsigned char *iv, unsigned int ivlen); unsigned int (*my_aes_get_size)(enum my_aes_mode mode, unsigned int source_length); unsigned int (*my_aes_ctx_size)(enum my_aes_mode mode); int (*my_random_bytes)(unsigned char* buf, int num); } *my_crypt_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_aes_crypt_init(A,B,C,D,E,F,G) \ my_crypt_service->my_aes_crypt_init(A,B,C,D,E,F,G) #define my_aes_crypt_update(A,B,C,D,E) \ my_crypt_service->my_aes_crypt_update(A,B,C,D,E) #define my_aes_crypt_finish(A,B,C) \ my_crypt_service->my_aes_crypt_finish(A,B,C) #define my_aes_crypt(A,B,C,D,E,F,G,H,I,J) \ my_crypt_service->my_aes_crypt(A,B,C,D,E,F,G,H,I,J) #define my_aes_get_size(A,B)\ my_crypt_service->my_aes_get_size(A,B) #define my_aes_ctx_size(A)\ my_crypt_service->my_aes_ctx_size(A) #define my_random_bytes(A,B)\ my_crypt_service->my_random_bytes(A,B) #else int my_aes_crypt_init(void *ctx, enum my_aes_mode mode, int flags, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen); int my_aes_crypt_update(void *ctx, const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen); int my_aes_crypt_finish(void *ctx, unsigned char *dst, unsigned int *dlen); int my_aes_crypt(enum my_aes_mode mode, int flags, const unsigned char *src, unsigned int slen, unsigned char *dst, unsigned int *dlen, const unsigned char *key, unsigned int klen, const unsigned char *iv, unsigned int ivlen); int my_random_bytes(unsigned char* buf, int num); unsigned int my_aes_get_size(enum my_aes_mode mode, unsigned int source_length); unsigned int my_aes_ctx_size(enum my_aes_mode mode); #endif #ifdef __cplusplus } #endif #endif /* MYSQL_SERVICE_MY_CRYPT_INCLUDED */ server/mysql/plugin_function.h000064400000002635151031265040012576 0ustar00#ifndef MARIADB_PLUGIN_FUNCTION_INCLUDED #define MARIADB_PLUGIN_FUNCTION_INCLUDED /* Copyright (C) 2019, Alexander Barkov and MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Function Plugin API. This file defines the API for server plugins that manage functions. */ #ifdef __cplusplus #include /* API for function plugins. (MariaDB_FUNCTION_PLUGIN) */ #define MariaDB_FUNCTION_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) class Plugin_function { int m_interface_version; Create_func *m_builder; public: Plugin_function(Create_func *builder) :m_interface_version(MariaDB_FUNCTION_INTERFACE_VERSION), m_builder(builder) { } Create_func *create_func() { return m_builder; } }; #endif /* __cplusplus */ #endif /* MARIADB_PLUGIN_FUNCTION_INCLUDED */ server/mysql/client_plugin.h000064400000014267151031265040012233 0ustar00#ifndef MYSQL_CLIENT_PLUGIN_INCLUDED /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab Copyright (c) 2010, 2011, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file MySQL Client Plugin API This file defines the API for plugins that work on the client side */ #define MYSQL_CLIENT_PLUGIN_INCLUDED /* On Windows, exports from DLL need to be declared Also, plugin needs to be declared as extern "C" because MSVC unlike other compilers, uses C++ mangling for variables not only for functions. */ #undef MYSQL_PLUGIN_EXPORT #if defined(_MSC_VER) #define MYSQL_PLUGIN_EXPORT_C __declspec(dllexport) #else /*_MSC_VER */ #define MYSQL_PLUGIN_EXPORT_C #endif #ifdef __cplusplus #define MYSQL_PLUGIN_EXPORT extern "C" MYSQL_PLUGIN_EXPORT_C #define C_MODE_START extern "C" { #define C_MODE_END } #else #define MYSQL_PLUGIN_EXPORT MYSQL_PLUGIN_EXPORT_C #define C_MODE_START #define C_MODE_END #endif #ifndef MYSQL_ABI_CHECK #include #include #endif /* known plugin types */ #define MYSQL_CLIENT_reserved1 0 #define MYSQL_CLIENT_reserved2 1 #define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2 #define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0100 #define MYSQL_CLIENT_MAX_PLUGINS 3 #define mysql_declare_client_plugin(X) \ C_MODE_START MYSQL_PLUGIN_EXPORT_C \ struct st_mysql_client_plugin_ ## X \ _mysql_client_plugin_declaration_ = { \ MYSQL_CLIENT_ ## X ## _PLUGIN, \ MYSQL_CLIENT_ ## X ## _PLUGIN_INTERFACE_VERSION, #define mysql_end_client_plugin }; C_MODE_END /* generic plugin header structure */ #define MYSQL_CLIENT_PLUGIN_HEADER \ int type; \ unsigned int interface_version; \ const char *name; \ const char *author; \ const char *desc; \ unsigned int version[3]; \ const char *license; \ void *mysql_api; \ int (*init)(char *, size_t, int, va_list); \ int (*deinit)(); \ int (*options)(const char *option, const void *); struct st_mysql_client_plugin { MYSQL_CLIENT_PLUGIN_HEADER }; struct st_mysql; /******** authentication plugin specific declarations *********/ #include struct st_mysql_client_plugin_AUTHENTICATION { MYSQL_CLIENT_PLUGIN_HEADER int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql); }; #include /******** using plugins ************/ /** loads a plugin and initializes it @param mysql MYSQL structure. @param name a name of the plugin to load @param type type of plugin that should be loaded, -1 to disable type check @param argc number of arguments to pass to the plugin initialization function @param ... arguments for the plugin initialization function @retval a pointer to the loaded plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, int argc, ...); /** loads a plugin and initializes it, taking va_list as an argument This is the same as mysql_load_plugin, but take va_list instead of a list of arguments. @param mysql MYSQL structure. @param name a name of the plugin to load @param type type of plugin that should be loaded, -1 to disable type check @param argc number of arguments to pass to the plugin initialization function @param args arguments for the plugin initialization function @retval a pointer to the loaded plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type, int argc, va_list args); /** finds an already loaded plugin by name, or loads it, if necessary @param mysql MYSQL structure. @param name a name of the plugin to load @param type type of plugin that should be loaded @retval a pointer to the plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type); /** adds a plugin structure to the list of loaded plugins This is useful if an application has the necessary functionality (for example, a special load data handler) statically linked into the application binary. It can use this function to register the plugin directly, avoiding the need to factor it out into a shared object. @param mysql MYSQL structure. It is only used for error reporting @param plugin an st_mysql_client_plugin structure to register @retval a pointer to the plugin, or NULL in case of a failure */ struct st_mysql_client_plugin * mysql_client_register_plugin(struct st_mysql *mysql, struct st_mysql_client_plugin *plugin); /** set plugin options Can be used to set extra options and affect behavior for a plugin. This function may be called multiple times to set several options @param plugin an st_mysql_client_plugin structure @param option a string which specifies the option to set @param value value for the option. @retval 0 on success, 1 in case of failure **/ int mysql_plugin_options(struct st_mysql_client_plugin *plugin, const char *option, const void *value); #endif server/mysql/plugin_auth.h000064400000012430151031265040011704 0ustar00#ifndef MYSQL_PLUGIN_AUTH_INCLUDED /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab Copyright (c) 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Authentication Plugin API. This file defines the API for server authentication plugins. */ #define MYSQL_PLUGIN_AUTH_INCLUDED #include #define MYSQL_AUTHENTICATION_INTERFACE_VERSION 0x0202 #include #ifdef __cplusplus extern "C" { #endif /* defines for MYSQL_SERVER_AUTH_INFO.password_used */ #define PASSWORD_USED_NO 0 #define PASSWORD_USED_YES 1 #define PASSWORD_USED_NO_MENTION 2 /** Provides server plugin access to authentication information */ typedef struct st_mysql_server_auth_info { /** User name as sent by the client and shown in USER(). NULL if the client packet with the user name was not received yet. */ const char *user_name; /** Length of user_name */ unsigned int user_name_length; /** A corresponding column value from the mysql.user table for the matching account name or the preprocessed value, if preprocess_hash method is not NULL */ const char *auth_string; /** Length of auth_string */ unsigned long auth_string_length; /** Matching account name as found in the mysql.user table. A plugin can override it with another name that will be used by MySQL for authorization, and shown in CURRENT_USER() */ char authenticated_as[MYSQL_USERNAME_LENGTH+1]; /** The unique user name that was used by the plugin to authenticate. Not used by the server. Available through the @@EXTERNAL_USER variable. */ char external_user[MYSQL_USERNAME_LENGTH+1]; /** This only affects the "Authentication failed. Password used: %s" error message. has the following values : 0 : %s will be NO. 1 : %s will be YES. 2 : there will be no %s. Set it as appropriate or ignore at will. */ int password_used; /** Set to the name of the connected client host, if it can be resolved, or to its IP address otherwise. */ const char *host_or_ip; /** Length of host_or_ip */ unsigned int host_or_ip_length; /** Current THD pointer (to use with various services) */ MYSQL_THD thd; } MYSQL_SERVER_AUTH_INFO; /** Server authentication plugin descriptor */ struct st_mysql_auth { int interface_version; /**< version plugin uses */ /** A plugin that a client must use for authentication with this server plugin. Can be NULL to mean "any plugin". */ const char *client_auth_plugin; /** Function provided by the plugin which should perform authentication (using the vio functions if necessary) and return 0 if successful. The plugin can also fill the info.authenticated_as field if a different username should be used for authorization. */ int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info); /** Create a password hash (or digest) out of a plain-text password Used in SET PASSWORD, GRANT, and CREATE USER to convert user specified plain-text password into a value that will be stored in mysql.user table. @see preprocess_hash @param password plain-text password @param password_length plain-text password length @param hash the digest will be stored there @param hash_length in: hash buffer size out: the actual length of the hash @return 0 for ok, 1 for error Can be NULL, in this case one will not be able to use SET PASSWORD or PASSWORD('...') in GRANT, CREATE USER, ALTER USER. */ int (*hash_password)(const char *password, size_t password_length, char *hash, size_t *hash_length); /** Prepare the password hash for authentication. Password hash is stored in the authentication_string column of the mysql.user table in a text form. If a plugin needs to preprocess the value somehow before the authentication (e.g. convert from hex or base64 to binary), it can do it in this method. This way the conversion will happen only once, not for every authentication attempt. The value written to the out buffer will be cached and later made available to the authenticate_user() method in the MYSQL_SERVER_AUTH_INFO::auth_string[] buffer. @return 0 for ok, 1 for error Can be NULL, in this case the mysql.user.authentication_string value will be given to the authenticate_user() method as is, unconverted. */ int (*preprocess_hash)(const char *hash, size_t hash_length, unsigned char *out, size_t *out_length); }; #ifdef __cplusplus } #endif #endif server/mysql/plugin.h000064400000072306151031265040010673 0ustar00/* Copyright (c) 2005, 2013, Oracle and/or its affiliates Copyright (C) 2009, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_PLUGIN_INCLUDED #define MYSQL_PLUGIN_INCLUDED /* On Windows, exports from DLL need to be declared Also, plugin needs to be declared as extern "C" because MSVC unlike other compilers, uses C++ mangling for variables not only for functions. */ #ifdef MYSQL_DYNAMIC_PLUGIN #ifdef _MSC_VER #define MYSQL_DLLEXPORT _declspec(dllexport) #else #define MYSQL_DLLEXPORT #endif #else #define MYSQL_DLLEXPORT #endif #ifdef __cplusplus #define MYSQL_PLUGIN_EXPORT extern "C" MYSQL_DLLEXPORT #else #define MYSQL_PLUGIN_EXPORT MYSQL_DLLEXPORT #endif #ifdef __cplusplus class THD; class Item; #define MYSQL_THD THD* #else struct THD; typedef struct THD* MYSQL_THD; #endif typedef char my_bool; typedef void * MYSQL_PLUGIN; #include #define MYSQL_XIDDATASIZE 128 /** struct st_mysql_xid is binary compatible with the XID structure as in the X/Open CAE Specification, Distributed Transaction Processing: The XA Specification, X/Open Company Ltd., 1991. http://www.opengroup.org/bookstore/catalog/c193.htm @see XID in sql/handler.h */ struct st_mysql_xid { long formatID; long gtrid_length; long bqual_length; char data[MYSQL_XIDDATASIZE]; /* Not \0-terminated */ }; typedef struct st_mysql_xid MYSQL_XID; /************************************************************************* Plugin API. Common for all plugin types. */ /* MySQL plugin interface version */ #define MYSQL_PLUGIN_INTERFACE_VERSION 0x0104 /* MariaDB plugin interface version */ #define MARIA_PLUGIN_INTERFACE_VERSION 0x010e /* The allowable types of plugins */ #define MYSQL_UDF_PLUGIN 0 /* not implemented */ #define MYSQL_STORAGE_ENGINE_PLUGIN 1 #define MYSQL_FTPARSER_PLUGIN 2 /* Full-text parser plugin */ #define MYSQL_DAEMON_PLUGIN 3 #define MYSQL_INFORMATION_SCHEMA_PLUGIN 4 #define MYSQL_AUDIT_PLUGIN 5 #define MYSQL_REPLICATION_PLUGIN 6 #define MYSQL_AUTHENTICATION_PLUGIN 7 #define MYSQL_MAX_PLUGIN_TYPE_NUM 12 /* The number of plugin types */ /* MariaDB plugin types */ #define MariaDB_PASSWORD_VALIDATION_PLUGIN 8 #define MariaDB_ENCRYPTION_PLUGIN 9 #define MariaDB_DATA_TYPE_PLUGIN 10 #define MariaDB_FUNCTION_PLUGIN 11 /* We use the following strings to define licenses for plugins */ #define PLUGIN_LICENSE_PROPRIETARY 0 #define PLUGIN_LICENSE_GPL 1 #define PLUGIN_LICENSE_BSD 2 #define PLUGIN_LICENSE_PROPRIETARY_STRING "PROPRIETARY" #define PLUGIN_LICENSE_GPL_STRING "GPL" #define PLUGIN_LICENSE_BSD_STRING "BSD" /* definitions of code maturity for plugins */ #define MariaDB_PLUGIN_MATURITY_UNKNOWN 0 #define MariaDB_PLUGIN_MATURITY_EXPERIMENTAL 1 #define MariaDB_PLUGIN_MATURITY_ALPHA 2 #define MariaDB_PLUGIN_MATURITY_BETA 3 #define MariaDB_PLUGIN_MATURITY_GAMMA 4 #define MariaDB_PLUGIN_MATURITY_STABLE 5 /* Macros for beginning and ending plugin declarations. Between mysql_declare_plugin and mysql_declare_plugin_end there should be a st_mysql_plugin struct for each plugin to be declared. */ #ifndef MYSQL_DYNAMIC_PLUGIN #define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ int VERSION= MYSQL_PLUGIN_INTERFACE_VERSION; \ int PSIZE= sizeof(struct st_mysql_plugin); \ struct st_mysql_plugin DECLS[]= { #define MARIA_DECLARE_PLUGIN__(NAME, VERSION, PSIZE, DECLS) \ MYSQL_PLUGIN_EXPORT int VERSION; \ int VERSION= MARIA_PLUGIN_INTERFACE_VERSION; \ MYSQL_PLUGIN_EXPORT int PSIZE; \ int PSIZE= sizeof(struct st_maria_plugin); \ MYSQL_PLUGIN_EXPORT struct st_maria_plugin DECLS[]; \ struct st_maria_plugin DECLS[]= { #else #define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ MYSQL_PLUGIN_EXPORT int _mysql_plugin_interface_version_; \ int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \ MYSQL_PLUGIN_EXPORT int _mysql_sizeof_struct_st_plugin_; \ int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin); \ MYSQL_PLUGIN_EXPORT struct st_mysql_plugin _mysql_plugin_declarations_[]; \ struct st_mysql_plugin _mysql_plugin_declarations_[]= { #define MARIA_DECLARE_PLUGIN__(NAME, VERSION, PSIZE, DECLS) \ MYSQL_PLUGIN_EXPORT int _maria_plugin_interface_version_; \ int _maria_plugin_interface_version_= MARIA_PLUGIN_INTERFACE_VERSION; \ MYSQL_PLUGIN_EXPORT int _maria_sizeof_struct_st_plugin_; \ int _maria_sizeof_struct_st_plugin_= sizeof(struct st_maria_plugin); \ MYSQL_PLUGIN_EXPORT struct st_maria_plugin _maria_plugin_declarations_[]; \ struct st_maria_plugin _maria_plugin_declarations_[]= { #endif #define mysql_declare_plugin(NAME) \ __MYSQL_DECLARE_PLUGIN(NAME, \ builtin_ ## NAME ## _plugin_interface_version, \ builtin_ ## NAME ## _sizeof_struct_st_plugin, \ builtin_ ## NAME ## _plugin) #define maria_declare_plugin(NAME) \ MARIA_DECLARE_PLUGIN__(NAME, \ builtin_maria_ ## NAME ## _plugin_interface_version, \ builtin_maria_ ## NAME ## _sizeof_struct_st_plugin, \ builtin_maria_ ## NAME ## _plugin) #define mysql_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0,0}} #define maria_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0,0}} /* declarations for SHOW STATUS support in plugins */ enum enum_mysql_show_type { SHOW_UNDEF, SHOW_BOOL, SHOW_UINT, SHOW_ULONG, SHOW_ULONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE, SHOW_SINT, SHOW_SLONG, SHOW_SLONGLONG, SHOW_SIMPLE_FUNC, SHOW_SIZE_T, SHOW_always_last }; /* backward compatibility mapping. */ #define SHOW_INT SHOW_UINT #define SHOW_LONG SHOW_ULONG #define SHOW_LONGLONG SHOW_ULONGLONG enum enum_var_type { SHOW_OPT_DEFAULT= 0, SHOW_OPT_SESSION, SHOW_OPT_GLOBAL }; struct st_mysql_show_var { const char *name; void *value; enum enum_mysql_show_type type; }; struct system_status_var; #define SHOW_VAR_FUNC_BUFF_SIZE (256 * sizeof(void*)) typedef int (*mysql_show_var_func)(MYSQL_THD, struct st_mysql_show_var*, void *, struct system_status_var *status_var, enum enum_var_type); static inline struct st_mysql_show_var SHOW_FUNC_ENTRY(const char *name, mysql_show_var_func func_arg) { struct st_mysql_show_var tmp; tmp.name= name; tmp.value= (void*) func_arg; tmp.type= SHOW_FUNC; return tmp; }; /* Constants for plugin flags. */ #define PLUGIN_OPT_NO_INSTALL 1UL /* Not dynamically loadable */ #define PLUGIN_OPT_NO_UNINSTALL 2UL /* Not dynamically unloadable */ /* declarations for server variables and command line options */ #define PLUGIN_VAR_BOOL 0x0001 #define PLUGIN_VAR_INT 0x0002 #define PLUGIN_VAR_LONG 0x0003 #define PLUGIN_VAR_LONGLONG 0x0004 #define PLUGIN_VAR_STR 0x0005 #define PLUGIN_VAR_ENUM 0x0006 #define PLUGIN_VAR_SET 0x0007 #define PLUGIN_VAR_DOUBLE 0x0008 #define PLUGIN_VAR_UNSIGNED 0x0080 #define PLUGIN_VAR_THDLOCAL 0x0100 /* Variable is per-connection */ #define PLUGIN_VAR_READONLY 0x0200 /* Server variable is read only */ #define PLUGIN_VAR_NOSYSVAR 0x0400 /* Not a server variable */ #define PLUGIN_VAR_NOCMDOPT 0x0800 /* Not a command line option */ #define PLUGIN_VAR_NOCMDARG 0x1000 /* No argument for cmd line */ #define PLUGIN_VAR_RQCMDARG 0x0000 /* Argument required for cmd line */ #define PLUGIN_VAR_OPCMDARG 0x2000 /* Argument optional for cmd line */ #define PLUGIN_VAR_DEPRECATED 0x4000 /* Server variable is deprecated */ #define PLUGIN_VAR_MEMALLOC 0x8000 /* String needs memory allocated */ struct st_mysql_sys_var; struct st_mysql_value; /* SYNOPSIS (*mysql_var_check_func)() thd thread handle var dynamic variable being altered save pointer to temporary storage value user provided value RETURN 0 user provided value is OK and the update func may be called. any other value indicates error. This function should parse the user provided value and store in the provided temporary storage any data as required by the update func. There is sufficient space in the temporary storage to store a double. Note that the update func may not be called if any other error occurs so any memory allocated should be thread-local so that it may be freed automatically at the end of the statement. */ typedef int (*mysql_var_check_func)(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save, struct st_mysql_value *value); /* SYNOPSIS (*mysql_var_update_func)() thd thread handle var dynamic variable being altered var_ptr pointer to dynamic variable save pointer to temporary storage RETURN NONE This function should use the validated value stored in the temporary store and persist it in the provided pointer to the dynamic variable. For example, strings may require memory to be allocated. */ typedef void (*mysql_var_update_func)(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save); /* the following declarations are for internal use only */ #define PLUGIN_VAR_MASK \ (PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR | \ PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_NOCMDARG | \ PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_RQCMDARG | \ PLUGIN_VAR_DEPRECATED | PLUGIN_VAR_MEMALLOC) #define MYSQL_PLUGIN_VAR_HEADER \ int flags; \ const char *name; \ const char *comment; \ mysql_var_check_func check; \ mysql_var_update_func update #define MYSQL_SYSVAR_NAME(name) mysql_sysvar_ ## name #define MYSQL_SYSVAR(name) \ ((struct st_mysql_sys_var *)&(MYSQL_SYSVAR_NAME(name))) /* for global variables, the value pointer is the first element after the header, the default value is the second. for thread variables, the value offset is the first element after the header, the default value is the second. */ #define DECLARE_MYSQL_SYSVAR_BASIC(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ type *value; \ const type def_val; \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_MYSQL_SYSVAR_CONST_BASIC(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ const type *value; \ const type def_val; \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_MYSQL_SYSVAR_SIMPLE(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ type *value; type def_val; \ type min_val; type max_val; \ type blk_sz; \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_MYSQL_SYSVAR_TYPELIB(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ type *value; type def_val; \ TYPELIB *typelib; \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_THDVAR_FUNC(type) \ type *(*resolve)(MYSQL_THD thd, int offset) #define DECLARE_MYSQL_THDVAR_BASIC(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ int offset; \ const type def_val; \ DECLARE_THDVAR_FUNC(type); \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_MYSQL_THDVAR_SIMPLE(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ int offset; \ type def_val; type min_val; \ type max_val; type blk_sz; \ DECLARE_THDVAR_FUNC(type); \ } MYSQL_SYSVAR_NAME(name) #define DECLARE_MYSQL_THDVAR_TYPELIB(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ int offset; \ const type def_val; \ DECLARE_THDVAR_FUNC(type); \ TYPELIB *typelib; \ } MYSQL_SYSVAR_NAME(name) /* the following declarations are for use by plugin implementors */ #define MYSQL_SYSVAR_BOOL(name, varname, opt, comment, check, update, def) \ DECLARE_MYSQL_SYSVAR_BASIC(name, char) = { \ PLUGIN_VAR_BOOL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def} #define MYSQL_SYSVAR_STR(name, varname, opt, comment, check, update, def) \ DECLARE_MYSQL_SYSVAR_BASIC(name, char *) = { \ PLUGIN_VAR_STR | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def} #define MYSQL_SYSVAR_CONST_STR(name, varname, opt, comment, check, update, def) \ DECLARE_MYSQL_SYSVAR_CONST_BASIC(name, char *) = { \ PLUGIN_VAR_STR | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def} #define MYSQL_SYSVAR_INT(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, int) = { \ PLUGIN_VAR_INT | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_UINT(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned int) = { \ PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_LONG(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, long) = { \ PLUGIN_VAR_LONG | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_ULONG(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned long) = { \ PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_LONGLONG(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, long long) = { \ PLUGIN_VAR_LONGLONG | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_ULONGLONG(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned long long) = { \ PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_SYSVAR_UINT64_T(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, uint64_t) = { \ PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #ifdef _WIN64 #define MYSQL_SYSVAR_SIZE_T(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, size_t) = { \ PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #else #define MYSQL_SYSVAR_SIZE_T(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, size_t) = { \ PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #endif #define MYSQL_SYSVAR_ENUM(name, varname, opt, comment, check, update, def, typelib) \ DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long) = { \ PLUGIN_VAR_ENUM | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, typelib } #define MYSQL_SYSVAR_SET(name, varname, opt, comment, check, update, def, typelib) \ DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long long) = { \ PLUGIN_VAR_SET | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, typelib } #define MYSQL_SYSVAR_DOUBLE(name, varname, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_SYSVAR_SIMPLE(name, double) = { \ PLUGIN_VAR_DOUBLE | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, min, max, blk } #define MYSQL_THDVAR_BOOL(name, opt, comment, check, update, def) \ DECLARE_MYSQL_THDVAR_BASIC(name, char) = { \ PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, NULL} #define MYSQL_THDVAR_STR(name, opt, comment, check, update, def) \ DECLARE_MYSQL_THDVAR_BASIC(name, char *) = { \ PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, NULL} #define MYSQL_THDVAR_INT(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, int) = { \ PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_UINT(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned int) = { \ PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_LONG(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, long) = { \ PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_ULONG(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned long) = { \ PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_LONGLONG(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, long long) = { \ PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_ULONGLONG(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned long long) = { \ PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } #define MYSQL_THDVAR_ENUM(name, opt, comment, check, update, def, typelib) \ DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long) = { \ PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, NULL, typelib } #define MYSQL_THDVAR_SET(name, opt, comment, check, update, def, typelib) \ DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long long) = { \ PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, NULL, typelib } #define MYSQL_THDVAR_DOUBLE(name, opt, comment, check, update, def, min, max, blk) \ DECLARE_MYSQL_THDVAR_SIMPLE(name, double) = { \ PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, min, max, blk, NULL } /* accessor macros */ #define SYSVAR(name) \ (*(MYSQL_SYSVAR_NAME(name).value)) /* when thd == null, result points to global value */ #define THDVAR(thd, name) \ (*(MYSQL_SYSVAR_NAME(name).resolve(thd, MYSQL_SYSVAR_NAME(name).offset))) /* Plugin description structure. */ struct st_mysql_plugin { int type; /* the plugin type (a MYSQL_XXX_PLUGIN value) */ void *info; /* pointer to type-specific plugin descriptor */ const char *name; /* plugin name */ const char *author; /* plugin author (for I_S.PLUGINS) */ const char *descr; /* general descriptive text (for I_S.PLUGINS) */ int license; /* the plugin license (PLUGIN_LICENSE_XXX) */ /* The function to invoke when plugin is loaded. Plugin initialisation done here should defer any ALTER TABLE queries to after the ddl recovery is done, in the signal_ddl_recovery_done() callback called by ha_signal_ddl_recovery_done(). */ int (*init)(void *); int (*deinit)(void *);/* the function to invoke when plugin is unloaded */ unsigned int version; /* plugin version (for I_S.PLUGINS) */ struct st_mysql_show_var *status_vars; struct st_mysql_sys_var **system_vars; void * __reserved1; /* reserved for dependency checking */ unsigned long flags; /* flags for plugin */ }; /* MariaDB extension for plugins declaration structure. It also copy current MySQL plugin fields to have more independency in plugins extension */ struct st_maria_plugin { int type; /* the plugin type (a MYSQL_XXX_PLUGIN value) */ void *info; /* pointer to type-specific plugin descriptor */ const char *name; /* plugin name */ const char *author; /* plugin author (for SHOW PLUGINS) */ const char *descr; /* general descriptive text (for SHOW PLUGINS ) */ int license; /* the plugin license (PLUGIN_LICENSE_XXX) */ /* The function to invoke when plugin is loaded. Plugin initialisation done here should defer any ALTER TABLE queries to after the ddl recovery is done, in the signal_ddl_recovery_done() callback called by ha_signal_ddl_recovery_done(). */ int (*init)(void *); int (*deinit)(void *);/* the function to invoke when plugin is unloaded */ unsigned int version; /* plugin version (for SHOW PLUGINS) */ struct st_mysql_show_var *status_vars; struct st_mysql_sys_var **system_vars; const char *version_info; /* plugin version string */ unsigned int maturity; /* MariaDB_PLUGIN_MATURITY_XXX */ }; /************************************************************************* API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) */ #include "plugin_ftparser.h" /************************************************************************* API for Storage Engine plugin. (MYSQL_DAEMON_PLUGIN) */ /* handlertons of different MySQL releases are incompatible */ #define MYSQL_DAEMON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) /* Here we define only the descriptor structure, that is referred from st_mysql_plugin. */ struct st_mysql_daemon { int interface_version; }; /************************************************************************* API for I_S plugin. (MYSQL_INFORMATION_SCHEMA_PLUGIN) */ /* handlertons of different MySQL releases are incompatible */ #define MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) /* Here we define only the descriptor structure, that is referred from st_mysql_plugin. */ struct st_mysql_information_schema { int interface_version; }; /************************************************************************* API for Storage Engine plugin. (MYSQL_STORAGE_ENGINE_PLUGIN) */ /* handlertons of different MySQL releases are incompatible */ #define MYSQL_HANDLERTON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) /* The real API is in the sql/handler.h Here we define only the descriptor structure, that is referred from st_mysql_plugin. */ struct st_mysql_storage_engine { int interface_version; }; struct handlerton; /* API for Replication plugin. (MYSQL_REPLICATION_PLUGIN) */ #define MYSQL_REPLICATION_INTERFACE_VERSION 0x0200 /** Replication plugin descriptor */ struct Mysql_replication { int interface_version; }; /************************************************************************* st_mysql_value struct for reading values from mysqld. Used by server variables framework to parse user-provided values. Will be used for arguments when implementing UDFs. Note that val_str() returns a string in temporary memory that will be freed at the end of statement. Copy the string if you need it to persist. */ #define MYSQL_VALUE_TYPE_STRING 0 #define MYSQL_VALUE_TYPE_REAL 1 #define MYSQL_VALUE_TYPE_INT 2 struct st_mysql_value { int (*value_type)(struct st_mysql_value *); const char *(*val_str)(struct st_mysql_value *, char *buffer, int *length); int (*val_real)(struct st_mysql_value *, double *realbuf); int (*val_int)(struct st_mysql_value *, long long *intbuf); int (*is_unsigned)(struct st_mysql_value *); }; /************************************************************************* Miscellaneous functions for plugin implementors */ #ifdef __cplusplus extern "C" { #endif int thd_in_lock_tables(const MYSQL_THD thd); int thd_tablespace_op(const MYSQL_THD thd); long long thd_test_options(const MYSQL_THD thd, long long test_options); int thd_sql_command(const MYSQL_THD thd); struct DDL_options_st; struct DDL_options_st *thd_ddl_options(const MYSQL_THD thd); void thd_storage_lock_wait(MYSQL_THD thd, long long value); int thd_tx_isolation(const MYSQL_THD thd); int thd_tx_is_read_only(const MYSQL_THD thd); /** Create a temporary file. @details The temporary file is created in a location specified by the mysql server configuration (--tmpdir option). The caller does not need to delete the file, it will be deleted automatically. @param prefix prefix for temporary file name @retval -1 error @retval >= 0 a file handle that can be passed to dup or my_close */ int mysql_tmpfile(const char *prefix); /** Return the thread id of a user thread @param thd user thread connection handle @return thread id */ unsigned long thd_get_thread_id(const MYSQL_THD thd); /** Get the XID for this connection's transaction @param thd user thread connection handle @param xid location where identifier is stored */ void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid); /** Invalidate the query cache for a given table. @param thd user thread connection handle @param key databasename\\0tablename\\0 @param key_length length of key in bytes, including the NUL bytes @param using_trx flag: TRUE if using transactions, FALSE otherwise */ void mysql_query_cache_invalidate4(MYSQL_THD thd, const char *key, unsigned int key_length, int using_trx); /** Provide a handler data getter to simplify coding */ void *thd_get_ha_data(const MYSQL_THD thd, const struct handlerton *hton); /** Provide a handler data setter to simplify coding @details Set ha_data pointer (storage engine per-connection information). To avoid unclean deactivation (uninstall) of storage engine plugin in the middle of transaction, additional storage engine plugin lock is acquired. If ha_data is not null and storage engine plugin was not locked by thd_set_ha_data() in this connection before, storage engine plugin gets locked. If ha_data is null and storage engine plugin was locked by thd_set_ha_data() in this connection before, storage engine plugin lock gets released. If handlerton::close_connection() didn't reset ha_data, server does it immediately after calling handlerton::close_connection(). */ void thd_set_ha_data(MYSQL_THD thd, const struct handlerton *hton, const void *ha_data); /** Signal that the first part of handler commit is finished, and that the committed transaction is now visible and has fixed commit ordering with respect to other transactions. The commit need _not_ be durable yet, and typically will not be when this call makes sense. This call is optional, if the storage engine does not call it the upper layer will after the handler commit() method is done. However, the storage engine may choose to call it itself to increase the possibility for group commit. In-order parallel replication uses this to apply different transaction in parallel, but delay the commits of later transactions until earlier transactions have committed first, thus achieving increased performance on multi-core systems while still preserving full transaction consistency. The storage engine can call this from within the commit() method, typically after the commit record has been written to the transaction log, but before the log has been fsync()'ed. This will allow the next replicated transaction to proceed to commit before the first one has done fsync() or similar. Thus, it becomes possible for multiple sequential replicated transactions to share a single fsync() inside the engine in group commit. Note that this method should _not_ be called from within the commit_ordered() method, or any other place in the storage engine. When commit_ordered() is used (typically when binlog is enabled), the transaction coordinator takes care of this and makes group commit in the storage engine possible without any other action needed on the part of the storage engine. This function thd_wakeup_subsequent_commits() is only needed when no transaction coordinator is used, meaning a single storage engine and no binary log. */ void thd_wakeup_subsequent_commits(MYSQL_THD thd, int wakeup_error); #ifdef __cplusplus } #endif #endif server/mysql/service_log_warnings.h000064400000002541151031265040013600 0ustar00/* Copyright (c) 2013, 2018, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SERVICE_LOG_WARNINGS #define MYSQL_SERVICE_LOG_WARNINGS /** @file This service provides access to the log warning level for the current session. thd_log_warnings(thd) @return thd->log_warnings */ #ifdef __cplusplus extern "C" { #endif extern struct thd_log_warnings_service_st { void *(*thd_log_warnings)(MYSQL_THD); } *thd_log_warnings_service; #ifdef MYSQL_DYNAMIC_PLUGIN # define thd_log_warnings(THD) thd_log_warnings_service->thd_log_warnings(THD) #else /** MDL_context accessor @param thd the current session @return pointer to thd->mdl_context */ int thd_log_warnings(MYSQL_THD thd); #endif #ifdef __cplusplus } #endif #endif server/mysql/service_thd_timezone.h000064400000004363151031265040013604 0ustar00#ifndef MYSQL_SERVICE_THD_TIMEZONE_INCLUDED /* Copyright (C) 2013 MariaDB Foundation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service provides functions to convert between my_time_t and MYSQL_TIME taking into account the current value of the time_zone session variable. The values of the my_time_t type are in Unix timestamp format, i.e. the number of seconds since "1970-01-01 00:00:00 UTC". The values of the MYSQL_TIME type are in the current time zone, according to thd->variables.time_zone. If the MYSQL_THD parameter is NULL, then global_system_variables.time_zone is used for conversion. */ #ifndef MYSQL_ABI_CHECK /* This service currently does not depend on any system headers. If it needs system headers in the future, make sure to put them inside this ifndef. */ #endif #include "mysql_time.h" #ifdef __cplusplus extern "C" { #endif extern struct thd_timezone_service_st { my_time_t (*thd_TIME_to_gmt_sec)(MYSQL_THD thd, const MYSQL_TIME *ltime, unsigned int *errcode); void (*thd_gmt_sec_to_TIME)(MYSQL_THD thd, MYSQL_TIME *ltime, my_time_t t); } *thd_timezone_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_TIME_to_gmt_sec(thd, ltime, errcode) \ (thd_timezone_service->thd_TIME_to_gmt_sec((thd), (ltime), (errcode))) #define thd_gmt_sec_to_TIME(thd, ltime, t) \ (thd_timezone_service->thd_gmt_sec_to_TIME((thd), (ltime), (t))) #else my_time_t thd_TIME_to_gmt_sec(MYSQL_THD thd, const MYSQL_TIME *ltime, unsigned int *errcode); void thd_gmt_sec_to_TIME(MYSQL_THD thd, MYSQL_TIME *ltime, my_time_t t); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_TIMEZONE_INCLUDED #endif server/mysql/service_md5.h000064400000004107151031265040011574 0ustar00#ifndef MYSQL_SERVICE_MD5_INCLUDED /* Copyright (c) 2014, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my md5 service Functions to calculate MD5 hash from a memory buffer */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #endif #define MY_MD5_HASH_SIZE 16 /* Hash size in bytes */ extern struct my_md5_service_st { void (*my_md5_type)(unsigned char*, const char*, size_t); void (*my_md5_multi_type)(unsigned char*, ...); size_t (*my_md5_context_size_type)(); void (*my_md5_init_type)(void *); void (*my_md5_input_type)(void *, const unsigned char *, size_t); void (*my_md5_result_type)(void *, unsigned char *); } *my_md5_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_md5(A,B,C) my_md5_service->my_md5_type(A,B,C) #define my_md5_multi my_md5_service->my_md5_multi_type #define my_md5_context_size() my_md5_service->my_md5_context_size_type() #define my_md5_init(A) my_md5_service->my_md5_init_type(A) #define my_md5_input(A,B,C) my_md5_service->my_md5_input_type(A,B,C) #define my_md5_result(A,B) my_md5_service->my_md5_result_type(A,B) #else void my_md5(unsigned char*, const char*, size_t); void my_md5_multi(unsigned char*, ...); size_t my_md5_context_size(); void my_md5_init(void *context); void my_md5_input(void *context, const unsigned char *buf, size_t len); void my_md5_result(void *context, unsigned char *digest); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_MD5_INCLUDED #endif server/mysql/service_wsrep.h000064400000033516151031265040012255 0ustar00#ifndef MYSQL_SERVICE_WSREP_INCLUDED #define MYSQL_SERVICE_WSREP_INCLUDED enum Wsrep_service_key_type { WSREP_SERVICE_KEY_SHARED, WSREP_SERVICE_KEY_REFERENCE, WSREP_SERVICE_KEY_UPDATE, WSREP_SERVICE_KEY_EXCLUSIVE }; #if (defined (MYSQL_DYNAMIC_PLUGIN) && defined(MYSQL_SERVICE_WSREP_DYNAMIC_INCLUDED)) || (!defined(MYSQL_DYNAMIC_PLUGIN) && defined(MYSQL_SERVICE_WSREP_STATIC_INCLUDED)) #else /* Copyright (c) 2015, 2020, MariaDB Corporation Ab 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file wsrep service Interface to WSREP functionality in the server. For engines that want to support galera. */ #include #ifdef __cplusplus #endif struct xid_t; struct wsrep_ws_handle; struct wsrep_buf; /* Must match to definition in sql/mysqld.h */ typedef int64 query_id_t; extern struct wsrep_service_st { my_bool (*get_wsrep_recovery_func)(); bool (*wsrep_consistency_check_func)(MYSQL_THD thd); int (*wsrep_is_wsrep_xid_func)(const void *xid); long long (*wsrep_xid_seqno_func)(const struct xid_t *xid); const unsigned char* (*wsrep_xid_uuid_func)(const struct xid_t *xid); my_bool (*wsrep_on_func)(const MYSQL_THD thd); bool (*wsrep_prepare_key_for_innodb_func)(MYSQL_THD thd, const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*); void (*wsrep_thd_LOCK_func)(const MYSQL_THD thd); int (*wsrep_thd_TRYLOCK_func)(const MYSQL_THD thd); void (*wsrep_thd_UNLOCK_func)(const MYSQL_THD thd); const char * (*wsrep_thd_query_func)(const MYSQL_THD thd); int (*wsrep_thd_retry_counter_func)(const MYSQL_THD thd); bool (*wsrep_thd_ignore_table_func)(MYSQL_THD thd); long long (*wsrep_thd_trx_seqno_func)(const MYSQL_THD thd); my_bool (*wsrep_thd_is_aborting_func)(const MYSQL_THD thd); void (*wsrep_set_data_home_dir_func)(const char *data_dir); my_bool (*wsrep_thd_is_BF_func)(const MYSQL_THD thd, my_bool sync); my_bool (*wsrep_thd_is_local_func)(const MYSQL_THD thd); void (*wsrep_thd_self_abort_func)(MYSQL_THD thd); int (*wsrep_thd_append_key_func)(MYSQL_THD thd, const struct wsrep_key* key, int n_keys, enum Wsrep_service_key_type); int (*wsrep_thd_append_table_key_func)(MYSQL_THD thd, const char* db, const char* table, enum Wsrep_service_key_type); my_bool (*wsrep_thd_is_local_transaction)(const MYSQL_THD thd); const char* (*wsrep_thd_client_state_str_func)(const MYSQL_THD thd); const char* (*wsrep_thd_client_mode_str_func)(const MYSQL_THD thd); const char* (*wsrep_thd_transaction_state_str_func)(const MYSQL_THD thd); query_id_t (*wsrep_thd_transaction_id_func)(const MYSQL_THD thd); my_bool (*wsrep_thd_bf_abort_func)(MYSQL_THD bf_thd, MYSQL_THD victim_thd, my_bool signal); my_bool (*wsrep_thd_order_before_func)(const MYSQL_THD left, const MYSQL_THD right); void (*wsrep_handle_SR_rollback_func)(MYSQL_THD BF_thd, MYSQL_THD victim_thd); my_bool (*wsrep_thd_skip_locking_func)(const MYSQL_THD thd); const char* (*wsrep_get_sr_table_name_func)(); my_bool (*wsrep_get_debug_func)(); void (*wsrep_commit_ordered_func)(MYSQL_THD thd); my_bool (*wsrep_thd_is_applying_func)(const MYSQL_THD thd); ulong (*wsrep_OSU_method_get_func)(const MYSQL_THD thd); my_bool (*wsrep_thd_has_ignored_error_func)(const MYSQL_THD thd); void (*wsrep_thd_set_ignored_error_func)(MYSQL_THD thd, my_bool val); void (*wsrep_report_bf_lock_wait_func)(const MYSQL_THD thd, unsigned long long trx_id); void (*wsrep_thd_kill_LOCK_func)(const MYSQL_THD thd); void (*wsrep_thd_kill_UNLOCK_func)(const MYSQL_THD thd); void (*wsrep_thd_set_wsrep_PA_unsafe_func)(MYSQL_THD thd); uint32 (*wsrep_get_domain_id_func)(); } *wsrep_service; #define MYSQL_SERVICE_WSREP_INCLUDED #endif #ifdef MYSQL_DYNAMIC_PLUGIN #define MYSQL_SERVICE_WSREP_DYNAMIC_INCLUDED #define get_wsrep_recovery() wsrep_service->get_wsrep_recovery_func() #define wsrep_consistency_check(T) wsrep_service->wsrep_consistency_check_func(T) #define wsrep_is_wsrep_xid(X) wsrep_service->wsrep_is_wsrep_xid_func(X) #define wsrep_xid_seqno(X) wsrep_service->wsrep_xid_seqno_func(X) #define wsrep_xid_uuid(X) wsrep_service->wsrep_xid_uuid_func(X) #define wsrep_on(thd) (thd) && WSREP_ON && wsrep_service->wsrep_on_func(thd) #define wsrep_prepare_key_for_innodb(A,B,C,D,E,F,G) wsrep_service->wsrep_prepare_key_for_innodb_func(A,B,C,D,E,F,G) #define wsrep_thd_LOCK(T) wsrep_service->wsrep_thd_LOCK_func(T) #define wsrep_thd_TRYLOCK(T) wsrep_service->wsrep_thd_TRYLOCK_func(T) #define wsrep_thd_UNLOCK(T) wsrep_service->wsrep_thd_UNLOCK_func(T) #define wsrep_thd_kill_LOCK(T) wsrep_service->wsrep_thd_kill_LOCK_func(T) #define wsrep_thd_kill_UNLOCK(T) wsrep_service->wsrep_thd_kill_UNLOCK_func(T) #define wsrep_thd_query(T) wsrep_service->wsrep_thd_query_func(T) #define wsrep_thd_retry_counter(T) wsrep_service->wsrep_thd_retry_counter_func(T) #define wsrep_thd_ignore_table(T) wsrep_service->wsrep_thd_ignore_table_func(T) #define wsrep_thd_trx_seqno(T) wsrep_service->wsrep_thd_trx_seqno_func(T) #define wsrep_set_data_home_dir(A) wsrep_service->wsrep_set_data_home_dir_func(A) #define wsrep_thd_is_BF(T,S) wsrep_service->wsrep_thd_is_BF_func(T,S) #define wsrep_thd_is_aborting(T) wsrep_service->wsrep_thd_is_aborting_func(T) #define wsrep_thd_is_local(T) wsrep_service->wsrep_thd_is_local_func(T) #define wsrep_thd_self_abort(T) wsrep_service->wsrep_thd_self_abort_func(T) #define wsrep_thd_append_key(T,W,N,K) wsrep_service->wsrep_thd_append_key_func(T,W,N,K) #define wsrep_thd_append_table_key(T,D,B,K) wsrep_service->wsrep_thd_append_table_key_func(T,D,B,K) #define wsrep_thd_is_local_transaction(T) wsrep_service->wsrep_thd_is_local_transaction_func(T) #define wsrep_thd_client_state_str(T) wsrep_service->wsrep_thd_client_state_str_func(T) #define wsrep_thd_client_mode_str(T) wsrep_service->wsrep_thd_client_mode_str_func(T) #define wsrep_thd_transaction_state_str(T) wsrep_service->wsrep_thd_transaction_state_str_func(T) #define wsrep_thd_transaction_id(T) wsrep_service->wsrep_thd_transaction_id_func(T) #define wsrep_thd_bf_abort(T,T2,S) wsrep_service->wsrep_thd_bf_abort_func(T,T2,S) #define wsrep_thd_order_before(L,R) wsrep_service->wsrep_thd_order_before_func(L,R) #define wsrep_handle_SR_rollback(B,V) wsrep_service->wsrep_handle_SR_rollback_func(B,V) #define wsrep_thd_skip_locking(T) wsrep_service->wsrep_thd_skip_locking_func(T) #define wsrep_get_sr_table_name() wsrep_service->wsrep_get_sr_table_name_func() #define wsrep_get_debug() wsrep_service->wsrep_get_debug_func() #define wsrep_commit_ordered(T) wsrep_service->wsrep_commit_ordered_func(T) #define wsrep_thd_is_applying(T) wsrep_service->wsrep_thd_is_applying_func(T) #define wsrep_OSU_method_get(T) wsrep_service->wsrep_OSU_method_get_func(T) #define wsrep_thd_has_ignored_error(T) wsrep_service->wsrep_thd_has_ignored_error_func(T) #define wsrep_thd_set_ignored_error(T,V) wsrep_service->wsrep_thd_set_ignored_error_func(T,V) #define wsrep_report_bf_lock_wait(T,I) wsrep_service->wsrep_report_bf_lock_wait(T,I) #define wsrep_thd_set_PA_unsafe(T) wsrep_service->wsrep_thd_set_PA_unsafe_func(T) #define wsrep_get_domain_id(T) wsrep_service->wsrep_get_domain_id_func(T) #else #define MYSQL_SERVICE_WSREP_STATIC_INCLUDED extern ulong wsrep_debug; extern my_bool wsrep_log_conflicts; extern my_bool wsrep_certify_nonPK; extern my_bool wsrep_load_data_splitting; extern my_bool wsrep_drupal_282555_workaround; extern my_bool wsrep_recovery; extern long wsrep_protocol_version; extern "C" bool wsrep_consistency_check(MYSQL_THD thd); bool wsrep_prepare_key_for_innodb(MYSQL_THD thd, const unsigned char* cache_key, size_t cache_key_len, const unsigned char* row_id, size_t row_id_len, struct wsrep_buf* key, size_t* key_len); extern "C" const char *wsrep_thd_query(const MYSQL_THD thd); extern "C" int wsrep_is_wsrep_xid(const void* xid); extern "C" long long wsrep_xid_seqno(const struct xid_t* xid); const unsigned char* wsrep_xid_uuid(const struct xid_t* xid); extern "C" long long wsrep_thd_trx_seqno(const MYSQL_THD thd); my_bool get_wsrep_recovery(); bool wsrep_thd_ignore_table(MYSQL_THD thd); void wsrep_set_data_home_dir(const char *data_dir); /* from mysql wsrep-lib */ #include "my_global.h" #include "my_pthread.h" /* Return true if wsrep is enabled for a thd. This means that wsrep is enabled globally and the thd has wsrep on */ extern "C" my_bool wsrep_on(const MYSQL_THD thd); /* Lock thd wsrep lock */ extern "C" void wsrep_thd_LOCK(const MYSQL_THD thd); /* Try thd wsrep lock. Return non-zero if lock could not be taken. */ extern "C" int wsrep_thd_TRYLOCK(const MYSQL_THD thd); /* Unlock thd wsrep lock */ extern "C" void wsrep_thd_UNLOCK(const MYSQL_THD thd); extern "C" void wsrep_thd_kill_LOCK(const MYSQL_THD thd); extern "C" void wsrep_thd_kill_UNLOCK(const MYSQL_THD thd); /* Return thd client state string */ extern "C" const char* wsrep_thd_client_state_str(const MYSQL_THD thd); /* Return thd client mode string */ extern "C" const char* wsrep_thd_client_mode_str(const MYSQL_THD thd); /* Return thd transaction state string */ extern "C" const char* wsrep_thd_transaction_state_str(const MYSQL_THD thd); /* Return current transaction id */ extern "C" query_id_t wsrep_thd_transaction_id(const MYSQL_THD thd); /* Mark thd own transaction as aborted */ extern "C" void wsrep_thd_self_abort(MYSQL_THD thd); /* Return true if thd is in replicating mode */ extern "C" my_bool wsrep_thd_is_local(const MYSQL_THD thd); /* Return true if thd is in high priority mode */ /* todo: rename to is_high_priority() */ extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd); /* Return true if thd is in TOI mode */ extern "C" my_bool wsrep_thd_is_toi(const MYSQL_THD thd); /* Return true if thd is in replicating TOI mode */ extern "C" my_bool wsrep_thd_is_local_toi(const MYSQL_THD thd); /* Return true if thd is in RSU mode */ extern "C" my_bool wsrep_thd_is_in_rsu(const MYSQL_THD thd); /* Return true if thd is in BF mode, either high_priority or TOI */ extern "C" my_bool wsrep_thd_is_BF(const MYSQL_THD thd, my_bool sync); /* Return true if thd is streaming in progress */ extern "C" my_bool wsrep_thd_is_SR(const MYSQL_THD thd); extern "C" void wsrep_handle_SR_rollback(MYSQL_THD BF_thd, MYSQL_THD victim_thd); /* Return thd retry counter */ extern "C" int wsrep_thd_retry_counter(const MYSQL_THD thd); /* BF abort victim_thd */ extern "C" my_bool wsrep_thd_bf_abort(MYSQL_THD bf_thd, MYSQL_THD victim_thd, my_bool signal); /* Return true if left thd is ordered before right thd */ extern "C" my_bool wsrep_thd_order_before(const MYSQL_THD left, const MYSQL_THD right); /* Return true if thd should skip locking. This means that the thd is operating on shared resource inside commit order critical section. */ extern "C" my_bool wsrep_thd_skip_locking(const MYSQL_THD thd); /* Return true if thd is aborting */ extern "C" my_bool wsrep_thd_is_aborting(const MYSQL_THD thd); struct wsrep_key; struct wsrep_key_array; extern "C" int wsrep_thd_append_key(MYSQL_THD thd, const struct wsrep_key* key, int n_keys, enum Wsrep_service_key_type); extern "C" int wsrep_thd_append_table_key(MYSQL_THD thd, const char* db, const char* table, enum Wsrep_service_key_type); extern "C" my_bool wsrep_thd_is_local_transaction(const MYSQL_THD thd); extern const char* wsrep_sr_table_name_full; extern "C" const char* wsrep_get_sr_table_name(); extern "C" my_bool wsrep_get_debug(); extern "C" void wsrep_commit_ordered(MYSQL_THD thd); extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd); extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd); extern "C" my_bool wsrep_thd_has_ignored_error(const MYSQL_THD thd); extern "C" void wsrep_thd_set_ignored_error(MYSQL_THD thd, my_bool val); extern "C" void wsrep_report_bf_lock_wait(const THD *thd, unsigned long long trx_id); /* declare parallel applying unsafety for the THD */ extern "C" void wsrep_thd_set_PA_unsafe(MYSQL_THD thd); extern "C" uint32 wsrep_get_domain_id(); #endif #endif /* MYSQL_SERVICE_WSREP_INCLUDED */ server/mysql/service_thd_rnd.h000064400000003556151031265040012540 0ustar00#ifndef MYSQL_SERVICE_THD_RND_INCLUDED /* Copyright (C) 2017 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service provides access to the thd-local random number generator. It's preferable over the global one, because concurrent threads can generate random numbers without fighting each other over the access to the shared rnd state. */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #endif extern struct thd_rnd_service_st { double (*thd_rnd_ptr)(MYSQL_THD thd); void (*thd_c_r_p_ptr)(MYSQL_THD thd, char *to, size_t length); } *thd_rnd_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_rnd(A) thd_rnd_service->thd_rnd_ptr(A) #define thd_create_random_password(A,B,C) thd_rnd_service->thd_c_r_p_ptr(A,B,C) #else double thd_rnd(MYSQL_THD thd); /** Generate string of printable random characters of requested length. @param to[out] Buffer for generation; must be at least length+1 bytes long; result string is always null-terminated @param length[in] How many random characters to put in buffer */ void thd_create_random_password(MYSQL_THD thd, char *to, size_t length); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_RND_INCLUDED #endif server/mysql/service_logger.h000064400000006737151031265040012401 0ustar00/* Copyright (C) 2012 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SERVICE_LOGGER_INCLUDED #define MYSQL_SERVICE_LOGGER_INCLUDED #ifndef MYSQL_ABI_CHECK #include #endif /** @file logger service Log file with rotation implementation. This service implements logging with possible rotation of the log files. Interface intentionally tries to be similar to FILE* related functions. So that one can open the log with logger_open(), specifying the limit on the logfile size and the rotations number. Then it's possible to write messages to the log with logger_printf or logger_vprintf functions. As the size of the logfile grows over the specified limit, it is renamed to 'logfile.1'. The former 'logfile.1' becomes 'logfile.2', etc. The file 'logfile.rotations' is removed. That's how the rotation works. The rotation can be forced with the logger_rotate() call. Finally the log should be closed with logger_close(). @notes: Implementation checks the size of the log file before it starts new printf into it. So the size of the file gets over the limit when it rotates. The access is secured with the mutex, so the log is threadsafe. */ #ifdef __cplusplus extern "C" { #endif typedef struct logger_handle_st LOGGER_HANDLE; extern struct logger_service_st { void (*logger_init_mutexes)(); LOGGER_HANDLE* (*open)(const char *path, unsigned long long size_limit, unsigned int rotations); int (*close)(LOGGER_HANDLE *log); int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr); int (*printf)(LOGGER_HANDLE *log, const char *fmt, ...); int (*write)(LOGGER_HANDLE *log, const char *buffer, size_t size); int (*rotate)(LOGGER_HANDLE *log); } *logger_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define logger_init_mutexes logger_service->logger_init_mutexes #define logger_open(path, size_limit, rotations) \ (logger_service->open(path, size_limit, rotations)) #define logger_close(log) (logger_service->close(log)) #define logger_rotate(log) (logger_service->rotate(log)) #define logger_vprintf(log, fmt, argptr) (logger_service->\ vprintf(log, fmt, argptr)) #define logger_printf (*logger_service->printf) #define logger_write(log, buffer, size) \ (logger_service->write(log, buffer, size)) #else void logger_init_mutexes(); LOGGER_HANDLE *logger_open(const char *path, unsigned long long size_limit, unsigned int rotations); int logger_close(LOGGER_HANDLE *log); int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list argptr); int logger_printf(LOGGER_HANDLE *log, const char *fmt, ...); int logger_write(LOGGER_HANDLE *log, const char *buffer, size_t size); int logger_rotate(LOGGER_HANDLE *log); #endif #ifdef __cplusplus } #endif #endif /*MYSQL_SERVICE_LOGGER_INCLUDED*/ server/mysql/plugin_ftparser.h000064400000017230151031265040012574 0ustar00/* Copyright (c) 2005 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_plugin_ftparser_h #define _my_plugin_ftparser_h #include "plugin.h" #ifdef __cplusplus extern "C" { #endif /************************************************************************* API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) */ #define MYSQL_FTPARSER_INTERFACE_VERSION 0x0100 /* Parsing modes. Set in MYSQL_FTPARSER_PARAM::mode */ enum enum_ftparser_mode { /* Fast and simple mode. This mode is used for indexing, and natural language queries. The parser is expected to return only those words that go into the index. Stopwords or too short/long words should not be returned. The 'boolean_info' argument of mysql_add_word() does not have to be set. */ MYSQL_FTPARSER_SIMPLE_MODE= 0, /* Parse with stopwords mode. This mode is used in boolean searches for "phrase matching." The parser is not allowed to ignore words in this mode. Every word should be returned, including stopwords and words that are too short or long. The 'boolean_info' argument of mysql_add_word() does not have to be set. */ MYSQL_FTPARSER_WITH_STOPWORDS= 1, /* Parse in boolean mode. This mode is used to parse a boolean query string. The parser should provide a valid MYSQL_FTPARSER_BOOLEAN_INFO structure in the 'boolean_info' argument to mysql_add_word(). Usually that means that the parser should recognize boolean operators in the parsing stream and set appropriate fields in MYSQL_FTPARSER_BOOLEAN_INFO structure accordingly. As for MYSQL_FTPARSER_WITH_STOPWORDS mode, no word should be ignored. Instead, use FT_TOKEN_STOPWORD for the token type of such a word. */ MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2 }; /* Token types for boolean mode searching (used for the type member of MYSQL_FTPARSER_BOOLEAN_INFO struct) FT_TOKEN_EOF: End of data. FT_TOKEN_WORD: Regular word. FT_TOKEN_LEFT_PAREN: Left parenthesis (start of group/sub-expression). FT_TOKEN_RIGHT_PAREN: Right parenthesis (end of group/sub-expression). FT_TOKEN_STOPWORD: Stopword. */ enum enum_ft_token_type { FT_TOKEN_EOF= 0, FT_TOKEN_WORD= 1, FT_TOKEN_LEFT_PAREN= 2, FT_TOKEN_RIGHT_PAREN= 3, FT_TOKEN_STOPWORD= 4 }; /* This structure is used in boolean search mode only. It conveys boolean-mode metadata to the MySQL search engine for every word in the search query. A valid instance of this structure must be filled in by the plugin parser and passed as an argument in the call to mysql_add_word (the callback function in the MYSQL_FTPARSER_PARAM structure) when a query is parsed in boolean mode. type: The token type. Should be one of the enum_ft_token_type values. yesno: Whether the word must be present for a match to occur: >0 Must be present <0 Must not be present 0 Neither; the word is optional but its presence increases the relevance With the default settings of the ft_boolean_syntax system variable, >0 corresponds to the '+' operator, <0 corresponds to the '-' operator, and 0 means neither operator was used. weight_adjust: A weighting factor that determines how much a match for the word counts. Positive values increase, negative - decrease the relative word's importance in the query. wasign: The sign of the word's weight in the query. If it's non-negative the match for the word will increase document relevance, if it's negative - decrease (the word becomes a "noise word", the less of it the better). trunc: Corresponds to the '*' operator in the default setting of the ft_boolean_syntax system variable. */ typedef struct st_mysql_ftparser_boolean_info { enum enum_ft_token_type type; int yesno; int weight_adjust; char wasign; char trunc; /* These are parser state and must be removed. */ char prev; char *quot; } MYSQL_FTPARSER_BOOLEAN_INFO; /* The following flag means that buffer with a string (document, word) may be overwritten by the caller before the end of the parsing (that is before st_mysql_ftparser::deinit() call). If one needs the string to survive between two successive calls of the parsing function, she needs to save a copy of it. The flag may be set by MySQL before calling st_mysql_ftparser::parse(), or it may be set by a plugin before calling st_mysql_ftparser_param::mysql_parse() or st_mysql_ftparser_param::mysql_add_word(). */ #define MYSQL_FTFLAGS_NEED_COPY 1 /* An argument of the full-text parser plugin. This structure is filled in by MySQL server and passed to the parsing function of the plugin as an in/out parameter. mysql_parse: A pointer to the built-in parser implementation of the server. It's set by the server and can be used by the parser plugin to invoke the MySQL default parser. If plugin's role is to extract textual data from .doc, .pdf or .xml content, it might extract plaintext from the content, and then pass the text to the default MySQL parser to be parsed. mysql_add_word: A server callback to add a new word. When parsing a document, the server sets this to point at a function that adds the word to MySQL full-text index. When parsing a search query, this function will add the new word to the list of words to search for. The boolean_info argument can be NULL for all cases except when mode is MYSQL_FTPARSER_FULL_BOOLEAN_INFO. A plugin can replace this callback to post-process every parsed word before passing it to the original mysql_add_word function. ftparser_state: A generic pointer. The plugin can set it to point to information to be used internally for its own purposes. mysql_ftparam: This is set by the server. It is used by MySQL functions called via mysql_parse() and mysql_add_word() callback. The plugin should not modify it. cs: Information about the character set of the document or query string. doc: A pointer to the document or query string to be parsed. length: Length of the document or query string, in bytes. flags: See MYSQL_FTFLAGS_* constants above. mode: The parsing mode. With boolean operators, with stopwords, or nothing. See enum_ftparser_mode above. */ typedef struct st_mysql_ftparser_param { int (*mysql_parse)(struct st_mysql_ftparser_param *, const char *doc, int doc_len); int (*mysql_add_word)(struct st_mysql_ftparser_param *, const char *word, int word_len, MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info); void *ftparser_state; void *mysql_ftparam; const struct charset_info_st *cs; const char *doc; int length; unsigned int flags; enum enum_ftparser_mode mode; } MYSQL_FTPARSER_PARAM; /* Full-text parser descriptor. interface_version is, e.g., MYSQL_FTPARSER_INTERFACE_VERSION. The parsing, initialization, and deinitialization functions are invoked per SQL statement for which the parser is used. */ struct st_mysql_ftparser { int interface_version; int (*parse)(MYSQL_FTPARSER_PARAM *param); int (*init)(MYSQL_FTPARSER_PARAM *param); int (*deinit)(MYSQL_FTPARSER_PARAM *param); }; #ifdef __cplusplus } #endif #endif server/mysql/service_sql.h000064400000012016151031265040011704 0ustar00/* Copyright (C) 2021 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #ifndef MYSQL_SERVICE_SQL #define MYSQL_SERVICE_SQL #ifndef MYSQL_ABI_CHECK #include #endif /** @file SQL service Interface for plugins to execute SQL queries on the local server. Functions of the service are the 'server-limited' client library: mysql_init mysql_real_connect_local mysql_real_connect mysql_errno mysql_error mysql_real_query mysql_affected_rows mysql_num_rows mysql_store_result mysql_free_result mysql_fetch_row mysql_close */ #ifdef __cplusplus extern "C" { #endif extern struct sql_service_st { MYSQL *(STDCALL *mysql_init_func)(MYSQL *mysql); MYSQL *(*mysql_real_connect_local_func)(MYSQL *mysql); MYSQL *(STDCALL *mysql_real_connect_func)(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); unsigned int(STDCALL *mysql_errno_func)(MYSQL *mysql); const char *(STDCALL *mysql_error_func)(MYSQL *mysql); int (STDCALL *mysql_real_query_func)(MYSQL *mysql, const char *q, unsigned long length); my_ulonglong (STDCALL *mysql_affected_rows_func)(MYSQL *mysql); my_ulonglong (STDCALL *mysql_num_rows_func)(MYSQL_RES *res); MYSQL_RES *(STDCALL *mysql_store_result_func)(MYSQL *mysql); void (STDCALL *mysql_free_result_func)(MYSQL_RES *result); MYSQL_ROW (STDCALL *mysql_fetch_row_func)(MYSQL_RES *result); void (STDCALL *mysql_close_func)(MYSQL *mysql); int (STDCALL *mysql_options_func)(MYSQL *mysql, enum mysql_option option, const void *arg); unsigned long *(STDCALL *mysql_fetch_lengths_func)(MYSQL_RES *res); int (STDCALL *mysql_set_character_set_func)(MYSQL *mysql, const char *cs_name); unsigned int (STDCALL *mysql_num_fields_func)(MYSQL_RES *res); int (STDCALL *mysql_select_db_func)(MYSQL *mysql, const char *db); MYSQL_RES *(STDCALL *mysql_use_result_func)(MYSQL *mysql); MYSQL_FIELD *(STDCALL *mysql_fetch_fields_func)(MYSQL_RES *res); unsigned long (STDCALL *mysql_real_escape_string_func)(MYSQL *mysql, char *to, const char *from, unsigned long length); my_bool (STDCALL *mysql_ssl_set_func)(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); } *sql_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define mysql_init(M) sql_service->mysql_init_func(M) #define mysql_real_connect_local(M) sql_service->mysql_real_connect_local_func(M) #define mysql_real_connect(M,H,U,PW,D,P,S,F) sql_service->mysql_real_connect_func(M,H,U,PW,D,P,S,F) #define mysql_errno(M) sql_service->mysql_errno_func(M) #define mysql_error(M) sql_service->mysql_error_func(M) #define mysql_real_query sql_service->mysql_real_query_func #define mysql_affected_rows(M) sql_service->mysql_affected_rows_func(M) #define mysql_num_rows(R) sql_service->mysql_num_rows_func(R) #define mysql_store_result(M) sql_service->mysql_store_result_func(M) #define mysql_free_result(R) sql_service->mysql_free_result_func(R) #define mysql_fetch_row(R) sql_service->mysql_fetch_row_func(R) #define mysql_close(M) sql_service->mysql_close_func(M) #define mysql_options(M,O,V) sql_service->mysql_options_func(M,O,V) #define mysql_fetch_lengths(R) sql_service->mysql_fetch_lengths_func(R) #define mysql_set_character_set(M,C) sql_service->mysql_set_character_set_func(M,C) #define mysql_num_fields(R) sql_service->mysql_num_fields_func(R) #define mysql_select_db(M,D) sql_service->mysql_select_db_func(M,D) #define mysql_use_result(M) sql_service->mysql_use_result_func(M) #define mysql_fetch_fields(R) sql_service->mysql_fetch_fields_func(R) #define mysql_real_escape_string(M,T,F,L) sql_service->mysql_real_escape_string_func(M,T,F,L) #define mysql_ssl_set(M,K,C1,C2,C3,C4) sql_service->mysql_ssl_set_func(M,K,C1,C2,C3,C4) #else /* Establishes the connection to the 'local' server that started the plugin. Like the mysql_real_connect() does for the remote server. The established connection has no user/host associated to it, neither it has the current db, so the queries should have database/table name specified. */ MYSQL *mysql_real_connect_local(MYSQL *mysql); /* The rest of the function declarations must be taken from the mysql.h */ #endif /*MYSQL_DYNAMIC_PLUGIN*/ #ifdef __cplusplus } #endif #endif /*MYSQL_SERVICE_SQL */ server/mysql/service_my_print_error.h000064400000004430151031265040014160 0ustar00/* Copyright (c) 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SERVICE_MY_PRINT_ERROR_INCLUDED #define MYSQL_SERVICE_MY_PRINT_ERROR_INCLUDED /** @file include/mysql/service_my_print_error.h This service provides functions for plugins to report errors to client (without client, the errors are written to the error log). */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #include #endif #define ME_ERROR_LOG 64 /* Write the message to the error log */ #define ME_ERROR_LOG_ONLY 128 /* Write the error message to error log only */ #define ME_NOTE 1024 /* Not an error, just a note */ #define ME_WARNING 2048 /* Not an error, just a warning */ #define ME_FATAL 4096 /* Fatal statement error */ extern struct my_print_error_service_st { void (*my_error_func)(unsigned int nr, unsigned long MyFlags, ...); void (*my_printf_error_func)(unsigned int nr, const char *fmt, unsigned long MyFlags,...); void (*my_printv_error_func)(unsigned int error, const char *format, unsigned long MyFlags, va_list ap); } *my_print_error_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_error my_print_error_service->my_error_func #define my_printf_error my_print_error_service->my_printf_error_func #define my_printv_error(A,B,C,D) my_print_error_service->my_printv_error_func(A,B,C,D) #else extern void my_error(unsigned int nr, unsigned long MyFlags, ...); extern void my_printf_error(unsigned int my_err, const char *format, unsigned long MyFlags, ...); extern void my_printv_error(unsigned int error, const char *format, unsigned long MyFlags,va_list ap); #endif /* MYSQL_DYNAMIC_PLUGIN */ #ifdef __cplusplus } #endif #endif server/mysql/services.h000064400000003342151031265040011212 0ustar00#ifndef MYSQL_SERVICES_INCLUDED /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. Copyright (c) 2012, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*#include */ #include #ifdef __cplusplus } #endif #define MYSQL_SERVICES_INCLUDED #endif server/mysql/service_thd_mdl.h000064400000002402151031265040012516 0ustar00/* Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #pragma once /** @file include/mysql/service_thd_mdl.h This service provides functions for plugins and storage engines to access metadata locks. */ #ifdef __cplusplus extern "C" { #endif extern struct thd_mdl_service_st { void *(*thd_mdl_context)(MYSQL_THD); } *thd_mdl_service; #ifdef MYSQL_DYNAMIC_PLUGIN # define thd_mdl_context(_THD) thd_mdl_service->thd_mdl_context(_THD) #else /** MDL_context accessor @param thd the current session @return pointer to thd->mdl_context */ void *thd_mdl_context(MYSQL_THD thd); #endif #ifdef __cplusplus } #endif server/mysql/psi/mysql_socket.h000064400000106615151031265040012706 0ustar00/* Copyright (c) 2010, 2023, Oracle and/or its affiliates. Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_SOCKET_H #define MYSQL_SOCKET_H /* For MY_STAT */ #include /* For my_chsize */ #include /* For socket api */ #ifdef _WIN32 #include #include #include #define SOCKBUF_T char #else #include #define SOCKBUF_T void #endif /** @file mysql/psi/mysql_socket.h [...] */ #include "mysql/psi/psi.h" #ifndef PSI_SOCKET_CALL #define PSI_SOCKET_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Socket_instrumentation Socket Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_socket_register(P1, P2, P3) Socket registration. */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_register(P1, P2, P3) \ inline_mysql_socket_register(P1, P2, P3) #else #define mysql_socket_register(P1, P2, P3) \ do {} while (0) #endif /** An instrumented socket. */ struct st_mysql_socket { /** The real socket descriptor. */ my_socket fd; /** Is this a Unix-domain socket? */ char is_unix_domain_socket; /** Is this a socket opened for the extra port? */ char is_extra_port; /** Address family of the socket. (See sa_family from struct sockaddr). */ unsigned short address_family; /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c MYSQL_SOCKET interface. */ struct PSI_socket *m_psi; }; /** An instrumented socket. @c MYSQL_SOCKET is a replacement for @c my_socket. */ typedef struct st_mysql_socket MYSQL_SOCKET; /** @def MYSQL_INVALID_SOCKET MYSQL_SOCKET initial value. */ //MYSQL_SOCKET MYSQL_INVALID_SOCKET= {INVALID_SOCKET, NULL}; #define MYSQL_INVALID_SOCKET mysql_socket_invalid() /** MYSQL_SOCKET helper. Initialize instrumented socket. @sa mysql_socket_getfd @sa mysql_socket_setfd */ static inline MYSQL_SOCKET mysql_socket_invalid() { MYSQL_SOCKET mysql_socket= {INVALID_SOCKET, 0, 0, 0, NULL}; return mysql_socket; } /** Set socket descriptor and address. @param socket nstrumented socket @param addr unformatted socket address @param addr_len length of socket address */ static inline void mysql_socket_set_address( #ifdef HAVE_PSI_SOCKET_INTERFACE MYSQL_SOCKET socket, const struct sockaddr *addr, socklen_t addr_len #else MYSQL_SOCKET socket __attribute__ ((unused)), const struct sockaddr *addr __attribute__ ((unused)), socklen_t addr_len __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_SOCKET_INTERFACE if (socket.m_psi != NULL) PSI_SOCKET_CALL(set_socket_info)(socket.m_psi, NULL, addr, addr_len); #endif } /** Set socket descriptor and address. @param socket instrumented socket */ static inline void mysql_socket_set_thread_owner( #ifdef HAVE_PSI_SOCKET_INTERFACE MYSQL_SOCKET socket #else MYSQL_SOCKET socket __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_SOCKET_INTERFACE if (socket.m_psi != NULL) PSI_SOCKET_CALL(set_socket_thread_owner)(socket.m_psi); #endif } /** MYSQL_SOCKET helper. Get socket descriptor. @param mysql_socket Instrumented socket @sa mysql_socket_getfd */ static inline my_socket mysql_socket_getfd(MYSQL_SOCKET mysql_socket) { return mysql_socket.fd; } /** MYSQL_SOCKET helper. Set socket descriptor. @param mysql_socket Instrumented socket @param fd Socket descriptor @sa mysql_socket_setfd */ static inline void mysql_socket_setfd(MYSQL_SOCKET *mysql_socket, my_socket fd) { if (likely(mysql_socket != NULL)) mysql_socket->fd= fd; } /** @def MYSQL_SOCKET_WAIT_VARIABLES Instrumentation helper for socket waits. This instrumentation declares local variables. Do not use a ';' after this macro @param LOCKER locker @param STATE locker state @sa MYSQL_START_SOCKET_WAIT. @sa MYSQL_END_SOCKET_WAIT. */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define MYSQL_SOCKET_WAIT_VARIABLES(LOCKER, STATE) \ struct PSI_socket_locker* LOCKER; \ PSI_socket_locker_state STATE; #else #define MYSQL_SOCKET_WAIT_VARIABLES(LOCKER, STATE) #endif /** @def MYSQL_START_SOCKET_WAIT Instrumentation helper for socket waits. This instrumentation marks the start of a wait event. @param LOCKER locker @param STATE locker state @param SOCKET instrumented socket @param OP The socket operation to be performed @param COUNT bytes to be written/read @sa MYSQL_END_SOCKET_WAIT. */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define MYSQL_START_SOCKET_WAIT(LOCKER, STATE, SOCKET, OP, COUNT) \ LOCKER= inline_mysql_start_socket_wait(STATE, SOCKET, OP, COUNT,\ __FILE__, __LINE__) #else #define MYSQL_START_SOCKET_WAIT(LOCKER, STATE, SOCKET, OP, COUNT) \ do {} while (0) #endif /** @def MYSQL_END_SOCKET_WAIT Instrumentation helper for socket waits. This instrumentation marks the end of a wait event. @param LOCKER locker @param COUNT actual bytes written/read, or -1 @sa MYSQL_START_SOCKET_WAIT. */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define MYSQL_END_SOCKET_WAIT(LOCKER, COUNT) \ inline_mysql_end_socket_wait(LOCKER, COUNT) #else #define MYSQL_END_SOCKET_WAIT(LOCKER, COUNT) \ do {} while (0) #endif /** @def MYSQL_SOCKET_SET_STATE Set the state (IDLE, ACTIVE) of an instrumented socket. @param SOCKET the instrumented socket @param STATE the new state @sa PSI_socket_state */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define MYSQL_SOCKET_SET_STATE(SOCKET, STATE) \ inline_mysql_socket_set_state(SOCKET, STATE) #else #define MYSQL_SOCKET_SET_STATE(SOCKET, STATE) \ do {} while (0) #endif #ifdef HAVE_PSI_SOCKET_INTERFACE /** Instrumentation calls for MYSQL_START_SOCKET_WAIT. @sa MYSQL_START_SOCKET_WAIT. */ static inline struct PSI_socket_locker* inline_mysql_start_socket_wait(PSI_socket_locker_state *state, MYSQL_SOCKET mysql_socket, enum PSI_socket_operation op, size_t byte_count, const char *src_file, uint src_line) { struct PSI_socket_locker *locker; if (psi_likely(mysql_socket.m_psi != NULL)) { locker= PSI_SOCKET_CALL(start_socket_wait) (state, mysql_socket.m_psi, op, byte_count, src_file, src_line); } else locker= NULL; return locker; } /** Instrumentation calls for MYSQL_END_SOCKET_WAIT. @sa MYSQL_END_SOCKET_WAIT. */ static inline void inline_mysql_end_socket_wait(struct PSI_socket_locker *locker, size_t byte_count) { if (psi_likely(locker != NULL)) PSI_SOCKET_CALL(end_socket_wait)(locker, byte_count); } /** Set the state (IDLE, ACTIVE) of an instrumented socket. @param socket the instrumented socket @param state the new state @sa PSI_socket_state */ static inline void inline_mysql_socket_set_state(MYSQL_SOCKET socket, enum PSI_socket_state state) { if (socket.m_psi != NULL) PSI_SOCKET_CALL(set_socket_state)(socket.m_psi, state); } #endif /* HAVE_PSI_SOCKET_INTERFACE */ /** @def mysql_socket_fd(K, F) Create a socket. @c mysql_socket_fd is a replacement for @c socket. @param K PSI_socket_key for this instrumented socket @param F File descriptor */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_fd(K, F) \ inline_mysql_socket_fd(K, F) #else #define mysql_socket_fd(K, F) \ inline_mysql_socket_fd(F) #endif /** @def mysql_socket_socket(K, D, T, P) Create a socket. @c mysql_socket_socket is a replacement for @c socket. @param K PSI_socket_key for this instrumented socket @param D Socket domain @param T Protocol type @param P Transport protocol */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_socket(K, D, T, P) \ inline_mysql_socket_socket(K, D, T, P) #else #define mysql_socket_socket(K, D, T, P) \ inline_mysql_socket_socket(D, T, P) #endif /** @def mysql_socket_bind(FD, AP, L) Bind a socket to a local port number and IP address @c mysql_socket_bind is a replacement for @c bind. @param FD Instrumented socket descriptor returned by socket() @param AP Pointer to local port number and IP address in sockaddr structure @param L Length of sockaddr structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_bind(FD, AP, L) \ inline_mysql_socket_bind(__FILE__, __LINE__, FD, AP, L) #else #define mysql_socket_bind(FD, AP, L) \ inline_mysql_socket_bind(FD, AP, L) #endif /** @def mysql_socket_getsockname(FD, AP, LP) Return port number and IP address of the local host @c mysql_socket_getsockname is a replacement for @c getsockname. @param FD Instrumented socket descriptor returned by socket() @param AP Pointer to returned address of local host in @c sockaddr structure @param LP Pointer to length of @c sockaddr structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_getsockname(FD, AP, LP) \ inline_mysql_socket_getsockname(__FILE__, __LINE__, FD, AP, LP) #else #define mysql_socket_getsockname(FD, AP, LP) \ inline_mysql_socket_getsockname(FD, AP, LP) #endif /** @def mysql_socket_connect(FD, AP, L) Establish a connection to a remote host. @c mysql_socket_connect is a replacement for @c connect. @param FD Instrumented socket descriptor returned by socket() @param AP Pointer to target address in sockaddr structure @param L Length of sockaddr structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_connect(FD, AP, L) \ inline_mysql_socket_connect(__FILE__, __LINE__, FD, AP, L) #else #define mysql_socket_connect(FD, AP, L) \ inline_mysql_socket_connect(FD, AP, L) #endif /** @def mysql_socket_getpeername(FD, AP, LP) Get port number and IP address of remote host that a socket is connected to. @c mysql_socket_getpeername is a replacement for @c getpeername. @param FD Instrumented socket descriptor returned by socket() or accept() @param AP Pointer to returned address of remote host in sockaddr structure @param LP Pointer to length of sockaddr structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_getpeername(FD, AP, LP) \ inline_mysql_socket_getpeername(__FILE__, __LINE__, FD, AP, LP) #else #define mysql_socket_getpeername(FD, AP, LP) \ inline_mysql_socket_getpeername(FD, AP, LP) #endif /** @def mysql_socket_send(FD, B, N, FL) Send data from the buffer, B, to a connected socket. @c mysql_socket_send is a replacement for @c send. @param FD Instrumented socket descriptor returned by socket() or accept() @param B Buffer to send @param N Number of bytes to send @param FL Control flags */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_send(FD, B, N, FL) \ inline_mysql_socket_send(__FILE__, __LINE__, FD, B, N, FL) #else #define mysql_socket_send(FD, B, N, FL) \ inline_mysql_socket_send(FD, B, N, FL) #endif /** @def mysql_socket_recv(FD, B, N, FL) Receive data from a connected socket. @c mysql_socket_recv is a replacement for @c recv. @param FD Instrumented socket descriptor returned by socket() or accept() @param B Buffer to receive to @param N Maximum bytes to receive @param FL Control flags */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_recv(FD, B, N, FL) \ inline_mysql_socket_recv(__FILE__, __LINE__, FD, B, N, FL) #else #define mysql_socket_recv(FD, B, N, FL) \ inline_mysql_socket_recv(FD, B, N, FL) #endif /** @def mysql_socket_sendto(FD, B, N, FL, AP, L) Send data to a socket at the specified address. @c mysql_socket_sendto is a replacement for @c sendto. @param FD Instrumented socket descriptor returned by socket() @param B Buffer to send @param N Number of bytes to send @param FL Control flags @param AP Pointer to destination sockaddr structure @param L Size of sockaddr structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_sendto(FD, B, N, FL, AP, L) \ inline_mysql_socket_sendto(__FILE__, __LINE__, FD, B, N, FL, AP, L) #else #define mysql_socket_sendto(FD, B, N, FL, AP, L) \ inline_mysql_socket_sendto(FD, B, N, FL, AP, L) #endif /** @def mysql_socket_recvfrom(FD, B, N, FL, AP, L) Receive data from a socket and return source address information @c mysql_socket_recvfrom is a replacement for @c recvfrom. @param FD Instrumented socket descriptor returned by socket() @param B Buffer to receive to @param N Maximum bytes to receive @param FL Control flags @param AP Pointer to source address in sockaddr_storage structure @param LP Size of sockaddr_storage structure */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_recvfrom(FD, B, N, FL, AP, LP) \ inline_mysql_socket_recvfrom(__FILE__, __LINE__, FD, B, N, FL, AP, LP) #else #define mysql_socket_recvfrom(FD, B, N, FL, AP, LP) \ inline_mysql_socket_recvfrom(FD, B, N, FL, AP, LP) #endif /** @def mysql_socket_getsockopt(FD, LV, ON, OP, OL) Get a socket option for the specified socket. @c mysql_socket_getsockopt is a replacement for @c getsockopt. @param FD Instrumented socket descriptor returned by socket() @param LV Protocol level @param ON Option to query @param OP Buffer which will contain the value for the requested option @param OL Pointer to length of OP */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_getsockopt(FD, LV, ON, OP, OL) \ inline_mysql_socket_getsockopt(__FILE__, __LINE__, FD, LV, ON, OP, OL) #else #define mysql_socket_getsockopt(FD, LV, ON, OP, OL) \ inline_mysql_socket_getsockopt(FD, LV, ON, OP, OL) #endif /** @def mysql_socket_setsockopt(FD, LV, ON, OP, OL) Set a socket option for the specified socket. @c mysql_socket_setsockopt is a replacement for @c setsockopt. @param FD Instrumented socket descriptor returned by socket() @param LV Protocol level @param ON Option to modify @param OP Buffer containing the value for the specified option @param OL Pointer to length of OP */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_setsockopt(FD, LV, ON, OP, OL) \ inline_mysql_socket_setsockopt(__FILE__, __LINE__, FD, LV, ON, OP, OL) #else #define mysql_socket_setsockopt(FD, LV, ON, OP, OL) \ inline_mysql_socket_setsockopt(FD, LV, ON, OP, OL) #endif /** @def mysql_sock_set_nonblocking Set socket to non-blocking. @param FD instrumented socket descriptor */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_sock_set_nonblocking(FD) \ inline_mysql_sock_set_nonblocking(__FILE__, __LINE__, FD) #else #define mysql_sock_set_nonblocking(FD) \ inline_mysql_sock_set_nonblocking(FD) #endif /** @def mysql_socket_listen(FD, N) Set socket state to listen for an incoming connection. @c mysql_socket_listen is a replacement for @c listen. @param FD Instrumented socket descriptor, bound and connected @param N Maximum number of pending connections allowed. */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_listen(FD, N) \ inline_mysql_socket_listen(__FILE__, __LINE__, FD, N) #else #define mysql_socket_listen(FD, N) \ inline_mysql_socket_listen(FD, N) #endif /** @def mysql_socket_accept(K, FD, AP, LP) Accept a connection from any remote host; TCP only. @c mysql_socket_accept is a replacement for @c accept. @param K PSI_socket_key for this instrumented socket @param FD Instrumented socket descriptor, bound and placed in a listen state @param AP Pointer to sockaddr structure with returned IP address and port of connected host @param LP Pointer to length of valid information in AP */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_accept(K, FD, AP, LP) \ inline_mysql_socket_accept(__FILE__, __LINE__, K, FD, AP, LP) #else #define mysql_socket_accept(K, FD, AP, LP) \ inline_mysql_socket_accept(FD, AP, LP) #endif /** @def mysql_socket_close(FD) Close a socket and sever any connections. @c mysql_socket_close is a replacement for @c close. @param FD Instrumented socket descriptor returned by socket() or accept() */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_close(FD) \ inline_mysql_socket_close(__FILE__, __LINE__, FD) #else #define mysql_socket_close(FD) \ inline_mysql_socket_close(FD) #endif /** @def mysql_socket_shutdown(FD, H) Disable receives and/or sends on a socket. @c mysql_socket_shutdown is a replacement for @c shutdown. @param FD Instrumented socket descriptor returned by socket() or accept() @param H Specifies which operations to shutdown */ #ifdef HAVE_PSI_SOCKET_INTERFACE #define mysql_socket_shutdown(FD, H) \ inline_mysql_socket_shutdown(__FILE__, __LINE__, FD, H) #else #define mysql_socket_shutdown(FD, H) \ inline_mysql_socket_shutdown(FD, H) #endif #ifdef HAVE_PSI_SOCKET_INTERFACE static inline void inline_mysql_socket_register( const char *category, PSI_socket_info *info, int count) { PSI_SOCKET_CALL(register_socket)(category, info, count); } #endif /** mysql_socket_fd */ static inline MYSQL_SOCKET inline_mysql_socket_fd ( #ifdef HAVE_PSI_SOCKET_INTERFACE PSI_socket_key key, #endif int fd) { MYSQL_SOCKET mysql_socket= MYSQL_INVALID_SOCKET; mysql_socket.fd= fd; DBUG_ASSERT(mysql_socket.fd != INVALID_SOCKET); #ifdef HAVE_PSI_SOCKET_INTERFACE mysql_socket.m_psi= PSI_SOCKET_CALL(init_socket) (key, (const my_socket*)&mysql_socket.fd, NULL, 0); #endif /** Currently systemd socket activation is the user of this function. Its API (man sd_listen_fds) says FD_CLOSE_EXEC is already called. If there becomes another user, we can call it again without detriment. If needed later: #if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) (void) fcntl(mysql_socket.fd, F_SETFD, FD_CLOEXEC); #endif */ return mysql_socket; } /** mysql_socket_socket */ static inline MYSQL_SOCKET inline_mysql_socket_socket ( #ifdef HAVE_PSI_SOCKET_INTERFACE PSI_socket_key key, #endif int domain, int type, int protocol) { MYSQL_SOCKET mysql_socket= MYSQL_INVALID_SOCKET; mysql_socket.fd= socket(domain, type | SOCK_CLOEXEC, protocol); #ifdef HAVE_PSI_SOCKET_INTERFACE if (likely(mysql_socket.fd != INVALID_SOCKET)) { mysql_socket.m_psi= PSI_SOCKET_CALL(init_socket) (key, (const my_socket*)&mysql_socket.fd, NULL, 0); } #endif /* SOCK_CLOEXEC isn't always a number - can't preprocessor compare */ #if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) && !defined(HAVE_SOCK_CLOEXEC) (void) fcntl(mysql_socket.fd, F_SETFD, FD_CLOEXEC); #endif return mysql_socket; } /** mysql_socket_bind */ static inline int inline_mysql_socket_bind ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, const struct sockaddr *addr, size_t len) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker_state state; PSI_socket_locker *locker; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_BIND, (size_t)0, src_file, src_line); /* Instrumented code */ result= bind(mysql_socket.fd, addr, (int)len); /* Instrumentation end */ if (result == 0) PSI_SOCKET_CALL(set_socket_info)(mysql_socket.m_psi, NULL, addr, (socklen_t)len); if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= bind(mysql_socket.fd, addr, (int)len); return result; } /** mysql_socket_getsockname */ static inline int inline_mysql_socket_getsockname ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, struct sockaddr *addr, socklen_t *len) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_BIND, (size_t)0, src_file, src_line); /* Instrumented code */ result= getsockname(mysql_socket.fd, addr, len); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= getsockname(mysql_socket.fd, addr, len); return result; } /** mysql_socket_connect */ static inline int inline_mysql_socket_connect ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, const struct sockaddr *addr, socklen_t len) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line); /* Instrumented code */ result= connect(mysql_socket.fd, addr, len); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= connect(mysql_socket.fd, addr, len); return result; } /** mysql_socket_getpeername */ static inline int inline_mysql_socket_getpeername ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, struct sockaddr *addr, socklen_t *len) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_BIND, (size_t)0, src_file, src_line); /* Instrumented code */ result= getpeername(mysql_socket.fd, addr, len); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= getpeername(mysql_socket.fd, addr, len); return result; } /** mysql_socket_send */ static inline ssize_t inline_mysql_socket_send ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, const SOCKBUF_T *buf, size_t n, int flags) { ssize_t result; DBUG_ASSERT(mysql_socket.fd != INVALID_SOCKET); #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_SEND, n, src_file, src_line); /* Instrumented code */ result= send(mysql_socket.fd, buf, IF_WIN((int),) n, flags); /* Instrumentation end */ if (locker != NULL) { size_t bytes_written= (result > 0) ? (size_t) result : 0; PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_written); } return result; } #endif /* Non instrumented code */ result= send(mysql_socket.fd, buf, IF_WIN((int),) n, flags); return result; } /** mysql_socket_recv */ static inline ssize_t inline_mysql_socket_recv ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, SOCKBUF_T *buf, size_t n, int flags) { ssize_t result; DBUG_ASSERT(mysql_socket.fd != INVALID_SOCKET); #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_RECV, (size_t)0, src_file, src_line); /* Instrumented code */ result= recv(mysql_socket.fd, buf, IF_WIN((int),) n, flags); /* Instrumentation end */ if (locker != NULL) { size_t bytes_read= (result > 0) ? (size_t) result : 0; PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_read); } return result; } #endif /* Non instrumented code */ result= recv(mysql_socket.fd, buf, IF_WIN((int),) n, flags); return result; } /** mysql_socket_sendto */ static inline ssize_t inline_mysql_socket_sendto ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, const SOCKBUF_T *buf, size_t n, int flags, const struct sockaddr *addr, socklen_t addr_len) { ssize_t result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_SEND, n, src_file, src_line); /* Instrumented code */ result= sendto(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len); /* Instrumentation end */ if (locker != NULL) { size_t bytes_written = (result > 0) ? (size_t) result : 0; PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_written); } return result; } #endif /* Non instrumented code */ result= sendto(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len); return result; } /** mysql_socket_recvfrom */ static inline ssize_t inline_mysql_socket_recvfrom ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, SOCKBUF_T *buf, size_t n, int flags, struct sockaddr *addr, socklen_t *addr_len) { ssize_t result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_RECV, (size_t)0, src_file, src_line); /* Instrumented code */ result= recvfrom(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len); /* Instrumentation end */ if (locker != NULL) { size_t bytes_read= (result > 0) ? (size_t) result : 0; PSI_SOCKET_CALL(end_socket_wait)(locker, bytes_read); } return result; } #endif /* Non instrumented code */ result= recvfrom(mysql_socket.fd, buf, IF_WIN((int),) n, flags, addr, addr_len); return result; } /** mysql_socket_getsockopt */ static inline int inline_mysql_socket_getsockopt ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, int level, int optname, SOCKBUF_T *optval, socklen_t *optlen) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_OPT, (size_t)0, src_file, src_line); /* Instrumented code */ result= getsockopt(mysql_socket.fd, level, optname, optval, optlen); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= getsockopt(mysql_socket.fd, level, optname, optval, optlen); return result; } /** mysql_socket_setsockopt */ static inline int inline_mysql_socket_setsockopt ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, int level, int optname, const SOCKBUF_T *optval, socklen_t optlen) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_OPT, (size_t)0, src_file, src_line); /* Instrumented code */ result= setsockopt(mysql_socket.fd, level, optname, optval, optlen); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= setsockopt(mysql_socket.fd, level, optname, optval, optlen); return result; } /** set_socket_nonblock */ static inline int set_socket_nonblock(my_socket fd) { int ret= 0; #ifdef _WIN32 { u_long nonblocking= 1; ret= ioctlsocket(fd, FIONBIO, &nonblocking); } #else { int fd_flags; fd_flags= fcntl(fd, F_GETFL, 0); if (fd_flags < 0) return errno; #if defined(O_NONBLOCK) fd_flags |= O_NONBLOCK; #elif defined(O_NDELAY) fd_flags |= O_NDELAY; #elif defined(O_FNDELAY) fd_flags |= O_FNDELAY; #else #error "No definition of non-blocking flag found." #endif /* O_NONBLOCK */ if (fcntl(fd, F_SETFL, fd_flags) == -1) ret= errno; } #endif /* _WIN32 */ return ret; } /** mysql_socket_set_nonblocking */ static inline int inline_mysql_sock_set_nonblocking ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket ) { int result= 0; #ifdef HAVE_PSI_SOCKET_INTERFACE if (mysql_socket.m_psi) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_OPT, (size_t)0, src_file, src_line); /* Instrumented code */ result= set_socket_nonblock(mysql_socket.fd); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= set_socket_nonblock(mysql_socket.fd); return result; } /** mysql_socket_listen */ static inline int inline_mysql_socket_listen ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, int backlog) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line); /* Instrumented code */ result= listen(mysql_socket.fd, backlog); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ result= listen(mysql_socket.fd, backlog); return result; } /** mysql_socket_accept */ static inline MYSQL_SOCKET inline_mysql_socket_accept ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, PSI_socket_key key, #endif MYSQL_SOCKET socket_listen, struct sockaddr *addr, socklen_t *addr_len) { #ifdef FD_CLOEXEC int flags __attribute__ ((unused)); #endif MYSQL_SOCKET socket_accept; #ifdef HAVE_PSI_SOCKET_INTERFACE if (socket_listen.m_psi != NULL) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, socket_listen.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line); /* Instrumented code */ #ifdef HAVE_ACCEPT4 socket_accept.fd= accept4(socket_listen.fd, addr, addr_len, SOCK_CLOEXEC); #else socket_accept.fd= accept(socket_listen.fd, addr, addr_len); #ifdef FD_CLOEXEC if (socket_accept.fd != INVALID_SOCKET) { flags= fcntl(socket_accept.fd, F_GETFD); if (flags != -1) { flags |= FD_CLOEXEC; fcntl(socket_accept.fd, F_SETFD, flags); } } #endif #endif /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); } else #endif { /* Non instrumented code */ #ifdef HAVE_ACCEPT4 socket_accept.fd= accept4(socket_listen.fd, addr, addr_len, SOCK_CLOEXEC); #else socket_accept.fd= accept(socket_listen.fd, addr, addr_len); #ifdef FD_CLOEXEC if (socket_accept.fd != INVALID_SOCKET) { flags= fcntl(socket_accept.fd, F_GETFD); if (flags != -1) { flags |= FD_CLOEXEC; fcntl(socket_accept.fd, F_SETFD, flags); } } #endif #endif } #ifdef HAVE_PSI_SOCKET_INTERFACE if (likely(socket_accept.fd != INVALID_SOCKET)) { /* Initialize the instrument with the new socket descriptor and address */ socket_accept.m_psi= PSI_SOCKET_CALL(init_socket) (key, (const my_socket*)&socket_accept.fd, addr, *addr_len); } #endif return socket_accept; } /** mysql_socket_close */ static inline int inline_mysql_socket_close ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket) { int result; #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { /* Instrumentation start */ PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_CLOSE, (size_t)0, src_file, src_line); /* Instrumented code */ result= closesocket(mysql_socket.fd); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); /* Remove the instrumentation for this socket. */ if (mysql_socket.m_psi != NULL) PSI_SOCKET_CALL(destroy_socket)(mysql_socket.m_psi); return result; } #endif /* Non instrumented code */ result= closesocket(mysql_socket.fd); return result; } /** mysql_socket_shutdown */ static inline int inline_mysql_socket_shutdown ( #ifdef HAVE_PSI_SOCKET_INTERFACE const char *src_file, uint src_line, #endif MYSQL_SOCKET mysql_socket, int how) { int result; #ifdef _WIN32 static LPFN_DISCONNECTEX DisconnectEx = NULL; if (DisconnectEx == NULL) { DWORD dwBytesReturned; GUID guidDisconnectEx = WSAID_DISCONNECTEX; WSAIoctl(mysql_socket.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidDisconnectEx, sizeof(GUID), &DisconnectEx, sizeof(DisconnectEx), &dwBytesReturned, NULL, NULL); } #endif /* Instrumentation start */ #ifdef HAVE_PSI_SOCKET_INTERFACE if (psi_likely(mysql_socket.m_psi != NULL)) { PSI_socket_locker *locker; PSI_socket_locker_state state; locker= PSI_SOCKET_CALL(start_socket_wait) (&state, mysql_socket.m_psi, PSI_SOCKET_SHUTDOWN, (size_t)0, src_file, src_line); /* Instrumented code */ #ifdef _WIN32 if (DisconnectEx) result= (DisconnectEx(mysql_socket.fd, (LPOVERLAPPED) NULL, (DWORD) 0, (DWORD) 0) == TRUE) ? 0 : -1; else #endif result= shutdown(mysql_socket.fd, how); /* Instrumentation end */ if (locker != NULL) PSI_SOCKET_CALL(end_socket_wait)(locker, (size_t)0); return result; } #endif /* Non instrumented code */ #ifdef _WIN32 if (DisconnectEx) result= (DisconnectEx(mysql_socket.fd, (LPOVERLAPPED) NULL, (DWORD) 0, (DWORD) 0) == TRUE) ? 0 : -1; else #endif result= shutdown(mysql_socket.fd, how); return result; } /** @} (end of group Socket_instrumentation) */ #endif server/mysql/psi/mysql_mdl.h000064400000010624151031265040012164 0ustar00/* Copyright (c) 2012, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef MYSQL_MDL_H #define MYSQL_MDL_H /** @file mysql/psi/mysql_mdl.h Instrumentation helpers for metadata locks. */ #include "mysql/psi/psi.h" #ifdef HAVE_PSI_METADATA_INTERFACE #ifndef PSI_METADATA_CALL #define PSI_METADATA_CALL(M) PSI_DYNAMIC_CALL(M) #endif #define PSI_CALL_start_metadata_wait(A,B,C,D) PSI_METADATA_CALL(start_metadata_wait)(A,B,C,D) #define PSI_CALL_end_metadata_wait(A,B) PSI_METADATA_CALL(end_metadata_wait)(A,B) #define PSI_CALL_create_metadata_lock(A,B,C,D,E,F,G) PSI_METADATA_CALL(create_metadata_lock)(A,B,C,D,E,F,G) #define PSI_CALL_set_metadata_lock_status(A,B) PSI_METADATA_CALL(set_metadata_lock_status)(A,B) #define PSI_CALL_destroy_metadata_lock(A) PSI_METADATA_CALL(destroy_metadata_lock)(A) #else #define PSI_CALL_start_metadata_wait(A,B,C,D) 0 #define PSI_CALL_end_metadata_wait(A,B) do { } while(0) #define PSI_CALL_create_metadata_lock(A,B,C,D,E,F,G) 0 #define PSI_CALL_set_metadata_lock_status(A,B) do {} while(0) #define PSI_CALL_destroy_metadata_lock(A) do {} while(0) #endif /** @defgroup Thread_instrumentation Metadata Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_mdl_create(K, M, A) Instrumented metadata lock creation. @param I Metadata lock identity @param K Metadata key @param T Metadata lock type @param D Metadata lock duration @param S Metadata lock status @param F request source file @param L request source line */ #ifdef HAVE_PSI_METADATA_INTERFACE #define mysql_mdl_create(I, K, T, D, S, F, L) \ inline_mysql_mdl_create(I, K, T, D, S, F, L) #else #define mysql_mdl_create(I, K, T, D, S, F, L) NULL #endif #ifdef HAVE_PSI_METADATA_INTERFACE #define mysql_mdl_set_status(L, S) \ inline_mysql_mdl_set_status(L, S) #else #define mysql_mdl_set_status(L, S) \ do {} while (0) #endif /** @def mysql_mdl_destroy(M) Instrumented metadata lock destruction. @param M Metadata lock */ #ifdef HAVE_PSI_METADATA_INTERFACE #define mysql_mdl_destroy(M) \ inline_mysql_mdl_destroy(M, __FILE__, __LINE__) #else #define mysql_mdl_destroy(M) \ do {} while (0) #endif #ifdef HAVE_PSI_METADATA_INTERFACE static inline PSI_metadata_lock * inline_mysql_mdl_create(void *identity, const MDL_key *mdl_key, enum_mdl_type mdl_type, enum_mdl_duration mdl_duration, MDL_ticket::enum_psi_status mdl_status, const char *src_file, uint src_line) { PSI_metadata_lock *result; /* static_cast: Fit a round C++ enum peg into a square C int hole ... */ result= PSI_METADATA_CALL(create_metadata_lock) (identity, mdl_key, static_cast (mdl_type), static_cast (mdl_duration), static_cast (mdl_status), src_file, src_line); return result; } static inline void inline_mysql_mdl_set_status( PSI_metadata_lock *psi, MDL_ticket::enum_psi_status mdl_status) { if (psi != NULL) PSI_METADATA_CALL(set_metadata_lock_status)(psi, mdl_status); } static inline void inline_mysql_mdl_destroy( PSI_metadata_lock *psi, const char *src_file, uint src_line) { if (psi != NULL) PSI_METADATA_CALL(destroy_metadata_lock)(psi); } #endif /* HAVE_PSI_METADATA_INTERFACE */ /** @} (end of group Metadata_instrumentation) */ #endif server/mysql/psi/psi_abi_v2.h000064400000002667151031265040012210 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file mysql/psi/psi_abi_v1.h ABI check for mysql/psi/psi.h, when using PSI_VERSION_2. This file is only used to automate detection of changes between versions. Do not include this file, include mysql/psi/psi.h instead. */ #define USE_PSI_2 #define HAVE_PSI_INTERFACE #define MY_GLOBAL_INCLUDED #include "mysql/psi/psi.h" server/mysql/psi/psi_base.h000064400000011027151031265040011746 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. Without limiting anything contained in the foregoing, this file, which is part of C Driver for MySQL (Connector/C), is also subject to the Universal FOSS Exception, version 1.0, a copy of which can be found at http://oss.oracle.com/licenses/universal-foss-exception. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_PSI_BASE_H #define MYSQL_PSI_BASE_H #ifdef EMBEDDED_LIBRARY #define DISABLE_ALL_PSI #endif /* EMBEDDED_LIBRARY */ #ifdef __cplusplus extern "C" { #endif /** @file mysql/psi/psi_base.h Performance schema instrumentation interface. @defgroup Instrumentation_interface Instrumentation Interface @ingroup Performance_schema @{ */ #define PSI_INSTRUMENT_ME 0 #define PSI_INSTRUMENT_MEM ((PSI_memory_key)0) #define PSI_NOT_INSTRUMENTED 0 /** Global flag. This flag indicate that an instrumentation point is a global variable, or a singleton. */ #define PSI_FLAG_GLOBAL (1 << 0) /** Mutable flag. This flag indicate that an instrumentation point is a general placeholder, that can mutate into a more specific instrumentation point. */ #define PSI_FLAG_MUTABLE (1 << 1) #define PSI_FLAG_THREAD (1 << 2) /** Stage progress flag. This flag apply to the stage instruments only. It indicates the instrumentation provides progress data. */ #define PSI_FLAG_STAGE_PROGRESS (1 << 3) /** Shared Exclusive flag. Indicates that rwlock support the shared exclusive state. */ #define PSI_RWLOCK_FLAG_SX (1 << 4) /** Transferable flag. This flag indicate that an instrumented object can be created by a thread and destroyed by another thread. */ #define PSI_FLAG_TRANSFER (1 << 5) /** Volatility flag. This flag indicate that an instrumented object has a volatility (life cycle) comparable to the volatility of a session. */ #define PSI_FLAG_VOLATILITY_SESSION (1 << 6) /** System thread flag. Indicates that the instrumented object exists on a system thread. */ #define PSI_FLAG_THREAD_SYSTEM (1 << 9) #ifdef HAVE_PSI_INTERFACE /** @def PSI_VERSION_1 Performance Schema Interface number for version 1. This version is supported. */ #define PSI_VERSION_1 1 /** @def PSI_VERSION_2 Performance Schema Interface number for version 2. This version is not implemented, it's a placeholder. */ #define PSI_VERSION_2 2 /** @def PSI_CURRENT_VERSION Performance Schema Interface number for the most recent version. The most current version is @c PSI_VERSION_1 */ #define PSI_CURRENT_VERSION 1 /** @def USE_PSI_1 Define USE_PSI_1 to use the interface version 1. */ /** @def USE_PSI_2 Define USE_PSI_2 to use the interface version 2. */ /** @def HAVE_PSI_1 Define HAVE_PSI_1 if the interface version 1 needs to be compiled in. */ /** @def HAVE_PSI_2 Define HAVE_PSI_2 if the interface version 2 needs to be compiled in. */ #ifndef USE_PSI_2 #ifndef USE_PSI_1 #define USE_PSI_1 #endif #endif #ifdef USE_PSI_1 #define HAVE_PSI_1 #endif #ifdef USE_PSI_2 #define HAVE_PSI_2 #endif /* Allow to override PSI_XXX_CALL at compile time with more efficient implementations, if available. If nothing better is available, make a dynamic call using the PSI_server function pointer. */ #define PSI_DYNAMIC_CALL(M) PSI_server->M #endif /* HAVE_PSI_INTERFACE */ /** @} */ /** Instrumented memory key. To instrument memory, a memory key must be obtained using @c register_memory. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_memory_key; #ifdef __cplusplus } #endif #endif /* MYSQL_PSI_BASE_H */ server/mysql/psi/mysql_table.h000064400000013061151031265040012475 0ustar00/* Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_TABLE_H #define MYSQL_TABLE_H /** @file mysql/psi/mysql_table.h Instrumentation helpers for table io. */ #include "mysql/psi/psi.h" #ifndef PSI_TABLE_CALL #define PSI_TABLE_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Table_instrumentation Table Instrumentation @ingroup Instrumentation_interface @{ */ #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_UNBIND_TABLE(handler) (handler)->unbind_psi() #define PSI_CALL_unbind_table PSI_TABLE_CALL(unbind_table) #define PSI_CALL_rebind_table PSI_TABLE_CALL(rebind_table) #define PSI_CALL_open_table PSI_TABLE_CALL(open_table) #define PSI_CALL_close_table PSI_TABLE_CALL(close_table) #define PSI_CALL_get_table_share PSI_TABLE_CALL(get_table_share) #define PSI_CALL_release_table_share PSI_TABLE_CALL(release_table_share) #define PSI_CALL_drop_table_share PSI_TABLE_CALL(drop_table_share) #else #define MYSQL_UNBIND_TABLE(handler) do { } while(0) #define PSI_CALL_unbind_table(A1) do { } while(0) #define PSI_CALL_rebind_table(A1,A2,A3) NULL #define PSI_CALL_close_table(A1,A2) do { } while(0) #define PSI_CALL_open_table(A1,A2) NULL #define PSI_CALL_get_table_share(A1,A2) NULL #define PSI_CALL_release_table_share(A1) do { } while(0) #define PSI_CALL_drop_table_share(A1,A2,A3,A4,A5) do { } while(0) #endif /** @def MYSQL_TABLE_WAIT_VARIABLES Instrumentation helper for table waits. This instrumentation declares local variables. Do not use a ';' after this macro @param LOCKER the locker @param STATE the locker state @sa MYSQL_START_TABLE_IO_WAIT. @sa MYSQL_END_TABLE_IO_WAIT. @sa MYSQL_START_TABLE_LOCK_WAIT. @sa MYSQL_END_TABLE_LOCK_WAIT. */ #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_TABLE_WAIT_VARIABLES(LOCKER, STATE) \ struct PSI_table_locker* LOCKER; \ PSI_table_locker_state STATE; #else #define MYSQL_TABLE_WAIT_VARIABLES(LOCKER, STATE) #endif /** @def MYSQL_START_TABLE_LOCK_WAIT Instrumentation helper for table lock waits. This instrumentation marks the start of a wait event. @param LOCKER the locker @param STATE the locker state @param PSI the instrumented table @param OP the table operation to be performed @param FLAGS per table operation flags. @sa MYSQL_END_TABLE_LOCK_WAIT. */ #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_START_TABLE_LOCK_WAIT(LOCKER, STATE, PSI, OP, FLAGS) \ LOCKER= inline_mysql_start_table_lock_wait(STATE, PSI, \ OP, FLAGS, __FILE__, __LINE__) #else #define MYSQL_START_TABLE_LOCK_WAIT(LOCKER, STATE, PSI, OP, FLAGS) \ do {} while (0) #endif /** @def MYSQL_END_TABLE_LOCK_WAIT Instrumentation helper for table lock waits. This instrumentation marks the end of a wait event. @param LOCKER the locker @sa MYSQL_START_TABLE_LOCK_WAIT. */ #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_END_TABLE_LOCK_WAIT(LOCKER) \ inline_mysql_end_table_lock_wait(LOCKER) #else #define MYSQL_END_TABLE_LOCK_WAIT(LOCKER) \ do {} while (0) #endif #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_UNLOCK_TABLE(T) \ inline_mysql_unlock_table(T) #else #define MYSQL_UNLOCK_TABLE(T) \ do {} while (0) #endif #ifdef HAVE_PSI_TABLE_INTERFACE /** Instrumentation calls for MYSQL_START_TABLE_LOCK_WAIT. @sa MYSQL_END_TABLE_LOCK_WAIT. */ static inline struct PSI_table_locker * inline_mysql_start_table_lock_wait(PSI_table_locker_state *state, struct PSI_table *psi, enum PSI_table_lock_operation op, ulong flags, const char *src_file, uint src_line) { if (psi_likely(psi != NULL)) { struct PSI_table_locker *locker; locker= PSI_TABLE_CALL(start_table_lock_wait) (state, psi, op, flags, src_file, src_line); return locker; } return NULL; } /** Instrumentation calls for MYSQL_END_TABLE_LOCK_WAIT. @sa MYSQL_START_TABLE_LOCK_WAIT. */ static inline void inline_mysql_end_table_lock_wait(struct PSI_table_locker *locker) { if (psi_likely(locker != NULL)) PSI_TABLE_CALL(end_table_lock_wait)(locker); } static inline void inline_mysql_unlock_table(struct PSI_table *table) { if (table != NULL) PSI_TABLE_CALL(unlock_table)(table); } #endif /** @} (end of group Table_instrumentation) */ #endif server/mysql/psi/psi_abi_v0.h000064400000002630151031265040012174 0ustar00/* Copyright (c) 2011, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file mysql/psi/psi_abi_v0.h ABI check for mysql/psi/psi.h, when compiling without instrumentation. This file is only used to automate detection of changes between versions. Do not include this file, include mysql/psi/psi.h instead. */ #define MY_GLOBAL_INCLUDED #include "mysql/psi/psi.h" server/mysql/psi/mysql_thread.h000064400000077376151031265040012700 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. Copyright (c) 2020, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_THREAD_H #define MYSQL_THREAD_H /** @file mysql/psi/mysql_thread.h Instrumentation helpers for mysys threads, mutexes, read write locks and conditions. This header file provides the necessary declarations to use the mysys thread API with the performance schema instrumentation. In some compilers (SunStudio), 'static inline' functions, when declared but not used, are not optimized away (because they are unused) by default, so that including a static inline function from a header file does create unwanted dependencies, causing unresolved symbols at link time. Other compilers, like gcc, optimize these dependencies by default. Since the instrumented APIs declared here are wrapper on top of my_pthread / safemutex / etc APIs, including mysql/psi/mysql_thread.h assumes that the dependency on my_pthread and safemutex already exists. */ /* Note: there are several orthogonal dimensions here. Dimension 1: Instrumentation HAVE_PSI_INTERFACE is defined when the instrumentation is compiled in. This may happen both in debug or production builds. Dimension 2: Debug SAFE_MUTEX is defined when debug is compiled in. This may happen both with and without instrumentation. Dimension 3: Platform Mutexes are implemented with one of: - the pthread library - fast mutexes - window apis This is implemented by various macro definitions in my_pthread.h This causes complexity with '#ifdef'-ery that can't be avoided. */ #include "mysql/psi/psi.h" #ifdef MYSQL_SERVER #ifndef MYSQL_DYNAMIC_PLUGIN #include "pfs_thread_provider.h" #endif #endif #ifndef PSI_MUTEX_CALL #define PSI_MUTEX_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifndef PSI_RWLOCK_CALL #define PSI_RWLOCK_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifndef PSI_COND_CALL #define PSI_COND_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifndef PSI_THREAD_CALL #define PSI_THREAD_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Thread_instrumentation Thread Instrumentation @ingroup Instrumentation_interface @{ */ #ifdef HAVE_PSI_THREAD_INTERFACE #define PSI_CALL_delete_current_thread PSI_THREAD_CALL(delete_current_thread) #define PSI_CALL_get_thread PSI_THREAD_CALL(get_thread) #define PSI_CALL_new_thread PSI_THREAD_CALL(new_thread) #define PSI_CALL_register_thread PSI_THREAD_CALL(register_thread) #define PSI_CALL_set_thread PSI_THREAD_CALL(set_thread) #define PSI_CALL_set_thread_THD PSI_THREAD_CALL(set_thread_THD) #define PSI_CALL_set_thread_connect_attrs PSI_THREAD_CALL(set_thread_connect_attrs) #define PSI_CALL_set_thread_db PSI_THREAD_CALL(set_thread_db) #define PSI_CALL_set_thread_id PSI_THREAD_CALL(set_thread_id) #define PSI_CALL_set_thread_os_id PSI_THREAD_CALL(set_thread_os_id) #define PSI_CALL_set_thread_info PSI_THREAD_CALL(set_thread_info) #define PSI_CALL_set_thread_start_time PSI_THREAD_CALL(set_thread_start_time) #define PSI_CALL_set_thread_account PSI_THREAD_CALL(set_thread_account) #define PSI_CALL_spawn_thread PSI_THREAD_CALL(spawn_thread) #define PSI_CALL_set_connection_type PSI_THREAD_CALL(set_connection_type) #else #define PSI_CALL_delete_current_thread() do { } while(0) #define PSI_CALL_get_thread() NULL #define PSI_CALL_new_thread(A1,A2,A3) NULL #define PSI_CALL_register_thread(A1,A2,A3) do { } while(0) #define PSI_CALL_set_thread(A1) do { } while(0) #define PSI_CALL_set_thread_THD(A1,A2) do { } while(0) #define PSI_CALL_set_thread_connect_attrs(A1,A2,A3) 0 #define PSI_CALL_set_thread_db(A1,A2) do { } while(0) #define PSI_CALL_set_thread_id(A1,A2) do { } while(0) #define PSI_CALL_set_thread_os_id(A1) do { } while(0) #define PSI_CALL_set_thread_info(A1, A2) do { } while(0) #define PSI_CALL_set_thread_start_time(A1) do { } while(0) #define PSI_CALL_set_thread_account(A1, A2, A3, A4) do { } while(0) #define PSI_CALL_spawn_thread(A1, A2, A3, A4, A5) 0 #define PSI_CALL_set_connection_type(A) do { } while(0) #endif /** An instrumented mutex structure. @sa mysql_mutex_t */ struct st_mysql_mutex { /** The real mutex. */ #ifdef SAFE_MUTEX safe_mutex_t m_mutex; #else pthread_mutex_t m_mutex; #endif /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c mysql_mutex_t interface. */ struct PSI_mutex *m_psi; }; /** Type of an instrumented mutex. @c mysql_mutex_t is a drop-in replacement for @c pthread_mutex_t. @sa mysql_mutex_assert_owner @sa mysql_mutex_assert_not_owner @sa mysql_mutex_init @sa mysql_mutex_lock @sa mysql_mutex_unlock @sa mysql_mutex_destroy */ typedef struct st_mysql_mutex mysql_mutex_t; /** An instrumented rwlock structure. @sa mysql_rwlock_t */ struct st_mysql_rwlock { /** The real rwlock */ rw_lock_t m_rwlock; /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c mysql_rwlock_t interface. */ struct PSI_rwlock *m_psi; }; /** An instrumented prlock structure. @sa mysql_prlock_t */ struct st_mysql_prlock { /** The real prlock */ rw_pr_lock_t m_prlock; /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c mysql_rwlock_t interface. */ struct PSI_rwlock *m_psi; }; /** Type of an instrumented rwlock. @c mysql_rwlock_t is a drop-in replacement for @c pthread_rwlock_t. @sa mysql_rwlock_init @sa mysql_rwlock_rdlock @sa mysql_rwlock_tryrdlock @sa mysql_rwlock_wrlock @sa mysql_rwlock_trywrlock @sa mysql_rwlock_unlock @sa mysql_rwlock_destroy */ typedef struct st_mysql_rwlock mysql_rwlock_t; /** Type of an instrumented prlock. A prlock is a read write lock that 'prefers readers' (pr). @c mysql_prlock_t is a drop-in replacement for @c rw_pr_lock_t. @sa mysql_prlock_init @sa mysql_prlock_rdlock @sa mysql_prlock_wrlock @sa mysql_prlock_unlock @sa mysql_prlock_destroy */ typedef struct st_mysql_prlock mysql_prlock_t; /** An instrumented cond structure. @sa mysql_cond_t */ struct st_mysql_cond { /** The real condition */ pthread_cond_t m_cond; /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c mysql_cond_t interface. */ struct PSI_cond *m_psi; }; /** Type of an instrumented condition. @c mysql_cond_t is a drop-in replacement for @c pthread_cond_t. @sa mysql_cond_init @sa mysql_cond_wait @sa mysql_cond_timedwait @sa mysql_cond_signal @sa mysql_cond_broadcast @sa mysql_cond_destroy */ typedef struct st_mysql_cond mysql_cond_t; /* Consider the following code: static inline void foo() { bar(); } when foo() is never called. With gcc, foo() is a local static function, so the dependencies are optimized away at compile time, and there is no dependency on bar(). With other compilers (HP, Sun Studio), the function foo() implementation is compiled, and bar() needs to be present to link. Due to the existing header dependencies in MySQL code, this header file is sometime used when it is not needed, which in turn cause link failures on some platforms. The proper fix would be to cut these extra dependencies in the calling code. DISABLE_MYSQL_THREAD_H is a work around to limit dependencies. DISABLE_MYSQL_PRLOCK_H is similar, and is used to disable specifically the prlock wrappers. */ #ifndef DISABLE_MYSQL_THREAD_H #define mysql_mutex_is_owner(M) safe_mutex_is_owner(&(M)->m_mutex) /** @def mysql_mutex_assert_owner(M) Wrapper, to use safe_mutex_assert_owner with instrumented mutexes. @c mysql_mutex_assert_owner is a drop-in replacement for @c safe_mutex_assert_owner. */ #define mysql_mutex_assert_owner(M) \ safe_mutex_assert_owner(&(M)->m_mutex) /** @def mysql_mutex_assert_not_owner(M) Wrapper, to use safe_mutex_assert_not_owner with instrumented mutexes. @c mysql_mutex_assert_not_owner is a drop-in replacement for @c safe_mutex_assert_not_owner. */ #define mysql_mutex_assert_not_owner(M) \ safe_mutex_assert_not_owner(&(M)->m_mutex) #define mysql_mutex_setflags(M, F) \ safe_mutex_setflags(&(M)->m_mutex, (F)) /** @def mysql_prlock_assert_write_owner(M) Drop-in replacement for @c rw_pr_lock_assert_write_owner. */ #define mysql_prlock_assert_write_owner(M) \ rw_pr_lock_assert_write_owner(&(M)->m_prlock) /** @def mysql_prlock_assert_not_write_owner(M) Drop-in replacement for @c rw_pr_lock_assert_not_write_owner. */ #define mysql_prlock_assert_not_write_owner(M) \ rw_pr_lock_assert_not_write_owner(&(M)->m_prlock) /** @def mysql_mutex_register(P1, P2, P3) Mutex registration. */ #define mysql_mutex_register(P1, P2, P3) \ inline_mysql_mutex_register(P1, P2, P3) /** @def mysql_mutex_init(K, M, A) Instrumented mutex_init. @c mysql_mutex_init is a replacement for @c pthread_mutex_init. @param K The PSI_mutex_key for this instrumented mutex @param M The mutex to initialize @param A Mutex attributes */ #ifdef HAVE_PSI_MUTEX_INTERFACE #ifdef SAFE_MUTEX #define mysql_mutex_init(K, M, A) \ inline_mysql_mutex_init(K, M, A, #M, __FILE__, __LINE__) #else #define mysql_mutex_init(K, M, A) \ inline_mysql_mutex_init(K, M, A) #endif #else #ifdef SAFE_MUTEX #define mysql_mutex_init(K, M, A) \ inline_mysql_mutex_init(M, A, #M, __FILE__, __LINE__) #else #define mysql_mutex_init(K, M, A) \ inline_mysql_mutex_init(M, A) #endif #endif /** @def mysql_mutex_destroy(M) Instrumented mutex_destroy. @c mysql_mutex_destroy is a drop-in replacement for @c pthread_mutex_destroy. */ #ifdef SAFE_MUTEX #define mysql_mutex_destroy(M) \ inline_mysql_mutex_destroy(M, __FILE__, __LINE__) #else #define mysql_mutex_destroy(M) \ inline_mysql_mutex_destroy(M) #endif /** @def mysql_mutex_lock(M) Instrumented mutex_lock. @c mysql_mutex_lock is a drop-in replacement for @c pthread_mutex_lock. @param M The mutex to lock */ #if defined(SAFE_MUTEX) || defined (HAVE_PSI_MUTEX_INTERFACE) #define mysql_mutex_lock(M) \ inline_mysql_mutex_lock(M, __FILE__, __LINE__) #else #define mysql_mutex_lock(M) \ inline_mysql_mutex_lock(M) #endif /** @def mysql_mutex_trylock(M) Instrumented mutex_lock. @c mysql_mutex_trylock is a drop-in replacement for @c pthread_mutex_trylock. */ #if defined(SAFE_MUTEX) || defined (HAVE_PSI_MUTEX_INTERFACE) #define mysql_mutex_trylock(M) \ inline_mysql_mutex_trylock(M, __FILE__, __LINE__) #else #define mysql_mutex_trylock(M) \ inline_mysql_mutex_trylock(M) #endif /** @def mysql_mutex_unlock(M) Instrumented mutex_unlock. @c mysql_mutex_unlock is a drop-in replacement for @c pthread_mutex_unlock. */ #ifdef SAFE_MUTEX #define mysql_mutex_unlock(M) \ inline_mysql_mutex_unlock(M, __FILE__, __LINE__) #else #define mysql_mutex_unlock(M) \ inline_mysql_mutex_unlock(M) #endif /** @def mysql_rwlock_register(P1, P2, P3) Rwlock registration. */ #define mysql_rwlock_register(P1, P2, P3) \ inline_mysql_rwlock_register(P1, P2, P3) /** @def mysql_rwlock_init(K, RW) Instrumented rwlock_init. @c mysql_rwlock_init is a replacement for @c pthread_rwlock_init. Note that pthread_rwlockattr_t is not supported in MySQL. @param K The PSI_rwlock_key for this instrumented rwlock @param RW The rwlock to initialize */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_rwlock_init(K, RW) inline_mysql_rwlock_init(K, RW) #else #define mysql_rwlock_init(K, RW) inline_mysql_rwlock_init(RW) #endif /** @def mysql_prlock_init(K, RW) Instrumented rw_pr_init. @c mysql_prlock_init is a replacement for @c rw_pr_init. @param K The PSI_rwlock_key for this instrumented prlock @param RW The prlock to initialize */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_prlock_init(K, RW) inline_mysql_prlock_init(K, RW) #else #define mysql_prlock_init(K, RW) inline_mysql_prlock_init(RW) #endif /** @def mysql_rwlock_destroy(RW) Instrumented rwlock_destroy. @c mysql_rwlock_destroy is a drop-in replacement for @c pthread_rwlock_destroy. */ #define mysql_rwlock_destroy(RW) inline_mysql_rwlock_destroy(RW) /** @def mysql_prlock_destroy(RW) Instrumented rw_pr_destroy. @c mysql_prlock_destroy is a drop-in replacement for @c rw_pr_destroy. */ #define mysql_prlock_destroy(RW) inline_mysql_prlock_destroy(RW) /** @def mysql_rwlock_rdlock(RW) Instrumented rwlock_rdlock. @c mysql_rwlock_rdlock is a drop-in replacement for @c pthread_rwlock_rdlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_rwlock_rdlock(RW) \ inline_mysql_rwlock_rdlock(RW, __FILE__, __LINE__) #else #define mysql_rwlock_rdlock(RW) \ inline_mysql_rwlock_rdlock(RW) #endif /** @def mysql_prlock_rdlock(RW) Instrumented rw_pr_rdlock. @c mysql_prlock_rdlock is a drop-in replacement for @c rw_pr_rdlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_prlock_rdlock(RW) \ inline_mysql_prlock_rdlock(RW, __FILE__, __LINE__) #else #define mysql_prlock_rdlock(RW) \ inline_mysql_prlock_rdlock(RW) #endif /** @def mysql_rwlock_wrlock(RW) Instrumented rwlock_wrlock. @c mysql_rwlock_wrlock is a drop-in replacement for @c pthread_rwlock_wrlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_rwlock_wrlock(RW) \ inline_mysql_rwlock_wrlock(RW, __FILE__, __LINE__) #else #define mysql_rwlock_wrlock(RW) \ inline_mysql_rwlock_wrlock(RW) #endif /** @def mysql_prlock_wrlock(RW) Instrumented rw_pr_wrlock. @c mysql_prlock_wrlock is a drop-in replacement for @c rw_pr_wrlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_prlock_wrlock(RW) \ inline_mysql_prlock_wrlock(RW, __FILE__, __LINE__) #else #define mysql_prlock_wrlock(RW) \ inline_mysql_prlock_wrlock(RW) #endif /** @def mysql_rwlock_tryrdlock(RW) Instrumented rwlock_tryrdlock. @c mysql_rwlock_tryrdlock is a drop-in replacement for @c pthread_rwlock_tryrdlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_rwlock_tryrdlock(RW) \ inline_mysql_rwlock_tryrdlock(RW, __FILE__, __LINE__) #else #define mysql_rwlock_tryrdlock(RW) \ inline_mysql_rwlock_tryrdlock(RW) #endif /** @def mysql_rwlock_trywrlock(RW) Instrumented rwlock_trywrlock. @c mysql_rwlock_trywrlock is a drop-in replacement for @c pthread_rwlock_trywrlock. */ #ifdef HAVE_PSI_RWLOCK_INTERFACE #define mysql_rwlock_trywrlock(RW) \ inline_mysql_rwlock_trywrlock(RW, __FILE__, __LINE__) #else #define mysql_rwlock_trywrlock(RW) \ inline_mysql_rwlock_trywrlock(RW) #endif /** @def mysql_rwlock_unlock(RW) Instrumented rwlock_unlock. @c mysql_rwlock_unlock is a drop-in replacement for @c pthread_rwlock_unlock. */ #define mysql_rwlock_unlock(RW) inline_mysql_rwlock_unlock(RW) /** @def mysql_prlock_unlock(RW) Instrumented rw_pr_unlock. @c mysql_prlock_unlock is a drop-in replacement for @c rw_pr_unlock. */ #define mysql_prlock_unlock(RW) inline_mysql_prlock_unlock(RW) /** @def mysql_cond_register(P1, P2, P3) Cond registration. */ #define mysql_cond_register(P1, P2, P3) \ inline_mysql_cond_register(P1, P2, P3) /** @def mysql_cond_init(K, C, A) Instrumented cond_init. @c mysql_cond_init is a replacement for @c pthread_cond_init. @param C The cond to initialize @param K The PSI_cond_key for this instrumented cond @param A Condition attributes */ #ifdef HAVE_PSI_COND_INTERFACE #define mysql_cond_init(K, C, A) inline_mysql_cond_init(K, C, A) #else #define mysql_cond_init(K, C, A) inline_mysql_cond_init(C, A) #endif /** @def mysql_cond_destroy(C) Instrumented cond_destroy. @c mysql_cond_destroy is a drop-in replacement for @c pthread_cond_destroy. */ #define mysql_cond_destroy(C) inline_mysql_cond_destroy(C) /** @def mysql_cond_wait(C) Instrumented cond_wait. @c mysql_cond_wait is a drop-in replacement for @c pthread_cond_wait. */ #if defined(SAFE_MUTEX) || defined(HAVE_PSI_COND_INTERFACE) #define mysql_cond_wait(C, M) \ inline_mysql_cond_wait(C, M, __FILE__, __LINE__) #else #define mysql_cond_wait(C, M) \ inline_mysql_cond_wait(C, M) #endif /** @def mysql_cond_timedwait(C, M, W) Instrumented cond_timedwait. @c mysql_cond_timedwait is a drop-in replacement for @c pthread_cond_timedwait. */ #if defined(SAFE_MUTEX) || defined(HAVE_PSI_COND_INTERFACE) #define mysql_cond_timedwait(C, M, W) \ inline_mysql_cond_timedwait(C, M, W, __FILE__, __LINE__) #else #define mysql_cond_timedwait(C, M, W) \ inline_mysql_cond_timedwait(C, M, W) #endif /** @def mysql_cond_signal(C) Instrumented cond_signal. @c mysql_cond_signal is a drop-in replacement for @c pthread_cond_signal. */ #define mysql_cond_signal(C) inline_mysql_cond_signal(C) /** @def mysql_cond_broadcast(C) Instrumented cond_broadcast. @c mysql_cond_broadcast is a drop-in replacement for @c pthread_cond_broadcast. */ #define mysql_cond_broadcast(C) inline_mysql_cond_broadcast(C) /** @def mysql_thread_register(P1, P2, P3) Thread registration. */ #define mysql_thread_register(P1, P2, P3) \ inline_mysql_thread_register(P1, P2, P3) /** @def mysql_thread_create(K, P1, P2, P3, P4) Instrumented pthread_create. This function creates both the thread instrumentation and a thread. @c mysql_thread_create is a replacement for @c pthread_create. The parameter P4 (or, if it is NULL, P1) will be used as the instrumented thread "identity". Providing a P1 / P4 parameter with a different value for each call will on average improve performances, since this thread identity value is used internally to randomize access to data and prevent contention. This is optional, and the improvement is not guaranteed, only statistical. @param K The PSI_thread_key for this instrumented thread @param P1 pthread_create parameter 1 @param P2 pthread_create parameter 2 @param P3 pthread_create parameter 3 @param P4 pthread_create parameter 4 */ #ifdef HAVE_PSI_THREAD_INTERFACE #define mysql_thread_create(K, P1, P2, P3, P4) \ inline_mysql_thread_create(K, P1, P2, P3, P4) #else #define mysql_thread_create(K, P1, P2, P3, P4) \ pthread_create(P1, P2, P3, P4) #endif /** @def mysql_thread_set_psi_id(I) Set the thread identifier for the instrumentation. @param I The thread identifier */ #ifdef HAVE_PSI_THREAD_INTERFACE #define mysql_thread_set_psi_id(I) inline_mysql_thread_set_psi_id(I) #else #define mysql_thread_set_psi_id(I) do {} while (0) #endif /** @def mysql_thread_set_psi_THD(T) Set the thread sql session for the instrumentation. @param I The thread identifier */ #ifdef HAVE_PSI_THREAD_INTERFACE #define mysql_thread_set_psi_THD(T) inline_mysql_thread_set_psi_THD(T) #else #define mysql_thread_set_psi_THD(T) do {} while (0) #endif static inline void inline_mysql_mutex_register( #ifdef HAVE_PSI_MUTEX_INTERFACE const char *category, PSI_mutex_info *info, int count #else const char *category __attribute__ ((unused)), void *info __attribute__ ((unused)), int count __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_MUTEX_INTERFACE PSI_MUTEX_CALL(register_mutex)(category, info, count); #endif } static inline int inline_mysql_mutex_init( #ifdef HAVE_PSI_MUTEX_INTERFACE PSI_mutex_key key, #endif mysql_mutex_t *that, const pthread_mutexattr_t *attr #ifdef SAFE_MUTEX , const char *src_name, const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_MUTEX_INTERFACE that->m_psi= PSI_MUTEX_CALL(init_mutex)(key, &that->m_mutex); #else that->m_psi= NULL; #endif #ifdef SAFE_MUTEX return safe_mutex_init(&that->m_mutex, attr, src_name, src_file, src_line); #else return pthread_mutex_init(&that->m_mutex, attr); #endif } static inline int inline_mysql_mutex_destroy( mysql_mutex_t *that #ifdef SAFE_MUTEX , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_MUTEX_INTERFACE if (that->m_psi != NULL) { PSI_MUTEX_CALL(destroy_mutex)(that->m_psi); that->m_psi= NULL; } #endif #ifdef SAFE_MUTEX return safe_mutex_destroy(&that->m_mutex, src_file, src_line); #else return pthread_mutex_destroy(&that->m_mutex); #endif } #ifdef HAVE_PSI_MUTEX_INTERFACE ATTRIBUTE_COLD int psi_mutex_lock(mysql_mutex_t *that, const char *file, uint line); ATTRIBUTE_COLD int psi_mutex_trylock(mysql_mutex_t *that, const char *file, uint line); #endif static inline int inline_mysql_mutex_lock( mysql_mutex_t *that #if defined(SAFE_MUTEX) || defined (HAVE_PSI_MUTEX_INTERFACE) , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_MUTEX_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_mutex_lock(that, src_file, src_line); #endif /* Non instrumented code */ #ifdef SAFE_MUTEX return safe_mutex_lock(&that->m_mutex, FALSE, src_file, src_line); #else return pthread_mutex_lock(&that->m_mutex); #endif } static inline int inline_mysql_mutex_trylock( mysql_mutex_t *that #if defined(SAFE_MUTEX) || defined (HAVE_PSI_MUTEX_INTERFACE) , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_MUTEX_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_mutex_trylock(that, src_file, src_line); #endif /* Non instrumented code */ #ifdef SAFE_MUTEX return safe_mutex_lock(&that->m_mutex, TRUE, src_file, src_line); #else return pthread_mutex_trylock(&that->m_mutex); #endif } static inline int inline_mysql_mutex_unlock( mysql_mutex_t *that #ifdef SAFE_MUTEX , const char *src_file, uint src_line #endif ) { int result; #ifdef HAVE_PSI_MUTEX_INTERFACE if (psi_likely(that->m_psi != NULL)) PSI_MUTEX_CALL(unlock_mutex)(that->m_psi); #endif #ifdef SAFE_MUTEX result= safe_mutex_unlock(&that->m_mutex, src_file, src_line); #else result= pthread_mutex_unlock(&that->m_mutex); #endif return result; } static inline void inline_mysql_rwlock_register( #ifdef HAVE_PSI_RWLOCK_INTERFACE const char *category, PSI_rwlock_info *info, int count #else const char *category __attribute__ ((unused)), void *info __attribute__ ((unused)), int count __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE PSI_RWLOCK_CALL(register_rwlock)(category, info, count); #endif } static inline int inline_mysql_rwlock_init( #ifdef HAVE_PSI_RWLOCK_INTERFACE PSI_rwlock_key key, #endif mysql_rwlock_t *that) { #ifdef HAVE_PSI_RWLOCK_INTERFACE that->m_psi= PSI_RWLOCK_CALL(init_rwlock)(key, &that->m_rwlock); #else that->m_psi= NULL; #endif /* pthread_rwlockattr_t is not used in MySQL. */ return my_rwlock_init(&that->m_rwlock, NULL); } #ifndef DISABLE_MYSQL_PRLOCK_H static inline int inline_mysql_prlock_init( #ifdef HAVE_PSI_RWLOCK_INTERFACE PSI_rwlock_key key, #endif mysql_prlock_t *that) { #ifdef HAVE_PSI_RWLOCK_INTERFACE that->m_psi= PSI_RWLOCK_CALL(init_rwlock)(key, &that->m_prlock); #else that->m_psi= NULL; #endif return rw_pr_init(&that->m_prlock); } #endif static inline int inline_mysql_rwlock_destroy( mysql_rwlock_t *that) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) { PSI_RWLOCK_CALL(destroy_rwlock)(that->m_psi); that->m_psi= NULL; } #endif return rwlock_destroy(&that->m_rwlock); } #ifndef DISABLE_MYSQL_PRLOCK_H static inline int inline_mysql_prlock_destroy( mysql_prlock_t *that) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) { PSI_RWLOCK_CALL(destroy_rwlock)(that->m_psi); that->m_psi= NULL; } #endif return rw_pr_destroy(&that->m_prlock); } #endif #ifdef HAVE_PSI_RWLOCK_INTERFACE ATTRIBUTE_COLD int psi_rwlock_rdlock(mysql_rwlock_t *that, const char *file, uint line); ATTRIBUTE_COLD int psi_rwlock_tryrdlock(mysql_rwlock_t *that, const char *file, uint line); ATTRIBUTE_COLD int psi_rwlock_wrlock(mysql_rwlock_t *that, const char *file, uint line); ATTRIBUTE_COLD int psi_rwlock_trywrlock(mysql_rwlock_t *that, const char *file, uint line); # ifndef DISABLE_MYSQL_PRLOCK_H ATTRIBUTE_COLD int psi_prlock_rdlock(mysql_prlock_t *that, const char *file, uint line); ATTRIBUTE_COLD int psi_prlock_wrlock(mysql_prlock_t *that, const char *file, uint line); # endif #endif static inline int inline_mysql_rwlock_rdlock( mysql_rwlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_rwlock_rdlock(that, src_file, src_line); #endif return rw_rdlock(&that->m_rwlock); } #ifndef DISABLE_MYSQL_PRLOCK_H static inline int inline_mysql_prlock_rdlock( mysql_prlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_prlock_rdlock(that, src_file, src_line); #endif return rw_pr_rdlock(&that->m_prlock); } #endif static inline int inline_mysql_rwlock_wrlock( mysql_rwlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_rwlock_wrlock(that, src_file, src_line); #endif return rw_wrlock(&that->m_rwlock); } #ifndef DISABLE_MYSQL_PRLOCK_H static inline int inline_mysql_prlock_wrlock( mysql_prlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_prlock_wrlock(that, src_file, src_line); #endif return rw_pr_wrlock(&that->m_prlock); } #endif static inline int inline_mysql_rwlock_tryrdlock( mysql_rwlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_rwlock_tryrdlock(that, src_file, src_line); #endif return rw_tryrdlock(&that->m_rwlock); } static inline int inline_mysql_rwlock_trywrlock( mysql_rwlock_t *that #ifdef HAVE_PSI_RWLOCK_INTERFACE , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_rwlock_trywrlock(that, src_file, src_line); #endif return rw_trywrlock(&that->m_rwlock); } static inline int inline_mysql_rwlock_unlock( mysql_rwlock_t *that) { int result; #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) PSI_RWLOCK_CALL(unlock_rwlock)(that->m_psi); #endif result= rw_unlock(&that->m_rwlock); return result; } #ifndef DISABLE_MYSQL_PRLOCK_H static inline int inline_mysql_prlock_unlock( mysql_prlock_t *that) { int result; #ifdef HAVE_PSI_RWLOCK_INTERFACE if (psi_likely(that->m_psi != NULL)) PSI_RWLOCK_CALL(unlock_rwlock)(that->m_psi); #endif result= rw_pr_unlock(&that->m_prlock); return result; } #endif static inline void inline_mysql_cond_register( #ifdef HAVE_PSI_COND_INTERFACE const char *category, PSI_cond_info *info, int count #else const char *category __attribute__ ((unused)), void *info __attribute__ ((unused)), int count __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_COND_INTERFACE PSI_COND_CALL(register_cond)(category, info, count); #endif } static inline int inline_mysql_cond_init( #ifdef HAVE_PSI_COND_INTERFACE PSI_cond_key key, #endif mysql_cond_t *that, const pthread_condattr_t *attr) { #ifdef HAVE_PSI_COND_INTERFACE that->m_psi= PSI_COND_CALL(init_cond)(key, &that->m_cond); #else that->m_psi= NULL; #endif return pthread_cond_init(&that->m_cond, attr); } static inline int inline_mysql_cond_destroy( mysql_cond_t *that) { #ifdef HAVE_PSI_COND_INTERFACE if (psi_likely(that->m_psi != NULL)) { PSI_COND_CALL(destroy_cond)(that->m_psi); that->m_psi= NULL; } #endif return pthread_cond_destroy(&that->m_cond); } #ifdef HAVE_PSI_COND_INTERFACE ATTRIBUTE_COLD int psi_cond_wait(mysql_cond_t *that, mysql_mutex_t *mutex, const char *file, uint line); ATTRIBUTE_COLD int psi_cond_timedwait(mysql_cond_t *that, mysql_mutex_t *mutex, const struct timespec *abstime, const char *file, uint line); #endif static inline int inline_mysql_cond_wait( mysql_cond_t *that, mysql_mutex_t *mutex #if defined(SAFE_MUTEX) || defined(HAVE_PSI_COND_INTERFACE) , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_COND_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_cond_wait(that, mutex, src_file, src_line); #endif return my_cond_wait(&that->m_cond, &mutex->m_mutex); } static inline int inline_mysql_cond_timedwait( mysql_cond_t *that, mysql_mutex_t *mutex, const struct timespec *abstime #if defined(SAFE_MUTEX) || defined(HAVE_PSI_COND_INTERFACE) , const char *src_file, uint src_line #endif ) { #ifdef HAVE_PSI_COND_INTERFACE if (psi_likely(that->m_psi != NULL)) return psi_cond_timedwait(that, mutex, abstime, src_file, src_line); #endif return my_cond_timedwait(&that->m_cond, &mutex->m_mutex, abstime); } static inline int inline_mysql_cond_signal( mysql_cond_t *that) { int result; #ifdef HAVE_PSI_COND_INTERFACE if (psi_likely(that->m_psi != NULL)) PSI_COND_CALL(signal_cond)(that->m_psi); #endif result= pthread_cond_signal(&that->m_cond); return result; } static inline int inline_mysql_cond_broadcast( mysql_cond_t *that) { int result; #ifdef HAVE_PSI_COND_INTERFACE if (psi_likely(that->m_psi != NULL)) PSI_COND_CALL(broadcast_cond)(that->m_psi); #endif result= pthread_cond_broadcast(&that->m_cond); return result; } static inline void inline_mysql_thread_register( #ifdef HAVE_PSI_THREAD_INTERFACE const char *category, PSI_thread_info *info, int count #else const char *category __attribute__ ((unused)), void *info __attribute__ ((unused)), int count __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_THREAD_INTERFACE PSI_THREAD_CALL(register_thread)(category, info, count); #endif } #ifdef HAVE_PSI_THREAD_INTERFACE static inline int inline_mysql_thread_create( PSI_thread_key key, pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg) { int result; result= PSI_THREAD_CALL(spawn_thread)(key, thread, attr, start_routine, arg); return result; } static inline void inline_mysql_thread_set_psi_id(my_thread_id id) { struct PSI_thread *psi= PSI_THREAD_CALL(get_thread)(); PSI_THREAD_CALL(set_thread_id)(psi, id); } #ifdef __cplusplus class THD; static inline void inline_mysql_thread_set_psi_THD(THD *thd) { struct PSI_thread *psi= PSI_THREAD_CALL(get_thread)(); PSI_THREAD_CALL(set_thread_THD)(psi, thd); } #endif /* __cplusplus */ static inline void mysql_thread_set_peer_port(uint port __attribute__ ((unused))) { #ifdef HAVE_PSI_THREAD_INTERFACE struct PSI_thread *psi = PSI_THREAD_CALL(get_thread)(); PSI_THREAD_CALL(set_thread_peer_port)(psi, port); #endif } #endif #endif /* DISABLE_MYSQL_THREAD_H */ /** @} (end of group Thread_instrumentation) */ #endif server/mysql/psi/mysql_stage.h000064400000012112151031265040012505 0ustar00/* Copyright (c) 2010, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_STAGE_H #define MYSQL_STAGE_H /** @file mysql/psi/mysql_stage.h Instrumentation helpers for stages. */ #include "mysql/psi/psi.h" #ifndef PSI_STAGE_CALL #define PSI_STAGE_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Stage_instrumentation Stage Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_stage_register(P1, P2, P3) Stage registration. */ #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_stage_register(P1, P2, P3) \ inline_mysql_stage_register(P1, P2, P3) #else #define mysql_stage_register(P1, P2, P3) \ do {} while (0) #endif /** @def MYSQL_SET_STAGE Set the current stage. Use this API when the file and line is passed from the caller. @param K the stage key @param F the source file name @param L the source file line @return the current stage progress */ #ifdef HAVE_PSI_STAGE_INTERFACE #define MYSQL_SET_STAGE(K, F, L) \ inline_mysql_set_stage(K, F, L) #else #define MYSQL_SET_STAGE(K, F, L) \ NULL #endif /** @def mysql_set_stage Set the current stage. @param K the stage key @return the current stage progress */ #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_set_stage(K) \ inline_mysql_set_stage(K, __FILE__, __LINE__) #else #define mysql_set_stage(K) \ NULL #endif /** @def mysql_end_stage End the last stage */ #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_end_stage() \ inline_mysql_end_stage() #else #define mysql_end_stage() \ do {} while (0) #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline void inline_mysql_stage_register( const char *category, PSI_stage_info **info, int count) { PSI_STAGE_CALL(register_stage)(category, info, count); } #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline PSI_stage_progress* inline_mysql_set_stage(PSI_stage_key key, const char *src_file, int src_line) { return PSI_STAGE_CALL(start_stage)(key, src_file, src_line); } #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline void inline_mysql_end_stage() { PSI_STAGE_CALL(end_stage)(); } #endif #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_stage_set_work_completed(P1, P2) \ inline_mysql_stage_set_work_completed(P1, P2) #define mysql_stage_get_work_completed(P1) \ inline_mysql_stage_get_work_completed(P1) #else #define mysql_stage_set_work_completed(P1, P2) \ do {} while (0) #define mysql_stage_get_work_completed(P1) \ do {} while (0) #endif #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_stage_inc_work_completed(P1, P2) \ inline_mysql_stage_inc_work_completed(P1, P2) #else #define mysql_stage_inc_work_completed(P1, P2) \ do {} while (0) #endif #ifdef HAVE_PSI_STAGE_INTERFACE #define mysql_stage_set_work_estimated(P1, P2) \ inline_mysql_stage_set_work_estimated(P1, P2) #define mysql_stage_get_work_estimated(P1) \ inline_mysql_stage_get_work_estimated(P1) #else #define mysql_stage_set_work_estimated(P1, P2) \ do {} while (0) #define mysql_stage_get_work_estimated(P1) \ do {} while (0) #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline void inline_mysql_stage_set_work_completed(PSI_stage_progress *progress, ulonglong val) { if (progress != NULL) progress->m_work_completed= val; } static inline ulonglong inline_mysql_stage_get_work_completed(PSI_stage_progress *progress) { return progress->m_work_completed; } #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline void inline_mysql_stage_inc_work_completed(PSI_stage_progress *progress, ulonglong val) { if (progress != NULL) progress->m_work_completed+= val; } #endif #ifdef HAVE_PSI_STAGE_INTERFACE static inline void inline_mysql_stage_set_work_estimated(PSI_stage_progress *progress, ulonglong val) { if (progress != NULL) progress->m_work_estimated= val; } static inline ulonglong inline_mysql_stage_get_work_estimated(PSI_stage_progress *progress) { return progress->m_work_estimated; } #endif /** @} (end of group Stage_instrumentation) */ #endif server/mysql/psi/mysql_ps.h000064400000007447151031265040012043 0ustar00/* Copyright (c) 2014, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MYSQL_PS_H #define MYSQL_PS_H /** @file mysql/psi/mysql_ps.h Instrumentation helpers for prepared statements. */ #include "mysql/psi/psi.h" #ifndef PSI_PS_CALL #define PSI_PS_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifdef HAVE_PSI_PS_INTERFACE #define MYSQL_CREATE_PS(IDENTITY, ID, LOCKER, NAME, NAME_LENGTH) \ inline_mysql_create_prepared_stmt(IDENTITY, ID, LOCKER, NAME, NAME_LENGTH) #define MYSQL_EXECUTE_PS(LOCKER, PREPARED_STMT) \ inline_mysql_execute_prepared_stmt(LOCKER, PREPARED_STMT) #define MYSQL_DESTROY_PS(PREPARED_STMT) \ inline_mysql_destroy_prepared_stmt(PREPARED_STMT) #define MYSQL_REPREPARE_PS(PREPARED_STMT) \ inline_mysql_reprepare_prepared_stmt(PREPARED_STMT) #define MYSQL_SET_PS_TEXT(PREPARED_STMT, SQLTEXT, SQLTEXT_LENGTH) \ inline_mysql_set_prepared_stmt_text(PREPARED_STMT, SQLTEXT, SQLTEXT_LENGTH) #else #define MYSQL_CREATE_PS(IDENTITY, ID, LOCKER, NAME, NAME_LENGTH) \ NULL #define MYSQL_EXECUTE_PS(LOCKER, PREPARED_STMT) \ do {} while (0) #define MYSQL_DESTROY_PS(PREPARED_STMT) \ do {} while (0) #define MYSQL_REPREPARE_PS(PREPARED_STMT) \ do {} while (0) #define MYSQL_SET_PS_TEXT(PREPARED_STMT, SQLTEXT, SQLTEXT_LENGTH) \ do {} while (0) #endif #ifdef HAVE_PSI_PS_INTERFACE static inline struct PSI_prepared_stmt* inline_mysql_create_prepared_stmt(void *identity, uint stmt_id, PSI_statement_locker *locker, const char *stmt_name, size_t stmt_name_length) { if (locker == NULL) return NULL; return PSI_PS_CALL(create_prepared_stmt)(identity, stmt_id, locker, stmt_name, stmt_name_length); } static inline void inline_mysql_execute_prepared_stmt(PSI_statement_locker *locker, PSI_prepared_stmt* prepared_stmt) { if (prepared_stmt != NULL && locker != NULL) PSI_PS_CALL(execute_prepared_stmt)(locker, prepared_stmt); } static inline void inline_mysql_destroy_prepared_stmt(PSI_prepared_stmt *prepared_stmt) { if (prepared_stmt != NULL) PSI_PS_CALL(destroy_prepared_stmt)(prepared_stmt); } static inline void inline_mysql_reprepare_prepared_stmt(PSI_prepared_stmt *prepared_stmt) { if (prepared_stmt != NULL) PSI_PS_CALL(reprepare_prepared_stmt)(prepared_stmt); } static inline void inline_mysql_set_prepared_stmt_text(PSI_prepared_stmt *prepared_stmt, const char *text, uint text_len) { if (prepared_stmt != NULL) { PSI_PS_CALL(set_prepared_stmt_text)(prepared_stmt, text, text_len); } } #endif #endif server/mysql/psi/mysql_memory.h000064400000005067151031265040012725 0ustar00/* Copyright (c) 2012, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef MYSQL_MEMORY_H #define MYSQL_MEMORY_H /** @file mysql/psi/mysql_memory.h Instrumentation helpers for memory allocation. */ #include "mysql/psi/psi.h" #ifdef HAVE_PSI_MEMORY_INTERFACE #define PSI_CALL_memory_alloc(A1,A2,A3) PSI_MEMORY_CALL(memory_alloc)(A1,A2,A3) #define PSI_CALL_memory_free(A1,A2,A3) PSI_MEMORY_CALL(memory_free)(A1,A2,A3) #define PSI_CALL_memory_realloc(A1,A2,A3,A4) PSI_MEMORY_CALL(memory_realloc)(A1,A2,A3,A4) #define PSI_CALL_register_memory(A1,A2,A3) PSI_MEMORY_CALL(register_memory)(A1,A2,A3) #else #define PSI_CALL_memory_alloc(A1,A2,A3) 0 #define PSI_CALL_memory_free(A1,A2,A3) do { } while(0) #define PSI_CALL_memory_realloc(A1,A2,A3,A4) 0 #define PSI_CALL_register_memory(A1,A2,A3) do { } while(0) #endif #ifndef PSI_MEMORY_CALL #define PSI_MEMORY_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Memory_instrumentation Memory Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_memory_register(P1, P2, P3) Memory registration. */ #define mysql_memory_register(P1, P2, P3) \ inline_mysql_memory_register(P1, P2, P3) static inline void inline_mysql_memory_register( #ifdef HAVE_PSI_MEMORY_INTERFACE const char *category, PSI_memory_info *info, int count) #else const char *category __attribute__((unused)), void *info __attribute__((unused)), int count __attribute__((unused))) #endif { PSI_CALL_register_memory(category, info, count); } /** @} (end of group Memory_instrumentation) */ #endif server/mysql/psi/mysql_transaction.h000064400000016100151031265040013730 0ustar00/* Copyright (c) 2013, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MYSQL_TRANSACTION_H #define MYSQL_TRANSACTION_H /** @file mysql/psi/mysql_transaction.h Instrumentation helpers for transactions. */ #include "mysql/psi/psi.h" #ifndef PSI_TRANSACTION_CALL #define PSI_TRANSACTION_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Transaction_instrumentation Transaction Instrumentation @ingroup Instrumentation_interface @{ */ #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_START_TRANSACTION(STATE, XID, TRXID, ISO, RO, AC) \ inline_mysql_start_transaction(STATE, XID, TRXID, ISO, RO, AC, __FILE__, __LINE__) #else #define MYSQL_START_TRANSACTION(STATE, XID, TRXID, ISO, RO, AC) \ 0 #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_SET_TRANSACTION_GTID(LOCKER, P1, P2) \ inline_mysql_set_transaction_gtid(LOCKER, P1, P2) #else #define MYSQL_SET_TRANSACTION_GTID(LOCKER, P1, P2) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_SET_TRANSACTION_XID(LOCKER, P1, P2) \ inline_mysql_set_transaction_xid(LOCKER, P1, P2) #else #define MYSQL_SET_TRANSACTION_XID(LOCKER, P1, P2) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_SET_TRANSACTION_XA_STATE(LOCKER, P1) \ inline_mysql_set_transaction_xa_state(LOCKER, P1) #else #define MYSQL_SET_TRANSACTION_XA_STATE(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_SET_TRANSACTION_TRXID(LOCKER, P1) \ inline_mysql_set_transaction_trxid(LOCKER, P1) #else #define MYSQL_SET_TRANSACTION_TRXID(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_INC_TRANSACTION_SAVEPOINTS(LOCKER, P1) \ inline_mysql_inc_transaction_savepoints(LOCKER, P1) #else #define MYSQL_INC_TRANSACTION_SAVEPOINTS(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_INC_TRANSACTION_ROLLBACK_TO_SAVEPOINT(LOCKER, P1) \ inline_mysql_inc_transaction_rollback_to_savepoint(LOCKER, P1) #else #define MYSQL_INC_TRANSACTION_ROLLBACK_TO_SAVEPOINT(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_INC_TRANSACTION_RELEASE_SAVEPOINT(LOCKER, P1) \ inline_mysql_inc_transaction_release_savepoint(LOCKER, P1) #else #define MYSQL_INC_TRANSACTION_RELEASE_SAVEPOINT(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_ROLLBACK_TRANSACTION(LOCKER) \ inline_mysql_rollback_transaction(LOCKER) #else #define MYSQL_ROLLBACK_TRANSACTION(LOCKER) \ do { } while(0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE #define MYSQL_COMMIT_TRANSACTION(LOCKER) \ inline_mysql_commit_transaction(LOCKER) #else #define MYSQL_COMMIT_TRANSACTION(LOCKER) \ do { } while(0) #endif #ifdef HAVE_PSI_TRANSACTION_INTERFACE static inline struct PSI_transaction_locker * inline_mysql_start_transaction(PSI_transaction_locker_state *state, const void *xid, ulonglong trxid, int isolation_level, my_bool read_only, my_bool autocommit, const char *src_file, int src_line) { PSI_transaction_locker *locker; locker= PSI_TRANSACTION_CALL(get_thread_transaction_locker)(state, xid, trxid, isolation_level, read_only, autocommit); if (likely(locker != NULL)) PSI_TRANSACTION_CALL(start_transaction)(locker, src_file, src_line); return locker; } static inline void inline_mysql_set_transaction_gtid(PSI_transaction_locker *locker, const void *sid, const void *gtid_spec) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(set_transaction_gtid)(locker, sid, gtid_spec); } static inline void inline_mysql_set_transaction_xid(PSI_transaction_locker *locker, const void *xid, int xa_state) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(set_transaction_xid)(locker, xid, xa_state); } static inline void inline_mysql_set_transaction_xa_state(PSI_transaction_locker *locker, int xa_state) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(set_transaction_xa_state)(locker, xa_state); } static inline void inline_mysql_set_transaction_trxid(PSI_transaction_locker *locker, const ulonglong *trxid) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(set_transaction_trxid)(locker, trxid); } static inline void inline_mysql_inc_transaction_savepoints(PSI_transaction_locker *locker, ulong count) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(inc_transaction_savepoints)(locker, count); } static inline void inline_mysql_inc_transaction_rollback_to_savepoint(PSI_transaction_locker *locker, ulong count) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(inc_transaction_rollback_to_savepoint)(locker, count); } static inline void inline_mysql_inc_transaction_release_savepoint(PSI_transaction_locker *locker, ulong count) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(inc_transaction_release_savepoint)(locker, count); } static inline void inline_mysql_rollback_transaction(struct PSI_transaction_locker *locker) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(end_transaction)(locker, false); } static inline void inline_mysql_commit_transaction(struct PSI_transaction_locker *locker) { if (likely(locker != NULL)) PSI_TRANSACTION_CALL(end_transaction)(locker, true); } #endif /** @} (end of group Transaction_instrumentation) */ #endif server/mysql/psi/mysql_sp.h000064400000006250151031265040012032 0ustar00/* Copyright (c) 2013, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MYSQL_SP_H #define MYSQL_SP_H /** @file mysql/psi/mysql_sp.h Instrumentation helpers for stored programs. */ #include "mysql/psi/psi.h" #ifndef PSI_SP_CALL #define PSI_SP_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifdef HAVE_PSI_SP_INTERFACE #define MYSQL_START_SP(STATE, SP_SHARE) \ inline_mysql_start_sp(STATE, SP_SHARE) #else #define MYSQL_START_SP(STATE, SP_SHARE) \ NULL #endif #ifdef HAVE_PSI_SP_INTERFACE #define MYSQL_END_SP(LOCKER) \ inline_mysql_end_sp(LOCKER) #else #define MYSQL_END_SP(LOCKER) \ do {} while (0) #endif #ifdef HAVE_PSI_SP_INTERFACE #define MYSQL_DROP_SP(OT, SN, SNL, ON, ONL) \ inline_mysql_drop_sp(OT, SN, SNL, ON, ONL) #else #define MYSQL_DROP_SP(OT, SN, SNL, ON, ONL) \ do {} while (0) #endif #ifdef HAVE_PSI_SP_INTERFACE #define MYSQL_GET_SP_SHARE(OT, SN, SNL, ON, ONL) \ inline_mysql_get_sp_share(OT, SN, SNL, ON, ONL) #else #define MYSQL_GET_SP_SHARE(OT, SN, SNL, ON, ONL) \ NULL #endif #ifdef HAVE_PSI_SP_INTERFACE static inline struct PSI_sp_locker* inline_mysql_start_sp(PSI_sp_locker_state *state, PSI_sp_share *sp_share) { return PSI_SP_CALL(start_sp)(state, sp_share); } static inline void inline_mysql_end_sp(PSI_sp_locker *locker) { if (likely(locker != NULL)) PSI_SP_CALL(end_sp)(locker); } static inline void inline_mysql_drop_sp(uint sp_type, const char* schema_name, uint shcema_name_length, const char* object_name, uint object_name_length) { PSI_SP_CALL(drop_sp)(sp_type, schema_name, shcema_name_length, object_name, object_name_length); } static inline PSI_sp_share* inline_mysql_get_sp_share(uint sp_type, const char* schema_name, uint shcema_name_length, const char* object_name, uint object_name_length) { return PSI_SP_CALL(get_sp_share)(sp_type, schema_name, shcema_name_length, object_name, object_name_length); } #endif #endif server/mysql/psi/mysql_file.h000064400000117763151031265040012343 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_FILE_H #define MYSQL_FILE_H /* For strlen() */ #include /* For MY_STAT */ #include /* For my_chsize */ #include /** @file mysql/psi/mysql_file.h Instrumentation helpers for mysys file io. This header file provides the necessary declarations to use the mysys file API with the performance schema instrumentation. In some compilers (SunStudio), 'static inline' functions, when declared but not used, are not optimized away (because they are unused) by default, so that including a static inline function from a header file does create unwanted dependencies, causing unresolved symbols at link time. Other compilers, like gcc, optimize these dependencies by default. Since the instrumented APIs declared here are wrapper on top of mysys file io APIs, including mysql/psi/mysql_file.h assumes that the dependency on my_sys already exists. */ #include "mysql/psi/psi.h" #ifndef PSI_FILE_CALL #define PSI_FILE_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup File_instrumentation File Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_file_register(P1, P2, P3) File registration. */ #define mysql_file_register(P1, P2, P3) \ inline_mysql_file_register(P1, P2, P3) /** @def mysql_file_fgets(P1, P2, F) Instrumented fgets. @c mysql_file_fgets is a replacement for @c fgets. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fgets(P1, P2, F) \ inline_mysql_file_fgets(__FILE__, __LINE__, P1, P2, F) #else #define mysql_file_fgets(P1, P2, F) \ inline_mysql_file_fgets(P1, P2, F) #endif /** @def mysql_file_fgetc(F) Instrumented fgetc. @c mysql_file_fgetc is a replacement for @c fgetc. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fgetc(F) inline_mysql_file_fgetc(__FILE__, __LINE__, F) #else #define mysql_file_fgetc(F) inline_mysql_file_fgetc(F) #endif /** @def mysql_file_fputs(P1, F) Instrumented fputs. @c mysql_file_fputs is a replacement for @c fputs. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fputs(P1, F) \ inline_mysql_file_fputs(__FILE__, __LINE__, P1, F) #else #define mysql_file_fputs(P1, F)\ inline_mysql_file_fputs(P1, F) #endif /** @def mysql_file_fputc(P1, F) Instrumented fputc. @c mysql_file_fputc is a replacement for @c fputc. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fputc(P1, F) \ inline_mysql_file_fputc(__FILE__, __LINE__, P1, F) #else #define mysql_file_fputc(P1, F) \ inline_mysql_file_fputc(P1, F) #endif /** @def mysql_file_fprintf Instrumented fprintf. @c mysql_file_fprintf is a replacement for @c fprintf. */ #define mysql_file_fprintf inline_mysql_file_fprintf /** @def mysql_file_vfprintf(F, P1, P2) Instrumented vfprintf. @c mysql_file_vfprintf is a replacement for @c vfprintf. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_vfprintf(F, P1, P2) \ inline_mysql_file_vfprintf(__FILE__, __LINE__, F, P1, P2) #else #define mysql_file_vfprintf(F, P1, P2) \ inline_mysql_file_vfprintf(F, P1, P2) #endif /** @def mysql_file_fflush(F, P1, P2) Instrumented fflush. @c mysql_file_fflush is a replacement for @c fflush. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fflush(F) \ inline_mysql_file_fflush(__FILE__, __LINE__, F) #else #define mysql_file_fflush(F) \ inline_mysql_file_fflush(F) #endif /** @def mysql_file_feof(F) Instrumented feof. @c mysql_file_feof is a replacement for @c feof. */ #define mysql_file_feof(F) inline_mysql_file_feof(F) /** @def mysql_file_fstat(FN, S, FL) Instrumented fstat. @c mysql_file_fstat is a replacement for @c my_fstat. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fstat(FN, S, FL) \ inline_mysql_file_fstat(__FILE__, __LINE__, FN, S, FL) #else #define mysql_file_fstat(FN, S, FL) \ inline_mysql_file_fstat(FN, S, FL) #endif /** @def mysql_file_stat(K, FN, S, FL) Instrumented stat. @c mysql_file_stat is a replacement for @c my_stat. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_stat(K, FN, S, FL) \ inline_mysql_file_stat(K, __FILE__, __LINE__, FN, S, FL) #else #define mysql_file_stat(K, FN, S, FL) \ inline_mysql_file_stat(FN, S, FL) #endif /** @def mysql_file_chsize(F, P1, P2, P3) Instrumented chsize. @c mysql_file_chsize is a replacement for @c my_chsize. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_chsize(F, P1, P2, P3) \ inline_mysql_file_chsize(__FILE__, __LINE__, F, P1, P2, P3) #else #define mysql_file_chsize(F, P1, P2, P3) \ inline_mysql_file_chsize(F, P1, P2, P3) #endif /** @def mysql_file_fopen(K, N, F1, F2) Instrumented fopen. @c mysql_file_fopen is a replacement for @c my_fopen. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fopen(K, N, F1, F2) \ inline_mysql_file_fopen(K, __FILE__, __LINE__, N, F1, F2) #else #define mysql_file_fopen(K, N, F1, F2) \ inline_mysql_file_fopen(N, F1, F2) #endif /** @def mysql_file_fclose(FD, FL) Instrumented fclose. @c mysql_file_fclose is a replacement for @c my_fclose. Without the instrumentation, this call will have the same behavior as the undocumented and possibly platform specific my_fclose(NULL, ...) behavior. With the instrumentation, mysql_fclose(NULL, ...) will safely return 0, which is an extension compared to my_fclose and is therefore compliant. mysql_fclose is on purpose *not* implementing @code assert(file != NULL) @endcode, since doing so could introduce regressions. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fclose(FD, FL) \ inline_mysql_file_fclose(__FILE__, __LINE__, FD, FL) #else #define mysql_file_fclose(FD, FL) \ inline_mysql_file_fclose(FD, FL) #endif /** @def mysql_file_fread(FD, P1, P2, P3) Instrumented fread. @c mysql_file_fread is a replacement for @c my_fread. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fread(FD, P1, P2, P3) \ inline_mysql_file_fread(__FILE__, __LINE__, FD, P1, P2, P3) #else #define mysql_file_fread(FD, P1, P2, P3) \ inline_mysql_file_fread(FD, P1, P2, P3) #endif /** @def mysql_file_fwrite(FD, P1, P2, P3) Instrumented fwrite. @c mysql_file_fwrite is a replacement for @c my_fwrite. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fwrite(FD, P1, P2, P3) \ inline_mysql_file_fwrite(__FILE__, __LINE__, FD, P1, P2, P3) #else #define mysql_file_fwrite(FD, P1, P2, P3) \ inline_mysql_file_fwrite(FD, P1, P2, P3) #endif /** @def mysql_file_fseek(FD, P, W, F) Instrumented fseek. @c mysql_file_fseek is a replacement for @c my_fseek. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_fseek(FD, P, W, F) \ inline_mysql_file_fseek(__FILE__, __LINE__, FD, P, W, F) #else #define mysql_file_fseek(FD, P, W, F) \ inline_mysql_file_fseek(FD, P, W, F) #endif /** @def mysql_file_ftell(FD, F) Instrumented ftell. @c mysql_file_ftell is a replacement for @c my_ftell. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_ftell(FD, F) \ inline_mysql_file_ftell(__FILE__, __LINE__, FD, F) #else #define mysql_file_ftell(FD, F) \ inline_mysql_file_ftell(FD, F) #endif /** @def mysql_file_create(K, N, F1, F2, F3) Instrumented create. @c mysql_file_create is a replacement for @c my_create. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_create(K, N, F1, F2, F3) \ inline_mysql_file_create(K, __FILE__, __LINE__, N, F1, F2, F3) #else #define mysql_file_create(K, N, F1, F2, F3) \ inline_mysql_file_create(N, F1, F2, F3) #endif /** @def mysql_file_create_temp(K, T, D, P, M, F) Instrumented create_temp_file. @c mysql_file_create_temp is a replacement for @c create_temp_file. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_create_temp(K, T, D, P, M, F) \ inline_mysql_file_create_temp(K, __FILE__, __LINE__, T, D, P, M, F) #else #define mysql_file_create_temp(K, T, D, P, M, F) \ inline_mysql_file_create_temp(T, D, P, M, F) #endif /** @def mysql_file_open(K, N, F1, F2) Instrumented open. @c mysql_file_open is a replacement for @c my_open. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_open(K, N, F1, F2) \ inline_mysql_file_open(K, __FILE__, __LINE__, N, F1, F2) #else #define mysql_file_open(K, N, F1, F2) \ inline_mysql_file_open(N, F1, F2) #endif /** @def mysql_file_close(FD, F) Instrumented close. @c mysql_file_close is a replacement for @c my_close. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_close(FD, F) \ inline_mysql_file_close(__FILE__, __LINE__, FD, F) #else #define mysql_file_close(FD, F) \ inline_mysql_file_close(FD, F) #endif /** @def mysql_file_read(FD, B, S, F) Instrumented read. @c mysql_read is a replacement for @c my_read. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_read(FD, B, S, F) \ inline_mysql_file_read(__FILE__, __LINE__, FD, B, S, F) #else #define mysql_file_read(FD, B, S, F) \ inline_mysql_file_read(FD, B, S, F) #endif /** @def mysql_file_write(FD, B, S, F) Instrumented write. @c mysql_file_write is a replacement for @c my_write. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_write(FD, B, S, F) \ inline_mysql_file_write(__FILE__, __LINE__, FD, B, S, F) #else #define mysql_file_write(FD, B, S, F) \ inline_mysql_file_write(FD, B, S, F) #endif /** @def mysql_file_pread(FD, B, S, O, F) Instrumented pread. @c mysql_pread is a replacement for @c my_pread. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_pread(FD, B, S, O, F) \ inline_mysql_file_pread(__FILE__, __LINE__, FD, B, S, O, F) #else #define mysql_file_pread(FD, B, S, O, F) \ inline_mysql_file_pread(FD, B, S, O, F) #endif /** @def mysql_file_pwrite(FD, B, S, O, F) Instrumented pwrite. @c mysql_file_pwrite is a replacement for @c my_pwrite. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_pwrite(FD, B, S, O, F) \ inline_mysql_file_pwrite(__FILE__, __LINE__, FD, B, S, O, F) #else #define mysql_file_pwrite(FD, B, S, O, F) \ inline_mysql_file_pwrite(FD, B, S, O, F) #endif /** @def mysql_file_seek(FD, P, W, F) Instrumented seek. @c mysql_file_seek is a replacement for @c my_seek. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_seek(FD, P, W, F) \ inline_mysql_file_seek(__FILE__, __LINE__, FD, P, W, F) #else #define mysql_file_seek(FD, P, W, F) \ inline_mysql_file_seek(FD, P, W, F) #endif /** @def mysql_file_tell(FD, F) Instrumented tell. @c mysql_file_tell is a replacement for @c my_tell. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_tell(FD, F) \ inline_mysql_file_tell(__FILE__, __LINE__, FD, F) #else #define mysql_file_tell(FD, F) \ inline_mysql_file_tell(FD, F) #endif /** @def mysql_file_delete(K, P1, P2) Instrumented delete. @c mysql_file_delete is a replacement for @c my_delete. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_delete(K, P1, P2) \ inline_mysql_file_delete(K, __FILE__, __LINE__, P1, P2) #else #define mysql_file_delete(K, P1, P2) \ inline_mysql_file_delete(P1, P2) #endif /** @def mysql_file_rename(K, P1, P2, P3) Instrumented rename. @c mysql_file_rename is a replacement for @c my_rename. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_rename(K, P1, P2, P3) \ inline_mysql_file_rename(K, __FILE__, __LINE__, P1, P2, P3) #else #define mysql_file_rename(K, P1, P2, P3) \ inline_mysql_file_rename(P1, P2, P3) #endif /** @def mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) Instrumented create with symbolic link. @c mysql_file_create_with_symlink is a replacement for @c my_create_with_symlink. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) \ inline_mysql_file_create_with_symlink(K, __FILE__, __LINE__, \ P1, P2, P3, P4, P5) #else #define mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) \ inline_mysql_file_create_with_symlink(P1, P2, P3, P4, P5) #endif /** @def mysql_file_delete_with_symlink(K, P1, P2, P3) Instrumented delete with symbolic link. @c mysql_file_delete_with_symlink is a replacement for @c my_handler_delete_with_symlink. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_delete_with_symlink(K, P1, P2, P3) \ inline_mysql_file_delete_with_symlink(K, __FILE__, __LINE__, P1, P2, P3) #else #define mysql_file_delete_with_symlink(K, P1, P2, P3) \ inline_mysql_file_delete_with_symlink(P1, P2, P3) #endif /** @def mysql_file_rename_with_symlink(K, P1, P2, P3) Instrumented rename with symbolic link. @c mysql_file_rename_with_symlink is a replacement for @c my_rename_with_symlink. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_rename_with_symlink(K, P1, P2, P3) \ inline_mysql_file_rename_with_symlink(K, __FILE__, __LINE__, P1, P2, P3) #else #define mysql_file_rename_with_symlink(K, P1, P2, P3) \ inline_mysql_file_rename_with_symlink(P1, P2, P3) #endif /** @def mysql_file_sync(P1, P2) Instrumented file sync. @c mysql_file_sync is a replacement for @c my_sync. */ #ifdef HAVE_PSI_FILE_INTERFACE #define mysql_file_sync(P1, P2) \ inline_mysql_file_sync(__FILE__, __LINE__, P1, P2) #else #define mysql_file_sync(P1, P2) \ inline_mysql_file_sync(P1, P2) #endif /** An instrumented FILE structure. @sa MYSQL_FILE */ struct st_mysql_file { /** The real file. */ FILE *m_file; /** The instrumentation hook. Note that this hook is not conditionally defined, for binary compatibility of the @c MYSQL_FILE interface. */ struct PSI_file *m_psi; }; /** Type of an instrumented file. @c MYSQL_FILE is a drop-in replacement for @c FILE. @sa mysql_file_open */ typedef struct st_mysql_file MYSQL_FILE; static inline void inline_mysql_file_register( #ifdef HAVE_PSI_FILE_INTERFACE const char *category, PSI_file_info *info, int count #else const char *category __attribute__ ((unused)), void *info __attribute__ ((unused)), int count __attribute__ ((unused)) #endif ) { #ifdef HAVE_PSI_FILE_INTERFACE PSI_FILE_CALL(register_file)(category, info, count); #endif } static inline char * inline_mysql_file_fgets( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif char *str, int size, MYSQL_FILE *file) { char *result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker) (&state, file->m_psi, PSI_FILE_READ); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) size, src_file, src_line); result= fgets(str, size, file->m_file); PSI_FILE_CALL(end_file_wait)(locker, result ? strlen(result) : 0); return result; } } #endif result= fgets(str, size, file->m_file); return result; } static inline int inline_mysql_file_fgetc( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file) { int result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_READ); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 1, src_file, src_line); result= fgetc(file->m_file); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 1); return result; } } #endif result= fgetc(file->m_file); return result; } static inline int inline_mysql_file_fputs( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif const char *str, MYSQL_FILE *file) { int result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes; locker= PSI_FILE_CALL(get_thread_file_stream_locker) (&state, file->m_psi, PSI_FILE_WRITE); if (likely(locker != NULL)) { bytes= str ? strlen(str) : 0; PSI_FILE_CALL(start_file_wait)(locker, bytes, src_file, src_line); result= fputs(str, file->m_file); PSI_FILE_CALL(end_file_wait)(locker, bytes); return result; } } #endif result= fputs(str, file->m_file); return result; } static inline int inline_mysql_file_fputc( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif char c, MYSQL_FILE *file) { int result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker) (&state, file->m_psi, PSI_FILE_WRITE); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 1, src_file, src_line); result= fputc(c, file->m_file); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 1); return result; } } #endif result= fputc(c, file->m_file); return result; } static inline int inline_mysql_file_fprintf(MYSQL_FILE *file, const char *format, ...) { /* TODO: figure out how to pass src_file and src_line from the caller. */ int result; va_list args; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker) (&state, file->m_psi, PSI_FILE_WRITE); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, __FILE__, __LINE__); va_start(args, format); result= vfprintf(file->m_file, format, args); va_end(args); PSI_FILE_CALL(end_file_wait)(locker, (size_t) result); return result; } } #endif va_start(args, format); result= vfprintf(file->m_file, format, args); va_end(args); return result; } static inline int inline_mysql_file_vfprintf( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, const char *format, va_list args) { int result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker) (&state, file->m_psi, PSI_FILE_WRITE); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= vfprintf(file->m_file, format, args); PSI_FILE_CALL(end_file_wait)(locker, (size_t) result); return result; } } #endif result= vfprintf(file->m_file, format, args); return result; } static inline int inline_mysql_file_fflush( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file) { int result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_FLUSH); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= fflush(file->m_file); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } } #endif result= fflush(file->m_file); return result; } static inline int inline_mysql_file_feof(MYSQL_FILE *file) { /* Not instrumented, there is no wait involved */ return feof(file->m_file); } static inline int inline_mysql_file_fstat( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif int filenr, MY_STAT *stat_area, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, filenr, PSI_FILE_FSTAT); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_fstat(filenr, stat_area, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } #endif result= my_fstat(filenr, stat_area, flags); return result; } static inline MY_STAT * inline_mysql_file_stat( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *path, MY_STAT *stat_area, myf flags) { MY_STAT *result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_STAT, path, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); result= my_stat(path, stat_area, flags); PSI_FILE_CALL(end_file_open_wait)(locker, result); return result; } #endif result= my_stat(path, stat_area, flags); return result; } static inline int inline_mysql_file_chsize( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, my_off_t newlength, int filler, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_CHSIZE); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) newlength, src_file, src_line); result= my_chsize(file, newlength, filler, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) newlength); return result; } #endif result= my_chsize(file, newlength, filler, flags); return result; } static inline MYSQL_FILE* inline_mysql_file_fopen( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *filename, int flags, myf myFlags) { MYSQL_FILE *that; that= (MYSQL_FILE*) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(MYSQL_FILE), MYF(MY_WME)); if (likely(that != NULL)) { #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_STREAM_OPEN, filename, that); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); that->m_file= my_fopen(filename, flags, myFlags); that->m_psi= PSI_FILE_CALL(end_file_open_wait)(locker, that->m_file); if (unlikely(that->m_file == NULL)) { my_free(that); return NULL; } return that; } #endif that->m_psi= NULL; that->m_file= my_fopen(filename, flags, myFlags); if (unlikely(that->m_file == NULL)) { my_free(that); return NULL; } } return that; } static inline int inline_mysql_file_fclose( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, myf flags) { int result= 0; if (likely(file != NULL)) { #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_STREAM_CLOSE); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_close_wait)(locker, src_file, src_line); result= my_fclose(file->m_file, flags); PSI_FILE_CALL(end_file_close_wait)(locker, result); my_free(file); return result; } } #endif result= my_fclose(file->m_file, flags); my_free(file); } return result; } static inline size_t inline_mysql_file_fread( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, uchar *buffer, size_t count, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_read; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_READ); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_fread(file->m_file, buffer, count, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_read= (result == 0) ? count : 0; else bytes_read= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_read); return result; } } #endif result= my_fread(file->m_file, buffer, count, flags); return result; } static inline size_t inline_mysql_file_fwrite( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, const uchar *buffer, size_t count, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_written; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_WRITE); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_fwrite(file->m_file, buffer, count, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_written= (result == 0) ? count : 0; else bytes_written= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_written); return result; } } #endif result= my_fwrite(file->m_file, buffer, count, flags); return result; } static inline my_off_t inline_mysql_file_fseek( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, my_off_t pos, int whence, myf flags) { my_off_t result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_SEEK); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_fseek(file->m_file, pos, whence, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } } #endif result= my_fseek(file->m_file, pos, whence, flags); return result; } static inline my_off_t inline_mysql_file_ftell( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif MYSQL_FILE *file, myf flags) { my_off_t result; #ifdef HAVE_PSI_FILE_INTERFACE if (psi_likely(file->m_psi)) { struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_stream_locker)(&state, file->m_psi, PSI_FILE_TELL); if (likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_ftell(file->m_file, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } } #endif result= my_ftell(file->m_file, flags); return result; } static inline File inline_mysql_file_create( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *filename, mode_t create_flags, int access_flags, myf myFlags) { File file; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_CREATE, filename, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); file= my_create(filename, create_flags, access_flags, myFlags); PSI_FILE_CALL(end_file_open_wait_and_bind_to_descriptor)(locker, file); return file; } #endif file= my_create(filename, create_flags, access_flags, myFlags); return file; } static inline File inline_mysql_file_create_temp( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif char *to, const char *dir, const char *pfx, int mode, myf myFlags) { File file; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker) (&state, key, PSI_FILE_CREATE, NULL, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); /* The file name is generated by create_temp_file(). */ file= create_temp_file(to, dir, pfx, mode, myFlags); PSI_FILE_CALL(end_temp_file_open_wait_and_bind_to_descriptor)(locker, file, (const char*)to); return file; } #endif file= create_temp_file(to, dir, pfx, mode, myFlags); return file; } static inline File inline_mysql_file_open( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *filename, int flags, myf myFlags) { File file; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_OPEN, filename, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); file= my_open(filename, flags, myFlags); PSI_FILE_CALL(end_file_open_wait_and_bind_to_descriptor)(locker, file); return file; } #endif file= my_open(filename, flags, myFlags); return file; } static inline int inline_mysql_file_close( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_CLOSE); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_close_wait)(locker, src_file, src_line); result= my_close(file, flags); PSI_FILE_CALL(end_file_close_wait)(locker, result); return result; } #endif result= my_close(file, flags); return result; } static inline size_t inline_mysql_file_read( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, uchar *buffer, size_t count, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_read; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_READ); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_read(file, buffer, count, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_read= (result == 0) ? count : 0; else bytes_read= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_read); return result; } #endif result= my_read(file, buffer, count, flags); return result; } static inline size_t inline_mysql_file_write( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, const uchar *buffer, size_t count, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_written; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_WRITE); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_write(file, buffer, count, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_written= (result == 0) ? count : 0; else bytes_written= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_written); return result; } #endif result= my_write(file, buffer, count, flags); return result; } static inline size_t inline_mysql_file_pread( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, uchar *buffer, size_t count, my_off_t offset, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_read; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_READ); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_pread(file, buffer, count, offset, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_read= (result == 0) ? count : 0; else bytes_read= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_read); return result; } #endif result= my_pread(file, buffer, count, offset, flags); return result; } static inline size_t inline_mysql_file_pwrite( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, const uchar *buffer, size_t count, my_off_t offset, myf flags) { size_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; size_t bytes_written; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_WRITE); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, count, src_file, src_line); result= my_pwrite(file, buffer, count, offset, flags); if (flags & (MY_NABP | MY_FNABP)) bytes_written= (result == 0) ? count : 0; else bytes_written= (result != MY_FILE_ERROR) ? result : 0; PSI_FILE_CALL(end_file_wait)(locker, bytes_written); return result; } #endif result= my_pwrite(file, buffer, count, offset, flags); return result; } static inline my_off_t inline_mysql_file_seek( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, my_off_t pos, int whence, myf flags) { my_off_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_SEEK); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_seek(file, pos, whence, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } #endif result= my_seek(file, pos, whence, flags); return result; } static inline my_off_t inline_mysql_file_tell( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File file, myf flags) { my_off_t result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, file, PSI_FILE_TELL); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_tell(file, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } #endif result= my_tell(file, flags); return result; } static inline int inline_mysql_file_delete( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *name, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_DELETE, name, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_close_wait)(locker, src_file, src_line); result= my_delete(name, flags); PSI_FILE_CALL(end_file_close_wait)(locker, result); return result; } #endif result= my_delete(name, flags); return result; } static inline int inline_mysql_file_rename( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *from, const char *to, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker) (&state, key, PSI_FILE_RENAME, from, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_rename(from, to, flags); PSI_FILE_CALL(end_file_rename_wait)(locker, from, to, result); return result; } #endif result= my_rename(from, to, flags); return result; } static inline File inline_mysql_file_create_with_symlink( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *linkname, const char *filename, mode_t create_flags, int access_flags, myf flags) { File file; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_CREATE, filename, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_open_wait)(locker, src_file, src_line); file= my_create_with_symlink(linkname, filename, create_flags, access_flags, flags); PSI_FILE_CALL(end_file_open_wait_and_bind_to_descriptor)(locker, file); return file; } #endif file= my_create_with_symlink(linkname, filename, create_flags, access_flags, flags); return file; } static inline int inline_mysql_file_delete_with_symlink( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *name, const char *ext, myf flags) { int result; char buf[FN_REFLEN]; char *fullname= fn_format(buf, name, "", ext, MY_UNPACK_FILENAME | MY_APPEND_EXT); #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker)(&state, key, PSI_FILE_DELETE, fullname, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_close_wait)(locker, src_file, src_line); result= my_handler_delete_with_symlink(fullname, flags); PSI_FILE_CALL(end_file_close_wait)(locker, result); return result; } #endif result= my_handler_delete_with_symlink(fullname, flags); return result; } static inline int inline_mysql_file_rename_with_symlink( #ifdef HAVE_PSI_FILE_INTERFACE PSI_file_key key, const char *src_file, uint src_line, #endif const char *from, const char *to, myf flags) { int result; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_name_locker) (&state, key, PSI_FILE_RENAME, from, &locker); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_rename_with_symlink(from, to, flags); PSI_FILE_CALL(end_file_rename_wait)(locker, from, to, result); return result; } #endif result= my_rename_with_symlink(from, to, flags); return result; } static inline int inline_mysql_file_sync( #ifdef HAVE_PSI_FILE_INTERFACE const char *src_file, uint src_line, #endif File fd, myf flags) { int result= 0; #ifdef HAVE_PSI_FILE_INTERFACE struct PSI_file_locker *locker; PSI_file_locker_state state; locker= PSI_FILE_CALL(get_thread_file_descriptor_locker)(&state, fd, PSI_FILE_SYNC); if (psi_likely(locker != NULL)) { PSI_FILE_CALL(start_file_wait)(locker, (size_t) 0, src_file, src_line); result= my_sync(fd, flags); PSI_FILE_CALL(end_file_wait)(locker, (size_t) 0); return result; } #endif result= my_sync(fd, flags); return result; } /** @} (end of group File_instrumentation) */ #endif server/mysql/psi/mysql_idle.h000064400000005743151031265040012333 0ustar00/* Copyright (c) 2011, 2023, Oracle and/or its affiliates Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_IDLE_H #define MYSQL_IDLE_H /** @file mysql/psi/mysql_idle.h Instrumentation helpers for idle waits. */ #include "mysql/psi/psi.h" #ifndef PSI_IDLE_CALL #define PSI_IDLE_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Idle_instrumentation Idle Instrumentation @ingroup Instrumentation_interface @{ */ /** @def MYSQL_START_IDLE_WAIT Instrumentation helper for table io_waits. This instrumentation marks the start of a wait event. @param LOCKER the locker @param STATE the locker state @sa MYSQL_END_IDLE_WAIT. */ #ifdef HAVE_PSI_IDLE_INTERFACE #define MYSQL_START_IDLE_WAIT(LOCKER, STATE) \ LOCKER= inline_mysql_start_idle_wait(STATE, __FILE__, __LINE__) #else #define MYSQL_START_IDLE_WAIT(LOCKER, STATE) \ do {} while (0) #endif /** @def MYSQL_END_IDLE_WAIT Instrumentation helper for idle waits. This instrumentation marks the end of a wait event. @param LOCKER the locker @sa MYSQL_START_IDLE_WAIT. */ #ifdef HAVE_PSI_IDLE_INTERFACE #define MYSQL_END_IDLE_WAIT(LOCKER) \ inline_mysql_end_idle_wait(LOCKER) #else #define MYSQL_END_IDLE_WAIT(LOCKER) \ do {} while (0) #endif #ifdef HAVE_PSI_IDLE_INTERFACE /** Instrumentation calls for MYSQL_START_IDLE_WAIT. @sa MYSQL_END_IDLE_WAIT. */ static inline struct PSI_idle_locker * inline_mysql_start_idle_wait(PSI_idle_locker_state *state, const char *src_file, uint src_line) { struct PSI_idle_locker *locker; locker= PSI_IDLE_CALL(start_idle_wait)(state, src_file, src_line); return locker; } /** Instrumentation calls for MYSQL_END_IDLE_WAIT. @sa MYSQL_START_IDLE_WAIT. */ static inline void inline_mysql_end_idle_wait(struct PSI_idle_locker *locker) { if (psi_likely(locker != NULL)) PSI_IDLE_CALL(end_idle_wait)(locker); } #endif /** @} (end of group Idle_instrumentation) */ #endif server/mysql/psi/psi_abi_v1.h000064400000002667151031265040012207 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file mysql/psi/psi_abi_v1.h ABI check for mysql/psi/psi.h, when using PSI_VERSION_1. This file is only used to automate detection of changes between versions. Do not include this file, include mysql/psi/psi.h instead. */ #define USE_PSI_1 #define HAVE_PSI_INTERFACE #define MY_GLOBAL_INCLUDED #include "mysql/psi/psi.h" server/mysql/psi/psi_memory.h000064400000010771151031265040012351 0ustar00/* Copyright (c) 2013, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. Without limiting anything contained in the foregoing, this file, which is part of C Driver for MySQL (Connector/C), is also subject to the Universal FOSS Exception, version 1.0, a copy of which can be found at http://oss.oracle.com/licenses/universal-foss-exception. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_PSI_MEMORY_H #define MYSQL_PSI_MEMORY_H #include "psi_base.h" #ifdef __cplusplus extern "C" { #endif /** @file mysql/psi/psi_memory.h Performance schema instrumentation interface. @defgroup Instrumentation_interface Instrumentation Interface @ingroup Performance_schema @{ */ #ifdef HAVE_PSI_INTERFACE #ifndef DISABLE_ALL_PSI #ifndef DISABLE_PSI_MEMORY #define HAVE_PSI_MEMORY_INTERFACE #endif /* DISABLE_PSI_MEMORY */ #endif /* DISABLE_ALL_PSI */ #endif /* HAVE_PSI_INTERFACE */ struct PSI_thread; #ifdef HAVE_PSI_1 /** @defgroup Group_PSI_v1 Application Binary Interface, version 1 @ingroup Instrumentation_interface @{ */ /** Memory instrument information. @since PSI_VERSION_1 This structure is used to register instrumented memory. */ struct PSI_memory_info_v1 { /** Pointer to the key assigned to the registered memory. */ PSI_memory_key *m_key; /** The name of the memory instrument to register. */ const char *m_name; /** The flags of the socket instrument to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_memory_info_v1 PSI_memory_info_v1; /** Memory registration API. @param category a category name (typically a plugin name) @param info an array of memory info to register @param count the size of the info array */ typedef void (*register_memory_v1_t) (const char *category, struct PSI_memory_info_v1 *info, int count); /** Instrument memory allocation. @param key the memory instrument key @param size the size of memory allocated @param[out] owner the memory owner @return the effective memory instrument key */ typedef PSI_memory_key (*memory_alloc_v1_t) (PSI_memory_key key, size_t size, struct PSI_thread ** owner); /** Instrument memory re allocation. @param key the memory instrument key @param old_size the size of memory previously allocated @param new_size the size of memory re allocated @param[in, out] owner the memory owner @return the effective memory instrument key */ typedef PSI_memory_key (*memory_realloc_v1_t) (PSI_memory_key key, size_t old_size, size_t new_size, struct PSI_thread ** owner); /** Instrument memory claim. @param key the memory instrument key @param size the size of memory allocated @param[in, out] owner the memory owner @return the effective memory instrument key */ typedef PSI_memory_key (*memory_claim_v1_t) (PSI_memory_key key, size_t size, struct PSI_thread ** owner); /** Instrument memory free. @param key the memory instrument key @param size the size of memory allocated @param owner the memory owner */ typedef void (*memory_free_v1_t) (PSI_memory_key key, size_t size, struct PSI_thread * owner); /** @} (end of group Group_PSI_v1) */ #ifdef _AIX PSI_memory_key key_memory_log_event; #endif #endif /* HAVE_PSI_1 */ #ifdef HAVE_PSI_2 struct PSI_memory_info_v2 { int placeholder; }; #endif /* HAVE_PSI_2 */ #ifdef USE_PSI_1 typedef struct PSI_memory_info_v1 PSI_memory_info; #endif #ifdef USE_PSI_2 typedef struct PSI_memory_info_v2 PSI_memory_info; #endif /** @} (end of group Instrumentation_interface) */ #ifdef __cplusplus } #endif #endif /* MYSQL_PSI_MEMORY_H */ server/mysql/psi/psi.h000064400000253735151031265040010772 0ustar00/* Copyright (c) 2008, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H #define MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H #ifndef MY_GLOBAL_INCLUDED /* Make sure a .c or .cc file contains an include to my_global.h first. When this include is missing, all the #ifdef HAVE_XXX have no effect, and the resulting binary won't build, or won't link, or will crash at runtime since various structures will have different binary definitions. */ #error "You must include my_global.h in the code for the build to be correct." #endif /* If PSI_ON_BY_DFAULT is defined, assume PSI will be enabled by default and optimize jumps testing for PSI this case. If not, optimize the binary for that PSI is not enabled */ #ifdef PSI_ON_BY_DEFAULT #define psi_likely(A) likely(A) #define psi_unlikely(A) unlikely(A) #else #define psi_likely(A) unlikely(A) #define psi_unlikely(A) likely(A) #endif #include "psi_base.h" #include "psi_memory.h" #ifdef _WIN32 typedef struct thread_attr pthread_attr_t; typedef DWORD pthread_t; typedef DWORD pthread_key_t; #endif /* MAINTAINER: The following pattern: typedef struct XYZ XYZ; is not needed in C++, but required for C. */ C_MODE_START /** @sa MDL_key. */ struct MDL_key; typedef struct MDL_key MDL_key; /** @sa enum_mdl_type. */ typedef int opaque_mdl_type; /** @sa enum_mdl_duration. */ typedef int opaque_mdl_duration; /** @sa MDL_wait::enum_wait_status. */ typedef int opaque_mdl_status; /** @sa enum_vio_type. */ typedef int opaque_vio_type; struct TABLE_SHARE; struct sql_digest_storage; #ifdef __cplusplus class THD; #else /* Phony declaration when compiling C code. This is ok, because the C code will never have a THD anyway. */ struct opaque_THD { int dummy; }; typedef struct opaque_THD THD; #endif /** @file mysql/psi/psi.h Performance schema instrumentation interface. @defgroup Instrumentation_interface Instrumentation Interface @ingroup Performance_schema @{ */ /** Interface for an instrumented mutex. This is an opaque structure. */ struct PSI_mutex; typedef struct PSI_mutex PSI_mutex; /** Interface for an instrumented rwlock. This is an opaque structure. */ struct PSI_rwlock; typedef struct PSI_rwlock PSI_rwlock; /** Interface for an instrumented condition. This is an opaque structure. */ struct PSI_cond; typedef struct PSI_cond PSI_cond; /** Interface for an instrumented table share. This is an opaque structure. */ struct PSI_table_share; typedef struct PSI_table_share PSI_table_share; /** Interface for an instrumented table handle. This is an opaque structure. */ struct PSI_table; typedef struct PSI_table PSI_table; /** Interface for an instrumented thread. This is an opaque structure. */ struct PSI_thread; typedef struct PSI_thread PSI_thread; /** Interface for an instrumented file handle. This is an opaque structure. */ struct PSI_file; typedef struct PSI_file PSI_file; /** Interface for an instrumented socket descriptor. This is an opaque structure. */ struct PSI_socket; typedef struct PSI_socket PSI_socket; /** Interface for an instrumented prepared statement. This is an opaque structure. */ struct PSI_prepared_stmt; typedef struct PSI_prepared_stmt PSI_prepared_stmt; /** Interface for an instrumented table operation. This is an opaque structure. */ struct PSI_table_locker; typedef struct PSI_table_locker PSI_table_locker; /** Interface for an instrumented statement. This is an opaque structure. */ struct PSI_statement_locker; typedef struct PSI_statement_locker PSI_statement_locker; /** Interface for an instrumented transaction. This is an opaque structure. */ struct PSI_transaction_locker; typedef struct PSI_transaction_locker PSI_transaction_locker; /** Interface for an instrumented idle operation. This is an opaque structure. */ struct PSI_idle_locker; typedef struct PSI_idle_locker PSI_idle_locker; /** Interface for an instrumented statement digest operation. This is an opaque structure. */ struct PSI_digest_locker; typedef struct PSI_digest_locker PSI_digest_locker; /** Interface for an instrumented stored procedure share. This is an opaque structure. */ struct PSI_sp_share; typedef struct PSI_sp_share PSI_sp_share; /** Interface for an instrumented stored program. This is an opaque structure. */ struct PSI_sp_locker; typedef struct PSI_sp_locker PSI_sp_locker; /** Interface for an instrumented metadata lock. This is an opaque structure. */ struct PSI_metadata_lock; typedef struct PSI_metadata_lock PSI_metadata_lock; /** Interface for an instrumented stage progress. This is a public structure, for efficiency. */ struct PSI_stage_progress { ulonglong m_work_completed; ulonglong m_work_estimated; }; typedef struct PSI_stage_progress PSI_stage_progress; /** IO operation performed on an instrumented table. */ enum PSI_table_io_operation { /** Row fetch. */ PSI_TABLE_FETCH_ROW= 0, /** Row write. */ PSI_TABLE_WRITE_ROW= 1, /** Row update. */ PSI_TABLE_UPDATE_ROW= 2, /** Row delete. */ PSI_TABLE_DELETE_ROW= 3 }; typedef enum PSI_table_io_operation PSI_table_io_operation; /** State data storage for @c start_table_io_wait_v1_t, @c start_table_lock_wait_v1_t. This structure provide temporary storage to a table locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_table_io_wait_v1_t @sa start_table_lock_wait_v1_t */ struct PSI_table_locker_state { /** Internal state. */ uint m_flags; /** Current io operation. */ enum PSI_table_io_operation m_io_operation; /** Current table handle. */ struct PSI_table *m_table; /** Current table share. */ struct PSI_table_share *m_table_share; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; /** Implementation specific. For table io, the table io index. For table lock, the lock type. */ uint m_index; }; typedef struct PSI_table_locker_state PSI_table_locker_state; /** Entry point for the performance schema interface. */ struct PSI_bootstrap { /** ABI interface finder. Calling this method with an interface version number returns either an instance of the ABI for this version, or NULL. @param version the interface version number to find @return a versioned interface (PSI_v1, PSI_v2 or PSI) @sa PSI_VERSION_1 @sa PSI_v1 @sa PSI_VERSION_2 @sa PSI_v2 @sa PSI_CURRENT_VERSION @sa PSI */ void* (*get_interface)(int version); }; typedef struct PSI_bootstrap PSI_bootstrap; #ifdef HAVE_PSI_INTERFACE #ifdef DISABLE_ALL_PSI #ifndef DISABLE_PSI_THREAD #define DISABLE_PSI_THREAD #endif #ifndef DISABLE_PSI_MUTEX #define DISABLE_PSI_MUTEX #endif #ifndef DISABLE_PSI_RWLOCK #define DISABLE_PSI_RWLOCK #endif #ifndef DISABLE_PSI_COND #define DISABLE_PSI_COND #endif #ifndef DISABLE_PSI_FILE #define DISABLE_PSI_FILE #endif #ifndef DISABLE_PSI_TABLE #define DISABLE_PSI_TABLE #endif #ifndef DISABLE_PSI_SOCKET #define DISABLE_PSI_SOCKET #endif #ifndef DISABLE_PSI_STAGE #define DISABLE_PSI_STAGE #endif #ifndef DISABLE_PSI_STATEMENT #define DISABLE_PSI_STATEMENT #endif #ifndef DISABLE_PSI_SP #define DISABLE_PSI_SP #endif #ifndef DISABLE_PSI_IDLE #define DISABLE_PSI_IDLE #endif #ifndef DISABLE_PSI_STATEMENT_DIGEST #define DISABLE_PSI_STATEMENT_DIGEST #endif #ifndef DISABLE_PSI_METADATA #define DISABLE_PSI_METADATA #endif #ifndef DISABLE_PSI_MEMORY #define DISABLE_PSI_MEMORY #endif #ifndef DISABLE_PSI_TRANSACTION #define DISABLE_PSI_TRANSACTION #endif #ifndef DISABLE_PSI_SP #define DISABLE_PSI_SP #endif #ifndef DISABLE_PSI_PS #define DISABLE_PSI_PS #endif #endif /** @def DISABLE_PSI_MUTEX Compiling option to disable the mutex instrumentation. This option is mostly intended to be used during development, when doing special builds with only a subset of the performance schema instrumentation, for code analysis / profiling / performance tuning of a specific instrumentation alone. @sa DISABLE_PSI_RWLOCK @sa DISABLE_PSI_COND @sa DISABLE_PSI_FILE @sa DISABLE_PSI_THREAD @sa DISABLE_PSI_TABLE @sa DISABLE_PSI_STAGE @sa DISABLE_PSI_STATEMENT @sa DISABLE_PSI_SP @sa DISABLE_PSI_STATEMENT_DIGEST @sa DISABLE_PSI_SOCKET @sa DISABLE_PSI_MEMORY @sa DISABLE_PSI_IDLE @sa DISABLE_PSI_METADATA @sa DISABLE PSI_TRANSACTION */ #ifndef DISABLE_PSI_MUTEX #define HAVE_PSI_MUTEX_INTERFACE #endif /** @def DISABLE_PSI_RWLOCK Compiling option to disable the rwlock instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_RWLOCK #define HAVE_PSI_RWLOCK_INTERFACE #endif /** @def DISABLE_PSI_COND Compiling option to disable the cond instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_COND #define HAVE_PSI_COND_INTERFACE #endif /** @def DISABLE_PSI_FILE Compiling option to disable the file instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_FILE #define HAVE_PSI_FILE_INTERFACE #endif /** @def DISABLE_PSI_THREAD Compiling option to disable the thread instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_THREAD #define HAVE_PSI_THREAD_INTERFACE #endif /** @def DISABLE_PSI_TABLE Compiling option to disable the table instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_TABLE #define HAVE_PSI_TABLE_INTERFACE #endif /** @def DISABLE_PSI_STAGE Compiling option to disable the stage instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_STAGE #define HAVE_PSI_STAGE_INTERFACE #endif /** @def DISABLE_PSI_STATEMENT Compiling option to disable the statement instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_STATEMENT #define HAVE_PSI_STATEMENT_INTERFACE #endif /** @def DISABLE_PSI_SP Compiling option to disable the stored program instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_SP #define HAVE_PSI_SP_INTERFACE #endif /** @def DISABLE_PSI_PS Compiling option to disable the prepared statement instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_STATEMENT #ifndef DISABLE_PSI_PS #define HAVE_PSI_PS_INTERFACE #endif #endif /** @def DISABLE_PSI_STATEMENT_DIGEST Compiling option to disable the statement digest instrumentation. */ #ifndef DISABLE_PSI_STATEMENT #ifndef DISABLE_PSI_STATEMENT_DIGEST #define HAVE_PSI_STATEMENT_DIGEST_INTERFACE #endif #endif /** @def DISABLE_PSI_TRANSACTION Compiling option to disable the transaction instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_TRANSACTION #define HAVE_PSI_TRANSACTION_INTERFACE #endif /** @def DISABLE_PSI_SOCKET Compiling option to disable the statement instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_SOCKET #define HAVE_PSI_SOCKET_INTERFACE #endif /** @def DISABLE_PSI_MEMORY Compiling option to disable the memory instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_MEMORY #define HAVE_PSI_MEMORY_INTERFACE #endif /** @def DISABLE_PSI_IDLE Compiling option to disable the idle instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_IDLE #define HAVE_PSI_IDLE_INTERFACE #endif /** @def DISABLE_PSI_METADATA Compiling option to disable the metadata instrumentation. @sa DISABLE_PSI_MUTEX */ #ifndef DISABLE_PSI_METADATA #define HAVE_PSI_METADATA_INTERFACE #endif /** @def PSI_VERSION_1 Performance Schema Interface number for version 1. This version is supported. */ #define PSI_VERSION_1 1 /** @def PSI_VERSION_2 Performance Schema Interface number for version 2. This version is not implemented, it's a placeholder. */ #define PSI_VERSION_2 2 /** @def PSI_CURRENT_VERSION Performance Schema Interface number for the most recent version. The most current version is @c PSI_VERSION_1 */ #define PSI_CURRENT_VERSION 1 #ifndef USE_PSI_2 #ifndef USE_PSI_1 #define USE_PSI_1 #endif #endif /** Interface for an instrumented mutex operation. This is an opaque structure. */ struct PSI_mutex_locker; typedef struct PSI_mutex_locker PSI_mutex_locker; /** Interface for an instrumented rwlock operation. This is an opaque structure. */ struct PSI_rwlock_locker; typedef struct PSI_rwlock_locker PSI_rwlock_locker; /** Interface for an instrumented condition operation. This is an opaque structure. */ struct PSI_cond_locker; typedef struct PSI_cond_locker PSI_cond_locker; /** Interface for an instrumented file operation. This is an opaque structure. */ struct PSI_file_locker; typedef struct PSI_file_locker PSI_file_locker; /** Interface for an instrumented socket operation. This is an opaque structure. */ struct PSI_socket_locker; typedef struct PSI_socket_locker PSI_socket_locker; /** Interface for an instrumented MDL operation. This is an opaque structure. */ struct PSI_metadata_locker; typedef struct PSI_metadata_locker PSI_metadata_locker; /** Operation performed on an instrumented mutex. */ enum PSI_mutex_operation { /** Lock. */ PSI_MUTEX_LOCK= 0, /** Lock attempt. */ PSI_MUTEX_TRYLOCK= 1 }; typedef enum PSI_mutex_operation PSI_mutex_operation; /** Operation performed on an instrumented rwlock. For basic READ / WRITE lock, operations are "READ" or "WRITE". For SX-locks, operations are "SHARED", "SHARED-EXCLUSIVE" or "EXCLUSIVE". */ enum PSI_rwlock_operation { /** Read lock. */ PSI_RWLOCK_READLOCK= 0, /** Write lock. */ PSI_RWLOCK_WRITELOCK= 1, /** Read lock attempt. */ PSI_RWLOCK_TRYREADLOCK= 2, /** Write lock attempt. */ PSI_RWLOCK_TRYWRITELOCK= 3, /** Shared lock. */ PSI_RWLOCK_SHAREDLOCK= 4, /** Shared Exclusive lock. */ PSI_RWLOCK_SHAREDEXCLUSIVELOCK= 5, /** Exclusive lock. */ PSI_RWLOCK_EXCLUSIVELOCK= 6, /** Shared lock attempt. */ PSI_RWLOCK_TRYSHAREDLOCK= 7, /** Shared Exclusive lock attempt. */ PSI_RWLOCK_TRYSHAREDEXCLUSIVELOCK= 8, /** Exclusive lock attempt. */ PSI_RWLOCK_TRYEXCLUSIVELOCK= 9 }; typedef enum PSI_rwlock_operation PSI_rwlock_operation; /** Operation performed on an instrumented condition. */ enum PSI_cond_operation { /** Wait. */ PSI_COND_WAIT= 0, /** Wait, with timeout. */ PSI_COND_TIMEDWAIT= 1 }; typedef enum PSI_cond_operation PSI_cond_operation; /** Operation performed on an instrumented file. */ enum PSI_file_operation { /** File creation, as in @c create(). */ PSI_FILE_CREATE= 0, /** Temporary file creation, as in @c create_temp_file(). */ PSI_FILE_CREATE_TMP= 1, /** File open, as in @c open(). */ PSI_FILE_OPEN= 2, /** File open, as in @c fopen(). */ PSI_FILE_STREAM_OPEN= 3, /** File close, as in @c close(). */ PSI_FILE_CLOSE= 4, /** File close, as in @c fclose(). */ PSI_FILE_STREAM_CLOSE= 5, /** Generic file read, such as @c fgets(), @c fgetc(), @c fread(), @c read(), @c pread(). */ PSI_FILE_READ= 6, /** Generic file write, such as @c fputs(), @c fputc(), @c fprintf(), @c vfprintf(), @c fwrite(), @c write(), @c pwrite(). */ PSI_FILE_WRITE= 7, /** Generic file seek, such as @c fseek() or @c seek(). */ PSI_FILE_SEEK= 8, /** Generic file tell, such as @c ftell() or @c tell(). */ PSI_FILE_TELL= 9, /** File flush, as in @c fflush(). */ PSI_FILE_FLUSH= 10, /** File stat, as in @c stat(). */ PSI_FILE_STAT= 11, /** File stat, as in @c fstat(). */ PSI_FILE_FSTAT= 12, /** File chsize, as in @c my_chsize(). */ PSI_FILE_CHSIZE= 13, /** File delete, such as @c my_delete() or @c my_handler_delete_with_symlink(). */ PSI_FILE_DELETE= 14, /** File rename, such as @c my_rename() or @c my_rename_with_symlink(). */ PSI_FILE_RENAME= 15, /** File sync, as in @c fsync() or @c my_sync(). */ PSI_FILE_SYNC= 16 }; typedef enum PSI_file_operation PSI_file_operation; /** Lock operation performed on an instrumented table. */ enum PSI_table_lock_operation { /** Table lock, in the server layer. */ PSI_TABLE_LOCK= 0, /** Table lock, in the storage engine layer. */ PSI_TABLE_EXTERNAL_LOCK= 1 }; typedef enum PSI_table_lock_operation PSI_table_lock_operation; /** State of an instrumented socket. */ enum PSI_socket_state { /** Idle, waiting for the next command. */ PSI_SOCKET_STATE_IDLE= 1, /** Active, executing a command. */ PSI_SOCKET_STATE_ACTIVE= 2 }; typedef enum PSI_socket_state PSI_socket_state; /** Operation performed on an instrumented socket. */ enum PSI_socket_operation { /** Socket creation, as in @c socket() or @c socketpair(). */ PSI_SOCKET_CREATE= 0, /** Socket connection, as in @c connect(), @c listen() and @c accept(). */ PSI_SOCKET_CONNECT= 1, /** Socket bind, as in @c bind(), @c getsockname() and @c getpeername(). */ PSI_SOCKET_BIND= 2, /** Socket close, as in @c shutdown(). */ PSI_SOCKET_CLOSE= 3, /** Socket send, @c send(). */ PSI_SOCKET_SEND= 4, /** Socket receive, @c recv(). */ PSI_SOCKET_RECV= 5, /** Socket send, @c sendto(). */ PSI_SOCKET_SENDTO= 6, /** Socket receive, @c recvfrom). */ PSI_SOCKET_RECVFROM= 7, /** Socket send, @c sendmsg(). */ PSI_SOCKET_SENDMSG= 8, /** Socket receive, @c recvmsg(). */ PSI_SOCKET_RECVMSG= 9, /** Socket seek, such as @c fseek() or @c seek(). */ PSI_SOCKET_SEEK= 10, /** Socket options, as in @c getsockopt() and @c setsockopt(). */ PSI_SOCKET_OPT= 11, /** Socket status, as in @c sockatmark() and @c isfdtype(). */ PSI_SOCKET_STAT= 12, /** Socket shutdown, as in @c shutdown(). */ PSI_SOCKET_SHUTDOWN= 13, /** Socket select, as in @c select() and @c poll(). */ PSI_SOCKET_SELECT= 14 }; typedef enum PSI_socket_operation PSI_socket_operation; #endif /** Instrumented mutex key. To instrument a mutex, a mutex key must be obtained using @c register_mutex. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_mutex_key; /** Instrumented rwlock key. To instrument a rwlock, a rwlock key must be obtained using @c register_rwlock. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_rwlock_key; /** Instrumented cond key. To instrument a condition, a condition key must be obtained using @c register_cond. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_cond_key; /** Instrumented thread key. To instrument a thread, a thread key must be obtained using @c register_thread. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_thread_key; /** Instrumented file key. To instrument a file, a file key must be obtained using @c register_file. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_file_key; /** Instrumented stage key. To instrument a stage, a stage key must be obtained using @c register_stage. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_stage_key; /** Instrumented statement key. To instrument a statement, a statement key must be obtained using @c register_statement. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_statement_key; /** Instrumented socket key. To instrument a socket, a socket key must be obtained using @c register_socket. Using a zero key always disable the instrumentation. */ typedef unsigned int PSI_socket_key; #ifdef HAVE_PSI_1 /** @defgroup Group_PSI_v1 Application Binary Interface, version 1 @ingroup Instrumentation_interface @{ */ /** Mutex information. @since PSI_VERSION_1 This structure is used to register an instrumented mutex. */ struct PSI_mutex_info_v1 { /** Pointer to the key assigned to the registered mutex. */ PSI_mutex_key *m_key; /** The name of the mutex to register. */ const char *m_name; /** The flags of the mutex to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_mutex_info_v1 PSI_mutex_info_v1; /** Rwlock information. @since PSI_VERSION_1 This structure is used to register an instrumented rwlock. */ struct PSI_rwlock_info_v1 { /** Pointer to the key assigned to the registered rwlock. */ PSI_rwlock_key *m_key; /** The name of the rwlock to register. */ const char *m_name; /** The flags of the rwlock to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_rwlock_info_v1 PSI_rwlock_info_v1; /** Condition information. @since PSI_VERSION_1 This structure is used to register an instrumented cond. */ struct PSI_cond_info_v1 { /** Pointer to the key assigned to the registered cond. */ PSI_cond_key *m_key; /** The name of the cond to register. */ const char *m_name; /** The flags of the cond to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_cond_info_v1 PSI_cond_info_v1; /** Thread instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented thread. */ struct PSI_thread_info_v1 { /** Pointer to the key assigned to the registered thread. */ PSI_thread_key *m_key; /** The name of the thread instrument to register. */ const char *m_name; /** The flags of the thread to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_thread_info_v1 PSI_thread_info_v1; /** File instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented file. */ struct PSI_file_info_v1 { /** Pointer to the key assigned to the registered file. */ PSI_file_key *m_key; /** The name of the file instrument to register. */ const char *m_name; /** The flags of the file instrument to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_file_info_v1 PSI_file_info_v1; /** Stage instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented stage. */ struct PSI_stage_info_v1 { /** The registered stage key. */ PSI_stage_key m_key; /** The name of the stage instrument to register. */ const char *m_name; /** The flags of the stage instrument to register. */ int m_flags; }; typedef struct PSI_stage_info_v1 PSI_stage_info_v1; /** Statement instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented statement. */ struct PSI_statement_info_v1 { /** The registered statement key. */ PSI_statement_key m_key; /** The name of the statement instrument to register. */ const char *m_name; /** The flags of the statement instrument to register. */ int m_flags; }; typedef struct PSI_statement_info_v1 PSI_statement_info_v1; /** Socket instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented socket. */ struct PSI_socket_info_v1 { /** Pointer to the key assigned to the registered socket. */ PSI_socket_key *m_key; /** The name of the socket instrument to register. */ const char *m_name; /** The flags of the socket instrument to register. @sa PSI_FLAG_GLOBAL */ int m_flags; }; typedef struct PSI_socket_info_v1 PSI_socket_info_v1; /** State data storage for @c start_idle_wait_v1_t. This structure provide temporary storage to an idle locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_idle_wait_v1_t. */ struct PSI_idle_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_idle_locker_state_v1 PSI_idle_locker_state_v1; /** State data storage for @c start_mutex_wait_v1_t. This structure provide temporary storage to a mutex locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_mutex_wait_v1_t */ struct PSI_mutex_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current operation. */ enum PSI_mutex_operation m_operation; /** Current mutex. */ struct PSI_mutex *m_mutex; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_mutex_locker_state_v1 PSI_mutex_locker_state_v1; /** State data storage for @c start_rwlock_rdwait_v1_t, @c start_rwlock_wrwait_v1_t. This structure provide temporary storage to a rwlock locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_rwlock_rdwait_v1_t @sa start_rwlock_wrwait_v1_t */ struct PSI_rwlock_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current operation. */ enum PSI_rwlock_operation m_operation; /** Current rwlock. */ struct PSI_rwlock *m_rwlock; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_rwlock_locker_state_v1 PSI_rwlock_locker_state_v1; /** State data storage for @c start_cond_wait_v1_t. This structure provide temporary storage to a condition locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_cond_wait_v1_t */ struct PSI_cond_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current operation. */ enum PSI_cond_operation m_operation; /** Current condition. */ struct PSI_cond *m_cond; /** Current mutex. */ struct PSI_mutex *m_mutex; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_cond_locker_state_v1 PSI_cond_locker_state_v1; /** State data storage for @c get_thread_file_name_locker_v1_t. This structure provide temporary storage to a file locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa get_thread_file_name_locker_v1_t @sa get_thread_file_stream_locker_v1_t @sa get_thread_file_descriptor_locker_v1_t */ struct PSI_file_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current operation. */ enum PSI_file_operation m_operation; /** Current file. */ struct PSI_file *m_file; /** Current file name. */ const char *m_name; /** Current file class. */ void *m_class; /** Current thread. */ struct PSI_thread *m_thread; /** Operation number of bytes. */ size_t m_number_of_bytes; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_file_locker_state_v1 PSI_file_locker_state_v1; /** State data storage for @c start_metadata_wait_v1_t. This structure provide temporary storage to a metadata locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_metadata_wait_v1_t */ struct PSI_metadata_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current metadata lock. */ struct PSI_metadata_lock *m_metadata_lock; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_wait; }; typedef struct PSI_metadata_locker_state_v1 PSI_metadata_locker_state_v1; /* Duplicate of NAME_LEN, to avoid dependency on mysql_com.h */ #define PSI_SCHEMA_NAME_LEN (64 * 3) /** State data storage for @c get_thread_statement_locker_v1_t, @c get_thread_statement_locker_v1_t. This structure provide temporary storage to a statement locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa get_thread_statement_locker_v1_t */ struct PSI_statement_locker_state_v1 { /** Discarded flag. */ my_bool m_discarded; /** In prepare flag. */ my_bool m_in_prepare; /** Metric, no index used flag. */ uchar m_no_index_used; /** Metric, no good index used flag. */ uchar m_no_good_index_used; /** Internal state. */ uint m_flags; /** Instrumentation class. */ void *m_class; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_statement; /** Locked time. */ ulonglong m_lock_time; /** Rows sent. */ ulonglong m_rows_sent; /** Rows examined. */ ulonglong m_rows_examined; /** Metric, temporary tables created on disk. */ ulong m_created_tmp_disk_tables; /** Metric, temporary tables created. */ ulong m_created_tmp_tables; /** Metric, number of select full join. */ ulong m_select_full_join; /** Metric, number of select full range join. */ ulong m_select_full_range_join; /** Metric, number of select range. */ ulong m_select_range; /** Metric, number of select range check. */ ulong m_select_range_check; /** Metric, number of select scan. */ ulong m_select_scan; /** Metric, number of sort merge passes. */ ulong m_sort_merge_passes; /** Metric, number of sort merge. */ ulong m_sort_range; /** Metric, number of sort rows. */ ulong m_sort_rows; /** Metric, number of sort scans. */ ulong m_sort_scan; /** Statement digest. */ const struct sql_digest_storage *m_digest; /** Current schema name. */ char m_schema_name[PSI_SCHEMA_NAME_LEN]; /** Length in bytes of @c m_schema_name. */ uint m_schema_name_length; /** Statement character set number. */ uint m_cs_number; PSI_sp_share *m_parent_sp_share; PSI_prepared_stmt *m_parent_prepared_stmt; }; typedef struct PSI_statement_locker_state_v1 PSI_statement_locker_state_v1; /** State data storage for @c get_thread_transaction_locker_v1_t, @c get_thread_transaction_locker_v1_t. This structure provide temporary storage to a transaction locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa get_thread_transaction_locker_v1_t */ struct PSI_transaction_locker_state_v1 { /** Internal state. */ uint m_flags; /** Instrumentation class. */ void *m_class; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Internal data. */ void *m_transaction; /** True if read-only transaction, false if read-write. */ my_bool m_read_only; /** True if transaction is autocommit. */ my_bool m_autocommit; /** Number of statements. */ ulong m_statement_count; /** Total number of savepoints. */ ulong m_savepoint_count; /** Number of rollback_to_savepoint. */ ulong m_rollback_to_savepoint_count; /** Number of release_savepoint. */ ulong m_release_savepoint_count; }; typedef struct PSI_transaction_locker_state_v1 PSI_transaction_locker_state_v1; /** State data storage for @c start_socket_wait_v1_t. This structure provide temporary storage to a socket locker. The content of this structure is considered opaque, the fields are only hints of what an implementation of the psi interface can use. This memory is provided by the instrumented code for performance reasons. @sa start_socket_wait_v1_t */ struct PSI_socket_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current socket. */ struct PSI_socket *m_socket; /** Current thread. */ struct PSI_thread *m_thread; /** Operation number of bytes. */ size_t m_number_of_bytes; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Current operation. */ enum PSI_socket_operation m_operation; /** Source file. */ const char* m_src_file; /** Source line number. */ int m_src_line; /** Internal data. */ void *m_wait; }; typedef struct PSI_socket_locker_state_v1 PSI_socket_locker_state_v1; struct PSI_sp_locker_state_v1 { /** Internal state. */ uint m_flags; /** Current thread. */ struct PSI_thread *m_thread; /** Timer start. */ ulonglong m_timer_start; /** Timer function. */ ulonglong (*m_timer)(void); /** Stored Procedure share. */ PSI_sp_share* m_sp_share; }; typedef struct PSI_sp_locker_state_v1 PSI_sp_locker_state_v1; /* Using typedef to make reuse between PSI_v1 and PSI_v2 easier later. */ /** Mutex registration API. @param category a category name (typically a plugin name) @param info an array of mutex info to register @param count the size of the info array */ typedef void (*register_mutex_v1_t) (const char *category, struct PSI_mutex_info_v1 *info, int count); /** Rwlock registration API. @param category a category name (typically a plugin name) @param info an array of rwlock info to register @param count the size of the info array */ typedef void (*register_rwlock_v1_t) (const char *category, struct PSI_rwlock_info_v1 *info, int count); /** Cond registration API. @param category a category name (typically a plugin name) @param info an array of cond info to register @param count the size of the info array */ typedef void (*register_cond_v1_t) (const char *category, struct PSI_cond_info_v1 *info, int count); /** Thread registration API. @param category a category name (typically a plugin name) @param info an array of thread info to register @param count the size of the info array */ typedef void (*register_thread_v1_t) (const char *category, struct PSI_thread_info_v1 *info, int count); /** File registration API. @param category a category name (typically a plugin name) @param info an array of file info to register @param count the size of the info array */ typedef void (*register_file_v1_t) (const char *category, struct PSI_file_info_v1 *info, int count); /** Stage registration API. @param category a category name @param info an array of stage info to register @param count the size of the info array */ typedef void (*register_stage_v1_t) (const char *category, struct PSI_stage_info_v1 **info, int count); /** Statement registration API. @param category a category name @param info an array of stage info to register @param count the size of the info array */ typedef void (*register_statement_v1_t) (const char *category, struct PSI_statement_info_v1 *info, int count); /** Socket registration API. @param category a category name (typically a plugin name) @param info an array of socket info to register @param count the size of the info array */ typedef void (*register_socket_v1_t) (const char *category, struct PSI_socket_info_v1 *info, int count); /** Mutex instrumentation initialisation API. @param key the registered mutex key @param identity the address of the mutex itself @return an instrumented mutex */ typedef struct PSI_mutex* (*init_mutex_v1_t) (PSI_mutex_key key, void *identity); /** Mutex instrumentation destruction API. @param mutex the mutex to destroy */ typedef void (*destroy_mutex_v1_t)(struct PSI_mutex *mutex); /** Rwlock instrumentation initialisation API. @param key the registered rwlock key @param identity the address of the rwlock itself @return an instrumented rwlock */ typedef struct PSI_rwlock* (*init_rwlock_v1_t) (PSI_rwlock_key key, void *identity); /** Rwlock instrumentation destruction API. @param rwlock the rwlock to destroy */ typedef void (*destroy_rwlock_v1_t)(struct PSI_rwlock *rwlock); /** Cond instrumentation initialisation API. @param key the registered key @param identity the address of the rwlock itself @return an instrumented cond */ typedef struct PSI_cond* (*init_cond_v1_t) (PSI_cond_key key, void *identity); /** Cond instrumentation destruction API. @param cond the rcond to destroy */ typedef void (*destroy_cond_v1_t)(struct PSI_cond *cond); /** Socket instrumentation initialisation API. @param key the registered mutex key @param socket descriptor @param addr the socket ip address @param addr_len length of socket ip address @return an instrumented socket */ typedef struct PSI_socket* (*init_socket_v1_t) (PSI_socket_key key, const my_socket *fd, const struct sockaddr *addr, socklen_t addr_len); /** socket instrumentation destruction API. @param socket the socket to destroy */ typedef void (*destroy_socket_v1_t)(struct PSI_socket *socket); /** Acquire a table share instrumentation. @param temporary True for temporary tables @param share The SQL layer table share @return a table share instrumentation, or NULL */ typedef struct PSI_table_share* (*get_table_share_v1_t) (my_bool temporary, struct TABLE_SHARE *share); /** Release a table share. @param info the table share to release */ typedef void (*release_table_share_v1_t)(struct PSI_table_share *share); /** Drop a table share. @param temporary True for temporary tables @param schema_name the table schema name @param schema_name_length the table schema name length @param table_name the table name @param table_name_length the table name length */ typedef void (*drop_table_share_v1_t) (my_bool temporary, const char *schema_name, int schema_name_length, const char *table_name, int table_name_length); /** Open an instrumentation table handle. @param share the table to open @param identity table handle identity @return a table handle, or NULL */ typedef struct PSI_table* (*open_table_v1_t) (struct PSI_table_share *share, const void *identity); /** Unbind a table handle from the current thread. This operation happens when an opened table is added to the open table cache. @param table the table to unbind */ typedef void (*unbind_table_v1_t) (struct PSI_table *table); /** Rebind a table handle to the current thread. This operation happens when a table from the open table cache is reused for a thread. @param table the table to unbind */ typedef PSI_table* (*rebind_table_v1_t) (PSI_table_share *share, const void *identity, PSI_table *table); /** Close an instrumentation table handle. Note that the table handle is invalid after this call. @param table the table handle to close */ typedef void (*close_table_v1_t)(struct TABLE_SHARE *server_share, struct PSI_table *table); /** Create a file instrumentation for a created file. This method does not create the file itself, but is used to notify the instrumentation interface that a file was just created. @param key the file instrumentation key for this file @param name the file name @param file the file handle */ typedef void (*create_file_v1_t)(PSI_file_key key, const char *name, File file); /** Spawn a thread. This method creates a new thread, with instrumentation. @param key the instrumentation key for this thread @param thread the resulting thread @param attr the thread attributes @param start_routine the thread start routine @param arg the thread start routine argument */ typedef int (*spawn_thread_v1_t)(PSI_thread_key key, pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); /** Create instrumentation for a thread. @param key the registered key @param identity an address typical of the thread @return an instrumented thread */ typedef struct PSI_thread* (*new_thread_v1_t) (PSI_thread_key key, const void *identity, ulonglong thread_id); /** Assign a THD to an instrumented thread. @param thread the instrumented thread @param THD the sql layer THD to assign */ typedef void (*set_thread_THD_v1_t)(struct PSI_thread *thread, THD *thd); /** Assign an id to an instrumented thread. @param thread the instrumented thread @param id the id to assign */ typedef void (*set_thread_id_v1_t)(struct PSI_thread *thread, ulonglong id); /** Assign the current operating system thread id to an instrumented thread. The operating system task id is obtained from @c gettid() @param thread the instrumented thread */ typedef void (*set_thread_os_id_v1_t)(struct PSI_thread *thread); /** Get the instrumentation for the running thread. For this function to return a result, the thread instrumentation must have been attached to the running thread using @c set_thread() @return the instrumentation for the running thread */ typedef struct PSI_thread* (*get_thread_v1_t)(void); /** Assign a user name to the instrumented thread. @param user the user name @param user_len the user name length */ typedef void (*set_thread_user_v1_t)(const char *user, int user_len); /** Assign a user name and host name to the instrumented thread. @param user the user name @param user_len the user name length @param host the host name @param host_len the host name length */ typedef void (*set_thread_account_v1_t)(const char *user, int user_len, const char *host, int host_len); /** Assign a current database to the instrumented thread. @param db the database name @param db_len the database name length */ typedef void (*set_thread_db_v1_t)(const char* db, int db_len); /** Assign a current command to the instrumented thread. @param command the current command */ typedef void (*set_thread_command_v1_t)(int command); /** Assign a connection type to the instrumented thread. @param conn_type the connection type */ typedef void (*set_connection_type_v1_t)(opaque_vio_type conn_type); /** Assign a start time to the instrumented thread. @param start_time the thread start time */ typedef void (*set_thread_start_time_v1_t)(time_t start_time); /** Assign a state to the instrumented thread. @param state the thread state */ typedef void (*set_thread_state_v1_t)(const char* state); /** Assign a process info to the instrumented thread. @param info the process into string @param info_len the process into string length */ typedef void (*set_thread_info_v1_t)(const char* info, uint info_len); /** Attach a thread instrumentation to the running thread. In case of thread pools, this method should be called when a worker thread picks a work item and runs it. Also, this method should be called if the instrumented code does not keep the pointer returned by @c new_thread() and relies on @c get_thread() instead. @param thread the thread instrumentation */ typedef void (*set_thread_v1_t)(struct PSI_thread *thread); /** Assign the remote (peer) port to the instrumented thread. @param thread pointer to the thread instrumentation @param port the remote port */ typedef void (*set_thread_peer_port_v1_t)(PSI_thread *thread, unsigned int port); /** Delete the current thread instrumentation. */ typedef void (*delete_current_thread_v1_t)(void); /** Delete a thread instrumentation. */ typedef void (*delete_thread_v1_t)(struct PSI_thread *thread); /** Get a file instrumentation locker, for opening or creating a file. @param state data storage for the locker @param key the file instrumentation key @param op the operation to perform @param name the file name @param identity a pointer representative of this file. @return a file locker, or NULL */ typedef struct PSI_file_locker* (*get_thread_file_name_locker_v1_t) (struct PSI_file_locker_state_v1 *state, PSI_file_key key, enum PSI_file_operation op, const char *name, const void *identity); /** Get a file stream instrumentation locker. @param state data storage for the locker @param file the file stream to access @param op the operation to perform @return a file locker, or NULL */ typedef struct PSI_file_locker* (*get_thread_file_stream_locker_v1_t) (struct PSI_file_locker_state_v1 *state, struct PSI_file *file, enum PSI_file_operation op); /** Get a file instrumentation locker. @param state data storage for the locker @param file the file descriptor to access @param op the operation to perform @return a file locker, or NULL */ typedef struct PSI_file_locker* (*get_thread_file_descriptor_locker_v1_t) (struct PSI_file_locker_state_v1 *state, File file, enum PSI_file_operation op); /** Record a mutex instrumentation unlock event. @param mutex the mutex instrumentation */ typedef void (*unlock_mutex_v1_t) (struct PSI_mutex *mutex); /** Record a rwlock instrumentation unlock event. @param rwlock the rwlock instrumentation */ typedef void (*unlock_rwlock_v1_t) (struct PSI_rwlock *rwlock); /** Record a condition instrumentation signal event. @param cond the cond instrumentation */ typedef void (*signal_cond_v1_t) (struct PSI_cond *cond); /** Record a condition instrumentation broadcast event. @param cond the cond instrumentation */ typedef void (*broadcast_cond_v1_t) (struct PSI_cond *cond); /** Record an idle instrumentation wait start event. @param state data storage for the locker @param file the source file name @param line the source line number @return an idle locker, or NULL */ typedef struct PSI_idle_locker* (*start_idle_wait_v1_t) (struct PSI_idle_locker_state_v1 *state, const char *src_file, uint src_line); /** Record an idle instrumentation wait end event. @param locker a thread locker for the running thread */ typedef void (*end_idle_wait_v1_t) (struct PSI_idle_locker *locker); /** Record a mutex instrumentation wait start event. @param state data storage for the locker @param mutex the instrumented mutex to lock @param op the operation to perform @param file the source file name @param line the source line number @return a mutex locker, or NULL */ typedef struct PSI_mutex_locker* (*start_mutex_wait_v1_t) (struct PSI_mutex_locker_state_v1 *state, struct PSI_mutex *mutex, enum PSI_mutex_operation op, const char *src_file, uint src_line); /** Record a mutex instrumentation wait end event. @param locker a thread locker for the running thread @param rc the wait operation return code */ typedef void (*end_mutex_wait_v1_t) (struct PSI_mutex_locker *locker, int rc); /** Record a rwlock instrumentation read wait start event. @param locker a thread locker for the running thread @param must must block: 1 for lock, 0 for trylock */ typedef struct PSI_rwlock_locker* (*start_rwlock_rdwait_v1_t) (struct PSI_rwlock_locker_state_v1 *state, struct PSI_rwlock *rwlock, enum PSI_rwlock_operation op, const char *src_file, uint src_line); /** Record a rwlock instrumentation read wait end event. @param locker a thread locker for the running thread @param rc the wait operation return code */ typedef void (*end_rwlock_rdwait_v1_t) (struct PSI_rwlock_locker *locker, int rc); /** Record a rwlock instrumentation write wait start event. @param locker a thread locker for the running thread @param must must block: 1 for lock, 0 for trylock */ typedef struct PSI_rwlock_locker* (*start_rwlock_wrwait_v1_t) (struct PSI_rwlock_locker_state_v1 *state, struct PSI_rwlock *rwlock, enum PSI_rwlock_operation op, const char *src_file, uint src_line); /** Record a rwlock instrumentation write wait end event. @param locker a thread locker for the running thread @param rc the wait operation return code */ typedef void (*end_rwlock_wrwait_v1_t) (struct PSI_rwlock_locker *locker, int rc); /** Record a condition instrumentation wait start event. @param locker a thread locker for the running thread @param must must block: 1 for wait, 0 for timedwait */ typedef struct PSI_cond_locker* (*start_cond_wait_v1_t) (struct PSI_cond_locker_state_v1 *state, struct PSI_cond *cond, struct PSI_mutex *mutex, enum PSI_cond_operation op, const char *src_file, uint src_line); /** Record a condition instrumentation wait end event. @param locker a thread locker for the running thread @param rc the wait operation return code */ typedef void (*end_cond_wait_v1_t) (struct PSI_cond_locker *locker, int rc); /** Record a table instrumentation io wait start event. @param locker a table locker for the running thread @param file the source file name @param line the source line number */ typedef struct PSI_table_locker* (*start_table_io_wait_v1_t) (struct PSI_table_locker_state *state, struct PSI_table *table, enum PSI_table_io_operation op, uint index, const char *src_file, uint src_line); /** Record a table instrumentation io wait end event. @param locker a table locker for the running thread @param numrows the number of rows involved in io */ typedef void (*end_table_io_wait_v1_t) (struct PSI_table_locker *locker, ulonglong numrows); /** Record a table instrumentation lock wait start event. @param locker a table locker for the running thread @param file the source file name @param line the source line number */ typedef struct PSI_table_locker* (*start_table_lock_wait_v1_t) (struct PSI_table_locker_state *state, struct PSI_table *table, enum PSI_table_lock_operation op, ulong flags, const char *src_file, uint src_line); /** Record a table instrumentation lock wait end event. @param locker a table locker for the running thread */ typedef void (*end_table_lock_wait_v1_t)(struct PSI_table_locker *locker); typedef void (*unlock_table_v1_t)(struct PSI_table *table); /** Start a file instrumentation open operation. @param locker the file locker @param op the operation to perform @param src_file the source file name @param src_line the source line number */ typedef void (*start_file_open_wait_v1_t) (struct PSI_file_locker *locker, const char *src_file, uint src_line); /** End a file instrumentation open operation, for file streams. @param locker the file locker. @param result the opened file (NULL indicates failure, non NULL success). @return an instrumented file handle */ typedef struct PSI_file* (*end_file_open_wait_v1_t) (struct PSI_file_locker *locker, void *result); /** End a file instrumentation open operation, for non stream files. @param locker the file locker. @param file the file number assigned by open() or create() for this file. */ typedef void (*end_file_open_wait_and_bind_to_descriptor_v1_t) (struct PSI_file_locker *locker, File file); /** End a file instrumentation open operation, for non stream temporary files. @param locker the file locker. @param file the file number assigned by open() or create() for this file. @param filename the file name generated during temporary file creation. */ typedef void (*end_temp_file_open_wait_and_bind_to_descriptor_v1_t) (struct PSI_file_locker *locker, File file, const char *filename); /** Record a file instrumentation start event. @param locker a file locker for the running thread @param op file operation to be performed @param count the number of bytes requested, or 0 if not applicable @param src_file the source file name @param src_line the source line number */ typedef void (*start_file_wait_v1_t) (struct PSI_file_locker *locker, size_t count, const char *src_file, uint src_line); /** Record a file instrumentation end event. Note that for file close operations, the instrumented file handle associated with the file (which was provided to obtain a locker) is invalid after this call. @param locker a file locker for the running thread @param count the number of bytes actually used in the operation, or 0 if not applicable, or -1 if the operation failed @sa get_thread_file_name_locker @sa get_thread_file_stream_locker @sa get_thread_file_descriptor_locker */ typedef void (*end_file_wait_v1_t) (struct PSI_file_locker *locker, size_t count); /** Start a file instrumentation close operation. @param locker the file locker @param op the operation to perform @param src_file the source file name @param src_line the source line number */ typedef void (*start_file_close_wait_v1_t) (struct PSI_file_locker *locker, const char *src_file, uint src_line); /** End a file instrumentation close operation. @param locker the file locker. @param rc the close operation return code (0 for success). @return an instrumented file handle */ typedef void (*end_file_close_wait_v1_t) (struct PSI_file_locker *locker, int rc); /** Rename a file instrumentation close operation. @param locker the file locker. @param old_name name of the file to be renamed. @param new_name name of the file after rename. @param rc the rename operation return code (0 for success). */ typedef void (*end_file_rename_wait_v1_t) (struct PSI_file_locker *locker, const char *old_name, const char *new_name, int rc); /** Start a new stage, and implicitly end the previous stage. @param key the key of the new stage @param src_file the source file name @param src_line the source line number @return the new stage progress */ typedef PSI_stage_progress* (*start_stage_v1_t) (PSI_stage_key key, const char *src_file, int src_line); typedef PSI_stage_progress* (*get_current_stage_progress_v1_t)(void); /** End the current stage. */ typedef void (*end_stage_v1_t) (void); /** Get a statement instrumentation locker. @param state data storage for the locker @param key the statement instrumentation key @param charset client character set @return a statement locker, or NULL */ typedef struct PSI_statement_locker* (*get_thread_statement_locker_v1_t) (struct PSI_statement_locker_state_v1 *state, PSI_statement_key key, const void *charset, PSI_sp_share *sp_share); /** Refine a statement locker to a more specific key. Note that only events declared mutable can be refined. @param the statement locker for the current event @param key the new key for the event @sa PSI_FLAG_MUTABLE */ typedef struct PSI_statement_locker* (*refine_statement_v1_t) (struct PSI_statement_locker *locker, PSI_statement_key key); /** Start a new statement event. @param locker the statement locker for this event @param db the active database name for this statement @param db_length the active database name length for this statement @param src_file source file name @param src_line source line number */ typedef void (*start_statement_v1_t) (struct PSI_statement_locker *locker, const char *db, uint db_length, const char *src_file, uint src_line); /** Set the statement text for a statement event. @param locker the current statement locker @param text the statement text @param text_len the statement text length */ typedef void (*set_statement_text_v1_t) (struct PSI_statement_locker *locker, const char *text, uint text_len); /** Set a statement event lock time. @param locker the statement locker @param lock_time the locked time, in microseconds */ typedef void (*set_statement_lock_time_t) (struct PSI_statement_locker *locker, ulonglong lock_time); /** Set a statement event rows sent metric. @param locker the statement locker @param count the number of rows sent */ typedef void (*set_statement_rows_sent_t) (struct PSI_statement_locker *locker, ulonglong count); /** Set a statement event rows examined metric. @param locker the statement locker @param count the number of rows examined */ typedef void (*set_statement_rows_examined_t) (struct PSI_statement_locker *locker, ulonglong count); /** Increment a statement event "created tmp disk tables" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_created_tmp_disk_tables_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "created tmp tables" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_created_tmp_tables_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "select full join" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_select_full_join_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "select full range join" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_select_full_range_join_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "select range join" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_select_range_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "select range check" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_select_range_check_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "select scan" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_select_scan_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "sort merge passes" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_sort_merge_passes_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "sort range" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_sort_range_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "sort rows" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_sort_rows_t) (struct PSI_statement_locker *locker, ulong count); /** Increment a statement event "sort scan" metric. @param locker the statement locker @param count the metric increment value */ typedef void (*inc_statement_sort_scan_t) (struct PSI_statement_locker *locker, ulong count); /** Set a statement event "no index used" metric. @param locker the statement locker @param count the metric value */ typedef void (*set_statement_no_index_used_t) (struct PSI_statement_locker *locker); /** Set a statement event "no good index used" metric. @param locker the statement locker @param count the metric value */ typedef void (*set_statement_no_good_index_used_t) (struct PSI_statement_locker *locker); /** End a statement event. @param locker the statement locker @param stmt_da the statement diagnostics area. @sa Diagnostics_area */ typedef void (*end_statement_v1_t) (struct PSI_statement_locker *locker, void *stmt_da); /** Get a transaction instrumentation locker. @param state data storage for the locker @param xid the xid for this transaction @param trxid the InnoDB transaction id @param iso_level isolation level for this transaction @param read_only true if transaction access mode is read-only @param autocommit true if transaction is autocommit @return a transaction locker, or NULL */ typedef struct PSI_transaction_locker* (*get_thread_transaction_locker_v1_t) (struct PSI_transaction_locker_state_v1 *state, const void *xid, ulonglong trxid, int isolation_level, my_bool read_only, my_bool autocommit); /** Start a new transaction event. @param locker the transaction locker for this event @param src_file source file name @param src_line source line number */ typedef void (*start_transaction_v1_t) (struct PSI_transaction_locker *locker, const char *src_file, uint src_line); /** Set the transaction xid. @param locker the transaction locker for this event @param xid the id of the XA transaction #param xa_state is the state of the XA transaction */ typedef void (*set_transaction_xid_v1_t) (struct PSI_transaction_locker *locker, const void *xid, int xa_state); /** Set the state of the XA transaction. @param locker the transaction locker for this event @param xa_state the new state of the xa transaction */ typedef void (*set_transaction_xa_state_v1_t) (struct PSI_transaction_locker *locker, int xa_state); /** Set the transaction gtid. @param locker the transaction locker for this event @param sid the source id for the transaction, mapped from sidno @param gtid_spec the gtid specifier for the transaction */ typedef void (*set_transaction_gtid_v1_t) (struct PSI_transaction_locker *locker, const void *sid, const void *gtid_spec); /** Set the transaction trx_id. @param locker the transaction locker for this event @param trxid the storage engine transaction ID */ typedef void (*set_transaction_trxid_v1_t) (struct PSI_transaction_locker *locker, const ulonglong *trxid); /** Increment a transaction event savepoint count. @param locker the transaction locker @param count the increment value */ typedef void (*inc_transaction_savepoints_v1_t) (struct PSI_transaction_locker *locker, ulong count); /** Increment a transaction event rollback to savepoint count. @param locker the transaction locker @param count the increment value */ typedef void (*inc_transaction_rollback_to_savepoint_v1_t) (struct PSI_transaction_locker *locker, ulong count); /** Increment a transaction event release savepoint count. @param locker the transaction locker @param count the increment value */ typedef void (*inc_transaction_release_savepoint_v1_t) (struct PSI_transaction_locker *locker, ulong count); /** Commit or rollback the transaction. @param locker the transaction locker for this event @param commit true if transaction was committed, false if rolled back */ typedef void (*end_transaction_v1_t) (struct PSI_transaction_locker *locker, my_bool commit); /** Record a socket instrumentation start event. @param locker a socket locker for the running thread @param op socket operation to be performed @param count the number of bytes requested, or 0 if not applicable @param src_file the source file name @param src_line the source line number */ typedef struct PSI_socket_locker* (*start_socket_wait_v1_t) (struct PSI_socket_locker_state_v1 *state, struct PSI_socket *socket, enum PSI_socket_operation op, size_t count, const char *src_file, uint src_line); /** Record a socket instrumentation end event. Note that for socket close operations, the instrumented socket handle associated with the socket (which was provided to obtain a locker) is invalid after this call. @param locker a socket locker for the running thread @param count the number of bytes actually used in the operation, or 0 if not applicable, or -1 if the operation failed @sa get_thread_socket_locker */ typedef void (*end_socket_wait_v1_t) (struct PSI_socket_locker *locker, size_t count); /** Set the socket state for an instrumented socket. @param socket the instrumented socket @param state socket state */ typedef void (*set_socket_state_v1_t)(struct PSI_socket *socket, enum PSI_socket_state state); /** Set the socket info for an instrumented socket. @param socket the instrumented socket @param fd the socket descriptor @param addr the socket ip address @param addr_len length of socket ip address @param thread_id associated thread id */ typedef void (*set_socket_info_v1_t)(struct PSI_socket *socket, const my_socket *fd, const struct sockaddr *addr, socklen_t addr_len); /** Bind a socket to the thread that owns it. @param socket instrumented socket */ typedef void (*set_socket_thread_owner_v1_t)(struct PSI_socket *socket); /** Get a prepare statement. @param locker a statement locker for the running thread. */ typedef PSI_prepared_stmt* (*create_prepared_stmt_v1_t) (void *identity, uint stmt_id, PSI_statement_locker *locker, const char *stmt_name, size_t stmt_name_length); /** destroy a prepare statement. @param prepared_stmt prepared statement. */ typedef void (*destroy_prepared_stmt_v1_t) (PSI_prepared_stmt *prepared_stmt); /** repreare a prepare statement. @param prepared_stmt prepared statement. */ typedef void (*reprepare_prepared_stmt_v1_t) (PSI_prepared_stmt *prepared_stmt); /** Record a prepare statement instrumentation execute event. @param locker a statement locker for the running thread. @param prepared_stmt prepared statement. */ typedef void (*execute_prepared_stmt_v1_t) (PSI_statement_locker *locker, PSI_prepared_stmt* prepared_stmt); /** Set the statement text for a prepared statement event. @param prepared_stmt prepared statement. @param text the prepared statement text @param text_len the prepared statement text length */ typedef void (*set_prepared_stmt_text_v1_t)(PSI_prepared_stmt *prepared_stmt, const char *text, uint text_len); /** Get a digest locker for the current statement. @param locker a statement locker for the running thread */ typedef struct PSI_digest_locker * (*digest_start_v1_t) (struct PSI_statement_locker *locker); /** Add a token to the current digest instrumentation. @param locker a digest locker for the current statement @param token the lexical token to add @param yylval the lexical token attributes */ typedef void (*digest_end_v1_t) (struct PSI_digest_locker *locker, const struct sql_digest_storage *digest); typedef PSI_sp_locker* (*start_sp_v1_t) (struct PSI_sp_locker_state_v1 *state, struct PSI_sp_share* sp_share); typedef void (*end_sp_v1_t) (struct PSI_sp_locker *locker); typedef void (*drop_sp_v1_t) (uint object_type, const char *schema_name, uint schema_name_length, const char *object_name, uint object_name_length); /** Acquire a sp share instrumentation. @param type of stored program @param schema name of stored program @param name of stored program @return a stored program share instrumentation, or NULL */ typedef struct PSI_sp_share* (*get_sp_share_v1_t) (uint object_type, const char *schema_name, uint schema_name_length, const char *object_name, uint object_name_length); /** Release a stored program share. @param info the stored program share to release */ typedef void (*release_sp_share_v1_t)(struct PSI_sp_share *share); typedef PSI_metadata_lock* (*create_metadata_lock_v1_t) (void *identity, const MDL_key *key, opaque_mdl_type mdl_type, opaque_mdl_duration mdl_duration, opaque_mdl_status mdl_status, const char *src_file, uint src_line); typedef void (*set_metadata_lock_status_v1_t)(PSI_metadata_lock *lock, opaque_mdl_status mdl_status); typedef void (*destroy_metadata_lock_v1_t)(PSI_metadata_lock *lock); typedef struct PSI_metadata_locker* (*start_metadata_wait_v1_t) (struct PSI_metadata_locker_state_v1 *state, struct PSI_metadata_lock *mdl, const char *src_file, uint src_line); typedef void (*end_metadata_wait_v1_t) (struct PSI_metadata_locker *locker, int rc); /** Stores an array of connection attributes @param buffer char array of length encoded connection attributes in network format @param length length of the data in buffer @param from_cs charset in which @c buffer is encoded @return state @retval non_0 attributes truncated @retval 0 stored the attribute */ typedef int (*set_thread_connect_attrs_v1_t)(const char *buffer, uint length, const void *from_cs); /** Performance Schema Interface, version 1. @since PSI_VERSION_1 */ struct PSI_v1 { /** @sa register_mutex_v1_t. */ register_mutex_v1_t register_mutex; /** @sa register_rwlock_v1_t. */ register_rwlock_v1_t register_rwlock; /** @sa register_cond_v1_t. */ register_cond_v1_t register_cond; /** @sa register_thread_v1_t. */ register_thread_v1_t register_thread; /** @sa register_file_v1_t. */ register_file_v1_t register_file; /** @sa register_stage_v1_t. */ register_stage_v1_t register_stage; /** @sa register_statement_v1_t. */ register_statement_v1_t register_statement; /** @sa register_socket_v1_t. */ register_socket_v1_t register_socket; /** @sa init_mutex_v1_t. */ init_mutex_v1_t init_mutex; /** @sa destroy_mutex_v1_t. */ destroy_mutex_v1_t destroy_mutex; /** @sa init_rwlock_v1_t. */ init_rwlock_v1_t init_rwlock; /** @sa destroy_rwlock_v1_t. */ destroy_rwlock_v1_t destroy_rwlock; /** @sa init_cond_v1_t. */ init_cond_v1_t init_cond; /** @sa destroy_cond_v1_t. */ destroy_cond_v1_t destroy_cond; /** @sa init_socket_v1_t. */ init_socket_v1_t init_socket; /** @sa destroy_socket_v1_t. */ destroy_socket_v1_t destroy_socket; /** @sa get_table_share_v1_t. */ get_table_share_v1_t get_table_share; /** @sa release_table_share_v1_t. */ release_table_share_v1_t release_table_share; /** @sa drop_table_share_v1_t. */ drop_table_share_v1_t drop_table_share; /** @sa open_table_v1_t. */ open_table_v1_t open_table; /** @sa unbind_table_v1_t. */ unbind_table_v1_t unbind_table; /** @sa rebind_table_v1_t. */ rebind_table_v1_t rebind_table; /** @sa close_table_v1_t. */ close_table_v1_t close_table; /** @sa create_file_v1_t. */ create_file_v1_t create_file; /** @sa spawn_thread_v1_t. */ spawn_thread_v1_t spawn_thread; /** @sa new_thread_v1_t. */ new_thread_v1_t new_thread; /** @sa set_thread_id_v1_t. */ set_thread_id_v1_t set_thread_id; /** @sa set_thread_THD_v1_t. */ set_thread_THD_v1_t set_thread_THD; /** @sa set_thread_os_id_v1_t. */ set_thread_os_id_v1_t set_thread_os_id; /** @sa get_thread_v1_t. */ get_thread_v1_t get_thread; /** @sa set_thread_user_v1_t. */ set_thread_user_v1_t set_thread_user; /** @sa set_thread_account_v1_t. */ set_thread_account_v1_t set_thread_account; /** @sa set_thread_db_v1_t. */ set_thread_db_v1_t set_thread_db; /** @sa set_thread_command_v1_t. */ set_thread_command_v1_t set_thread_command; /** @sa set_connection_type_v1_t. */ set_connection_type_v1_t set_connection_type; /** @sa set_thread_start_time_v1_t. */ set_thread_start_time_v1_t set_thread_start_time; /** @sa set_thread_state_v1_t. */ set_thread_state_v1_t set_thread_state; /** @sa set_thread_info_v1_t. */ set_thread_info_v1_t set_thread_info; /** @sa set_thread_v1_t. */ set_thread_v1_t set_thread; /** @sa delete_current_thread_v1_t. */ delete_current_thread_v1_t delete_current_thread; /** @sa delete_thread_v1_t. */ delete_thread_v1_t delete_thread; /** @sa get_thread_file_name_locker_v1_t. */ get_thread_file_name_locker_v1_t get_thread_file_name_locker; /** @sa get_thread_file_stream_locker_v1_t. */ get_thread_file_stream_locker_v1_t get_thread_file_stream_locker; /** @sa get_thread_file_descriptor_locker_v1_t. */ get_thread_file_descriptor_locker_v1_t get_thread_file_descriptor_locker; /** @sa unlock_mutex_v1_t. */ unlock_mutex_v1_t unlock_mutex; /** @sa unlock_rwlock_v1_t. */ unlock_rwlock_v1_t unlock_rwlock; /** @sa signal_cond_v1_t. */ signal_cond_v1_t signal_cond; /** @sa broadcast_cond_v1_t. */ broadcast_cond_v1_t broadcast_cond; /** @sa start_idle_wait_v1_t. */ start_idle_wait_v1_t start_idle_wait; /** @sa end_idle_wait_v1_t. */ end_idle_wait_v1_t end_idle_wait; /** @sa start_mutex_wait_v1_t. */ start_mutex_wait_v1_t start_mutex_wait; /** @sa end_mutex_wait_v1_t. */ end_mutex_wait_v1_t end_mutex_wait; /** @sa start_rwlock_rdwait_v1_t. */ start_rwlock_rdwait_v1_t start_rwlock_rdwait; /** @sa end_rwlock_rdwait_v1_t. */ end_rwlock_rdwait_v1_t end_rwlock_rdwait; /** @sa start_rwlock_wrwait_v1_t. */ start_rwlock_wrwait_v1_t start_rwlock_wrwait; /** @sa end_rwlock_wrwait_v1_t. */ end_rwlock_wrwait_v1_t end_rwlock_wrwait; /** @sa start_cond_wait_v1_t. */ start_cond_wait_v1_t start_cond_wait; /** @sa end_cond_wait_v1_t. */ end_cond_wait_v1_t end_cond_wait; /** @sa start_table_io_wait_v1_t. */ start_table_io_wait_v1_t start_table_io_wait; /** @sa end_table_io_wait_v1_t. */ end_table_io_wait_v1_t end_table_io_wait; /** @sa start_table_lock_wait_v1_t. */ start_table_lock_wait_v1_t start_table_lock_wait; /** @sa end_table_lock_wait_v1_t. */ end_table_lock_wait_v1_t end_table_lock_wait; /** @sa start_file_open_wait_v1_t. */ start_file_open_wait_v1_t start_file_open_wait; /** @sa end_file_open_wait_v1_t. */ end_file_open_wait_v1_t end_file_open_wait; /** @sa end_file_open_wait_and_bind_to_descriptor_v1_t. */ end_file_open_wait_and_bind_to_descriptor_v1_t end_file_open_wait_and_bind_to_descriptor; /** @sa end_temp_file_open_wait_and_bind_to_descriptor_v1_t. */ end_temp_file_open_wait_and_bind_to_descriptor_v1_t end_temp_file_open_wait_and_bind_to_descriptor; /** @sa start_file_wait_v1_t. */ start_file_wait_v1_t start_file_wait; /** @sa end_file_wait_v1_t. */ end_file_wait_v1_t end_file_wait; /** @sa start_file_close_wait_v1_t. */ start_file_close_wait_v1_t start_file_close_wait; /** @sa end_file_close_wait_v1_t. */ end_file_close_wait_v1_t end_file_close_wait; /** @sa rename_file_close_wait_v1_t. */ end_file_rename_wait_v1_t end_file_rename_wait; /** @sa start_stage_v1_t. */ start_stage_v1_t start_stage; /** @sa get_current_stage_progress_v1_t. */ get_current_stage_progress_v1_t get_current_stage_progress; /** @sa end_stage_v1_t. */ end_stage_v1_t end_stage; /** @sa get_thread_statement_locker_v1_t. */ get_thread_statement_locker_v1_t get_thread_statement_locker; /** @sa refine_statement_v1_t. */ refine_statement_v1_t refine_statement; /** @sa start_statement_v1_t. */ start_statement_v1_t start_statement; /** @sa set_statement_text_v1_t. */ set_statement_text_v1_t set_statement_text; /** @sa set_statement_lock_time_t. */ set_statement_lock_time_t set_statement_lock_time; /** @sa set_statement_rows_sent_t. */ set_statement_rows_sent_t set_statement_rows_sent; /** @sa set_statement_rows_examined_t. */ set_statement_rows_examined_t set_statement_rows_examined; /** @sa inc_statement_created_tmp_disk_tables. */ inc_statement_created_tmp_disk_tables_t inc_statement_created_tmp_disk_tables; /** @sa inc_statement_created_tmp_tables. */ inc_statement_created_tmp_tables_t inc_statement_created_tmp_tables; /** @sa inc_statement_select_full_join. */ inc_statement_select_full_join_t inc_statement_select_full_join; /** @sa inc_statement_select_full_range_join. */ inc_statement_select_full_range_join_t inc_statement_select_full_range_join; /** @sa inc_statement_select_range. */ inc_statement_select_range_t inc_statement_select_range; /** @sa inc_statement_select_range_check. */ inc_statement_select_range_check_t inc_statement_select_range_check; /** @sa inc_statement_select_scan. */ inc_statement_select_scan_t inc_statement_select_scan; /** @sa inc_statement_sort_merge_passes. */ inc_statement_sort_merge_passes_t inc_statement_sort_merge_passes; /** @sa inc_statement_sort_range. */ inc_statement_sort_range_t inc_statement_sort_range; /** @sa inc_statement_sort_rows. */ inc_statement_sort_rows_t inc_statement_sort_rows; /** @sa inc_statement_sort_scan. */ inc_statement_sort_scan_t inc_statement_sort_scan; /** @sa set_statement_no_index_used. */ set_statement_no_index_used_t set_statement_no_index_used; /** @sa set_statement_no_good_index_used. */ set_statement_no_good_index_used_t set_statement_no_good_index_used; /** @sa end_statement_v1_t. */ end_statement_v1_t end_statement; /** @sa get_thread_transaction_locker_v1_t. */ get_thread_transaction_locker_v1_t get_thread_transaction_locker; /** @sa start_transaction_v1_t. */ start_transaction_v1_t start_transaction; /** @sa set_transaction_xid_v1_t. */ set_transaction_xid_v1_t set_transaction_xid; /** @sa set_transaction_xa_state_v1_t. */ set_transaction_xa_state_v1_t set_transaction_xa_state; /** @sa set_transaction_gtid_v1_t. */ set_transaction_gtid_v1_t set_transaction_gtid; /** @sa set_transaction_trxid_v1_t. */ set_transaction_trxid_v1_t set_transaction_trxid; /** @sa inc_transaction_savepoints_v1_t. */ inc_transaction_savepoints_v1_t inc_transaction_savepoints; /** @sa inc_transaction_rollback_to_savepoint_v1_t. */ inc_transaction_rollback_to_savepoint_v1_t inc_transaction_rollback_to_savepoint; /** @sa inc_transaction_release_savepoint_v1_t. */ inc_transaction_release_savepoint_v1_t inc_transaction_release_savepoint; /** @sa end_transaction_v1_t. */ end_transaction_v1_t end_transaction; /** @sa start_socket_wait_v1_t. */ start_socket_wait_v1_t start_socket_wait; /** @sa end_socket_wait_v1_t. */ end_socket_wait_v1_t end_socket_wait; /** @sa set_socket_state_v1_t. */ set_socket_state_v1_t set_socket_state; /** @sa set_socket_info_v1_t. */ set_socket_info_v1_t set_socket_info; /** @sa set_socket_thread_owner_v1_t. */ set_socket_thread_owner_v1_t set_socket_thread_owner; /** @sa create_prepared_stmt_v1_t. */ create_prepared_stmt_v1_t create_prepared_stmt; /** @sa destroy_prepared_stmt_v1_t. */ destroy_prepared_stmt_v1_t destroy_prepared_stmt; /** @sa reprepare_prepared_stmt_v1_t. */ reprepare_prepared_stmt_v1_t reprepare_prepared_stmt; /** @sa execute_prepared_stmt_v1_t. */ execute_prepared_stmt_v1_t execute_prepared_stmt; /** @sa set_prepared_stmt_text_v1_t. */ set_prepared_stmt_text_v1_t set_prepared_stmt_text; /** @sa digest_start_v1_t. */ digest_start_v1_t digest_start; /** @sa digest_end_v1_t. */ digest_end_v1_t digest_end; /** @sa set_thread_connect_attrs_v1_t. */ set_thread_connect_attrs_v1_t set_thread_connect_attrs; /** @sa start_sp_v1_t. */ start_sp_v1_t start_sp; /** @sa start_sp_v1_t. */ end_sp_v1_t end_sp; /** @sa drop_sp_v1_t. */ drop_sp_v1_t drop_sp; /** @sa get_sp_share_v1_t. */ get_sp_share_v1_t get_sp_share; /** @sa release_sp_share_v1_t. */ release_sp_share_v1_t release_sp_share; /** @sa register_memory_v1_t. */ register_memory_v1_t register_memory; /** @sa memory_alloc_v1_t. */ memory_alloc_v1_t memory_alloc; /** @sa memory_realloc_v1_t. */ memory_realloc_v1_t memory_realloc; /** @sa memory_claim_v1_t. */ memory_claim_v1_t memory_claim; /** @sa memory_free_v1_t. */ memory_free_v1_t memory_free; unlock_table_v1_t unlock_table; create_metadata_lock_v1_t create_metadata_lock; set_metadata_lock_status_v1_t set_metadata_lock_status; destroy_metadata_lock_v1_t destroy_metadata_lock; start_metadata_wait_v1_t start_metadata_wait; end_metadata_wait_v1_t end_metadata_wait; set_thread_peer_port_v1_t set_thread_peer_port; }; /** @} (end of group Group_PSI_v1) */ #endif /* HAVE_PSI_1 */ #ifdef USE_PSI_2 #define HAVE_PSI_2 #endif #ifdef HAVE_PSI_2 /** @defgroup Group_PSI_v2 Application Binary Interface, version 2 @ingroup Instrumentation_interface @{ */ /** Performance Schema Interface, version 2. This is a placeholder, this interface is not defined yet. @since PSI_VERSION_2 */ struct PSI_v2 { /** Placeholder */ int placeholder; /* ... extended interface ... */ }; /** Placeholder */ struct PSI_mutex_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_rwlock_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_cond_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_thread_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_file_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_stage_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_statement_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_transaction_info_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_idle_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_mutex_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_rwlock_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_cond_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_file_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_statement_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_transaction_locker_state_v2 { /** Placeholder */ int placeholder; }; /** Placeholder */ struct PSI_socket_locker_state_v2 { /** Placeholder */ int placeholder; }; struct PSI_metadata_locker_state_v2 { int placeholder; }; /** @} (end of group Group_PSI_v2) */ #endif /* HAVE_PSI_2 */ /** @typedef PSI The instrumentation interface for the current version. @sa PSI_CURRENT_VERSION */ /** @typedef PSI_mutex_info The mutex information structure for the current version. */ /** @typedef PSI_rwlock_info The rwlock information structure for the current version. */ /** @typedef PSI_cond_info The cond information structure for the current version. */ /** @typedef PSI_thread_info The thread information structure for the current version. */ /** @typedef PSI_file_info The file information structure for the current version. */ /* Export the required version */ #ifdef USE_PSI_1 typedef struct PSI_v1 PSI; typedef struct PSI_mutex_info_v1 PSI_mutex_info; typedef struct PSI_rwlock_info_v1 PSI_rwlock_info; typedef struct PSI_cond_info_v1 PSI_cond_info; typedef struct PSI_thread_info_v1 PSI_thread_info; typedef struct PSI_file_info_v1 PSI_file_info; typedef struct PSI_stage_info_v1 PSI_stage_info; typedef struct PSI_statement_info_v1 PSI_statement_info; typedef struct PSI_transaction_info_v1 PSI_transaction_info; typedef struct PSI_socket_info_v1 PSI_socket_info; typedef struct PSI_idle_locker_state_v1 PSI_idle_locker_state; typedef struct PSI_mutex_locker_state_v1 PSI_mutex_locker_state; typedef struct PSI_rwlock_locker_state_v1 PSI_rwlock_locker_state; typedef struct PSI_cond_locker_state_v1 PSI_cond_locker_state; typedef struct PSI_file_locker_state_v1 PSI_file_locker_state; typedef struct PSI_statement_locker_state_v1 PSI_statement_locker_state; typedef struct PSI_transaction_locker_state_v1 PSI_transaction_locker_state; typedef struct PSI_socket_locker_state_v1 PSI_socket_locker_state; typedef struct PSI_sp_locker_state_v1 PSI_sp_locker_state; typedef struct PSI_metadata_locker_state_v1 PSI_metadata_locker_state; #endif #ifdef USE_PSI_2 typedef struct PSI_v2 PSI; typedef struct PSI_mutex_info_v2 PSI_mutex_info; typedef struct PSI_rwlock_info_v2 PSI_rwlock_info; typedef struct PSI_cond_info_v2 PSI_cond_info; typedef struct PSI_thread_info_v2 PSI_thread_info; typedef struct PSI_file_info_v2 PSI_file_info; typedef struct PSI_stage_info_v2 PSI_stage_info; typedef struct PSI_statement_info_v2 PSI_statement_info; typedef struct PSI_transaction_info_v2 PSI_transaction_info; typedef struct PSI_socket_info_v2 PSI_socket_info; typedef struct PSI_idle_locker_state_v2 PSI_idle_locker_state; typedef struct PSI_mutex_locker_state_v2 PSI_mutex_locker_state; typedef struct PSI_rwlock_locker_state_v2 PSI_rwlock_locker_state; typedef struct PSI_cond_locker_state_v2 PSI_cond_locker_state; typedef struct PSI_file_locker_state_v2 PSI_file_locker_state; typedef struct PSI_statement_locker_state_v2 PSI_statement_locker_state; typedef struct PSI_transaction_locker_state_v2 PSI_transaction_locker_state; typedef struct PSI_socket_locker_state_v2 PSI_socket_locker_state; typedef struct PSI_sp_locker_state_v2 PSI_sp_locker_state; typedef struct PSI_metadata_locker_state_v2 PSI_metadata_locker_state; #endif #ifndef HAVE_PSI_INTERFACE /** Dummy structure, used to declare PSI_server when no instrumentation is available. The content does not matter, since PSI_server will be NULL. */ struct PSI_none { int opaque; }; typedef struct PSI_none PSI; /** Stage instrument information. @since PSI_VERSION_1 This structure is used to register an instrumented stage. */ struct PSI_stage_info_none { /** Unused stage key. */ unsigned int m_key; /** The name of the stage instrument. */ const char *m_name; /** Unused stage flags. */ int m_flags; }; /** The stage instrumentation has to co exist with the legacy THD::set_proc_info instrumentation. To avoid duplication of the instrumentation in the server, the common PSI_stage_info structure is used, so we export it here, even when not building with HAVE_PSI_INTERFACE. */ typedef struct PSI_stage_info_none PSI_stage_info; typedef struct PSI_stage_info_none PSI_statement_info; typedef struct PSI_stage_info_none PSI_sp_locker_state; typedef struct PSI_stage_info_none PSI_metadata_locker_state; typedef struct PSI_stage_info_none PSI_metadata_locker; #endif /* HAVE_PSI_INTERFACE */ extern MYSQL_PLUGIN_IMPORT PSI *PSI_server; /* Allow to override PSI_XXX_CALL at compile time with more efficient implementations, if available. If nothing better is available, make a dynamic call using the PSI_server function pointer. */ #define PSI_DYNAMIC_CALL(M) PSI_server->M /** @} */ C_MODE_END #endif /* MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H */ server/mysql/psi/mysql_statement.h000064400000015706151031265040013422 0ustar00/* Copyright (c) 2010, 2023, Oracle and/or its affiliates. Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQL_STATEMENT_H #define MYSQL_STATEMENT_H /** @file mysql/psi/mysql_statement.h Instrumentation helpers for statements. */ #include "mysql/psi/psi.h" class Diagnostics_area; typedef const struct charset_info_st CHARSET_INFO; #ifndef PSI_STATEMENT_CALL #define PSI_STATEMENT_CALL(M) PSI_DYNAMIC_CALL(M) #endif #ifndef PSI_DIGEST_CALL #define PSI_DIGEST_CALL(M) PSI_DYNAMIC_CALL(M) #endif /** @defgroup Statement_instrumentation Statement Instrumentation @ingroup Instrumentation_interface @{ */ /** @def mysql_statement_register(P1, P2, P3) Statement registration. */ #ifdef HAVE_PSI_STATEMENT_INTERFACE #define mysql_statement_register(P1, P2, P3) \ inline_mysql_statement_register(P1, P2, P3) #else #define mysql_statement_register(P1, P2, P3) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE #define MYSQL_DIGEST_START(LOCKER) \ inline_mysql_digest_start(LOCKER) #else #define MYSQL_DIGEST_START(LOCKER) \ NULL #endif #ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE #define MYSQL_DIGEST_END(LOCKER, DIGEST) \ inline_mysql_digest_end(LOCKER, DIGEST) #else #define MYSQL_DIGEST_END(LOCKER, DIGEST) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_START_STATEMENT(STATE, K, DB, DB_LEN, CS, SPS) \ inline_mysql_start_statement(STATE, K, DB, DB_LEN, CS, SPS, __FILE__, __LINE__) #else #define MYSQL_START_STATEMENT(STATE, K, DB, DB_LEN, CS, SPS) \ NULL #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_REFINE_STATEMENT(LOCKER, K) \ inline_mysql_refine_statement(LOCKER, K) #else #define MYSQL_REFINE_STATEMENT(LOCKER, K) \ NULL #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_SET_STATEMENT_TEXT(LOCKER, P1, P2) \ inline_mysql_set_statement_text(LOCKER, P1, P2) #else #define MYSQL_SET_STATEMENT_TEXT(LOCKER, P1, P2) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_SET_STATEMENT_LOCK_TIME(LOCKER, P1) \ inline_mysql_set_statement_lock_time(LOCKER, P1) #else #define MYSQL_SET_STATEMENT_LOCK_TIME(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_SET_STATEMENT_ROWS_SENT(LOCKER, P1) \ inline_mysql_set_statement_rows_sent(LOCKER, P1) #else #define MYSQL_SET_STATEMENT_ROWS_SENT(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_SET_STATEMENT_ROWS_EXAMINED(LOCKER, P1) \ inline_mysql_set_statement_rows_examined(LOCKER, P1) #else #define MYSQL_SET_STATEMENT_ROWS_EXAMINED(LOCKER, P1) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE #define MYSQL_END_STATEMENT(LOCKER, DA) \ inline_mysql_end_statement(LOCKER, DA) #else #define MYSQL_END_STATEMENT(LOCKER, DA) \ do {} while (0) #endif #ifdef HAVE_PSI_STATEMENT_INTERFACE static inline void inline_mysql_statement_register( const char *category, PSI_statement_info *info, int count) { PSI_STATEMENT_CALL(register_statement)(category, info, count); } #ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE static inline struct PSI_digest_locker * inline_mysql_digest_start(PSI_statement_locker *locker) { PSI_digest_locker* digest_locker= NULL; if (psi_likely(locker != NULL)) digest_locker= PSI_DIGEST_CALL(digest_start)(locker); return digest_locker; } #endif #ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE static inline void inline_mysql_digest_end(PSI_digest_locker *locker, const sql_digest_storage *digest) { if (psi_likely(locker != NULL)) PSI_DIGEST_CALL(digest_end)(locker, digest); } #endif static inline struct PSI_statement_locker * inline_mysql_start_statement(PSI_statement_locker_state *state, PSI_statement_key key, const char *db, size_t db_len, CHARSET_INFO *charset, PSI_sp_share *sp_share, const char *src_file, uint src_line) { PSI_statement_locker *locker; locker= PSI_STATEMENT_CALL(get_thread_statement_locker)(state, key, charset, sp_share); if (psi_likely(locker != NULL)) PSI_STATEMENT_CALL(start_statement)(locker, db, (uint)db_len, src_file, src_line); return locker; } static inline struct PSI_statement_locker * inline_mysql_refine_statement(PSI_statement_locker *locker, PSI_statement_key key) { if (psi_likely(locker != NULL)) { locker= PSI_STATEMENT_CALL(refine_statement)(locker, key); } return locker; } static inline void inline_mysql_set_statement_text(PSI_statement_locker *locker, const char *text, uint text_len) { if (psi_likely(locker != NULL)) { PSI_STATEMENT_CALL(set_statement_text)(locker, text, text_len); } } static inline void inline_mysql_set_statement_lock_time(PSI_statement_locker *locker, ulonglong count) { if (psi_likely(locker != NULL)) { PSI_STATEMENT_CALL(set_statement_lock_time)(locker, count); } } static inline void inline_mysql_set_statement_rows_sent(PSI_statement_locker *locker, ulonglong count) { if (psi_likely(locker != NULL)) { PSI_STATEMENT_CALL(set_statement_rows_sent)(locker, count); } } static inline void inline_mysql_set_statement_rows_examined(PSI_statement_locker *locker, ulonglong count) { if (psi_likely(locker != NULL)) { PSI_STATEMENT_CALL(set_statement_rows_examined)(locker, count); } } static inline void inline_mysql_end_statement(struct PSI_statement_locker *locker, Diagnostics_area *stmt_da) { PSI_STAGE_CALL(end_stage)(); if (psi_likely(locker != NULL)) PSI_STATEMENT_CALL(end_statement)(locker, stmt_da); } #endif /** @} (end of group Statement_instrumentation) */ #endif server/mysql/plugin_encryption.h000064400000010521151031265040013134 0ustar00#ifndef MYSQL_PLUGIN_ENCRYPTION_INCLUDED /* Copyright (C) 2014, 2015 Sergei Golubchik and MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Encryption Plugin API. This file defines the API for server plugins that manage encryption keys for MariaDB on-disk data encryption. */ #define MYSQL_PLUGIN_ENCRYPTION_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #define MariaDB_ENCRYPTION_INTERFACE_VERSION 0x0300 /** Encryption plugin descriptor */ struct st_mariadb_encryption { int interface_version; /**< version plugin uses */ /*********** KEY MANAGEMENT ********************************************/ /** function returning latest key version for a given key id @return a version or ENCRYPTION_KEY_VERSION_INVALID to indicate an error. */ unsigned int (*get_latest_key_version)(unsigned int key_id); /** function returning a key for a key version @param version the requested key version @param key the key will be stored there. Can be NULL - in which case no key will be returned @param key_length in: key buffer size out: the actual length of the key This method can be used to query the key length - the required buffer size - by passing key==NULL. If the buffer size is less than the key length the content of the key buffer is undefined (the plugin is free to partially fill it with the key data or leave it untouched). @return 0 on success, or ENCRYPTION_KEY_VERSION_INVALID, ENCRYPTION_KEY_BUFFER_TOO_SMALL or any other non-zero number for errors */ unsigned int (*get_key)(unsigned int key_id, unsigned int version, unsigned char *key, unsigned int *key_length); /*********** ENCRYPTION ************************************************/ /* the caller uses encryption as follows: 1. create the encryption context object of the crypt_ctx_size() bytes. 2. initialize it with crypt_ctx_init(). 3. repeat crypt_ctx_update() until there are no more data to encrypt. 4. write the remaining output bytes and destroy the context object with crypt_ctx_finish(). */ /** returns the size of the encryption context object in bytes */ unsigned int (*crypt_ctx_size)(unsigned int key_id, unsigned int key_version); /** initializes the encryption context object. */ int (*crypt_ctx_init)(void *ctx, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen, int flags, unsigned int key_id, unsigned int key_version); /** processes (encrypts or decrypts) a chunk of data writes the output to th dst buffer. note that it might write more bytes that were in the input. or less. or none at all. */ int (*crypt_ctx_update)(void *ctx, const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen); /** writes the remaining output bytes and destroys the encryption context crypt_ctx_update might've cached part of the output in the context, this method will flush these data out. */ int (*crypt_ctx_finish)(void *ctx, unsigned char* dst, unsigned int* dlen); /** returns the length of the encrypted data it returns the exact length, given only the source length. which means, this API only supports encryption algorithms where the length of the encrypted data only depends on the length of the input (a.k.a. compression is not supported). */ unsigned int (*encrypted_length)(unsigned int slen, unsigned int key_id, unsigned int key_version); }; #ifdef __cplusplus } #endif #endif server/mysql/auth_dialog_client.h000064400000004015151031265040013203 0ustar00#ifndef MYSQL_AUTH_DIALOG_CLIENT_INCLUDED /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Definitions needed to use Dialog client authentication plugin */ struct st_mysql; #define MYSQL_AUTH_DIALOG_CLIENT_INCLUDED /** type of the mysql_authentication_dialog_ask function @param mysql mysql @param type type of the input 1 - ordinary string input 2 - password string @param prompt prompt @param buf a buffer to store the use input @param buf_len the length of the buffer @retval a pointer to the user input string. It may be equal to 'buf' or to 'mysql->password'. In all other cases it is assumed to be an allocated string, and the "dialog" plugin will free() it. */ typedef char *(*mysql_authentication_dialog_ask_t)(struct st_mysql *mysql, int type, const char *prompt, char *buf, int buf_len); /** first byte of the question string is the question "type". It can be an "ordinary" or a "password" question. The last bit set marks a last question in the authentication exchange. */ #define ORDINARY_QUESTION "\2" #define LAST_QUESTION "\3" #define PASSWORD_QUESTION "\4" #define LAST_PASSWORD "\5" #endif server/mysql/service_progress_report.h000064400000006434151031265040014353 0ustar00#ifndef MYSQL_SERVICE_PROGRESS_REPORT_INCLUDED /* Copyright (C) 2011 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service allows plugins to report progress of long running operations to the server. The progress report is visible in SHOW PROCESSLIST, INFORMATION_SCHEMA.PROCESSLIST, and is sent to the client if requested. The functions are documented at https://mariadb.com/kb/en/progress-reporting/#how-to-add-support-for-progress-reporting-to-a-storage-engine */ #ifdef __cplusplus extern "C" { #endif #define thd_proc_info(thd, msg) set_thd_proc_info(thd, msg, \ __func__, __FILE__, __LINE__) extern struct progress_report_service_st { void (*thd_progress_init_func)(MYSQL_THD thd, unsigned int max_stage); void (*thd_progress_report_func)(MYSQL_THD thd, unsigned long long progress, unsigned long long max_progress); void (*thd_progress_next_stage_func)(MYSQL_THD thd); void (*thd_progress_end_func)(MYSQL_THD thd); const char *(*set_thd_proc_info_func)(MYSQL_THD, const char *info, const char *func, const char *file, unsigned int line); } *progress_report_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_progress_init(thd,max_stage) (progress_report_service->thd_progress_init_func((thd),(max_stage))) #define thd_progress_report(thd, progress, max_progress) (progress_report_service->thd_progress_report_func((thd), (progress), (max_progress))) #define thd_progress_next_stage(thd) (progress_report_service->thd_progress_next_stage_func(thd)) #define thd_progress_end(thd) (progress_report_service->thd_progress_end_func(thd)) #define set_thd_proc_info(thd,info,func,file,line) (progress_report_service->set_thd_proc_info_func((thd),(info),(func),(file),(line))) #else /** Report progress for long running operations @param thd User thread connection handle @param progress Where we are now @param max_progress Progress will continue up to this */ void thd_progress_init(MYSQL_THD thd, unsigned int max_stage); void thd_progress_report(MYSQL_THD thd, unsigned long long progress, unsigned long long max_progress); void thd_progress_next_stage(MYSQL_THD thd); void thd_progress_end(MYSQL_THD thd); const char *set_thd_proc_info(MYSQL_THD, const char * info, const char *func, const char *file, unsigned int line); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_PROGRESS_REPORT_INCLUDED #endif server/mysql/service_thd_alloc.h000064400000010612151031265040013036 0ustar00#ifndef MYSQL_SERVICE_THD_ALLOC_INCLUDED /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service provides functions to allocate memory in a connection local memory pool. The memory allocated there will be automatically freed at the end of the statement, don't use it for allocations that should live longer than that. For short living allocations this is more efficient than using my_malloc and friends, and automatic "garbage collection" allows not to think about memory leaks. The pool is best for small to medium objects, don't use it for large allocations - they are better served with my_malloc. */ #ifndef MYSQL_ABI_CHECK #include #endif #ifdef __cplusplus extern "C" { #endif struct st_mysql_lex_string { char *str; size_t length; }; typedef struct st_mysql_lex_string MYSQL_LEX_STRING; struct st_mysql_const_lex_string { const char *str; size_t length; }; typedef struct st_mysql_const_lex_string MYSQL_CONST_LEX_STRING; extern struct thd_alloc_service_st { void *(*thd_alloc_func)(MYSQL_THD, size_t); void *(*thd_calloc_func)(MYSQL_THD, size_t); char *(*thd_strdup_func)(MYSQL_THD, const char *); char *(*thd_strmake_func)(MYSQL_THD, const char *, size_t); void *(*thd_memdup_func)(MYSQL_THD, const void*, size_t); MYSQL_CONST_LEX_STRING *(*thd_make_lex_string_func)(MYSQL_THD, MYSQL_CONST_LEX_STRING *, const char *, size_t, int); } *thd_alloc_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_alloc(thd,size) (thd_alloc_service->thd_alloc_func((thd), (size))) #define thd_calloc(thd,size) (thd_alloc_service->thd_calloc_func((thd), (size))) #define thd_strdup(thd,str) (thd_alloc_service->thd_strdup_func((thd), (str))) #define thd_strmake(thd,str,size) \ (thd_alloc_service->thd_strmake_func((thd), (str), (size))) #define thd_memdup(thd,str,size) \ (thd_alloc_service->thd_memdup_func((thd), (str), (size))) #define thd_make_lex_string(thd, lex_str, str, size, allocate_lex_string) \ (thd_alloc_service->thd_make_lex_string_func((thd), (lex_str), (str), \ (size), (allocate_lex_string))) #else /** Allocate memory in the connection's local memory pool @details When properly used in place of @c my_malloc(), this can significantly improve concurrency. Don't use this or related functions to allocate large chunks of memory. Use for temporary storage only. The memory will be freed automatically at the end of the statement; no explicit code is required to prevent memory leaks. @see alloc_root() */ void *thd_alloc(MYSQL_THD thd, size_t size); /** @see thd_alloc() */ void *thd_calloc(MYSQL_THD thd, size_t size); /** @see thd_alloc() */ char *thd_strdup(MYSQL_THD thd, const char *str); /** @see thd_alloc() */ char *thd_strmake(MYSQL_THD thd, const char *str, size_t size); /** @see thd_alloc() */ void *thd_memdup(MYSQL_THD thd, const void* str, size_t size); /** Create a LEX_STRING in this connection's local memory pool @param thd user thread connection handle @param lex_str pointer to LEX_STRING object to be initialized @param str initializer to be copied into lex_str @param size length of str, in bytes @param allocate_lex_string flag: if TRUE, allocate new LEX_STRING object, instead of using lex_str value @return NULL on failure, or pointer to the LEX_STRING object @see thd_alloc() */ MYSQL_CONST_LEX_STRING *thd_make_lex_string(MYSQL_THD thd, MYSQL_CONST_LEX_STRING *lex_str, const char *str, size_t size, int allocate_lex_string); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_ALLOC_INCLUDED #endif server/mysql/service_encryption.h000064400000013031151031265040013275 0ustar00#ifndef MYSQL_SERVICE_ENCRYPTION_INCLUDED /* Copyright (c) 2015, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file encryption service Functions to support data encryption and encryption key management. They are normally implemented in an encryption plugin, so this service connects encryption *consumers* (e.g. storage engines) to the encryption *provider* (encryption plugin). */ #ifndef MYSQL_ABI_CHECK #include #ifdef _WIN32 #ifndef __cplusplus #define inline __inline #endif #endif #endif #ifdef __cplusplus extern "C" { #endif /* returned from encryption_key_get_latest_version() */ #define ENCRYPTION_KEY_VERSION_INVALID (~(unsigned int)0) #define ENCRYPTION_KEY_NOT_ENCRYPTED (0) #define ENCRYPTION_KEY_SYSTEM_DATA 1 #define ENCRYPTION_KEY_TEMPORARY_DATA 2 /* returned from encryption_key_get() */ #define ENCRYPTION_KEY_BUFFER_TOO_SMALL (100) #define ENCRYPTION_FLAG_DECRYPT 0 #define ENCRYPTION_FLAG_ENCRYPT 1 #define ENCRYPTION_FLAG_NOPAD 2 struct encryption_service_st { unsigned int (*encryption_key_get_latest_version_func)(unsigned int key_id); unsigned int (*encryption_key_get_func)(unsigned int key_id, unsigned int key_version, unsigned char* buffer, unsigned int* length); unsigned int (*encryption_ctx_size_func)(unsigned int key_id, unsigned int key_version); int (*encryption_ctx_init_func)(void *ctx, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen, int flags, unsigned int key_id, unsigned int key_version); int (*encryption_ctx_update_func)(void *ctx, const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen); int (*encryption_ctx_finish_func)(void *ctx, unsigned char* dst, unsigned int* dlen); unsigned int (*encryption_encrypted_length_func)(unsigned int slen, unsigned int key_id, unsigned int key_version); }; #ifdef MYSQL_DYNAMIC_PLUGIN extern struct encryption_service_st *encryption_service; #define encryption_key_get_latest_version(KI) encryption_service->encryption_key_get_latest_version_func(KI) #define encryption_key_get(KI,KV,K,S) encryption_service->encryption_key_get_func((KI),(KV),(K),(S)) #define encryption_ctx_size(KI,KV) encryption_service->encryption_ctx_size_func((KI),(KV)) #define encryption_ctx_init(CTX,K,KL,IV,IVL,F,KI,KV) encryption_service->encryption_ctx_init_func((CTX),(K),(KL),(IV),(IVL),(F),(KI),(KV)) #define encryption_ctx_update(CTX,S,SL,D,DL) encryption_service->encryption_ctx_update_func((CTX),(S),(SL),(D),(DL)) #define encryption_ctx_finish(CTX,D,DL) encryption_service->encryption_ctx_finish_func((CTX),(D),(DL)) #define encryption_encrypted_length(SL,KI,KV) encryption_service->encryption_encrypted_length_func((SL),(KI),(KV)) #else extern struct encryption_service_st encryption_handler; #define encryption_key_get_latest_version(KI) encryption_handler.encryption_key_get_latest_version_func(KI) #define encryption_key_get(KI,KV,K,S) encryption_handler.encryption_key_get_func((KI),(KV),(K),(S)) #define encryption_ctx_size(KI,KV) encryption_handler.encryption_ctx_size_func((KI),(KV)) #define encryption_ctx_init(CTX,K,KL,IV,IVL,F,KI,KV) encryption_handler.encryption_ctx_init_func((CTX),(K),(KL),(IV),(IVL),(F),(KI),(KV)) #define encryption_ctx_update(CTX,S,SL,D,DL) encryption_handler.encryption_ctx_update_func((CTX),(S),(SL),(D),(DL)) #define encryption_ctx_finish(CTX,D,DL) encryption_handler.encryption_ctx_finish_func((CTX),(D),(DL)) #define encryption_encrypted_length(SL,KI,KV) encryption_handler.encryption_encrypted_length_func((SL),(KI),(KV)) #endif static inline unsigned int encryption_key_id_exists(unsigned int id) { return encryption_key_get_latest_version(id) != ENCRYPTION_KEY_VERSION_INVALID; } static inline unsigned int encryption_key_version_exists(unsigned int id, unsigned int version) { unsigned int unused; return encryption_key_get(id, version, NULL, &unused) != ENCRYPTION_KEY_VERSION_INVALID; } static inline int encryption_crypt(const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen, const unsigned char* key, unsigned int klen, const unsigned char* iv, unsigned int ivlen, int flags, unsigned int key_id, unsigned int key_version) { void *ctx= alloca(encryption_ctx_size(key_id, key_version)); int res1, res2; unsigned int d1, d2; if ((res1= encryption_ctx_init(ctx, key, klen, iv, ivlen, flags, key_id, key_version))) return res1; res1= encryption_ctx_update(ctx, src, slen, dst, &d1); res2= encryption_ctx_finish(ctx, dst + d1, &d2); *dlen= d1 + d2; return res1 ? res1 : res2; } #ifdef __cplusplus } #endif #define MYSQL_SERVICE_ENCRYPTION_INCLUDED #endif server/mysql/plugin_audit.h000064400000012641151031265040012055 0ustar00/* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_audit_h #define _my_audit_h /************************************************************************* API for Audit plugin. (MYSQL_AUDIT_PLUGIN) */ #include "plugin.h" #ifdef __cplusplus extern "C" { #endif #define MYSQL_AUDIT_CLASS_MASK_SIZE 1 #define MYSQL_AUDIT_INTERFACE_VERSION 0x0302 /************************************************************************* AUDIT CLASS : GENERAL LOG events occurs before emitting to the general query log. ERROR events occur before transmitting errors to the user. RESULT events occur after transmitting a resultset to the user. STATUS events occur after transmitting a resultset or errors to the user. */ #define MYSQL_AUDIT_GENERAL_CLASS 0 #define MYSQL_AUDIT_GENERAL_CLASSMASK (1 << MYSQL_AUDIT_GENERAL_CLASS) #define MYSQL_AUDIT_GENERAL_LOG 0 #define MYSQL_AUDIT_GENERAL_ERROR 1 #define MYSQL_AUDIT_GENERAL_RESULT 2 #define MYSQL_AUDIT_GENERAL_STATUS 3 struct mysql_event_general { unsigned int event_subclass; int general_error_code; unsigned long general_thread_id; const char *general_user; unsigned int general_user_length; const char *general_command; unsigned int general_command_length; const char *general_query; unsigned int general_query_length; const struct charset_info_st *general_charset; unsigned long long general_time; unsigned long long general_rows; /* Added in version 0x302 */ unsigned long long query_id; MYSQL_CONST_LEX_STRING database; }; /* AUDIT CLASS : CONNECTION CONNECT occurs after authentication phase is completed. DISCONNECT occurs after connection is terminated. CHANGE_USER occurs after COM_CHANGE_USER RPC is completed. */ #define MYSQL_AUDIT_CONNECTION_CLASS 1 #define MYSQL_AUDIT_CONNECTION_CLASSMASK (1 << MYSQL_AUDIT_CONNECTION_CLASS) #define MYSQL_AUDIT_CONNECTION_CONNECT 0 #define MYSQL_AUDIT_CONNECTION_DISCONNECT 1 #define MYSQL_AUDIT_CONNECTION_CHANGE_USER 2 struct mysql_event_connection { unsigned int event_subclass; int status; unsigned long thread_id; const char *user; unsigned int user_length; const char *priv_user; unsigned int priv_user_length; const char *external_user; unsigned int external_user_length; const char *proxy_user; unsigned int proxy_user_length; const char *host; unsigned int host_length; const char *ip; unsigned int ip_length; MYSQL_CONST_LEX_STRING database; }; /* AUDIT CLASS : TABLE LOCK occurs when a connection "locks" (this does not necessarily mean a table lock and also happens for row-locking engines) the table at the beginning of a statement. This event is generated at the beginning of every statement for every affected table, unless there's a LOCK TABLES statement in effect (in which case it is generated once for LOCK TABLES and then is suppressed until the tables are unlocked). CREATE/DROP/RENAME occur when a table is created, dropped, or renamed. */ #define MYSQL_AUDIT_TABLE_CLASS 15 #define MYSQL_AUDIT_TABLE_CLASSMASK (1 << MYSQL_AUDIT_TABLE_CLASS) #define MYSQL_AUDIT_TABLE_LOCK 0 #define MYSQL_AUDIT_TABLE_CREATE 1 #define MYSQL_AUDIT_TABLE_DROP 2 #define MYSQL_AUDIT_TABLE_RENAME 3 #define MYSQL_AUDIT_TABLE_ALTER 4 struct mysql_event_table { unsigned int event_subclass; unsigned long thread_id; const char *user; const char *priv_user; const char *priv_host; const char *external_user; const char *proxy_user; const char *host; const char *ip; MYSQL_CONST_LEX_STRING database; MYSQL_CONST_LEX_STRING table; /* for MYSQL_AUDIT_TABLE_RENAME */ MYSQL_CONST_LEX_STRING new_database; MYSQL_CONST_LEX_STRING new_table; /* for MYSQL_AUDIT_TABLE_LOCK, true if read-only, false if read/write */ int read_only; /* Added in version 0x302 */ unsigned long long query_id; }; /************************************************************************* Here we define the descriptor structure, that is referred from st_mysql_plugin. release_thd() event occurs when the event class consumer is to be disassociated from the specified THD. This would typically occur before some operation which may require sleeping - such as when waiting for the next query from the client. event_notify() is invoked whenever an event occurs which is of any class for which the plugin has interest. The second argument indicates the specific event class and the third argument is data as required for that class. class_mask is an array of bits used to indicate what event classes that this plugin wants to receive. */ struct st_mysql_audit { int interface_version; void (*release_thd)(MYSQL_THD); void (*event_notify)(MYSQL_THD, unsigned int, const void *); unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; }; #ifdef __cplusplus } #endif #endif server/mysql/service_print_check_msg.h000064400000003020151031265040014237 0ustar00/* Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #pragma once /** @file include/mysql/service_print_check_msg.h This service provides functions to write messages for check or repair */ #ifdef __cplusplus extern "C" { #endif extern struct print_check_msg_service_st { void (*print_check_msg)(MYSQL_THD, const char *db_name, const char *table_name, const char *op, const char *msg_type, const char *message, my_bool print_to_log); } *print_check_msg_service; #ifdef MYSQL_DYNAMIC_PLUGIN # define print_check_msg_context(_THD) print_check_msg_service->print_check_msg #else extern void print_check_msg(MYSQL_THD, const char *db_name, const char *table_name, const char *op, const char *msg_type, const char *message, my_bool print_to_log); #endif #ifdef __cplusplus } #endif server/mysql/plugin_auth_common.h000064400000010635151031265040013261 0ustar00#ifndef MYSQL_PLUGIN_AUTH_COMMON_INCLUDED /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab Copyright (c) 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef _WIN32 #include #endif /** @file This file defines constants and data structures that are the same for both client- and server-side authentication plugins. */ #define MYSQL_PLUGIN_AUTH_COMMON_INCLUDED /** the max allowed length for a user name */ #define MYSQL_USERNAME_LENGTH 512 /** return values of the plugin authenticate_user() method. */ /** Authentication failed, plugin internal error. An error occurred in the authentication plugin itself. These errors are reported in table performance_schema.host_cache, column COUNT_AUTH_PLUGIN_ERRORS. */ #define CR_AUTH_PLUGIN_ERROR 3 /** Authentication failed, client server handshake. An error occurred during the client server handshake. These errors are reported in table performance_schema.host_cache, column COUNT_HANDSHAKE_ERRORS. */ #define CR_AUTH_HANDSHAKE 2 /** Authentication failed, user credentials. For example, wrong passwords. These errors are reported in table performance_schema.host_cache, column COUNT_AUTHENTICATION_ERRORS. */ #define CR_AUTH_USER_CREDENTIALS 1 /** Authentication failed. Additionally, all other CR_xxx values (libmysql error code) can be used too. The client plugin may set the error code and the error message directly in the MYSQL structure and return CR_ERROR. If a CR_xxx specific error code was returned, an error message in the MYSQL structure will be overwritten. If CR_ERROR is returned without setting the error in MYSQL, CR_UNKNOWN_ERROR will be user. */ #define CR_ERROR 0 /** Authentication (client part) was successful. It does not mean that the authentication as a whole was successful, usually it only means that the client was able to send the user name and the password to the server. If CR_OK is returned, the libmysql reads the next packet expecting it to be one of OK, ERROR, or CHANGE_PLUGIN packets. */ #define CR_OK -1 /** Authentication was successful. It means that the client has done its part successfully and also that a plugin has read the last packet (one of OK, ERROR, CHANGE_PLUGIN). In this case, libmysql will not read a packet from the server, but it will use the data at mysql->net.read_pos. A plugin may return this value if the number of roundtrips in the authentication protocol is not known in advance, and the client plugin needs to read one packet more to determine if the authentication is finished or not. */ #define CR_OK_HANDSHAKE_COMPLETE -2 typedef struct st_plugin_vio_info { enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET, MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol; int socket; /**< it's set, if the protocol is SOCKET or TCP */ #ifdef _WIN32 HANDLE handle; /**< it's set, if the protocol is PIPE or MEMORY */ #endif } MYSQL_PLUGIN_VIO_INFO; /** Provides plugin access to communication channel */ typedef struct st_plugin_vio { /** Plugin provides a pointer reference and this function sets it to the contents of any incoming packet. Returns the packet length, or -1 if the plugin should terminate. */ int (*read_packet)(struct st_plugin_vio *vio, unsigned char **buf); /** Plugin provides a buffer with data and the length and this function sends it as a packet. Returns 0 on success, 1 on failure. */ int (*write_packet)(struct st_plugin_vio *vio, const unsigned char *packet, int packet_len); /** Fills in a st_plugin_vio_info structure, providing the information about the connection. */ void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info); } MYSQL_PLUGIN_VIO; #endif server/mysql/service_my_snprintf.h000064400000007212151031265040013457 0ustar00#ifndef MYSQL_SERVICE_MY_SNPRINTF_INCLUDED /* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my_snprintf service Portable and limited vsnprintf() implementation. This is a portable, limited vsnprintf() implementation, with some extra features. "Portable" means that it'll produce identical result on all platforms (for example, on Windows and Linux system printf %e formats the exponent differently, on different systems %p either prints leading 0x or not, %s may accept null pointer or crash on it). "Limited" means that it does not support all the C89 features. But it supports few extensions, not in any standard. my_vsnprintf(to, n, fmt, ap) @param[out] to A buffer to store the result in @param[in] n Store up to n-1 characters, followed by an end 0 @param[in] fmt printf-like format string @param[in] ap Arguments @return a number of bytes written to a buffer *excluding* terminating '\0' @post The syntax of a format string is generally the same: % where everything but the format is optional. Three one-character flags are recognized: '0' has the standard zero-padding semantics; '-' is parsed, but silently ignored; '`' (backtick) is only supported for strings (%s) and means that the string will be quoted according to MySQL identifier quoting rules. Both and can be specified as numbers or '*'. If an asterisk is used, an argument of type int is consumed. can be 'l', 'll', or 'z'. Supported formats are 's' (null pointer is accepted, printed as "(null)"), 'b' (extension, see below), 'c', 'd', 'i', 'u', 'x', 'o', 'X', 'p' (works as 0x%x), 'f', 'g', 'M' (extension, see below), 'T' (extension, see below). Standard syntax for positional arguments $n is supported. Extensions: Flag '`' (backtick): see above. Format 'b': binary buffer, prints exactly bytes from the argument, without stopping at '\0'. Format 'M': takes one integer, prints this integer, space, double quote error message, double quote. In other words printf("%M", n) === printf("%d \"%s\"", n, strerror(n)) Format 'T': takes string and print it like s but if the strints should be truncated puts "..." at the end. */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #include #endif extern struct my_snprintf_service_st { size_t (*my_snprintf_type)(char*, size_t, const char*, ...); size_t (*my_vsnprintf_type)(char *, size_t, const char*, va_list); } *my_snprintf_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_vsnprintf my_snprintf_service->my_vsnprintf_type #define my_snprintf my_snprintf_service->my_snprintf_type #else size_t my_snprintf(char* to, size_t n, const char* fmt, ...); size_t my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_MY_SNPRINTF_INCLUDED #endif server/mysql/service_sha1.h000064400000004162151031265040011744 0ustar00#ifndef MYSQL_SERVICE_SHA1_INCLUDED /* Copyright (c) 2013, 2014, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my sha1 service Functions to calculate SHA1 hash from a memory buffer */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #endif #define MY_SHA1_HASH_SIZE 20 /* Hash size in bytes */ extern struct my_sha1_service_st { void (*my_sha1_type)(unsigned char*, const char*, size_t); void (*my_sha1_multi_type)(unsigned char*, ...); size_t (*my_sha1_context_size_type)(); void (*my_sha1_init_type)(void *); void (*my_sha1_input_type)(void *, const unsigned char *, size_t); void (*my_sha1_result_type)(void *, unsigned char *); } *my_sha1_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_sha1(A,B,C) my_sha1_service->my_sha1_type(A,B,C) #define my_sha1_multi my_sha1_service->my_sha1_multi_type #define my_sha1_context_size() my_sha1_service->my_sha1_context_size_type() #define my_sha1_init(A) my_sha1_service->my_sha1_init_type(A) #define my_sha1_input(A,B,C) my_sha1_service->my_sha1_input_type(A,B,C) #define my_sha1_result(A,B) my_sha1_service->my_sha1_result_type(A,B) #else void my_sha1(unsigned char*, const char*, size_t); void my_sha1_multi(unsigned char*, ...); size_t my_sha1_context_size(); void my_sha1_init(void *context); void my_sha1_input(void *context, const unsigned char *buf, size_t len); void my_sha1_result(void *context, unsigned char *digest); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_SHA1_INCLUDED #endif server/mysql/service_encryption_scheme.h000064400000013016151031265040014624 0ustar00#ifndef MYSQL_SERVICE_ENCRYPTION_SCHEME_INCLUDED /* Copyright (c) 2015, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file encryption scheme service A higher-level access to encryption service. This is a helper service that storage engines use to encrypt tables on disk. It requests keys from the plugin, generates temporary or local keys from the global (as returned by the plugin) keys, etc. To use the service: * st_encryption_scheme object is created per space. A "space" can be a table space in XtraDB/InnoDB, a file in Aria, etc. The whole space is encrypted with the one key id. * The service does not take the key and the IV as parameters for encryption or decryption. Instead it takes two 32-bit integers and one 64-bit integer (and requests the key from an encryption plugin, if needed). * The service requests the global key from the encryption plugin automatically as needed. Three last keys are cached in the st_encryption_scheme. Number of key requests (number of cache misses) are counted in st_encryption_scheme::keyserver_requests * If an st_encryption_scheme can be used concurrently by different threads, it needs to be able to lock itself when accessing the key cache. Set the st_encryption_scheme::locker appropriately. If non-zero, it will be invoked by encrypt/decrypt functions to lock and unlock the scheme when needed. * Implementation details (in particular, key derivation) are defined by the scheme type. Currently only schema type 1 is supported. In the schema type 1, every "space" (table space in XtraDB/InnoDB, file in Aria) is encrypted with a different space-local key: * Every space has a 16-byte unique identifier (typically it's generated randomly and stored in the space). The caller should put it into st_encryption_scheme::iv. * Space-local key is generated by encrypting this identifier with the global encryption key (of the given id and version) using AES_ECB. * Encryption/decryption parameters for a page are typically the 4-byte space id, 4-byte page position (offset, page number, etc), and the 8-byte LSN. This guarantees that they'll be different for any two pages (of the same or different tablespaces) and also that they'll change for the same page when it's modified. They don't need to be secret (they create the IV, not the encryption key). */ #ifdef __cplusplus extern "C" { #endif #define ENCRYPTION_SCHEME_KEY_INVALID -1 #define ENCRYPTION_SCHEME_BLOCK_LENGTH 16 struct st_encryption_scheme_key { unsigned int version; unsigned char key[ENCRYPTION_SCHEME_BLOCK_LENGTH]; }; struct st_encryption_scheme { unsigned char iv[ENCRYPTION_SCHEME_BLOCK_LENGTH]; struct st_encryption_scheme_key key[3]; unsigned int keyserver_requests; unsigned int key_id; unsigned int type; void (*locker)(struct st_encryption_scheme *self, int release); }; extern struct encryption_scheme_service_st { int (*encryption_scheme_encrypt_func) (const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen, struct st_encryption_scheme *scheme, unsigned int key_version, unsigned int i32_1, unsigned int i32_2, unsigned long long i64); int (*encryption_scheme_decrypt_func) (const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen, struct st_encryption_scheme *scheme, unsigned int key_version, unsigned int i32_1, unsigned int i32_2, unsigned long long i64); } *encryption_scheme_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define encryption_scheme_encrypt(S,SL,D,DL,SCH,KV,I32,J32,I64) encryption_scheme_service->encryption_scheme_encrypt_func(S,SL,D,DL,SCH,KV,I32,J32,I64) #define encryption_scheme_decrypt(S,SL,D,DL,SCH,KV,I32,J32,I64) encryption_scheme_service->encryption_scheme_decrypt_func(S,SL,D,DL,SCH,KV,I32,J32,I64) #else int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen, struct st_encryption_scheme *scheme, unsigned int key_version, unsigned int i32_1, unsigned int i32_2, unsigned long long i64); int encryption_scheme_decrypt(const unsigned char* src, unsigned int slen, unsigned char* dst, unsigned int* dlen, struct st_encryption_scheme *scheme, unsigned int key_version, unsigned int i32_1, unsigned int i32_2, unsigned long long i64); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_ENCRYPTION_SCHEME_INCLUDED #endif server/mysql/service_json.h000064400000010707151031265040012063 0ustar00/* Copyright (C) 2018 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #ifndef MYSQL_SERVICE_JSON #define MYSQL_SERVICE_JSON /** @file json service Exports JSON parsing methods for plugins to use. Functions of the service: json_type - returns the type of the JSON argument, and the parsed value if it's scalar (not object or array) json_get_array_item - expects JSON array as an argument, and returns the type of the element at index `n_item`. Returns JSV_NOTHING type if the array is shorter than n_item and the actual length of the array in value_len. If successful, then `value` up till `value[value_len]` contains the array element at the desired index (n_item). json_get_object_key - expects JSON object as an argument, searches for a key in the object, return it's type and stores its value in `value`. JSV_NOTHING if no such key found, the number of keys in v_len. json_get_object_nkey - expects JSON object as an argument. finds n_key's key in the object, returns it's name, type and value. JSV_NOTHING if object has less keys than n_key. */ #ifdef __cplusplus extern "C" { #endif enum json_types { JSV_BAD_JSON=-1, JSV_NOTHING=0, JSV_OBJECT=1, JSV_ARRAY=2, JSV_STRING=3, JSV_NUMBER=4, JSV_TRUE=5, JSV_FALSE=6, JSV_NULL=7 }; extern struct json_service_st { enum json_types (*json_type)(const char *js, const char *js_end, const char **value, int *value_len); enum json_types (*json_get_array_item)(const char *js, const char *js_end, int n_item, const char **value, int *value_len); enum json_types (*json_get_object_key)(const char *js, const char *js_end, const char *key, const char **value, int *value_len); enum json_types (*json_get_object_nkey)(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, const char **value, int *value_len); int (*json_escape_string)(const char *str,const char *str_end, char *json, char *json_end); int (*json_unescape_json)(const char *json_str, const char *json_end, char *res, char *res_end); } *json_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define json_type json_service->json_type #define json_get_array_item json_service->json_get_array_item #define json_get_object_key json_service->json_get_object_key #define json_get_object_nkey json_service->json_get_object_nkey #define json_escape_string json_service->json_escape_string #define json_unescape_json json_service->json_unescape_json #else enum json_types json_type(const char *js, const char *js_end, const char **value, int *value_len); enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, const char **value, int *value_len); enum json_types json_get_object_key(const char *js, const char *js_end, const char *key, const char **value, int *value_len); enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey, const char **keyname, const char **keyname_end, const char **value, int *value_len); int json_escape_string(const char *str,const char *str_end, char *json, char *json_end); int json_unescape_json(const char *json_str, const char *json_end, char *res, char *res_end); #endif /*MYSQL_DYNAMIC_PLUGIN*/ #ifdef __cplusplus } #endif #endif /*MYSQL_SERVICE_JSON */ server/mysql/service_thd_specifics.h000064400000007146151031265040013724 0ustar00#ifndef MYSQL_SERVICE_THD_SPECIFICS_INCLUDED /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file THD specific for plugin(s) This API provides pthread_getspecific like functionality to plugin authors. This is a functional alternative to the declarative MYSQL_THDVAR A plugin should at init call thd_key_create that create a key that will have storage in each THD. The key should be used by all threads and can be used concurrently from all threads. A plugin should at deinit call thd_key_delete. Alternatively, a plugin can use thd_key_create_from_var(K,V) to create a key that corresponds to a named MYSQL_THDVAR variable. This API is also safe when using pool-of-threads in which case pthread_getspecific is not, because the actual OS thread may change. @note Normally one should prefer MYSQL_THDVAR declarative API. The benefits are: - It supports typed variables (int, char*, enum, etc), not only void*. - The memory allocated for MYSQL_THDVAR is free'd automatically (if PLUGIN_VAR_MEMALLOC is specified). - Continuous loading and unloading of the same plugin does not allocate memory for same variables over and over again. An example of using MYSQL_THDVAR for a thd local storage: MYSQL_THDVAR_STR(my_tls, PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT, "thd local storage example", 0, 0, 0); */ #ifdef __cplusplus extern "C" { #endif typedef int MYSQL_THD_KEY_T; extern struct thd_specifics_service_st { int (*thd_key_create_func)(MYSQL_THD_KEY_T *key); void (*thd_key_delete_func)(MYSQL_THD_KEY_T *key); void *(*thd_getspecific_func)(MYSQL_THD thd, MYSQL_THD_KEY_T key); int (*thd_setspecific_func)(MYSQL_THD thd, MYSQL_THD_KEY_T key, void *value); } *thd_specifics_service; #define thd_key_create_from_var(K, V) do { *(K)= MYSQL_SYSVAR_NAME(V).offset; } while(0) #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_key_create(K) (thd_specifics_service->thd_key_create_func(K)) #define thd_key_delete(K) (thd_specifics_service->thd_key_delete_func(K)) #define thd_getspecific(T, K) (thd_specifics_service->thd_getspecific_func(T, K)) #define thd_setspecific(T, K, V) (thd_specifics_service->thd_setspecific_func(T, K, V)) #else /** * create THD specific storage * @return 0 on success * else errno is returned */ int thd_key_create(MYSQL_THD_KEY_T *key); /** * delete THD specific storage */ void thd_key_delete(MYSQL_THD_KEY_T *key); /** * get/set thd specific storage * - first time this is called from a thread it will return 0 * - this call is thread-safe in that different threads may call this * simultaneously if operating on different THDs. * - this call acquires no mutexes and is implemented as an array lookup */ void* thd_getspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key); int thd_setspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key, void *value); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_SPECIFICS_INCLUDED #endif server/mysql/service_base64.h000064400000005564151031265040012203 0ustar00#ifndef MYSQL_SERVICE_BASE64_INCLUDED /* Copyright (c) 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file my base64 service Functions for base64 en- and decoding */ #ifdef __cplusplus extern "C" { #endif #ifndef MYSQL_ABI_CHECK #include #endif /* Allow multiple chunks 'AAA= AA== AA==', binlog uses this */ #define MY_BASE64_DECODE_ALLOW_MULTIPLE_CHUNKS 1 extern struct base64_service_st { int (*base64_needed_encoded_length_ptr)(int length_of_data); int (*base64_encode_max_arg_length_ptr)(void); int (*base64_needed_decoded_length_ptr)(int length_of_encoded_data); int (*base64_decode_max_arg_length_ptr)(); int (*base64_encode_ptr)(const void *src, size_t src_len, char *dst); int (*base64_decode_ptr)(const char *src, size_t src_len, void *dst, const char **end_ptr, int flags); } *base64_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define my_base64_needed_encoded_length(A) base64_service->base64_needed_encoded_length_ptr(A) #define my_base64_encode_max_arg_length() base64_service->base64_encode_max_arg_length_ptr() #define my_base64_needed_decoded_length(A) base64_service->base64_needed_decoded_length_ptr(A) #define my_base64_decode_max_arg_length() base64_service->base64_decode_max_arg_length_ptr() #define my_base64_encode(A,B,C) base64_service->base64_encode_ptr(A,B,C) #define my_base64_decode(A,B,C,D,E) base64_service->base64_decode_ptr(A,B,C,D,E) #else /* Calculate how much memory needed for dst of my_base64_encode() */ int my_base64_needed_encoded_length(int length_of_data); /* Maximum length my_base64_encode_needed_length() can accept with no overflow. */ int my_base64_encode_max_arg_length(void); /* Calculate how much memory needed for dst of my_base64_decode() */ int my_base64_needed_decoded_length(int length_of_encoded_data); /* Maximum length my_base64_decode_needed_length() can accept with no overflow. */ int my_base64_decode_max_arg_length(); /* Encode data as a my_base64 string */ int my_base64_encode(const void *src, size_t src_len, char *dst); /* Decode a my_base64 string into data */ int my_base64_decode(const char *src, size_t src_len, void *dst, const char **end_ptr, int flags); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_BASE64_INCLUDED #endif server/mysql/service_thd_autoinc.h000064400000003234151031265040013410 0ustar00#ifndef MYSQL_SERVICE_THD_AUTOINC_INCLUDED /* Copyright (C) 2013 MariaDB Foundation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file This service provides access to the auto_increment related system variables: @@auto_increment_offset @@auto_increment_increment */ #ifdef __cplusplus extern "C" { #endif extern struct thd_autoinc_service_st { void (*thd_get_autoinc_func)(const MYSQL_THD thd, unsigned long* off, unsigned long* inc); } *thd_autoinc_service; #ifdef MYSQL_DYNAMIC_PLUGIN #define thd_get_autoinc(thd, off, inc) \ (thd_autoinc_service->thd_get_autoinc_func((thd), (off), (inc))) #else /** Return autoincrement system variables @param IN thd user thread connection handle @param OUT off the value of @@SESSION.auto_increment_offset @param OUT inc the value of @@SESSION.auto_increment_increment */ void thd_get_autoinc(const MYSQL_THD thd, unsigned long* off, unsigned long* inc); #endif #ifdef __cplusplus } #endif #define MYSQL_SERVICE_THD_AUTOINC_INCLUDED #endif server/my_config.h000064400000034353151031265040010202 0ustar00/* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MY_CONFIG_H #define MY_CONFIG_H #define DOT_FRM_VERSION 6 /* Headers we may want to use. */ #define STDC_HEADERS 1 #define _GNU_SOURCE 1 #define HAVE_ALLOCA_H 1 #define HAVE_ARPA_INET_H 1 #define HAVE_ASM_TERMBITS_H 1 #define HAVE_CRYPT_H 1 #define HAVE_CURSES_H 1 /* #undef HAVE_BFD_H */ /* #undef HAVE_NDIR_H */ #define HAVE_DIRENT_H 1 #define HAVE_DLFCN_H 1 #define HAVE_EXECINFO_H 1 #define HAVE_FCNTL_H 1 #define HAVE_FCNTL_DIRECT 1 #define HAVE_FENV_H 1 #define HAVE_FLOAT_H 1 #define HAVE_FNMATCH_H 1 #define HAVE_FPU_CONTROL_H 1 #define HAVE_GETMNTENT 1 /* #undef HAVE_GETMNTENT_IN_SYS_MNTAB */ /* #undef HAVE_GETMNTINFO */ /* #undef HAVE_GETMNTINFO64 */ /* #undef HAVE_GETMNTINFO_TAKES_statvfs */ #define HAVE_GRP_H 1 /* #undef HAVE_IA64INTRIN_H */ /* #undef HAVE_IEEEFP_H */ #define HAVE_INTTYPES_H 1 /* #undef HAVE_KQUEUE */ #define HAVE_LIMITS_H 1 #define HAVE_LINK_H 1 #define HAVE_LINUX_UNISTD_H 1 #define HAVE_LINUX_MMAN_H 1 #define HAVE_LOCALE_H 1 #define HAVE_MALLOC_H 1 #define HAVE_MEMORY_H 1 #define HAVE_NETINET_IN_H 1 #define HAVE_PATHS_H 1 #define HAVE_POLL_H 1 #define HAVE_PWD_H 1 #define HAVE_SCHED_H 1 /* #undef HAVE_SELECT_H */ /* #undef HAVE_SOLARIS_LARGE_PAGES */ #define HAVE_STDDEF_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STDARG_H 1 #define HAVE_STRINGS_H 1 #define HAVE_STRING_H 1 #define HAVE_STDINT_H 1 /* #undef HAVE_SYNCH_H */ /* #undef HAVE_SYSENT_H */ #define HAVE_SYS_DIR_H 1 #define HAVE_SYS_FILE_H 1 /* #undef HAVE_SYS_FPU_H */ #define HAVE_SYS_IOCTL_H 1 /* #undef HAVE_SYS_MALLOC_H */ #define HAVE_SYS_MMAN_H 1 /* #undef HAVE_SYS_MNTENT_H */ /* #undef HAVE_SYS_NDIR_H */ /* #undef HAVE_SYS_PTE_H */ /* #undef HAVE_SYS_PTEM_H */ #define HAVE_SYS_PRCTL_H 1 #define HAVE_SYS_RESOURCE_H 1 #define HAVE_SYS_SELECT_H 1 #define HAVE_SYS_SOCKET_H 1 /* #undef HAVE_SYS_SOCKIO_H */ #define HAVE_SYS_UTSNAME_H 1 #define HAVE_SYS_STAT_H 1 /* #undef HAVE_SYS_STREAM_H */ #define HAVE_SYS_SYSCALL_H 1 #define HAVE_SYS_TIMEB_H 1 #define HAVE_SYS_TIMES_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_UN_H 1 /* #undef HAVE_SYS_VADVISE_H */ #define HAVE_SYS_STATVFS_H 1 #define HAVE_UCONTEXT_H 1 #define HAVE_TERM_H 1 /* #undef HAVE_TERMBITS_H */ #define HAVE_TERMIOS_H 1 #define HAVE_TERMIO_H 1 #define HAVE_TERMCAP_H 1 #define HAVE_TIME_H 1 #define HAVE_UNISTD_H 1 #define HAVE_UTIME_H 1 /* #undef HAVE_VARARGS_H */ /* #undef HAVE_SYS_UTIME_H */ #define HAVE_SYS_WAIT_H 1 #define HAVE_SYS_PARAM_H 1 /* Libraries */ /* #undef HAVE_LIBWRAP */ #define HAVE_SYSTEMD 1 #define HAVE_SYSTEMD_SD_LISTEN_FDS_WITH_NAMES 1 /* Does "struct timespec" have a "sec" and "nsec" field? */ /* #undef HAVE_TIMESPEC_TS_SEC */ /* Readline */ /* #undef HAVE_HIST_ENTRY */ /* #undef USE_LIBEDIT_INTERFACE */ #define USE_NEW_READLINE_INTERFACE 1 #define FIONREAD_IN_SYS_IOCTL 1 #define GWINSZ_IN_SYS_IOCTL 1 /* #undef TIOCSTAT_IN_SYS_IOCTL */ /* #undef FIONREAD_IN_SYS_FILIO */ /* Functions we may want to use. */ #define HAVE_ACCEPT4 1 #define HAVE_ACCESS 1 #define HAVE_ALARM 1 #define HAVE_ALLOCA 1 /* #undef HAVE_BFILL */ #define HAVE_INDEX 1 #define HAVE_CLOCK_GETTIME 1 #define HAVE_CRYPT 1 #define HAVE_CUSERID 1 #define HAVE_DLADDR 1 #define HAVE_DLERROR 1 #define HAVE_DLOPEN 1 #define HAVE_FCHMOD 1 #define HAVE_FCNTL 1 #define HAVE_FDATASYNC 1 #define HAVE_DECL_FDATASYNC 1 #define HAVE_FEDISABLEEXCEPT 1 #define HAVE_FESETROUND 1 /* #undef HAVE_FP_EXCEPT */ #define HAVE_FSEEKO 1 #define HAVE_FSYNC 1 #define HAVE_FTIME 1 #define HAVE_GETIFADDRS 1 #define HAVE_GETCWD 1 #define HAVE_GETHOSTBYADDR_R 1 /* #undef HAVE_GETHRTIME */ #define HAVE_GETPAGESIZE 1 /* #undef HAVE_GETPAGESIZES */ #define HAVE_GETPASS 1 /* #undef HAVE_GETPASSPHRASE */ #define HAVE_GETPWNAM 1 #define HAVE_GETPWUID 1 #define HAVE_GETRLIMIT 1 #define HAVE_GETRUSAGE 1 #define HAVE_GETTIMEOFDAY 1 #define HAVE_GETWD 1 #define HAVE_GMTIME_R 1 /* #undef gmtime_r */ #define HAVE_IN_ADDR_T 1 #define HAVE_INITGROUPS 1 #define HAVE_LDIV 1 #define HAVE_LRAND48 1 #define HAVE_LOCALTIME_R 1 #define HAVE_LSTAT 1 /* #define HAVE_MLOCK 1 see Bug#54662 */ #define HAVE_NL_LANGINFO 1 #define HAVE_MADVISE 1 #define HAVE_DECL_MADVISE 1 /* #undef HAVE_DECL_MHA_MAPSIZE_VA */ #define HAVE_MALLINFO 1 /* #undef HAVE_MALLINFO2 */ /* #undef HAVE_MALLOC_ZONE */ #define HAVE_MEMCPY 1 #define HAVE_MEMMOVE 1 #define HAVE_MKSTEMP 1 #define HAVE_MKOSTEMP 1 #define HAVE_MLOCKALL 1 #define HAVE_MMAP 1 #define HAVE_MMAP64 1 #define HAVE_PERROR 1 #define HAVE_POLL 1 #define HAVE_POSIX_FALLOCATE 1 #define HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE 1 #define HAVE_PREAD 1 /* #undef HAVE_READ_REAL_TIME */ /* #undef HAVE_PTHREAD_ATTR_CREATE */ #define HAVE_PTHREAD_ATTR_GETGUARDSIZE 1 #define HAVE_PTHREAD_ATTR_GETSTACKSIZE 1 #define HAVE_PTHREAD_ATTR_SETSCOPE 1 #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 #define HAVE_PTHREAD_GETATTR_NP 1 /* #undef HAVE_PTHREAD_CONDATTR_CREATE */ #define HAVE_PTHREAD_GETAFFINITY_NP 1 #define HAVE_PTHREAD_KEY_DELETE 1 /* #undef HAVE_PTHREAD_KILL */ #define HAVE_PTHREAD_RWLOCK_RDLOCK 1 #define HAVE_PTHREAD_SIGMASK 1 /* #undef HAVE_PTHREAD_YIELD_NP */ #define HAVE_PTHREAD_YIELD_ZERO_ARG 1 #define PTHREAD_ONCE_INITIALIZER PTHREAD_ONCE_INIT #define HAVE_PUTENV 1 /* #undef HAVE_READDIR_R */ #define HAVE_READLINK 1 #define HAVE_REALPATH 1 #define HAVE_RENAME 1 /* #undef HAVE_RWLOCK_INIT */ #define HAVE_SCHED_YIELD 1 #define HAVE_SELECT 1 #define HAVE_SETENV 1 #define HAVE_SETLOCALE 1 #define HAVE_SETMNTENT 1 #define HAVE_SETUPTERM 1 #define HAVE_SIGSET 1 #define HAVE_SIGACTION 1 /* #undef HAVE_SIGTHREADMASK */ #define HAVE_SIGWAIT 1 #define HAVE_SIGWAITINFO 1 #define HAVE_SLEEP 1 #define HAVE_STPCPY 1 #define HAVE_STRERROR 1 #define HAVE_STRCOLL 1 #define HAVE_STRNLEN 1 #define HAVE_STRPBRK 1 #define HAVE_STRTOK_R 1 #define HAVE_STRTOLL 1 #define HAVE_STRTOUL 1 #define HAVE_STRTOULL 1 /* #undef HAVE_TELL */ /* #undef HAVE_THR_YIELD */ #define HAVE_TIME 1 #define HAVE_TIMES 1 #define HAVE_VIDATTR 1 #define HAVE_VIO_READ_BUFF 1 #define HAVE_VASPRINTF 1 #define HAVE_VSNPRINTF 1 #define HAVE_FTRUNCATE 1 #define HAVE_TZNAME 1 /* Symbols we may use */ /* #undef HAVE_SYS_ERRLIST */ /* used by stacktrace functions */ #define HAVE_BACKTRACE 1 #define HAVE_BACKTRACE_SYMBOLS 1 #define HAVE_BACKTRACE_SYMBOLS_FD 1 /* #undef HAVE_PRINTSTACK */ #define HAVE_IPV6 1 /* #undef ss_family */ /* #undef HAVE_SOCKADDR_IN_SIN_LEN */ /* #undef HAVE_SOCKADDR_IN6_SIN6_LEN */ #define STRUCT_TIMESPEC_HAS_TV_SEC 1 #define STRUCT_TIMESPEC_HAS_TV_NSEC 1 /* this means that valgrind headers and macros are available */ #define HAVE_VALGRIND_MEMCHECK_H 1 /* this means WITH_VALGRIND - we change some code paths for valgrind */ /* #undef HAVE_valgrind */ /* Types we may use */ #ifdef __APPLE__ /* Special handling required for OSX to support universal binaries that mix 32 and 64 bit architectures. */ #if(__LP64__) #define SIZEOF_LONG 8 #else #define SIZEOF_LONG 4 #endif #define SIZEOF_VOIDP SIZEOF_LONG #define SIZEOF_CHARP SIZEOF_LONG #define SIZEOF_SIZE_T SIZEOF_LONG #else /* No indentation, to fetch the lines from verification scripts */ #define SIZEOF_LONG 8 #define SIZEOF_VOIDP 8 #define SIZEOF_CHARP 8 #define SIZEOF_SIZE_T 8 #endif #define HAVE_LONG 1 #define HAVE_CHARP 1 #define SIZEOF_INT 4 #define HAVE_INT 1 #define SIZEOF_LONG_LONG 8 #define HAVE_LONG_LONG 1 #define SIZEOF_OFF_T 8 #define HAVE_OFF_T 1 /* #undef SIZEOF_UCHAR */ /* #undef HAVE_UCHAR */ #define SIZEOF_UINT 4 #define HAVE_UINT 1 #define SIZEOF_ULONG 8 #define HAVE_ULONG 1 /* #undef SIZEOF_INT8 */ /* #undef HAVE_INT8 */ /* #undef SIZEOF_UINT8 */ /* #undef HAVE_UINT8 */ /* #undef SIZEOF_INT16 */ /* #undef HAVE_INT16 */ /* #undef SIZEOF_UINT16 */ /* #undef HAVE_UINT16 */ /* #undef SIZEOF_INT32 */ /* #undef HAVE_INT32 */ /* #undef SIZEOF_UINT32 */ /* #undef HAVE_UINT32 */ /* #undef SIZEOF_INT64 */ /* #undef HAVE_INT64 */ /* #undef SIZEOF_UINT64 */ /* #undef HAVE_UINT64 */ #define SOCKET_SIZE_TYPE socklen_t #define HAVE_MBSTATE_T 1 #define MAX_INDEXES 64 #define QSORT_TYPE_IS_VOID 1 #define RETQSORTTYPE void #define RETSIGTYPE void #define VOID_SIGHANDLER 1 #define HAVE_SIGHANDLER_T 1 #define STRUCT_RLIMIT struct rlimit #ifdef __APPLE__ #if __BIG_ENDIAN #define WORDS_BIGENDIAN 1 #endif #else /* #undef WORDS_BIGENDIAN */ #endif /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #define C_HAS_inline 1 #if !(C_HAS_inline) #ifndef __cplusplus # define inline #endif #endif #define TARGET_OS_LINUX 1 #define HAVE_WCTYPE_H 1 #define HAVE_WCHAR_H 1 #define HAVE_LANGINFO_H 1 #define HAVE_MBRLEN 1 #define HAVE_MBSRTOWCS 1 #define HAVE_MBRTOWC 1 #define HAVE_WCWIDTH 1 #define HAVE_ISWLOWER 1 #define HAVE_ISWUPPER 1 #define HAVE_TOWLOWER 1 #define HAVE_TOWUPPER 1 #define HAVE_ISWCTYPE 1 #define HAVE_WCHAR_T 1 #define HAVE_STRCASECMP 1 #define HAVE_TCGETATTR 1 #define HAVE_WEAK_SYMBOL 1 #define HAVE_ABI_CXA_DEMANGLE 1 #define HAVE_ATTRIBUTE_CLEANUP 1 #define HAVE_POSIX_SIGNALS 1 /* #undef HAVE_BSD_SIGNALS */ /* #undef HAVE_SVR3_SIGNALS */ /* #undef HAVE_V7_SIGNALS */ #define HAVE_ERR_remove_thread_state 1 #define HAVE_X509_check_host 1 /* #undef HAVE_SOLARIS_STYLE_GETHOST */ #define HAVE_GCC_C11_ATOMICS 1 /* #undef HAVE_SOLARIS_ATOMIC */ /* #undef NO_FCNTL_NONBLOCK */ #define NO_ALARM 1 /* #undef _LARGE_FILES */ #define _LARGEFILE_SOURCE 1 /* #undef _LARGEFILE64_SOURCE */ #define TIME_WITH_SYS_TIME 1 #define STACK_DIRECTION -1 #define SYSTEM_TYPE "Linux" #define MACHINE_TYPE "x86_64" #define DEFAULT_MACHINE "x86_64" #define HAVE_DTRACE 1 #define SIGNAL_WITH_VIO_CLOSE 1 /* Windows stuff, mostly functions, that have Posix analogs but named differently */ /* #undef S_IROTH */ /* #undef S_IFIFO */ /* #undef IPPROTO_IPV6 */ /* #undef IPV6_V6ONLY */ /* #undef sigset_t */ /* #undef mode_t */ /* #undef SIGQUIT */ /* #undef SIGPIPE */ /* #undef popen */ /* #undef pclose */ /* #undef ssize_t */ /* #undef strcasecmp */ /* #undef strncasecmp */ /* #undef snprintf */ /* #undef strtok_r */ /* #undef strtoll */ /* #undef strtoull */ /* #undef vsnprintf */ #if defined(_MSC_VER) && (_MSC_VER > 1800) #define tzname _tzname #define P_tmpdir "C:\\TEMP" #endif #if defined(_MSC_VER) && (_MSC_VER > 1310) # define HAVE_SETENV #define setenv(a,b,c) _putenv_s(a,b) #endif #define PSAPI_VERSION 1 /* for GetProcessMemoryInfo() */ /* We don't want the min/max macros */ #ifdef _WIN32 #define NOMINMAX 1 #endif /* MySQL features */ #define LOCAL_INFILE_MODE_OFF 0 #define LOCAL_INFILE_MODE_ON 1 #define LOCAL_INFILE_MODE_AUTO 2 #define ENABLED_LOCAL_INFILE LOCAL_INFILE_MODE_AUTO #define ENABLED_PROFILING 1 /* #undef EXTRA_DEBUG */ /* #undef USE_SYMDIR */ /* Character sets and collations */ #define MYSQL_DEFAULT_CHARSET_NAME "latin1" #define MYSQL_DEFAULT_COLLATION_NAME "latin1_swedish_ci" #define USE_MB #define USE_MB_IDENT /* This should mean case insensitive file system */ /* #undef FN_NO_CASE_SENSE */ #define HAVE_CHARSET_armscii8 1 #define HAVE_CHARSET_ascii 1 #define HAVE_CHARSET_big5 1 #define HAVE_CHARSET_cp1250 1 #define HAVE_CHARSET_cp1251 1 #define HAVE_CHARSET_cp1256 1 #define HAVE_CHARSET_cp1257 1 #define HAVE_CHARSET_cp850 1 #define HAVE_CHARSET_cp852 1 #define HAVE_CHARSET_cp866 1 #define HAVE_CHARSET_cp932 1 #define HAVE_CHARSET_dec8 1 #define HAVE_CHARSET_eucjpms 1 #define HAVE_CHARSET_euckr 1 #define HAVE_CHARSET_gb2312 1 #define HAVE_CHARSET_gbk 1 #define HAVE_CHARSET_geostd8 1 #define HAVE_CHARSET_greek 1 #define HAVE_CHARSET_hebrew 1 #define HAVE_CHARSET_hp8 1 #define HAVE_CHARSET_keybcs2 1 #define HAVE_CHARSET_koi8r 1 #define HAVE_CHARSET_koi8u 1 #define HAVE_CHARSET_latin1 1 #define HAVE_CHARSET_latin2 1 #define HAVE_CHARSET_latin5 1 #define HAVE_CHARSET_latin7 1 #define HAVE_CHARSET_macce 1 #define HAVE_CHARSET_macroman 1 #define HAVE_CHARSET_sjis 1 #define HAVE_CHARSET_swe7 1 #define HAVE_CHARSET_tis620 1 #define HAVE_CHARSET_ucs2 1 #define HAVE_CHARSET_ujis 1 #define HAVE_CHARSET_utf8mb4 1 #define HAVE_CHARSET_utf8mb3 1 #define HAVE_CHARSET_utf16 1 #define HAVE_CHARSET_utf32 1 #define HAVE_UCA_COLLATIONS 1 #define HAVE_COMPRESS 1 #define HAVE_EncryptAes128Ctr 1 #define HAVE_EncryptAes128Gcm 1 #define HAVE_des 1 /* Stuff that always need to be defined (compile breaks without it) */ #define HAVE_SPATIAL 1 #define HAVE_RTREE_KEYS 1 #define HAVE_QUERY_CACHE 1 #define BIG_TABLES 1 /* Important storage engines (those that really need define WITH__STORAGE_ENGINE for the whole server) */ #define WITH_INNOBASE_STORAGE_ENGINE 1 #define WITH_PARTITION_STORAGE_ENGINE 1 #define WITH_PERFSCHEMA_STORAGE_ENGINE 1 #define WITH_ARIA_STORAGE_ENGINE 1 #define USE_ARIA_FOR_TMP_TABLES 1 #define DEFAULT_MYSQL_HOME "/usr" #define SHAREDIR "/usr/share/mysql" #define DEFAULT_BASEDIR "/usr" #define MYSQL_DATADIR "/var/lib/mysql" #define DEFAULT_CHARSET_HOME "/usr" #define PLUGINDIR "/usr/lib64/mysql/plugin" #define DEFAULT_SYSCONFDIR "/etc" #define DEFAULT_TMPDIR P_tmpdir /* #undef SO_EXT */ #define MYSQL_VERSION_MAJOR 10 #define MYSQL_VERSION_MINOR 6 #define MYSQL_VERSION_PATCH 23 #define MYSQL_VERSION_EXTRA "" #define PACKAGE "mysql" #define PACKAGE_BUGREPORT "" #define PACKAGE_NAME "MySQL Server" #define PACKAGE_STRING "MySQL Server 10.6.23" #define PACKAGE_TARNAME "mysql" #define PACKAGE_VERSION "10.6.23" #define VERSION "10.6.23" #define PROTOCOL_VERSION 10 #define PCRE2_CODE_UNIT_WIDTH 8 #define MALLOC_LIBRARY "system" /* time_t related defines */ #define SIZEOF_TIME_T 8 /* #undef TIME_T_UNSIGNED */ #ifndef EMBEDDED_LIBRARY /* #undef WSREP_INTERFACE_VERSION */ #define WITH_WSREP 1 #define WSREP_PROC_INFO 1 #endif #if !defined(__STDC_FORMAT_MACROS) #define __STDC_FORMAT_MACROS #endif // !defined(__STDC_FORMAT_MACROS) #endif #define HAVE_VFORK 1 server/byte_order_generic_x86_64.h000064400000010041151031265040013064 0ustar00/* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Optimized function-like macros for the x86 architecture (_WIN32 included). */ #define sint2korr(A) (int16) (*((int16 *) (A))) #define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ (((uint32) 255L << 24) | \ (((uint32) (uchar) (A)[2]) << 16) |\ (((uint32) (uchar) (A)[1]) << 8) | \ ((uint32) (uchar) (A)[0])) : \ (((uint32) (uchar) (A)[2]) << 16) |\ (((uint32) (uchar) (A)[1]) << 8) | \ ((uint32) (uchar) (A)[0]))) #define sint4korr(A) (int32) (*((int32 *) (A))) #define uint2korr(A) (uint16) (*((uint16 *) (A))) #define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) |\ (((uint32) ((uchar) (A)[1])) << 8) |\ (((uint32) ((uchar) (A)[2])) << 16)) #define uint4korr(A) (uint32) (*((uint32 *) (A))) static inline ulonglong uint5korr(const void *p) { ulonglong a= *(uint32 *) p; ulonglong b= *(4 + (uchar *) p); return a | (b << 32); } static inline ulonglong uint6korr(const void *p) { ulonglong a= *(uint32 *) p; ulonglong b= *(uint16 *) (4 + (char *) p); return a | (b << 32); } #define uint8korr(A) (ulonglong) (*((ulonglong *) (A))) #define sint8korr(A) (longlong) (*((longlong *) (A))) #define int2store(T,A) do { uchar *pT= (uchar*)(T);\ *((uint16*)(pT))= (uint16) (A);\ } while (0) #define int3store(T,A) do { *(T)= (uchar) ((A));\ *(T+1)=(uchar) (((uint) (A) >> 8));\ *(T+2)=(uchar) (((A) >> 16));\ } while (0) #define int4store(T,A) do { uchar *pT= (uchar*)(T);\ *((uint32 *) (pT))= (uint32) (A); \ } while (0) #define int5store(T,A) do { uchar *pT= (uchar*)(T);\ *((uint32 *) (pT))= (uint32) (A); \ *((pT)+4)=(uchar) (((A) >> 32));\ } while (0) #define int6store(T,A) do { uchar *pT= (uchar*)(T);\ *((uint32 *) (pT))= (uint32) (A); \ *((uint16*)(pT+4))= (uint16) (A >> 32);\ } while (0) #define int8store(T,A) do { uchar *pT= (uchar*)(T);\ *((ulonglong *) (pT))= (ulonglong) (A);\ } while(0) #if defined(__GNUC__) #define HAVE_mi_uint5korr #define HAVE_mi_uint6korr #define HAVE_mi_uint7korr #define HAVE_mi_uint8korr /* Read numbers stored in high-bytes-first order */ static inline ulonglong mi_uint5korr(const void *p) { ulonglong a= *(uint32 *) p; ulonglong b= *(4 + (uchar *) p); ulonglong v= (a | (b << 32)) << 24; asm ("bswapq %0" : "=r" (v) : "0" (v)); return v; } static inline ulonglong mi_uint6korr(const void *p) { ulonglong a= *(uint32 *) p; ulonglong b= *(uint16 *) (4 + (char *) p); ulonglong v= (a | (b << 32)) << 16; asm ("bswapq %0" : "=r" (v) : "0" (v)); return v; } static inline ulonglong mi_uint7korr(const void *p) { ulonglong a= *(uint32 *) p; ulonglong b= *(uint16 *) (4 + (char *) p); ulonglong c= *(6 + (uchar *) p); ulonglong v= (a | (b << 32) | (c << 48)) << 8; asm ("bswapq %0" : "=r" (v) : "0" (v)); return v; } static inline ulonglong mi_uint8korr(const void *p) { ulonglong v= *(ulonglong *) p; asm ("bswapq %0" : "=r" (v) : "0" (v)); return v; } #endif server/my_alloc.h000064400000004025151031265040010020 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Data structures for mysys/my_alloc.c (root memory allocator) */ #ifndef _my_alloc_h #define _my_alloc_h #include "mysql/psi/psi_base.h" #define ALLOC_MAX_BLOCK_TO_DROP 4096 #define ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP 10 #define ROOT_FLAG_READ_ONLY 4 #ifdef __cplusplus extern "C" { #endif typedef struct st_used_mem { /* struct for once_alloc (block) */ struct st_used_mem *next; /* Next block in use */ size_t left; /* memory left in block */ size_t size; /* size of block */ } USED_MEM; typedef struct st_mem_root { USED_MEM *free; /* blocks with free memory in it */ USED_MEM *used; /* blocks almost without free memory */ USED_MEM *pre_alloc; /* preallocated block */ /* if block have less memory it will be put in 'used' list */ size_t min_malloc; size_t block_size; /* initial block size */ unsigned int block_num; /* allocated blocks counter */ /* first free block in queue test counter (if it exceed MAX_BLOCK_USAGE_BEFORE_DROP block will be dropped in 'used' list) */ unsigned short first_block_usage; unsigned short flags; void (*error_handler)(void); PSI_memory_key m_psi_key; } MEM_ROOT; #ifdef __cplusplus } #endif #endif server/my_dir.h000064400000007457151031265040007520 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MY_DIR_H #define MY_DIR_H #include #ifdef __cplusplus extern "C" { #endif /* Defines for my_dir and my_stat */ #define MY_S_IFMT S_IFMT /* type of file */ #define MY_S_IFDIR S_IFDIR /* directory */ #define MY_S_IFCHR S_IFCHR /* character special */ #define MY_S_IFBLK S_IFBLK /* block special */ #define MY_S_IFREG S_IFREG /* regular */ #define MY_S_IFIFO S_IFIFO /* fifo */ #define MY_S_ISUID S_ISUID /* set user id on execution */ #define MY_S_ISGID S_ISGID /* set group id on execution */ #define MY_S_ISVTX S_ISVTX /* save swapped text even after use */ #ifndef S_IREAD #define MY_S_IREAD S_IRUSR /* read permission, owner */ #define MY_S_IWRITE S_IWUSR /* write permission, owner */ #define MY_S_IEXEC S_IXUSR /* execute/search permission, owner */ #else #define MY_S_IREAD S_IREAD /* read permission, owner */ #define MY_S_IWRITE S_IWRITE /* write permission, owner */ #define MY_S_IEXEC S_IEXEC /* execute/search permission, owner */ #endif #define MY_S_ISDIR(m) (((m) & MY_S_IFMT) == MY_S_IFDIR) #define MY_S_ISCHR(m) (((m) & MY_S_IFMT) == MY_S_IFCHR) #define MY_S_ISBLK(m) (((m) & MY_S_IFMT) == MY_S_IFBLK) #define MY_S_ISREG(m) (((m) & MY_S_IFMT) == MY_S_IFREG) #define MY_S_ISFIFO(m) (((m) & MY_S_IFMT) == MY_S_IFIFO) /* Ensure these doesn't clash with anything in my_sys.h */ #define MY_WANT_SORT 8192 /* my_lib; sort files */ #define MY_WANT_STAT 16384 /* my_lib; stat files */ #define MY_DONT_SORT 0 /* typedefs for my_dir & my_stat */ #ifdef USE_MY_STAT_STRUCT typedef struct my_stat { dev_t st_dev; /* major & minor device numbers */ ino_t st_ino; /* inode number */ ushort st_mode; /* file permissions (& suid sgid .. bits) */ short st_nlink; /* number of links to file */ ushort st_uid; /* user id */ ushort st_gid; /* group id */ dev_t st_rdev; /* more major & minor device numbers (???) */ off_t st_size; /* size of file */ time_t st_atime; /* time for last read */ time_t st_mtime; /* time for last contents modify */ time_t st_ctime; /* time for last inode or contents modify */ } MY_STAT; #else #if defined(_MSC_VER) #define MY_STAT struct _stati64 /* 64 bit file size */ #else #define MY_STAT struct stat /* Original struct has what we need */ #endif #endif /* USE_MY_STAT_STRUCT */ /* Struct describing one file returned from my_dir */ typedef struct fileinfo { char *name; MY_STAT *mystat; } FILEINFO; typedef struct st_my_dir /* Struct returned from my_dir */ { /* These members are just copies of parts of DYNAMIC_ARRAY structure, which is allocated right after the end of MY_DIR structure (MEM_ROOT for storing names is also resides there). We've left them here because we don't want to change code that uses my_dir. */ struct fileinfo *dir_entry; uint number_of_files; } MY_DIR; extern MY_DIR *my_dir(const char *path,myf MyFlags); extern void my_dirend(MY_DIR *buffer); extern MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags); extern int my_fstat(int filenr, MY_STAT *stat_area, myf MyFlags); #ifdef __cplusplus } #endif #endif /* MY_DIR_H */ server/my_valgrind.h000064400000010700151031265040010531 0ustar00/* Copyright (C) 2010, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MY_VALGRIND_INCLUDED #define MY_VALGRIND_INCLUDED /* clang -> gcc */ #ifndef __has_feature # define __has_feature(x) 0 #endif #if __has_feature(address_sanitizer) # define __SANITIZE_ADDRESS__ 1 #endif #if __has_feature(memory_sanitizer) # include # define HAVE_valgrind # define HAVE_MEM_CHECK # define MEM_UNDEFINED(a,len) __msan_allocated_memory(a,len) # define MEM_MAKE_ADDRESSABLE(a,len) MEM_UNDEFINED(a,len) # define MEM_MAKE_DEFINED(a,len) __msan_unpoison(a,len) # define MEM_NOACCESS(a,len) ((void) 0) # define MEM_CHECK_ADDRESSABLE(a,len) ((void) 0) # define MEM_CHECK_DEFINED(a,len) __msan_check_mem_is_initialized(a,len) # define MEM_GET_VBITS(a,b,len) __msan_copy_shadow(b,a,len) # define MEM_SET_VBITS(a,b,len) __msan_copy_shadow(a,b,len) # define REDZONE_SIZE 8 # ifdef __linux__ # define MSAN_STAT_WORKAROUND(st) MEM_MAKE_DEFINED(st, sizeof(*st)) # else # define MSAN_STAT_WORKAROUND(st) ((void) 0) # endif #elif defined(HAVE_VALGRIND_MEMCHECK_H) && defined(HAVE_valgrind) # include # define HAVE_MEM_CHECK # define MEM_UNDEFINED(a,len) VALGRIND_MAKE_MEM_UNDEFINED(a,len) # define MEM_MAKE_ADDRESSABLE(a,len) MEM_UNDEFINED(a,len) # define MEM_MAKE_DEFINED(a,len) VALGRIND_MAKE_MEM_DEFINED(a,len) # define MEM_NOACCESS(a,len) VALGRIND_MAKE_MEM_NOACCESS(a,len) # define MEM_CHECK_ADDRESSABLE(a,len) VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,len) # define MEM_CHECK_DEFINED(a,len) VALGRIND_CHECK_MEM_IS_DEFINED(a,len) # define MEM_GET_VBITS(a,b,len) VALGRIND_GET_VBITS(a,b,len) # define MEM_SET_VBITS(a,b,len) VALGRIND_SET_VBITS(a,b,len) # define REDZONE_SIZE 8 # define MSAN_STAT_WORKAROUND(st) ((void) 0) #elif defined(__SANITIZE_ADDRESS__) && (!defined(_MSC_VER) || defined (__clang__)) # include /* How to do manual poisoning: https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning */ # define MEM_UNDEFINED(a,len) ((void) 0) # define MEM_MAKE_ADDRESSABLE(a,len) ASAN_UNPOISON_MEMORY_REGION(a,len) # define MEM_MAKE_DEFINED(a,len) ((void) 0) # define MEM_NOACCESS(a,len) ASAN_POISON_MEMORY_REGION(a,len) # define MEM_CHECK_ADDRESSABLE(a,len) \ assert(!__asan_region_is_poisoned((void*) a,len)) # define MEM_CHECK_DEFINED(a,len) ((void) 0) # define MEM_GET_VBITS(a,b,len) ((void) 0) # define MEM_SET_VBITS(a,b,len) ((void) 0) # define MSAN_STAT_WORKAROUND(st) ((void) 0) # define REDZONE_SIZE 8 #else # define MEM_UNDEFINED(a,len) ((void) 0) # define MEM_MAKE_ADDRESSABLE(a,len) ((void) 0) # define MEM_MAKE_DEFINED(a,len) ((void) 0) # define MEM_NOACCESS(a,len) ((void) 0) # define MEM_CHECK_ADDRESSABLE(a,len) ((void) 0) # define MEM_CHECK_DEFINED(a,len) ((void) 0) # define MEM_GET_VBITS(a,b,len) ((void) 0) # define MEM_SET_VBITS(a,b,len) ((void) 0) # define REDZONE_SIZE 0 # define MSAN_STAT_WORKAROUND(st) ((void) 0) #endif /* __has_feature(memory_sanitizer) */ #ifdef TRASH_FREED_MEMORY /* _TRASH_FILL() has to call MEM_MAKE_ADDRESSABLE() to cancel any effect of TRASH_FREE(). This can happen in the case one does TRASH_ALLOC(A,B) ; TRASH_FREE(A,B) ; TRASH_ALLOC(A,B) to reuse the same memory in an internal memory allocator like MEM_ROOT. _TRASH_FILL() is an internal function and should not be used externally. */ #define _TRASH_FILL(A,B,C) do { const size_t trash_tmp= (B); MEM_MAKE_ADDRESSABLE(A, trash_tmp); memset(A, C, trash_tmp); } while (0) #else #define _TRASH_FILL(A,B,C) do { MEM_UNDEFINED((A), (B)); } while (0) #endif /** Note that some memory became allocated and/or uninitialized. */ #define TRASH_ALLOC(A,B) do { _TRASH_FILL(A,B,0xA5); MEM_MAKE_ADDRESSABLE(A,B); } while(0) /** Note that some memory became freed. (Prohibit further access to it.) */ #define TRASH_FREE(A,B) do { _TRASH_FILL(A,B,0x8F); MEM_NOACCESS(A,B); } while(0) #endif /* MY_VALGRIND_INCLUDED */ server/my_alloca.h000064400000002627151031265040010167 0ustar00/* Copyright (c) 2023, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MY_ALLOCA_INCLUDED #define MY_ALLOCA_INCLUDED #ifdef _WIN32 #include /*for alloca*/ /* MSVC may define "alloca" when compiling in /Ze mode (with extensions from Microsoft), but otherwise only the _alloca function is defined: */ #ifndef alloca #define alloca _alloca #endif #else #ifdef HAVE_ALLOCA_H #include #endif #endif #if defined(_AIX) && !defined(__GNUC__) && !defined(_AIX43) #pragma alloca #endif /* _AIX */ /* If the GCC/LLVM compiler from the MinGW is used, alloca may not be defined when using the MSVC CRT: */ #if defined(__GNUC__) && !defined(HAVE_ALLOCA_H) && !defined(alloca) #define alloca __builtin_alloca #endif /* GNUC */ #endif /* MY_ALLOCA_INCLUDED */ server/typelib.h000064400000004534151031265040007676 0ustar00/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _typelib_h #define _typelib_h #include "my_alloc.h" typedef struct st_typelib { /* Different types saved here */ unsigned int count; /* How many types */ const char *name; /* Name of typelib */ const char **type_names; unsigned int *type_lengths; } TYPELIB; extern my_ulonglong find_typeset(const char *x, TYPELIB *typelib, int *error_position); extern int find_type_with_warning(const char *x, TYPELIB *typelib, const char *option); #define FIND_TYPE_BASIC 0 /** makes @c find_type() require the whole name, no prefix */ #define FIND_TYPE_NO_PREFIX (1U << 0) /** always implicitly on, so unused, but old code may pass it */ #define FIND_TYPE_NO_OVERWRITE 0 /** makes @c find_type() accept a number. Not used either */ #define FIND_TYPE_ALLOW_NUMBER 0 /** makes @c find_type() treat ',' and '=' as terminators */ #define FIND_TYPE_COMMA_TERM (1U << 3) extern int find_type(const char *x, const TYPELIB *typelib, unsigned int flags); extern void make_type(char *to,unsigned int nr,TYPELIB *typelib); extern const char *get_type(TYPELIB *typelib,unsigned int nr); extern TYPELIB *copy_typelib(MEM_ROOT *root, const TYPELIB *from); extern TYPELIB sql_protocol_typelib; my_ulonglong find_set_from_flags(const TYPELIB *lib, unsigned int default_name, my_ulonglong cur_set, my_ulonglong default_set, const char *str, unsigned int length, char **err_pos, unsigned int *err_len); #endif /* _typelib_h */ server/my_pthread.h000064400000065737151031265040010376 0ustar00/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. Copyright (c) 2009, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Defines to make different thread packages compatible */ #ifndef _my_pthread_h #define _my_pthread_h #ifndef ETIME #define ETIME ETIMEDOUT /* For FreeBSD */ #endif #ifdef __cplusplus #define EXTERNC extern "C" extern "C" { #else #define EXTERNC #endif /* __cplusplus */ #if defined(_WIN32) typedef CRITICAL_SECTION pthread_mutex_t; typedef DWORD pthread_t; typedef struct thread_attr { DWORD dwStackSize ; DWORD dwCreatingFlag ; } pthread_attr_t ; typedef struct { int dummy; } pthread_condattr_t; /* Implementation of posix conditions */ typedef struct st_pthread_link { DWORD thread_id; struct st_pthread_link *next; } pthread_link; /** Implementation of Windows condition variables. We use native conditions on Vista and later, and fallback to own implementation on earlier OS version. */ typedef CONDITION_VARIABLE pthread_cond_t; typedef int pthread_mutexattr_t; #define pthread_self() GetCurrentThreadId() #define pthread_handler_t EXTERNC void * __cdecl typedef void * (__cdecl *pthread_handler)(void *); typedef INIT_ONCE my_pthread_once_t; #define MY_PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT; #if !STRUCT_TIMESPEC_HAS_TV_SEC || !STRUCT_TIMESPEC_HAS_TV_NSEC struct timespec { time_t tv_sec; long tv_nsec; }; #endif int win_pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_create(pthread_t *, const pthread_attr_t *, pthread_handler, void *); int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_destroy(pthread_cond_t *cond); int pthread_attr_init(pthread_attr_t *connect_att); int pthread_attr_setstacksize(pthread_attr_t *connect_att,size_t stack); int pthread_attr_destroy(pthread_attr_t *connect_att); int my_pthread_once(my_pthread_once_t *once_control,void (*init_routine)(void)); static inline struct tm *localtime_r(const time_t *timep, struct tm *tmp) { localtime_s(tmp, timep); return tmp; } static inline struct tm *gmtime_r(const time_t *clock, struct tm *res) { gmtime_s(res, clock); return res; } void pthread_exit(void *a); int pthread_join(pthread_t thread, void **value_ptr); int pthread_cancel(pthread_t thread); #ifndef ETIMEDOUT #define ETIMEDOUT 145 /* Win32 doesn't have this */ #endif #define HAVE_LOCALTIME_R 1 #define _REENTRANT 1 #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 #undef SAFE_MUTEX /* This will cause conflicts */ #define pthread_key(T,V) DWORD V #define pthread_key_create(A,B) ((*A=TlsAlloc())==0xFFFFFFFF) #define pthread_key_delete(A) TlsFree(A) #define my_pthread_setspecific_ptr(T,V) (!TlsSetValue((T),(V))) #define pthread_setspecific(A,B) (!TlsSetValue((A),(LPVOID)(B))) #define pthread_getspecific(A) (TlsGetValue(A)) #define my_pthread_getspecific(T,A) ((T) TlsGetValue(A)) #define my_pthread_getspecific_ptr(T,V) ((T) TlsGetValue(V)) #define pthread_equal(A,B) ((A) == (B)) #define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0) #define pthread_mutex_lock(A) (EnterCriticalSection(A),0) #define pthread_mutex_trylock(A) win_pthread_mutex_trylock((A)) #define pthread_mutex_unlock(A) (LeaveCriticalSection(A), 0) #define pthread_mutex_destroy(A) (DeleteCriticalSection(A), 0) #define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) /* Dummy defines for easier code */ #define pthread_attr_setdetachstate(A,B) pthread_dummy(0) #define pthread_attr_setscope(A,B) #define pthread_detach_this_thread() #define pthread_condattr_init(A) #define pthread_condattr_destroy(A) #define pthread_yield() SwitchToThread() #define my_sigset(A,B) signal(A,B) #else /* Normal threads */ #ifdef HAVE_rts_threads #define sigwait org_sigwait #include #undef sigwait #endif #include #ifndef _REENTRANT #define _REENTRANT #endif #ifdef HAVE_SCHED_H #include #endif #ifdef HAVE_SYNCH_H #include #endif #define pthread_key(T,V) pthread_key_t V #define my_pthread_getspecific_ptr(T,V) my_pthread_getspecific(T,(V)) #define my_pthread_setspecific_ptr(T,V) pthread_setspecific(T,(void*) (V)) #define pthread_detach_this_thread() #define pthread_handler_t EXTERNC void * typedef void *(* pthread_handler)(void *); #define my_pthread_once_t pthread_once_t #if defined(PTHREAD_ONCE_INITIALIZER) #define MY_PTHREAD_ONCE_INIT PTHREAD_ONCE_INITIALIZER #else #define MY_PTHREAD_ONCE_INIT PTHREAD_ONCE_INIT #endif #define my_pthread_once(C,F) pthread_once(C,F) /* Test first for RTS or FSU threads */ #if defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) #define HAVE_rts_threads extern int my_pthread_create_detached; #define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) #define PTHREAD_CREATE_DETACHED &my_pthread_create_detached #define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_GLOBAL #define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_LOCAL #define USE_ALARM_THREAD #endif /* defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) */ #if defined(_BSDI_VERSION) && _BSDI_VERSION < 199910 int sigwait(sigset_t *set, int *sig); #endif static inline int my_sigwait(sigset_t *set, int *sig, int *code) { #ifdef HAVE_SIGWAITINFO siginfo_t siginfo; *sig= sigwaitinfo(set, &siginfo); *code= siginfo.si_code; return *sig < 0 ? errno : 0; #else *code= 0; return sigwait(set, sig); #endif } #if defined(HAVE_SIGTHREADMASK) && !defined(HAVE_PTHREAD_SIGMASK) #define pthread_sigmask(A,B,C) sigthreadmask((A),(B),(C)) #endif #if !defined(HAVE_SIGWAIT) && !defined(HAVE_rts_threads) && !defined(sigwait) && !defined(alpha_linux_port) && !defined(_AIX) int sigwait(sigset_t *setp, int *sigp); /* Use our implementation */ #endif /* We define my_sigset() and use that instead of the system sigset() so that we can favor an implementation based on sigaction(). On some systems, such as Mac OS X, sigset() results in flags such as SA_RESTART being set, and we want to make sure that no such flags are set. */ #if defined(HAVE_SIGACTION) && !defined(my_sigset) #define my_sigset(A,B) do { struct sigaction l_s; sigset_t l_set; \ DBUG_ASSERT((A) != 0); \ sigemptyset(&l_set); \ l_s.sa_handler = (B); \ l_s.sa_mask = l_set; \ l_s.sa_flags = 0; \ sigaction((A), &l_s, NULL); \ } while (0) #elif defined(HAVE_SIGSET) && !defined(my_sigset) #define my_sigset(A,B) sigset((A),(B)) #elif !defined(my_sigset) #define my_sigset(A,B) signal((A),(B)) #endif #if !defined(HAVE_PTHREAD_ATTR_SETSCOPE) #define pthread_attr_setscope(A,B) #undef HAVE_GETHOSTBYADDR_R /* No definition */ #endif #define my_pthread_getspecific(A,B) ((A) pthread_getspecific(B)) #ifndef HAVE_LOCALTIME_R struct tm *localtime_r(const time_t *clock, struct tm *res); #endif #ifndef HAVE_GMTIME_R struct tm *gmtime_r(const time_t *clock, struct tm *res); #endif #ifdef HAVE_PTHREAD_CONDATTR_CREATE /* DCE threads on HPUX 10.20 */ #define pthread_condattr_init pthread_condattr_create #define pthread_condattr_destroy pthread_condattr_delete #endif /* FSU THREADS */ #if !defined(HAVE_PTHREAD_KEY_DELETE) && !defined(pthread_key_delete) #define pthread_key_delete(A) pthread_dummy(0) #endif #if defined(HAVE_PTHREAD_ATTR_CREATE) && !defined(HAVE_SIGWAIT) /* This is set on AIX_3_2 and Siemens unix (and DEC OSF/1 3.2 too) */ #define pthread_key_create(A,B) \ pthread_keycreate(A,(B) ?\ (pthread_destructor_t) (B) :\ (pthread_destructor_t) pthread_dummy) #define pthread_attr_init(A) pthread_attr_create(A) #define pthread_attr_destroy(A) pthread_attr_delete(A) #define pthread_attr_setdetachstate(A,B) pthread_dummy(0) #define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D)) #ifndef pthread_sigmask #define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) #endif #define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) #undef pthread_detach_this_thread #define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); } #else /* HAVE_PTHREAD_ATTR_CREATE && !HAVE_SIGWAIT */ #define HAVE_PTHREAD_KILL 1 #endif #endif /* defined(_WIN32) */ #if defined(HPUX10) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) #undef pthread_cond_timedwait #define pthread_cond_timedwait(a,b,c) my_pthread_cond_timedwait((a),(b),(c)) int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec *abstime); #endif #if defined(HPUX10) #define pthread_attr_getstacksize(A,B) my_pthread_attr_getstacksize(A,B) void my_pthread_attr_getstacksize(pthread_attr_t *attrib, size_t *size); #endif #if defined(HAVE_POSIX1003_4a_MUTEX) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) #undef pthread_mutex_trylock #define pthread_mutex_trylock(a) my_pthread_mutex_trylock((a)) int my_pthread_mutex_trylock(pthread_mutex_t *mutex); #endif #ifdef HAVE_SCHED_YIELD #define pthread_yield() sched_yield() #else #if !defined(HAVE_PTHREAD_YIELD_ZERO_ARG) /* no pthread_yield() available */ #if defined(HAVE_PTHREAD_YIELD_NP) /* can be Mac OS X */ #define pthread_yield() pthread_yield_np() #elif defined(HAVE_THR_YIELD) #define pthread_yield() thr_yield() #endif //defined(HAVE_PTHREAD_YIELD_NP) #endif //!defined(HAVE_PTHREAD_YIELD_ZERO_ARG) #endif //HAVE_SCHED_YIELD size_t my_setstacksize(pthread_attr_t *attr, size_t stacksize); /* The defines set_timespec and set_timespec_nsec should be used for calculating an absolute time at which pthread_cond_timedwait should timeout */ #define set_timespec(ABSTIME,SEC) set_timespec_nsec((ABSTIME),(SEC)*1000000000ULL) #ifndef set_timespec_nsec #define set_timespec_nsec(ABSTIME,NSEC) \ set_timespec_time_nsec((ABSTIME), my_hrtime_coarse().val*1000 + (NSEC)) #endif /* !set_timespec_nsec */ /* adapt for two different flavors of struct timespec */ #ifdef HAVE_TIMESPEC_TS_SEC #define MY_tv_sec ts_sec #define MY_tv_nsec ts_nsec #else #define MY_tv_sec tv_sec #define MY_tv_nsec tv_nsec #endif /* HAVE_TIMESPEC_TS_SEC */ /** Compare two timespec structs. @retval 1 If TS1 ends after TS2. @retval 0 If TS1 is equal to TS2. @retval -1 If TS1 ends before TS2. */ #ifndef cmp_timespec #define cmp_timespec(TS1, TS2) \ ((TS1.MY_tv_sec > TS2.MY_tv_sec || \ (TS1.MY_tv_sec == TS2.MY_tv_sec && TS1.MY_tv_nsec > TS2.MY_tv_nsec)) ? 1 : \ ((TS1.MY_tv_sec < TS2.MY_tv_sec || \ (TS1.MY_tv_sec == TS2.MY_tv_sec && TS1.MY_tv_nsec < TS2.MY_tv_nsec)) ? -1 : 0)) #endif /* !cmp_timespec */ #ifndef set_timespec_time_nsec #define set_timespec_time_nsec(ABSTIME,NSEC) do { \ ulonglong _now_= (NSEC); \ (ABSTIME).MY_tv_sec= (time_t) (_now_ / 1000000000ULL); \ (ABSTIME).MY_tv_nsec= (ulong) (_now_ % 1000000000UL); \ } while(0) #endif /* !set_timespec_time_nsec */ #ifdef MYSQL_CLIENT #define _current_thd() NULL #else MYSQL_THD _current_thd(); #endif /* safe_mutex adds checking to mutex for easier debugging */ struct st_hash; typedef struct st_safe_mutex_t { pthread_mutex_t global,mutex; const char *file, *name; uint line,count; myf create_flags, active_flags; ulong id; pthread_t thread; struct st_hash *locked_mutex, *used_mutex; struct st_safe_mutex_t *prev, *next; #ifdef SAFE_MUTEX_DETECT_DESTROY struct st_safe_mutex_info_t *info; /* to track destroying of mutexes */ #endif } safe_mutex_t; typedef struct st_safe_mutex_deadlock_t { const char *file, *name; safe_mutex_t *mutex; uint line; ulong count; ulong id; my_bool warning_only; } safe_mutex_deadlock_t; #ifdef SAFE_MUTEX_DETECT_DESTROY /* Used to track the destroying of mutexes. This needs to be a separate structure because the safe_mutex_t structure could be freed before the mutexes are destroyed. */ typedef struct st_safe_mutex_info_t { struct st_safe_mutex_info_t *next; struct st_safe_mutex_info_t *prev; const char *init_file; uint32 init_line; } safe_mutex_info_t; #endif /* SAFE_MUTEX_DETECT_DESTROY */ int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr, const char *name, const char *file, uint line); int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file, uint line); int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line); int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line); int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file, uint line); int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp, const struct timespec *abstime, const char *file, uint line); void safe_mutex_global_init(void); void safe_mutex_end(FILE *file); void safe_mutex_free_deadlock_data(safe_mutex_t *mp); /* Wrappers if safe mutex is actually used */ #define MYF_TRY_LOCK 1 #define MYF_NO_DEADLOCK_DETECTION 2 #ifdef SAFE_MUTEX #define safe_mutex_is_owner(mp) ((mp)->count > 0 && \ pthread_equal(pthread_self(), (mp)->thread)) #define safe_mutex_assert_owner(mp) DBUG_ASSERT(safe_mutex_is_owner(mp)) #define safe_mutex_assert_not_owner(mp) DBUG_ASSERT(!safe_mutex_is_owner(mp)) #define safe_mutex_setflags(mp, F) do { (mp)->create_flags|= (F); } while (0) #define my_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) #define my_cond_wait(A,B) safe_cond_wait((A), (B), __FILE__, __LINE__) #else #define safe_mutex_is_owner(mp) (1) #define safe_mutex_assert_owner(mp) do {} while (0) #define safe_mutex_assert_not_owner(mp) do {} while (0) #define safe_mutex_setflags(mp, F) do {} while (0) #define my_cond_timedwait(A,B,C) pthread_cond_timedwait((A),(B),(C)) #define my_cond_wait(A,B) pthread_cond_wait((A), (B)) #endif /* !SAFE_MUTEX */ /* READ-WRITE thread locking */ #if defined(USE_MUTEX_INSTEAD_OF_RW_LOCKS) /* use these defs for simple mutex locking */ #define rw_lock_t pthread_mutex_t #define my_rwlock_init(A,B) pthread_mutex_init((A),(B)) #define rw_rdlock(A) pthread_mutex_lock((A)) #define rw_wrlock(A) pthread_mutex_lock((A)) #define rw_tryrdlock(A) pthread_mutex_trylock((A)) #define rw_trywrlock(A) pthread_mutex_trylock((A)) #define rw_unlock(A) pthread_mutex_unlock((A)) #define rwlock_destroy(A) pthread_mutex_destroy((A)) #elif defined(HAVE_PTHREAD_RWLOCK_RDLOCK) #define rw_lock_t pthread_rwlock_t #define my_rwlock_init(A,B) pthread_rwlock_init((A),(B)) #define rw_rdlock(A) pthread_rwlock_rdlock(A) #define rw_wrlock(A) pthread_rwlock_wrlock(A) #define rw_tryrdlock(A) pthread_rwlock_tryrdlock((A)) #define rw_trywrlock(A) pthread_rwlock_trywrlock((A)) #define rw_unlock(A) pthread_rwlock_unlock(A) #define rwlock_destroy(A) pthread_rwlock_destroy(A) #elif defined(HAVE_RWLOCK_INIT) #ifdef HAVE_RWLOCK_T /* For example Solaris 2.6-> */ #define rw_lock_t rwlock_t #endif #define my_rwlock_init(A,B) rwlock_init((A),USYNC_THREAD,0) #else /* Use our own version of read/write locks */ #define NEED_MY_RW_LOCK 1 #define rw_lock_t my_rw_lock_t #define my_rwlock_init(A,B) my_rw_init((A)) #define rw_rdlock(A) my_rw_rdlock((A)) #define rw_wrlock(A) my_rw_wrlock((A)) #define rw_tryrdlock(A) my_rw_tryrdlock((A)) #define rw_trywrlock(A) my_rw_trywrlock((A)) #define rw_unlock(A) my_rw_unlock((A)) #define rwlock_destroy(A) my_rw_destroy((A)) #define rw_lock_assert_write_owner(A) my_rw_lock_assert_write_owner((A)) #define rw_lock_assert_not_write_owner(A) my_rw_lock_assert_not_write_owner((A)) #endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */ /** Portable implementation of special type of read-write locks. These locks have two properties which are unusual for rwlocks: 1) They "prefer readers" in the sense that they do not allow situations in which rwlock is rd-locked and there is a pending rd-lock which is blocked (e.g. due to pending request for wr-lock). This is a stronger guarantee than one which is provided for PTHREAD_RWLOCK_PREFER_READER_NP rwlocks in Linux. MDL subsystem deadlock detector relies on this property for its correctness. 2) They are optimized for uncontended wr-lock/unlock case. This is a scenario in which they are most often used within MDL subsystem. Optimizing for it gives significant performance improvements in some of the tests involving many connections. Another important requirement imposed on this type of rwlock by the MDL subsystem is that it should be OK to destroy rwlock object which is in unlocked state even though some threads might have not yet fully left unlock operation for it (of course there is an external guarantee that no thread will try to lock rwlock which is destroyed). Putting it another way the unlock operation should not access rwlock data after changing its state to unlocked. TODO/FIXME: We should consider alleviating this requirement as it blocks us from doing certain performance optimizations. */ typedef struct st_rw_pr_lock_t { /** Lock which protects the structure. Also held for the duration of wr-lock. */ pthread_mutex_t lock; /** Condition variable which is used to wake-up writers waiting for readers to go away. */ pthread_cond_t no_active_readers; /** Number of active readers. */ uint active_readers; /** Number of writers waiting for readers to go away. */ uint writers_waiting_readers; /** Indicates whether there is an active writer. */ my_bool active_writer; #ifdef SAFE_MUTEX /** Thread holding wr-lock (for debug purposes only). */ pthread_t writer_thread; #endif } rw_pr_lock_t; extern int rw_pr_init(rw_pr_lock_t *); extern int rw_pr_rdlock(rw_pr_lock_t *); extern int rw_pr_wrlock(rw_pr_lock_t *); extern int rw_pr_unlock(rw_pr_lock_t *); extern int rw_pr_destroy(rw_pr_lock_t *); #ifdef SAFE_MUTEX #define rw_pr_lock_assert_write_owner(A) \ DBUG_ASSERT((A)->active_writer && pthread_equal(pthread_self(), \ (A)->writer_thread)) #define rw_pr_lock_assert_not_write_owner(A) \ DBUG_ASSERT(! (A)->active_writer || ! pthread_equal(pthread_self(), \ (A)->writer_thread)) #else #define rw_pr_lock_assert_write_owner(A) #define rw_pr_lock_assert_not_write_owner(A) #endif /* SAFE_MUTEX */ #ifdef NEED_MY_RW_LOCK #ifdef _WIN32 /** Implementation of Windows rwlock. We use native (slim) rwlocks on Windows, which requires Win7 or later. */ typedef struct _my_rwlock_t { SRWLOCK srwlock; /* native reader writer lock */ BOOL have_exclusive_srwlock; /* used for unlock */ } my_rw_lock_t; #else /* _WIN32 */ /* On systems which don't support native read/write locks we have to use own implementation. */ typedef struct st_my_rw_lock_t { pthread_mutex_t lock; /* lock for structure */ pthread_cond_t readers; /* waiting readers */ pthread_cond_t writers; /* waiting writers */ int state; /* -1:writer,0:free,>0:readers */ int waiters; /* number of waiting writers */ #ifdef SAFE_MUTEX pthread_t write_thread; #endif } my_rw_lock_t; #endif /*! _WIN32 */ extern int my_rw_init(my_rw_lock_t *); extern int my_rw_destroy(my_rw_lock_t *); extern int my_rw_rdlock(my_rw_lock_t *); extern int my_rw_wrlock(my_rw_lock_t *); extern int my_rw_unlock(my_rw_lock_t *); extern int my_rw_tryrdlock(my_rw_lock_t *); extern int my_rw_trywrlock(my_rw_lock_t *); #ifdef SAFE_MUTEX #define my_rw_lock_assert_write_owner(A) \ DBUG_ASSERT((A)->state == -1 && pthread_equal(pthread_self(), \ (A)->write_thread)) #define my_rw_lock_assert_not_write_owner(A) \ DBUG_ASSERT((A)->state >= 0 || ! pthread_equal(pthread_self(), \ (A)->write_thread)) #else #define my_rw_lock_assert_write_owner(A) #define my_rw_lock_assert_not_write_owner(A) #endif #endif /* NEED_MY_RW_LOCK */ #define GETHOSTBYADDR_BUFF_SIZE 2048 #if !defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && ! defined(pthread_attr_setstacksize) #define pthread_attr_setstacksize(A,B) pthread_dummy(0) #endif /* Define mutex types, see my_thr_init.c */ #define MY_MUTEX_INIT_SLOW NULL #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP extern pthread_mutexattr_t my_fast_mutexattr; #define MY_MUTEX_INIT_FAST &my_fast_mutexattr #else #define MY_MUTEX_INIT_FAST NULL #endif #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP extern pthread_mutexattr_t my_errorcheck_mutexattr; #define MY_MUTEX_INIT_ERRCHK &my_errorcheck_mutexattr #else #define MY_MUTEX_INIT_ERRCHK NULL #endif #ifndef ESRCH /* Define it to something */ #define ESRCH 1 #endif typedef uint64 my_thread_id; /** Long-standing formats (such as the client-server protocol and the binary log) hard-coded `my_thread_id` to 32 bits in practice. (Though not all `thread_id`s are typed as such, @ref my_thread_id itself among those.) @see MDEV-35706 */ #define MY_THREAD_ID_MAX UINT32_MAX extern void my_threadattr_global_init(void); extern my_bool my_thread_global_init(void); extern void my_thread_global_reinit(void); extern void my_thread_global_end(void); extern my_bool my_thread_init(void); extern void my_thread_end(void); extern const char *my_thread_name(void); extern my_thread_id my_thread_dbug_id(void); extern int pthread_dummy(int); extern void my_mutex_init(void); extern void my_mutex_end(void); /* All thread specific variables are in the following struct */ #define THREAD_NAME_SIZE 10 #ifndef DEFAULT_THREAD_STACK /* We need to have at least 256K stack to handle calls to myisamchk_init() with the current number of keys and key parts. */ #if !defined(__has_feature) #define __has_feature(x) 0 #endif #if defined(__clang__) && __has_feature(memory_sanitizer) && !defined(DBUG_OFF) /* MSAN in Debug with clang-20.1 required more memory to complete mtr begin/end checks. The result without increase was MSAN errors triggered on a call instruction. */ # define DEFAULT_THREAD_STACK (2L<<20) # elif defined(__SANITIZE_ADDRESS__) || defined(WITH_UBSAN) /* Optimized WITH_ASAN=ON executables produced by GCC 12.3.0, GCC 13.2.0, or clang 16.0.6 would fail ./mtr main.1st when the stack size is 5 MiB. The minimum is more than 6 MiB for CMAKE_BUILD_TYPE=RelWithDebInfo and more than 10 MiB for CMAKE_BUILD_TYPE=Debug. Let us add some safety margin. */ # define DEFAULT_THREAD_STACK (11L<<20) # else # define DEFAULT_THREAD_STACK (292*1024L) /* 299008 */ # endif #endif #define MY_PTHREAD_LOCK_READ 0 #define MY_PTHREAD_LOCK_WRITE 1 #include #define INSTRUMENT_ME 0 /* Thread specific variables Aria key cache is using the following variables for keeping track of state: suspend, next, prev, keycache_link, keycache_file, suspend, lock_type MariaDB uses the following to mutex, current_mutex, current_cond, abort */ struct st_my_thread_var { int thr_errno; mysql_cond_t suspend; mysql_mutex_t mutex; struct st_my_thread_var *next,**prev; mysql_mutex_t * volatile current_mutex; mysql_cond_t * volatile current_cond; void *keycache_link; void *keycache_file; void *stack_ends_here; safe_mutex_t *mutex_in_use; pthread_t pthread_self; my_thread_id id, dbug_id; int volatile abort; uint lock_type; /* used by conditional release the queue */ my_bool init; #ifndef DBUG_OFF void *dbug; char name[THREAD_NAME_SIZE+1]; #endif }; struct st_my_thread_var *_my_thread_var(void); extern void **my_thread_var_dbug(void); extern safe_mutex_t **my_thread_var_mutex_in_use(void); extern uint my_thread_end_wait_time; extern my_bool safe_mutex_deadlock_detector; #define my_thread_var (_my_thread_var()) #define my_errno my_thread_var->thr_errno int set_mysys_var(struct st_my_thread_var *mysys_var); /* thread_safe_xxx functions are for critical statistic or counters. The implementation is guaranteed to be thread safe, on all platforms. Note that the calling code should *not* assume the counter is protected by the mutex given, as the implementation of these helpers may change to use my_atomic operations instead. */ #ifndef thread_safe_increment #ifdef _WIN32 #define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V)) #define thread_safe_decrement(V,L) InterlockedDecrement((long*) &(V)) #else #define thread_safe_increment(V,L) \ (mysql_mutex_lock((L)), (V)++, mysql_mutex_unlock((L))) #define thread_safe_decrement(V,L) \ (mysql_mutex_lock((L)), (V)--, mysql_mutex_unlock((L))) #endif #endif #ifndef thread_safe_add #ifdef _WIN32 #define thread_safe_add(V,C,L) InterlockedExchangeAdd((long*) &(V),(C)) #define thread_safe_sub(V,C,L) InterlockedExchangeAdd((long*) &(V),-(long) (C)) #else #define thread_safe_add(V,C,L) \ (mysql_mutex_lock((L)), (V)+=(C), mysql_mutex_unlock((L))) #define thread_safe_sub(V,C,L) \ (mysql_mutex_lock((L)), (V)-=(C), mysql_mutex_unlock((L))) #endif #endif /* statistics_xxx functions are for non critical statistic, maintained in global variables. When compiling with SAFE_STATISTICS: - race conditions can not occur. - some locking occurs, which may cause performance degradation. When compiling without SAFE_STATISTICS: - race conditions can occur, making the result slightly inaccurate. - the lock given is not honored. */ #ifdef SAFE_STATISTICS #define statistic_increment(V,L) thread_safe_increment((V),(L)) #define statistic_decrement(V,L) thread_safe_decrement((V),(L)) #define statistic_add(V,C,L) thread_safe_add((V),(C),(L)) #define statistic_sub(V,C,L) thread_safe_sub((V),(C),(L)) #else #define statistic_decrement(V,L) (V)-- #define statistic_increment(V,L) (V)++ #define statistic_add(V,C,L) (V)+=(C) #define statistic_sub(V,C,L) (V)-=(C) #endif /* SAFE_STATISTICS */ /* No locking needed, the counter is owned by the thread */ #define status_var_increment(V) (V)++ #define status_var_decrement(V) (V)-- #define status_var_add(V,C) (V)+=(C) #define status_var_sub(V,C) (V)-=(C) #ifdef SAFE_MUTEX #define mysql_mutex_record_order(A,B) \ do { \ mysql_mutex_lock(A); mysql_mutex_lock(B); \ mysql_mutex_unlock(B); mysql_mutex_unlock(A); \ } while(0) #else #define mysql_mutex_record_order(A,B) do { } while(0) #endif /* At least Windows and NetBSD do not have this definition */ #ifndef PTHREAD_STACK_MIN #define PTHREAD_STACK_MIN 65536 #endif #ifdef __cplusplus } #endif #endif /* _my_ptread_h */ server/byte_order_generic_x86.h000064400000010272151031265040012561 0ustar00/* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Optimized function-like macros for the x86 architecture (_WIN32 included). */ #define sint2korr(A) (*((const int16 *) (A))) #define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ (((uint32) 255L << 24) | \ (((uint32) (uchar) (A)[2]) << 16) |\ (((uint32) (uchar) (A)[1]) << 8) | \ ((uint32) (uchar) (A)[0])) : \ (((uint32) (uchar) (A)[2]) << 16) |\ (((uint32) (uchar) (A)[1]) << 8) | \ ((uint32) (uchar) (A)[0]))) #define sint4korr(A) (*((const long *) (A))) #define uint2korr(A) (*((const uint16 *) (A))) #define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) |\ (((uint32) ((uchar) (A)[1])) << 8) |\ (((uint32) ((uchar) (A)[2])) << 16)) #define uint4korr(A) (*((const uint32 *) (A))) #define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) |\ (((uint32) ((uchar) (A)[1])) << 8) |\ (((uint32) ((uchar) (A)[2])) << 16) |\ (((uint32) ((uchar) (A)[3])) << 24)) |\ (((ulonglong) ((uchar) (A)[4])) << 32)) #define uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) | \ (((uint32) ((uchar) (A)[1])) << 8) | \ (((uint32) ((uchar) (A)[2])) << 16) | \ (((uint32) ((uchar) (A)[3])) << 24)) | \ (((ulonglong) ((uchar) (A)[4])) << 32) | \ (((ulonglong) ((uchar) (A)[5])) << 40)) #define uint8korr(A) (*((const ulonglong *) (A))) #define sint8korr(A) (*((const longlong *) (A))) #define int2store(T,A) *((uint16*) (T))= (uint16) (A) #define int3store(T,A) do { *(T)= (uchar) ((A));\ *(T+1)=(uchar) (((uint) (A) >> 8));\ *(T+2)=(uchar) (((A) >> 16));\ } while (0) #define int4store(T,A) *((long *) (T))= (long) (A) #define int5store(T,A) do { *(T)= (uchar)((A));\ *((T)+1)=(uchar) (((A) >> 8));\ *((T)+2)=(uchar) (((A) >> 16));\ *((T)+3)=(uchar) (((A) >> 24));\ *((T)+4)=(uchar) (((A) >> 32));\ } while(0) #define int6store(T,A) do { *(T)= (uchar)((A)); \ *((T)+1)=(uchar) (((A) >> 8)); \ *((T)+2)=(uchar) (((A) >> 16)); \ *((T)+3)=(uchar) (((A) >> 24)); \ *((T)+4)=(uchar) (((A) >> 32)); \ *((T)+5)=(uchar) (((A) >> 40)); \ } while(0) #define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A) typedef union { double v; long m[2]; } doubleget_union; #define doubleget(V,M) \ do { doubleget_union _tmp; \ _tmp.m[0] = *((const long*)(M)); \ _tmp.m[1] = *(((const long*) (M))+1); \ (V) = _tmp.v; } while(0) #define doublestore(T,V) \ do { *((long *) T) = ((const doubleget_union *)&V)->m[0]; \ *(((long *) T)+1) = ((const doubleget_union *)&V)->m[1]; \ } while (0) #define float4get(V,M) \ do { *((float *) &(V)) = *((const float*) (M)); } while(0) #define float8get(V,M) doubleget((V),(M)) #define float4store(V,M) memcpy((uchar*)(V), (uchar*)(&M), sizeof(float)) #define floatstore(T,V) memcpy((uchar*)(T), (uchar*)(&V), sizeof(float)) #define floatget(V,M) memcpy((uchar*)(&V),(uchar*) (M), sizeof(float)) #define float8store(V,M) doublestore((V),(M)) server/private/my_md5.h000064400000002716151031265040011072 0ustar00#ifndef MY_MD5_INCLUDED #define MY_MD5_INCLUDED /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. Copyright (c) 2013 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include "m_string.h" #define MD5_HASH_SIZE 16 /* Hash size in bytes */ /* Wrapper function for MD5 implementation. */ #ifdef __cplusplus extern "C" { #endif #define compute_md5_hash(A,B,C) my_md5(A,B,C) /* Convert an array of bytes to a hexadecimal representation. Used to generate a hexadecimal representation of a message digest. */ static inline void array_to_hex(char *to, const unsigned char *str, uint len) { const unsigned char *str_end= str + len; for (; str != str_end; ++str) { *to++= _dig_vec_lower[((uchar) *str) >> 4]; *to++= _dig_vec_lower[((uchar) *str) & 0x0F]; } } #ifdef __cplusplus } #endif #endif /* MY_MD5_INCLUDED */ server/private/event_data_objects.h000064400000010133151031265040013513 0ustar00#ifndef _EVENT_DATA_OBJECTS_H_ #define _EVENT_DATA_OBJECTS_H_ /* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @addtogroup Event_Scheduler @{ @file event_data_objects.h */ #include "event_parse_data.h" #include "thr_lock.h" /* thr_lock_type */ class Field; class THD; class Time_zone; struct TABLE; void init_scheduler_psi_keys(void); class Event_queue_element_for_exec { public: Event_queue_element_for_exec() : dbname{nullptr, 0}, name{nullptr, 0} {} ~Event_queue_element_for_exec(); bool init(const LEX_CSTRING &dbname, const LEX_CSTRING &name); LEX_CSTRING dbname; LEX_CSTRING name; bool dropped; THD *thd; private: /* Prevent use of these */ Event_queue_element_for_exec(const Event_queue_element_for_exec &); void operator=(Event_queue_element_for_exec &); #ifdef HAVE_PSI_INTERFACE public: PSI_statement_info* get_psi_info() { return & psi_info; } static PSI_statement_info psi_info; #endif }; class Event_basic { protected: MEM_ROOT mem_root; public: LEX_CSTRING dbname; LEX_CSTRING name; LEX_CSTRING definer;// combination of user and host Time_zone *time_zone; Event_basic(); virtual ~Event_basic(); virtual bool load_from_row(THD *thd, TABLE *table) = 0; protected: bool load_string_fields(Field **fields, ...); bool load_time_zone(THD *thd, const LEX_CSTRING *tz_name); }; class Event_queue_element : public Event_basic { public: int on_completion; int status; uint32 originator; my_time_t last_executed; my_time_t execute_at; my_time_t starts; my_time_t ends; bool starts_null; bool ends_null; bool execute_at_null; longlong expression; interval_type interval; bool dropped; uint execution_count; Event_queue_element(); virtual ~Event_queue_element(); virtual bool load_from_row(THD *thd, TABLE *table) override; bool compute_next_execution_time(); void mark_last_executed(THD *thd); }; class Event_timed : public Event_queue_element { Event_timed(const Event_timed &); /* Prevent use of these */ void operator=(Event_timed &); public: LEX_CSTRING body; LEX_CSTRING definer_user; LEX_CSTRING definer_host; LEX_CSTRING comment; ulonglong created; ulonglong modified; sql_mode_t sql_mode; class Stored_program_creation_ctx *creation_ctx; LEX_CSTRING body_utf8; Event_timed(); virtual ~Event_timed(); void init(); virtual bool load_from_row(THD *thd, TABLE *table) override; int get_create_event(THD *thd, String *buf); }; class Event_job_data : public Event_basic { public: LEX_CSTRING body; LEX_CSTRING definer_user; LEX_CSTRING definer_host; sql_mode_t sql_mode; class Stored_program_creation_ctx *creation_ctx; Event_job_data(); virtual bool load_from_row(THD *thd, TABLE *table) override; bool execute(THD *thd, bool drop); private: bool construct_sp_sql(THD *thd, String *sp_sql); bool construct_drop_event_sql(THD *thd, String *sp_sql); Event_job_data(const Event_job_data &); /* Prevent use of these */ void operator=(Event_job_data &); }; /* Compares only the schema part of the identifier */ bool event_basic_db_equal(const LEX_CSTRING *db, Event_basic *et); /* Compares the whole identifier*/ bool event_basic_identifier_equal(const LEX_CSTRING *db, const LEX_CSTRING *name, Event_basic *b); /** @} (End of group Event_Scheduler) */ #endif /* _EVENT_DATA_OBJECTS_H_ */ server/private/thr_alarm.h000064400000005564151031265040011655 0ustar00/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Prototypes when using thr_alarm library functions */ #ifndef _thr_alarm_h #define _thr_alarm_h #ifdef __cplusplus extern "C" { #endif #ifndef USE_ALARM_THREAD #define USE_ONE_SIGNAL_HAND /* One must call process_alarm */ #endif #ifdef HAVE_rts_threads #undef USE_ONE_SIGNAL_HAND #define USE_ALARM_THREAD #define THR_SERVER_ALARM SIGUSR1 #else #define THR_SERVER_ALARM SIGALRM #endif typedef struct st_alarm_info { time_t next_alarm_time; uint active_alarms; uint max_used_alarms; } ALARM_INFO; void thr_alarm_info(ALARM_INFO *info); extern my_bool my_disable_thr_alarm; #ifdef _WIN32 #define DONT_USE_THR_ALARM #endif #if defined(DONT_USE_THR_ALARM) #define USE_ALARM_THREAD #undef USE_ONE_SIGNAL_HAND typedef my_bool thr_alarm_t; typedef my_bool ALARM; #define thr_alarm_init(A) (*(A))=0 #define thr_alarm_in_use(A) (*(A) != 0) #define thr_end_alarm(A) #define thr_alarm(A,B,C) ((*(A)=1)-1) /* The following should maybe be (*(A)) */ #define thr_got_alarm(A) 0 #define init_thr_alarm(A) #define thr_alarm_kill(A) #define resize_thr_alarm(N) #define end_thr_alarm(A) #else #if defined(_WIN32) typedef struct st_thr_alarm_entry { UINT_PTR crono; } thr_alarm_entry; #else /* System with posix threads */ typedef int thr_alarm_entry; #define thr_got_alarm(thr_alarm) (**(thr_alarm)) #endif /* _WIN32 */ typedef thr_alarm_entry* thr_alarm_t; typedef struct st_alarm { time_t expire_time; thr_alarm_entry alarmed; /* set when alarm is due */ pthread_t thread; my_thread_id thread_id; uint index_in_queue; my_bool malloced; } ALARM; extern uint thr_client_alarm; extern pthread_t alarm_thread; #define thr_alarm_init(A) (*(A))=0 #define thr_alarm_in_use(A) (*(A)!= 0) void init_thr_alarm(uint max_alarm); void resize_thr_alarm(uint max_alarms); my_bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); void thr_alarm_kill(my_thread_id thread_id); void thr_end_alarm(thr_alarm_t *alarmed); void end_thr_alarm(my_bool free_structures); sig_handler process_alarm(int); #ifndef thr_got_alarm my_bool thr_got_alarm(thr_alarm_t *alrm); #endif #endif /* DONT_USE_THR_ALARM */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _thr_alarm_h */ server/private/thr_malloc.h000064400000002262151031265040012020 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef THR_MALLOC_INCLUDED #define THR_MALLOC_INCLUDED typedef struct st_mem_root MEM_ROOT; void init_sql_alloc(PSI_memory_key key, MEM_ROOT *root, uint block_size, uint pre_alloc_size, myf my_flags); char *sql_strmake_with_convert(THD *thd, const char *str, size_t arg_length, CHARSET_INFO *from_cs, size_t max_res_length, CHARSET_INFO *to_cs, size_t *result_length); #endif /* THR_MALLOC_INCLUDED */ server/private/my_apc.h000064400000011213151031265040011140 0ustar00#ifndef SQL_MY_APC_INCLUDED #define SQL_MY_APC_INCLUDED /* Copyright (c) 2011, 2013 Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Interface ~~~~~~~~~ ( - This is an APC request queue - We assume there is a particular owner thread which periodically calls process_apc_requests() to serve the call requests. - Other threads can post call requests, and block until they are exectued. ) Implementation ~~~~~~~~~~~~~~ - The target has a mutex-guarded request queue. - After the request has been put into queue, the requestor waits for request to be satisfied. The worker satisifes the request and signals the requestor. */ class THD; /* Target for asynchronous procedure calls (APCs). - A target is running in some particular thread, - One can make calls to it from other threads. */ class Apc_target { mysql_mutex_t *LOCK_thd_kill_ptr; public: Apc_target() : enabled(0), apc_calls(NULL) {} ~Apc_target() { DBUG_ASSERT(!enabled && !apc_calls);} void init(mysql_mutex_t *target_mutex); /* Destroy the target. The target must be disabled when this call is made. */ void destroy() { DBUG_ASSERT(!enabled); } /* Enter ther state where the target is available for serving APC requests */ void enable() { enabled++; } /* Make the target unavailable for serving APC requests. @note This call will serve all requests that were already enqueued */ void disable() { DBUG_ASSERT(enabled); mysql_mutex_lock(LOCK_thd_kill_ptr); bool process= !--enabled && have_apc_requests(); mysql_mutex_unlock(LOCK_thd_kill_ptr); if (unlikely(process)) process_apc_requests(true); } void process_apc_requests(bool force); /* A lightweight function, intended to be used in frequent checks like this: if (apc_target.have_requests()) apc_target.process_apc_requests() */ inline bool have_apc_requests() { return MY_TEST(apc_calls); } inline bool is_enabled() { return enabled; } /* Functor class for calls you can schedule */ class Apc_call { public: /* This function will be called in the target thread */ virtual void call_in_target_thread()= 0; virtual ~Apc_call() = default; }; /* Make a call in the target thread (see function definition for details) */ bool make_apc_call(THD *caller_thd, Apc_call *call, int timeout_sec, bool *timed_out); #ifndef DBUG_OFF int n_calls_processed; /* Number of calls served by this target */ #endif private: class Call_request; /* Non-zero value means we're enabled. It's an int, not bool, because one can call enable() N times (and then needs to call disable() N times before the target is really disabled) */ int enabled; /* Circular, double-linked list of all enqueued call requests. We use this structure, because we - process requests sequentially: requests are added at the end of the list and removed from the front. With circular list, we can keep one pointer, and access both front an back of the list with it. - a thread that has posted a request may time out (or be KILLed) and cancel the request, which means we need a fast request-removal operation. */ Call_request *apc_calls; class Call_request { public: Apc_call *call; /* Functor to be called */ /* The caller will actually wait for "processed==TRUE" */ bool processed; /* Condition that will be signalled when the request has been served */ mysql_cond_t COND_request; /* Double linked-list linkage */ Call_request *next; Call_request *prev; const char *what; /* (debug) state of the request */ }; void enqueue_request(Call_request *qe); void dequeue_request(Call_request *qe); /* return the first call request in queue, or NULL if there are none enqueued */ Call_request *get_first_in_queue() { return apc_calls; } }; #ifdef HAVE_PSI_INTERFACE void init_show_explain_psi_keys(void); #else #define init_show_explain_psi_keys() /* no-op */ #endif #endif //SQL_MY_APC_INCLUDED server/private/opt_range.h000064400000164307151031265040011663 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* classes to use when handling where clause */ #ifndef _opt_range_h #define _opt_range_h #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "records.h" /* READ_RECORD */ #include "queues.h" /* QUEUE */ #include "filesort.h" /* SORT_INFO */ /* It is necessary to include set_var.h instead of item.h because there are dependencies on include order for set_var.h and item.h. This will be resolved later. */ #include "sql_class.h" // set_var.h: THD #include "set_var.h" /* Item */ class JOIN; class Item_sum; struct KEY_PART { uint16 key,part; /* See KEY_PART_INFO for meaning of the next two: */ uint16 store_length, length; uint8 null_bit; /* Keypart flags (0 when this structure is used by partition pruning code for fake partitioning index description) */ uint8 flag; Field *field; Field::imagetype image_type; }; class RANGE_OPT_PARAM; /* A construction block of the SEL_ARG-graph. The following description only covers graphs of SEL_ARG objects with sel_arg->type==KEY_RANGE: One SEL_ARG object represents an "elementary interval" in form min_value <=? table.keypartX <=? max_value The interval is a non-empty interval of any kind: with[out] minimum/maximum bound, [half]open/closed, single-point interval, etc. 1. SEL_ARG GRAPH STRUCTURE SEL_ARG objects are linked together in a graph. The meaning of the graph is better demostrated by an example: tree->keys[i] | | $ $ | part=1 $ part=2 $ part=3 | $ $ | +-------+ $ +-------+ $ +--------+ | | kp1<1 |--$-->| kp2=5 |--$-->| kp3=10 | | +-------+ $ +-------+ $ +--------+ | | $ $ | | | $ $ +--------+ | | $ $ | kp3=12 | | | $ $ +--------+ | +-------+ $ $ \->| kp1=2 |--$--------------$-+ +-------+ $ $ | +--------+ | $ $ ==>| kp3=11 | +-------+ $ $ | +--------+ | kp1=3 |--$--------------$-+ | +-------+ $ $ +--------+ | $ $ | kp3=14 | ... $ $ +--------+ The entire graph is partitioned into "interval lists". An interval list is a sequence of ordered disjoint intervals over the same key part. SEL_ARG are linked via "next" and "prev" pointers. Additionally, all intervals in the list form an RB-tree, linked via left/right/parent pointers. The RB-tree root SEL_ARG object will be further called "root of the interval list". In the example pic, there are 4 interval lists: "kp<1 OR kp1=2 OR kp1=3", "kp2=5", "kp3=10 OR kp3=12", "kp3=11 OR kp3=13". The vertical lines represent SEL_ARG::next/prev pointers. In an interval list, each member X may have SEL_ARG::next_key_part pointer pointing to the root of another interval list Y. The pointed interval list must cover a key part with greater number (i.e. Y->part > X->part). In the example pic, the next_key_part pointers are represented by horisontal lines. 2. SEL_ARG GRAPH SEMANTICS It represents a condition in a special form (we don't have a name for it ATM) The SEL_ARG::next/prev is "OR", and next_key_part is "AND". For example, the picture represents the condition in form: (kp1 < 1 AND kp2=5 AND (kp3=10 OR kp3=12)) OR (kp1=2 AND (kp3=11 OR kp3=14)) OR (kp1=3 AND (kp3=11 OR kp3=14)) 3. SEL_ARG GRAPH USE Use get_mm_tree() to construct SEL_ARG graph from WHERE condition. Then walk the SEL_ARG graph and get a list of dijsoint ordered key intervals (i.e. intervals in form (constA1, .., const1_K) < (keypart1,.., keypartK) < (constB1, .., constB_K) Those intervals can be used to access the index. The uses are in: - check_quick_select() - Walk the SEL_ARG graph and find an estimate of how many table records are contained within all intervals. - get_quick_select() - Walk the SEL_ARG, materialize the key intervals, and create QUICK_RANGE_SELECT object that will read records within these intervals. 4. SPACE COMPLEXITY NOTES SEL_ARG graph is a representation of an ordered disjoint sequence of intervals over the ordered set of index tuple values. For multi-part keys, one can construct a WHERE expression such that its list of intervals will be of combinatorial size. Here is an example: (keypart1 IN (1,2, ..., n1)) AND (keypart2 IN (1,2, ..., n2)) AND (keypart3 IN (1,2, ..., n3)) For this WHERE clause the list of intervals will have n1*n2*n3 intervals of form (keypart1, keypart2, keypart3) = (k1, k2, k3), where 1 <= k{i} <= n{i} SEL_ARG graph structure aims to reduce the amount of required space by "sharing" the elementary intervals when possible (the pic at the beginning of this comment has examples of such sharing). The sharing may prevent combinatorial blowup: There are WHERE clauses that have combinatorial-size interval lists but will be represented by a compact SEL_ARG graph. Example: (keypartN IN (1,2, ..., n1)) AND ... (keypart2 IN (1,2, ..., n2)) AND (keypart1 IN (1,2, ..., n3)) but not in all cases: - There are WHERE clauses that do have a compact SEL_ARG-graph representation but get_mm_tree() and its callees will construct a graph of combinatorial size. Example: (keypart1 IN (1,2, ..., n1)) AND (keypart2 IN (1,2, ..., n2)) AND ... (keypartN IN (1,2, ..., n3)) - There are WHERE clauses for which the minimal possible SEL_ARG graph representation will have combinatorial size. Example: By induction: Let's take any interval on some keypart in the middle: kp15=c0 Then let's AND it with this interval 'structure' from preceding and following keyparts: (kp14=c1 AND kp16=c3) OR keypart14=c2) (*) We will obtain this SEL_ARG graph: kp14 $ kp15 $ kp16 $ $ +---------+ $ +---------+ $ +---------+ | kp14=c1 |--$-->| kp15=c0 |--$-->| kp16=c3 | +---------+ $ +---------+ $ +---------+ | $ $ +---------+ $ +---------+ $ | kp14=c2 |--$-->| kp15=c0 | $ +---------+ $ +---------+ $ $ $ Note that we had to duplicate "kp15=c0" and there was no way to avoid that. The induction step: AND the obtained expression with another "wrapping" expression like (*). When the process ends because of the limit on max. number of keyparts we'll have: WHERE clause length is O(3*#max_keyparts) SEL_ARG graph size is O(2^(#max_keyparts/2)) (it is also possible to construct a case where instead of 2 in 2^n we have a bigger constant, e.g. 4, and get a graph with 4^(31/2)= 2^31 nodes) We avoid consuming too much memory by setting a limit on the number of SEL_ARG object we can construct during one range analysis invocation. 5. SEL_ARG GRAPH WEIGHT A SEL_ARG graph has a property we call weight, and we define it as follows: If the SEL_ARG graph does not have any node with multiple incoming next_key_part edges, then its weight is the number of SEL_ARG objects used. If there is a node with multiple incoming next_key_part edges, clone that node, (and the nodes connected to it via prev/next links) and redirect one of the incoming next_key_part edges to the clone. Continue with cloning until we get a graph that has no nodes with multiple incoming next_key_part edges. Then, the number of SEL_ARG objects in the graph is the weight of the original graph. Example: kp1 $ kp2 $ kp3 $ $ | +-------+ $ $ \->| kp1=2 |--$--------------$-+ +-------+ $ $ | +--------+ | $ $ ==>| kp3=11 | +-------+ $ $ | +--------+ | kp1>3 |--$--------------$-+ | +-------+ $ $ +--------+ $ $ | kp3=14 | $ $ +--------+ $ $ | $ $ +--------+ $ $ | kp3=14 | $ $ +--------+ Here, the weight is 2 + 2*3=8. The rationale behind using this definition of weight is: - it has the same order-of-magnitude as the number of ranges that the SEL_ARG graph is describing, - it is a lot easier to compute than computing the number of ranges, - it can be updated incrementally when performing AND/OR operations on parts of the graph. */ class SEL_ARG :public Sql_alloc { static int sel_cmp(Field *field, uchar *a, uchar *b, uint8 a_flag, uint8 b_flag); public: uint8 min_flag,max_flag,maybe_flag; uint8 part; // Which key part uint8 maybe_null; /* The ordinal number the least significant component encountered in the ranges of the SEL_ARG tree (the first component has number 1) Note: this number is currently not precise, it is an upper bound. @seealso SEL_ARG::get_max_key_part() */ uint16 max_part_no; /* Number of children of this element in the RB-tree, plus 1 for this element itself. */ uint32 elements; /* Valid only for elements which are RB-tree roots: Number of times this RB-tree is referred to (it is referred by SEL_ARG::next_key_part or by SEL_TREE::keys[i] or by a temporary SEL_ARG* variable) */ ulong use_count; Field *field; uchar *min_value,*max_value; // Pointer to range /* eq_tree() requires that left == right == 0 if the type is MAYBE_KEY. */ SEL_ARG *left,*right; /* R-B tree children */ SEL_ARG *next,*prev; /* Links for bi-directional interval list */ SEL_ARG *parent; /* R-B tree parent */ SEL_ARG *next_key_part; enum leaf_color { BLACK,RED } color; enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type; /* For R-B root nodes only: the graph weight, as defined above in the SEL_ARG GRAPH WEIGHT section. */ uint weight; enum { MAX_WEIGHT = 32000 }; #ifndef DBUG_OFF uint verify_weight(); #endif /* See RANGE_OPT_PARAM::alloced_sel_args */ enum { DEFAULT_MAX_SEL_ARGS = 16000 }; SEL_ARG() = default; SEL_ARG(SEL_ARG &); SEL_ARG(Field *,const uchar *, const uchar *); SEL_ARG(Field *field, uint8 part, uchar *min_value, uchar *max_value, uint8 min_flag, uint8 max_flag, uint8 maybe_flag); SEL_ARG(enum Type type_arg) :min_flag(0), max_part_no(0) /* first key part means 1. 0 mean 'no parts'*/, elements(1),use_count(1),left(0),right(0), next_key_part(0), color(BLACK), type(type_arg), weight(1) {} /** returns true if a range predicate is equal. Use all_same() to check for equality of all the predicates on this keypart. */ inline bool is_same(const SEL_ARG *arg) const { if (type != arg->type || part != arg->part) return false; if (type != KEY_RANGE) return true; return cmp_min_to_min(arg) == 0 && cmp_max_to_max(arg) == 0; } uint get_max_key_part() const; /** returns true if all the predicates in the keypart tree are equal */ bool all_same(const SEL_ARG *arg) const { if (type != arg->type || part != arg->part) return false; if (type != KEY_RANGE) return true; if (arg == this) return true; const SEL_ARG *cmp_arg= arg->first(); const SEL_ARG *cur_arg= first(); for (; cur_arg && cmp_arg && cur_arg->is_same(cmp_arg); cur_arg= cur_arg->next, cmp_arg= cmp_arg->next) ; if (cur_arg || cmp_arg) return false; return true; } inline void merge_flags(SEL_ARG *arg) { maybe_flag|=arg->maybe_flag; } inline void maybe_smaller() { maybe_flag=1; } /* Return true iff it's a single-point null interval */ inline bool is_null_interval() { return maybe_null && max_value[0] == 1; } inline int cmp_min_to_min(const SEL_ARG* arg) const { return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag); } inline int cmp_min_to_max(const SEL_ARG* arg) const { return sel_cmp(field,min_value, arg->max_value, min_flag, arg->max_flag); } inline int cmp_max_to_max(const SEL_ARG* arg) const { return sel_cmp(field,max_value, arg->max_value, max_flag, arg->max_flag); } inline int cmp_max_to_min(const SEL_ARG* arg) const { return sel_cmp(field,max_value, arg->min_value, max_flag, arg->min_flag); } SEL_ARG *clone_and(THD *thd, SEL_ARG* arg) { // Get overlapping range uchar *new_min,*new_max; uint8 flag_min,flag_max; if (cmp_min_to_min(arg) >= 0) { new_min=min_value; flag_min=min_flag; } else { new_min=arg->min_value; flag_min=arg->min_flag; /* purecov: deadcode */ } if (cmp_max_to_max(arg) <= 0) { new_max=max_value; flag_max=max_flag; } else { new_max=arg->max_value; flag_max=arg->max_flag; } return new (thd->mem_root) SEL_ARG(field, part, new_min, new_max, flag_min, flag_max, MY_TEST(maybe_flag && arg->maybe_flag)); } SEL_ARG *clone_first(SEL_ARG *arg) { // min <= X < arg->min return new SEL_ARG(field,part, min_value, arg->min_value, min_flag, arg->min_flag & NEAR_MIN ? 0 : NEAR_MAX, maybe_flag | arg->maybe_flag); } SEL_ARG *clone_last(SEL_ARG *arg) { // min <= X <= key_max return new SEL_ARG(field, part, min_value, arg->max_value, min_flag, arg->max_flag, maybe_flag | arg->maybe_flag); } SEL_ARG *clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, SEL_ARG **next); bool copy_min(SEL_ARG* arg) { // Get overlapping range if (cmp_min_to_min(arg) > 0) { min_value=arg->min_value; min_flag=arg->min_flag; if ((max_flag & (NO_MAX_RANGE | NO_MIN_RANGE)) == (NO_MAX_RANGE | NO_MIN_RANGE)) return 1; // Full range } maybe_flag|=arg->maybe_flag; return 0; } bool copy_max(SEL_ARG* arg) { // Get overlapping range if (cmp_max_to_max(arg) <= 0) { max_value=arg->max_value; max_flag=arg->max_flag; if ((max_flag & (NO_MAX_RANGE | NO_MIN_RANGE)) == (NO_MAX_RANGE | NO_MIN_RANGE)) return 1; // Full range } maybe_flag|=arg->maybe_flag; return 0; } void copy_min_to_min(SEL_ARG *arg) { min_value=arg->min_value; min_flag=arg->min_flag; } void copy_min_to_max(SEL_ARG *arg) { max_value=arg->min_value; max_flag=arg->min_flag & NEAR_MIN ? 0 : NEAR_MAX; } void copy_max_to_min(SEL_ARG *arg) { min_value=arg->max_value; min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN; } /* returns a number of keypart values (0 or 1) appended to the key buffer */ int store_min(uint length, uchar **min_key,uint min_key_flag) { /* "(kp1 > c1) AND (kp2 OP c2) AND ..." -> (kp1 > c1) */ if ((min_flag & GEOM_FLAG) || (!(min_flag & NO_MIN_RANGE) && !(min_key_flag & (NO_MIN_RANGE | NEAR_MIN)))) { if (maybe_null && *min_value) { **min_key=1; bzero(*min_key+1,length-1); } else memcpy(*min_key,min_value,length); (*min_key)+= length; return 1; } return 0; } /* returns a number of keypart values (0 or 1) appended to the key buffer */ int store_max(uint length, uchar **max_key, uint max_key_flag) { if (!(max_flag & NO_MAX_RANGE) && !(max_key_flag & (NO_MAX_RANGE | NEAR_MAX))) { if (maybe_null && *max_value) { **max_key=1; bzero(*max_key+1,length-1); } else memcpy(*max_key,max_value,length); (*max_key)+= length; return 1; } return 0; } /* Returns a number of keypart values appended to the key buffer for min key and max key. This function is used by both Range Analysis and Partition pruning. For partition pruning we have to ensure that we don't store also subpartition fields. Thus we have to stop at the last partition part and not step into the subpartition fields. For Range Analysis we set last_part to MAX_KEY which we should never reach. */ int store_min_key(KEY_PART *key, uchar **range_key, uint *range_key_flag, uint last_part) { SEL_ARG *key_tree= first(); uint res= key_tree->store_min(key[key_tree->part].store_length, range_key, *range_key_flag); // add flags only if a key_part is written to the buffer if (!res) return 0; *range_key_flag|= key_tree->min_flag; if (key_tree->next_key_part && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE && key_tree->part != last_part && key_tree->next_key_part->part == key_tree->part+1 && !(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN))) res+= key_tree->next_key_part->store_min_key(key, range_key, range_key_flag, last_part); return res; } /* returns a number of keypart values appended to the key buffer */ int store_max_key(KEY_PART *key, uchar **range_key, uint *range_key_flag, uint last_part) { SEL_ARG *key_tree= last(); uint res=key_tree->store_max(key[key_tree->part].store_length, range_key, *range_key_flag); if (!res) return 0; *range_key_flag|= key_tree->max_flag; if (key_tree->next_key_part && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE && key_tree->part != last_part && key_tree->next_key_part->part == key_tree->part+1 && !(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX))) res+= key_tree->next_key_part->store_max_key(key, range_key, range_key_flag, last_part); return res; } SEL_ARG *insert(SEL_ARG *key); SEL_ARG *tree_delete(SEL_ARG *key); SEL_ARG *find_range(SEL_ARG *key); SEL_ARG *rb_insert(SEL_ARG *leaf); friend SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key, SEL_ARG *par); #ifdef EXTRA_DEBUG friend int test_rb_tree(SEL_ARG *element,SEL_ARG *parent); void test_use_count(SEL_ARG *root); #endif SEL_ARG *first(); const SEL_ARG *first() const; SEL_ARG *last(); void make_root(); inline bool simple_key() { return !next_key_part && elements == 1; } void increment_use_count(long count) { if (next_key_part) { next_key_part->use_count+=count; count*= (next_key_part->use_count-count); for (SEL_ARG *pos=next_key_part->first(); pos ; pos=pos->next) if (pos->next_key_part) pos->increment_use_count(count); } } void incr_refs() { increment_use_count(1); use_count++; } void incr_refs_all() { for (SEL_ARG *pos=first(); pos ; pos=pos->next) { pos->increment_use_count(1); } use_count++; } void free_tree() { for (SEL_ARG *pos=first(); pos ; pos=pos->next) if (pos->next_key_part) { pos->next_key_part->use_count--; pos->next_key_part->free_tree(); } } inline SEL_ARG **parent_ptr() { return parent->left == this ? &parent->left : &parent->right; } /* Check if this SEL_ARG object represents a single-point interval SYNOPSIS is_singlepoint() DESCRIPTION Check if this SEL_ARG object (not tree) represents a single-point interval, i.e. if it represents a "keypart = const" or "keypart IS NULL". RETURN TRUE This SEL_ARG object represents a singlepoint interval FALSE Otherwise */ bool is_singlepoint() const { /* Check for NEAR_MIN ("strictly less") and NO_MIN_RANGE (-inf < field) flags, and the same for right edge. */ if (min_flag || max_flag) return FALSE; uchar *min_val= min_value; uchar *max_val= max_value; if (maybe_null) { /* First byte is a NULL value indicator */ if (*min_val != *max_val) return FALSE; if (*min_val) return TRUE; /* This "x IS NULL" */ min_val++; max_val++; } return !field->key_cmp(min_val, max_val); } SEL_ARG *clone_tree(RANGE_OPT_PARAM *param); }; extern MYSQL_PLUGIN_IMPORT SEL_ARG null_element; class SEL_ARG_IMPOSSIBLE: public SEL_ARG { public: SEL_ARG_IMPOSSIBLE(Field *field) :SEL_ARG(field, 0, 0) { type= SEL_ARG::IMPOSSIBLE; } }; class RANGE_OPT_PARAM { public: THD *thd; /* Current thread handle */ TABLE *table; /* Table being analyzed */ table_map prev_tables; table_map read_tables; table_map current_table; /* Bit of the table being analyzed */ /* Array of parts of all keys for which range analysis is performed */ KEY_PART *key_parts; KEY_PART *key_parts_end; MEM_ROOT *mem_root; /* Memory that will be freed when range analysis completes */ MEM_ROOT *old_root; /* Memory that will last until the query end */ /* Number of indexes used in range analysis (In SEL_TREE::keys only first #keys elements are not empty) */ uint keys; /* If true, the index descriptions describe real indexes (and it is ok to call field->optimize_range(real_keynr[...], ...). Otherwise index description describes fake indexes. */ bool using_real_indexes; /* Aggressively remove "scans" that do not have conditions on first keyparts. Such scans are usable when doing partition pruning but not regular range optimization. */ bool remove_jump_scans; /* TRUE <=> Range analyzer should remove parts of condition that are found to be always FALSE. */ bool remove_false_where_parts; /* Which functions should give SQL notes for unusable keys. */ Item_func::Bitmap note_unusable_keys; /* used_key_no -> table_key_no translation table. Only makes sense if using_real_indexes==TRUE */ uint real_keynr[MAX_KEY]; /* Used to store 'current key tuples', in both range analysis and partitioning (list) analysis */ uchar *min_key; uchar *max_key; /* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */ uint alloced_sel_args; bool force_default_mrr; KEY_PART *key[MAX_KEY]; /* First key parts of keys used in the query */ bool statement_should_be_aborted() const { return thd->killed || thd->is_error() || alloced_sel_args > thd->variables.optimizer_max_sel_args; } }; class Explain_quick_select; /* A "MIN_TUPLE < tbl.key_tuple < MAX_TUPLE" interval. One of endpoints may be absent. 'flags' member has flags which tell whether the endpoints are '<' or '<='. */ class QUICK_RANGE :public Sql_alloc { public: uchar *min_key,*max_key; uint16 min_length,max_length,flag; key_part_map min_keypart_map, // bitmap of used keyparts in min_key max_keypart_map; // bitmap of used keyparts in max_key #ifdef HAVE_valgrind uint16 dummy; /* Avoid warnings on 'flag' */ #endif QUICK_RANGE(); /* Full range */ QUICK_RANGE(THD *thd, const uchar *min_key_arg, uint min_length_arg, key_part_map min_keypart_map_arg, const uchar *max_key_arg, uint max_length_arg, key_part_map max_keypart_map_arg, uint flag_arg) : min_key((uchar*) thd->memdup(min_key_arg, min_length_arg + 1)), max_key((uchar*) thd->memdup(max_key_arg, max_length_arg + 1)), min_length((uint16) min_length_arg), max_length((uint16) max_length_arg), flag((uint16) flag_arg), min_keypart_map(min_keypart_map_arg), max_keypart_map(max_keypart_map_arg) { #ifdef HAVE_valgrind dummy=0; #endif } /** Initializes a key_range object for communication with storage engine. This function facilitates communication with the Storage Engine API by translating the minimum endpoint of the interval represented by this QUICK_RANGE into an index range endpoint specifier for the engine. @param Pointer to an uninitialized key_range C struct. @param prefix_length The length of the search key prefix to be used for lookup. @param keypart_map A set (bitmap) of keyparts to be used. */ void make_min_endpoint(key_range *kr, uint prefix_length, key_part_map keypart_map) { make_min_endpoint(kr); kr->length= MY_MIN(kr->length, prefix_length); kr->keypart_map&= keypart_map; } /** Initializes a key_range object for communication with storage engine. This function facilitates communication with the Storage Engine API by translating the minimum endpoint of the interval represented by this QUICK_RANGE into an index range endpoint specifier for the engine. @param Pointer to an uninitialized key_range C struct. */ void make_min_endpoint(key_range *kr) { kr->key= (const uchar*)min_key; kr->length= min_length; kr->keypart_map= min_keypart_map; kr->flag= ((flag & NEAR_MIN) ? HA_READ_AFTER_KEY : (flag & EQ_RANGE) ? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); } /** Initializes a key_range object for communication with storage engine. This function facilitates communication with the Storage Engine API by translating the maximum endpoint of the interval represented by this QUICK_RANGE into an index range endpoint specifier for the engine. @param Pointer to an uninitialized key_range C struct. @param prefix_length The length of the search key prefix to be used for lookup. @param keypart_map A set (bitmap) of keyparts to be used. */ void make_max_endpoint(key_range *kr, uint prefix_length, key_part_map keypart_map) { make_max_endpoint(kr); kr->length= MY_MIN(kr->length, prefix_length); kr->keypart_map&= keypart_map; } /** Initializes a key_range object for communication with storage engine. This function facilitates communication with the Storage Engine API by translating the maximum endpoint of the interval represented by this QUICK_RANGE into an index range endpoint specifier for the engine. @param Pointer to an uninitialized key_range C struct. */ void make_max_endpoint(key_range *kr) { kr->key= (const uchar*)max_key; kr->length= max_length; kr->keypart_map= max_keypart_map; /* We use READ_AFTER_KEY here because if we are reading on a key prefix we want to find all keys with this prefix */ kr->flag= (flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); } }; /* Quick select interface. This class is a parent for all QUICK_*_SELECT and FT_SELECT classes. The usage scenario is as follows: 1. Create quick select quick= new QUICK_XXX_SELECT(...); 2. Perform lightweight initialization. This can be done in 2 ways: 2.a: Regular initialization if (quick->init()) { //the only valid action after failed init() call is delete delete quick; } 2.b: Special initialization for quick selects merged by QUICK_ROR_*_SELECT if (quick->init_ror_merged_scan()) delete quick; 3. Perform zero, one, or more scans. while (...) { // initialize quick select for scan. This may allocate // buffers and/or prefetch rows. if (quick->reset()) { //the only valid action after failed reset() call is delete delete quick; //abort query } // perform the scan do { res= quick->get_next(); } while (res && ...) } 4. Delete the select: delete quick; NOTE quick select doesn't use Sql_alloc/MEM_ROOT allocation because "range checked for each record" functionality may create/destroy O(#records_in_some_table) quick selects during query execution. */ class QUICK_SELECT_I { public: ha_rows records; /* estimate of # of records to be retrieved */ double read_time; /* time to perform this retrieval */ TABLE *head; /* Index this quick select uses, or MAX_KEY for quick selects that use several indexes */ uint index; /* Total length of first used_key_parts parts of the key. Applicable if index!= MAX_KEY. */ uint max_used_key_length; /* Max. number of (first) key parts this quick select uses for retrieval. eg. for "(key1p1=c1 AND key1p2=c2) OR key1p1=c2" used_key_parts == 2. Applicable if index!= MAX_KEY. For QUICK_GROUP_MIN_MAX_SELECT it includes MIN/MAX argument keyparts. */ uint used_key_parts; QUICK_SELECT_I(); virtual ~QUICK_SELECT_I() = default;; /* Do post-constructor initialization. SYNOPSIS init() init() performs initializations that should have been in constructor if it was possible to return errors from constructors. The join optimizer may create and then delete quick selects without retrieving any rows so init() must not contain any IO or CPU intensive code. If init() call fails the only valid action is to delete this quick select, reset() and get_next() must not be called. RETURN 0 OK other Error code */ virtual int init() = 0; /* Initialize quick select for row retrieval. SYNOPSIS reset() reset() should be called when it is certain that row retrieval will be necessary. This call may do heavyweight initialization like buffering first N records etc. If reset() call fails get_next() must not be called. Note that reset() may be called several times if * the quick select is executed in a subselect * a JOIN buffer is used RETURN 0 OK other Error code */ virtual int reset(void) = 0; virtual int get_next() = 0; /* get next record to retrieve */ /* Range end should be called when we have looped over the whole index */ virtual void range_end() {} virtual bool reverse_sorted() = 0; virtual bool unique_key_range() { return false; } /* Request that this quick select produces sorted output. Not all quick selects can do it, the caller is responsible for calling this function only for those quick selects that can. */ virtual void need_sorted_output() = 0; enum { QS_TYPE_RANGE = 0, QS_TYPE_INDEX_INTERSECT = 1, QS_TYPE_INDEX_MERGE = 2, QS_TYPE_RANGE_DESC = 3, QS_TYPE_FULLTEXT = 4, QS_TYPE_ROR_INTERSECT = 5, QS_TYPE_ROR_UNION = 6, QS_TYPE_GROUP_MIN_MAX = 7 }; /* Get type of this quick select - one of the QS_TYPE_* values */ virtual int get_type() = 0; /* Initialize this quick select as a merged scan inside a ROR-union or a ROR- intersection scan. The caller must not additionally call init() if this function is called. SYNOPSIS init_ror_merged_scan() reuse_handler If true, the quick select may use table->handler, otherwise it must create and use a separate handler object. RETURN 0 Ok other Error */ virtual int init_ror_merged_scan(bool reuse_handler, MEM_ROOT *alloc) { DBUG_ASSERT(0); return 1; } /* Save ROWID of last retrieved row in file->ref. This used in ROR-merging. */ virtual void save_last_pos(){}; void add_key_and_length(String *key_names, String *used_lengths, bool *first); /* Append comma-separated list of keys this quick select uses to key_names; append comma-separated list of corresponding used lengths to used_lengths. This is used by select_describe. */ virtual void add_keys_and_lengths(String *key_names, String *used_lengths)=0; void add_key_name(String *str, bool *first); /* Save information about quick select's query plan */ virtual Explain_quick_select* get_explain(MEM_ROOT *alloc)= 0; /* Return 1 if any index used by this quick select uses field which is marked in passed bitmap. */ virtual bool is_keys_used(const MY_BITMAP *fields); /** Simple sanity check that the quick select has been set up correctly. Function is overridden by quick selects that merge indices. */ virtual bool is_valid() { return index != MAX_KEY; }; /* rowid of last row retrieved by this quick select. This is used only when doing ROR-index_merge selects */ uchar *last_rowid; /* Table record buffer used by this quick select. */ uchar *record; virtual void replace_handler(handler *new_file) { DBUG_ASSERT(0); /* Only supported in QUICK_RANGE_SELECT */ } #ifndef DBUG_OFF /* Print quick select information to DBUG_FILE. Caller is responsible for locking DBUG_FILE before this call and unlocking it afterwards. */ virtual void dbug_dump(int indent, bool verbose)= 0; #endif /* Returns a QUICK_SELECT with reverse order of to the index. */ virtual QUICK_SELECT_I *make_reverse(uint used_key_parts_arg) { return NULL; } /* Add the key columns used by the quick select into table's read set. This is used by an optimization in filesort. */ virtual void add_used_key_part_to_set()=0; }; struct st_qsel_param; class PARAM; /* MRR range sequence, array implementation: sequence traversal context. */ typedef struct st_quick_range_seq_ctx { QUICK_RANGE **first; QUICK_RANGE **cur; QUICK_RANGE **last; } QUICK_RANGE_SEQ_CTX; range_seq_t quick_range_seq_init(void *init_param, uint n_ranges, uint flags); bool quick_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range); /* Quick select that does a range scan on a single key. The records are returned in key order. */ class QUICK_RANGE_SELECT : public QUICK_SELECT_I { protected: THD *thd; bool no_alloc; MEM_ROOT *parent_alloc; /* true if we enabled key only reads */ handler *file; /* Members to deal with case when this quick select is a ROR-merged scan */ bool in_ror_merged_scan; MY_BITMAP column_bitmap; bool free_file; /* TRUE <=> this->file is "owned" by this quick select */ /* Range pointers to be used when not using MRR interface */ /* Members needed to use the MRR interface */ QUICK_RANGE_SEQ_CTX qr_traversal_ctx; public: uint mrr_flags; /* Flags to be used with MRR interface */ protected: uint mrr_buf_size; /* copy from thd->variables.mrr_buff_size */ HANDLER_BUFFER *mrr_buf_desc; /* the handler buffer */ /* Info about index we're scanning */ DYNAMIC_ARRAY ranges; /* ordered array of range ptrs */ QUICK_RANGE **cur_range; /* current element in ranges */ QUICK_RANGE *last_range; KEY_PART *key_parts; KEY_PART_INFO *key_part_info; bool dont_free; /* Used by QUICK_SELECT_DESC */ int cmp_next(QUICK_RANGE *range); int cmp_prev(QUICK_RANGE *range); bool row_in_ranges(); public: MEM_ROOT alloc; QUICK_RANGE_SELECT(THD *thd, TABLE *table,uint index_arg,bool no_alloc, MEM_ROOT *parent_alloc, bool *create_err); ~QUICK_RANGE_SELECT(); virtual QUICK_RANGE_SELECT *clone(bool *create_error) { return new QUICK_RANGE_SELECT(thd, head, index, no_alloc, parent_alloc, create_error); } void need_sorted_output() override; int init() override; int reset(void) override; int get_next() override; void range_end() override; int get_next_prefix(uint prefix_length, uint group_key_parts, uchar *cur_prefix); bool reverse_sorted() override { return 0; } bool unique_key_range() override; int init_ror_merged_scan(bool reuse_handler, MEM_ROOT *alloc) override; void save_last_pos() override { file->position(record); } int get_type() override { return QS_TYPE_RANGE; } void add_keys_and_lengths(String *key_names, String *used_lengths) override; Explain_quick_select *get_explain(MEM_ROOT *alloc) override; #ifndef DBUG_OFF void dbug_dump(int indent, bool verbose) override; #endif void replace_handler(handler *new_file) override { file= new_file; } QUICK_SELECT_I *make_reverse(uint used_key_parts_arg) override; void add_used_key_part_to_set() override; private: /* Default copy ctor used by QUICK_SELECT_DESC */ friend class TRP_ROR_INTERSECT; friend QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, struct st_table_ref *ref, ha_rows records); friend bool get_quick_keys(PARAM *param, QUICK_RANGE_SELECT *quick, KEY_PART *key, SEL_ARG *key_tree, uchar *min_key, uint min_key_flag, uchar *max_key, uint max_key_flag); friend QUICK_RANGE_SELECT *get_quick_select(PARAM*,uint idx, SEL_ARG *key_tree, uint mrr_flags, uint mrr_buf_size, MEM_ROOT *alloc); friend class QUICK_SELECT_DESC; friend class QUICK_INDEX_SORT_SELECT; friend class QUICK_INDEX_MERGE_SELECT; friend class QUICK_ROR_INTERSECT_SELECT; friend class QUICK_INDEX_INTERSECT_SELECT; friend class QUICK_GROUP_MIN_MAX_SELECT; friend bool quick_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range); friend range_seq_t quick_range_seq_init(void *init_param, uint n_ranges, uint flags); friend int read_keys_and_merge_scans(THD *thd, TABLE *head, List quick_selects, QUICK_RANGE_SELECT *pk_quick_select, READ_RECORD *read_record, bool intersection, key_map *filtered_scans, Unique **unique_ptr); }; class QUICK_RANGE_SELECT_GEOM: public QUICK_RANGE_SELECT { public: QUICK_RANGE_SELECT_GEOM(THD *thd, TABLE *table, uint index_arg, bool no_alloc, MEM_ROOT *parent_alloc, bool *create_err) :QUICK_RANGE_SELECT(thd, table, index_arg, no_alloc, parent_alloc, create_err) {}; QUICK_RANGE_SELECT *clone(bool *create_error) override { DBUG_ASSERT(0); return new QUICK_RANGE_SELECT_GEOM(thd, head, index, no_alloc, parent_alloc, create_error); } int get_next() override; }; /* QUICK_INDEX_SORT_SELECT is the base class for the common functionality of: - QUICK_INDEX_MERGE_SELECT, access based on multi-index merge/union - QUICK_INDEX_INTERSECT_SELECT, access based on multi-index intersection QUICK_INDEX_SORT_SELECT uses * QUICK_RANGE_SELECTs to get rows * Unique class - to remove duplicate rows for QUICK_INDEX_MERGE_SELECT - to intersect rows for QUICK_INDEX_INTERSECT_SELECT INDEX MERGE OPTIMIZER Current implementation doesn't detect all cases where index merge could be used, in particular: * index_merge+'using index' is not supported * If WHERE part contains complex nested AND and OR conditions, some ways to retrieve rows using index merge will not be considered. The choice of read plan may depend on the order of conjuncts/disjuncts in WHERE part of the query, see comments near imerge_list_or_list and SEL_IMERGE::or_sel_tree_with_checks functions for details. * There is no "index_merge_ref" method (but index merge on non-first table in join is possible with 'range checked for each record'). ROW RETRIEVAL ALGORITHM index merge/intersection uses Unique class for duplicates removal. index merge/intersection takes advantage of Clustered Primary Key (CPK) if the table has one. The index merge/intersection algorithm consists of two phases: Phase 1 (implemented by a QUICK_INDEX_MERGE_SELECT::read_keys_and_merge call): prepare() { activate 'index only'; while(retrieve next row for non-CPK scan) { if (there is a CPK scan and row will be retrieved by it) skip this row; else put its rowid into Unique; } deactivate 'index only'; } Phase 2 (implemented as sequence of QUICK_INDEX_MERGE_SELECT::get_next calls): fetch() { retrieve all rows from row pointers stored in Unique (merging/intersecting them); free Unique; if (! intersection) retrieve all rows for CPK scan; } */ class QUICK_INDEX_SORT_SELECT : public QUICK_SELECT_I { protected: Unique *unique; public: QUICK_INDEX_SORT_SELECT(THD *thd, TABLE *table); ~QUICK_INDEX_SORT_SELECT(); int init() override; void need_sorted_output() override { DBUG_ASSERT(0); /* Can't do it */ } int reset(void) override; bool reverse_sorted() override { return false; } bool unique_key_range() override { return false; } bool is_keys_used(const MY_BITMAP *fields) override; #ifndef DBUG_OFF void dbug_dump(int indent, bool verbose) override; #endif Explain_quick_select *get_explain(MEM_ROOT *alloc) override; bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range); /* range quick selects this index merge/intersect consists of */ List quick_selects; /* quick select that uses clustered primary key (NULL if none) */ QUICK_RANGE_SELECT* pk_quick_select; MEM_ROOT alloc; THD *thd; bool is_valid() override { List_iterator_fast it(quick_selects); QUICK_RANGE_SELECT *quick; bool valid= true; while ((quick= it++)) { if (!quick->is_valid()) { valid= false; break; } } return valid; } virtual int read_keys_and_merge()= 0; /* used to get rows collected in Unique */ READ_RECORD read_record; void add_used_key_part_to_set() override; }; class QUICK_INDEX_MERGE_SELECT : public QUICK_INDEX_SORT_SELECT { private: /* true if this select is currently doing a clustered PK scan */ bool doing_pk_scan; protected: int read_keys_and_merge() override; public: QUICK_INDEX_MERGE_SELECT(THD *thd_arg, TABLE *table) :QUICK_INDEX_SORT_SELECT(thd_arg, table) {} int get_next() override; int get_type() override { return QS_TYPE_INDEX_MERGE; } void add_keys_and_lengths(String *key_names, String *used_lengths) override; }; class QUICK_INDEX_INTERSECT_SELECT : public QUICK_INDEX_SORT_SELECT { protected: int read_keys_and_merge() override; public: QUICK_INDEX_INTERSECT_SELECT(THD *thd_arg, TABLE *table) :QUICK_INDEX_SORT_SELECT(thd_arg, table) {} key_map filtered_scans; int get_next() override; int get_type() override { return QS_TYPE_INDEX_INTERSECT; } void add_keys_and_lengths(String *key_names, String *used_lengths) override; Explain_quick_select *get_explain(MEM_ROOT *alloc) override; }; /* Rowid-Ordered Retrieval (ROR) index intersection quick select. This quick select produces intersection of row sequences returned by several QUICK_RANGE_SELECTs it "merges". All merged QUICK_RANGE_SELECTs must return rowids in rowid order. QUICK_ROR_INTERSECT_SELECT will return rows in rowid order, too. All merged quick selects retrieve {rowid, covered_fields} tuples (not full table records). QUICK_ROR_INTERSECT_SELECT retrieves full records if it is not being used by QUICK_ROR_INTERSECT_SELECT and all merged quick selects together don't cover needed all fields. If one of the merged quick selects is a Clustered PK range scan, it is used only to filter rowid sequence produced by other merged quick selects. */ class QUICK_ROR_INTERSECT_SELECT : public QUICK_SELECT_I { public: QUICK_ROR_INTERSECT_SELECT(THD *thd, TABLE *table, bool retrieve_full_rows, MEM_ROOT *parent_alloc); ~QUICK_ROR_INTERSECT_SELECT(); int init() override; void need_sorted_output() override { DBUG_ASSERT(0); /* Can't do it */ } int reset(void) override; int get_next() override; bool reverse_sorted() override { return false; } bool unique_key_range() override { return false; } int get_type() override { return QS_TYPE_ROR_INTERSECT; } void add_keys_and_lengths(String *key_names, String *used_lengths) override; Explain_quick_select *get_explain(MEM_ROOT *alloc) override; bool is_keys_used(const MY_BITMAP *fields) override; void add_used_key_part_to_set() override; #ifndef DBUG_OFF void dbug_dump(int indent, bool verbose) override; #endif int init_ror_merged_scan(bool reuse_handler, MEM_ROOT *alloc) override; bool push_quick_back(MEM_ROOT *alloc, QUICK_RANGE_SELECT *quick_sel_range); class QUICK_SELECT_WITH_RECORD : public Sql_alloc { public: QUICK_RANGE_SELECT *quick; uchar *key_tuple; ~QUICK_SELECT_WITH_RECORD() { delete quick; } }; /* Range quick selects this intersection consists of, not including cpk_quick. */ List quick_selects; bool is_valid() override { List_iterator_fast it(quick_selects); QUICK_SELECT_WITH_RECORD *quick; bool valid= true; while ((quick= it++)) { if (!quick->quick->is_valid()) { valid= false; break; } } return valid; } /* Merged quick select that uses Clustered PK, if there is one. This quick select is not used for row retrieval, it is used for row retrieval. */ QUICK_RANGE_SELECT *cpk_quick; MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */ THD *thd; /* current thread */ bool need_to_fetch_row; /* if true, do retrieve full table records. */ /* in top-level quick select, true if merged scans where initialized */ bool scans_inited; }; /* Rowid-Ordered Retrieval index union select. This quick select produces union of row sequences returned by several quick select it "merges". All merged quick selects must return rowids in rowid order. QUICK_ROR_UNION_SELECT will return rows in rowid order, too. All merged quick selects are set not to retrieve full table records. ROR-union quick select always retrieves full records. */ class QUICK_ROR_UNION_SELECT : public QUICK_SELECT_I { public: QUICK_ROR_UNION_SELECT(THD *thd, TABLE *table); ~QUICK_ROR_UNION_SELECT(); int init() override; void need_sorted_output() override { DBUG_ASSERT(0); /* Can't do it */ } int reset(void) override; int get_next() override; bool reverse_sorted() override { return false; } bool unique_key_range() override { return false; } int get_type() override { return QS_TYPE_ROR_UNION; } void add_keys_and_lengths(String *key_names, String *used_lengths) override; Explain_quick_select *get_explain(MEM_ROOT *alloc) override; bool is_keys_used(const MY_BITMAP *fields) override; void add_used_key_part_to_set() override; #ifndef DBUG_OFF void dbug_dump(int indent, bool verbose) override; #endif bool push_quick_back(QUICK_SELECT_I *quick_sel_range); List quick_selects; /* Merged quick selects */ bool is_valid() override { List_iterator_fast it(quick_selects); QUICK_SELECT_I *quick; bool valid= true; while ((quick= it++)) { if (!quick->is_valid()) { valid= false; break; } } return valid; } QUEUE queue; /* Priority queue for merge operation */ MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */ THD *thd; /* current thread */ uchar *cur_rowid; /* buffer used in get_next() */ uchar *prev_rowid; /* rowid of last row returned by get_next() */ bool have_prev_rowid; /* true if prev_rowid has valid data */ uint rowid_length; /* table rowid length */ private: bool scans_inited; }; /* Index scan for GROUP-BY queries with MIN/MAX aggregate functions. This class provides a specialized index access method for GROUP-BY queries of the forms: SELECT A_1,...,A_k, [B_1,...,B_m], [MIN(C)], [MAX(C)] FROM T WHERE [RNG(A_1,...,A_p ; where p <= k)] [AND EQ(B_1,...,B_m)] [AND PC(C)] [AND PA(A_i1,...,A_iq)] GROUP BY A_1,...,A_k; or SELECT DISTINCT A_i1,...,A_ik FROM T WHERE [RNG(A_1,...,A_p ; where p <= k)] [AND PA(A_i1,...,A_iq)]; where all selected fields are parts of the same index. The class of queries that can be processed by this quick select is fully specified in the description of get_best_trp_group_min_max() in opt_range.cc. The get_next() method directly produces result tuples, thus obviating the need to call end_send_group() because all grouping is already done inside get_next(). Since one of the requirements is that all select fields are part of the same index, this class produces only index keys, and not complete records. */ class QUICK_GROUP_MIN_MAX_SELECT : public QUICK_SELECT_I { private: handler * const file; /* The handler used to get data. */ JOIN *join; /* Descriptor of the current query */ KEY *index_info; /* The index chosen for data access */ uchar *record; /* Buffer where the next record is returned. */ uchar *tmp_record; /* Temporary storage for next_min(), next_max(). */ uchar *group_prefix; /* Key prefix consisting of the GROUP fields. */ const uint group_prefix_len; /* Length of the group prefix. */ uint group_key_parts; /* A number of keyparts in the group prefix */ bool have_min; /* Specify whether we are computing */ bool have_max; /* a MIN, a MAX, or both. */ bool have_agg_distinct;/* aggregate_function(DISTINCT ...). */ bool seen_first_key; /* Denotes whether the first key was retrieved.*/ bool doing_key_read; /* true if we enabled key only reads */ KEY_PART_INFO *min_max_arg_part; /* The keypart of the only argument field */ /* of all MIN/MAX functions. */ uint min_max_arg_len; /* The length of the MIN/MAX argument field */ uchar *key_infix; /* Infix of constants from equality predicates. */ uint key_infix_len; DYNAMIC_ARRAY min_max_ranges; /* Array of range ptrs for the MIN/MAX field. */ uint real_prefix_len; /* Length of key prefix extended with key_infix. */ uint real_key_parts; /* A number of keyparts in the above value. */ List *min_functions; List *max_functions; List_iterator *min_functions_it; List_iterator *max_functions_it; /* Use index scan to get the next different key instead of jumping into it through index read */ bool is_index_scan; public: /* The following two members are public to allow easy access from TRP_GROUP_MIN_MAX::make_quick() */ MEM_ROOT alloc; /* Memory pool for this and quick_prefix_select data. */ QUICK_RANGE_SELECT *quick_prefix_select;/* For retrieval of group prefixes. */ private: int next_prefix(); int next_min_in_range(); int next_max_in_range(); int next_min(); int next_max(); void update_min_result(); void update_max_result(); int cmp_min_max_key(const uchar *key, uint16 length); public: QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min, bool have_max, bool have_agg_distinct, KEY_PART_INFO *min_max_arg_part, uint group_prefix_len, uint group_key_parts, uint used_key_parts, KEY *index_info, uint use_index, double read_cost, ha_rows records, uint key_infix_len, uchar *key_infix, MEM_ROOT *parent_alloc, bool is_index_scan); ~QUICK_GROUP_MIN_MAX_SELECT(); bool add_range(SEL_ARG *sel_range); void update_key_stat(); void adjust_prefix_ranges(); bool alloc_buffers(); int init() override; void need_sorted_output() override { /* always do it */ } int reset() override; int get_next() override; bool reverse_sorted() override { return false; } bool unique_key_range() override { return false; } int get_type() override { return QS_TYPE_GROUP_MIN_MAX; } void add_keys_and_lengths(String *key_names, String *used_lengths) override; void add_used_key_part_to_set() override; #ifndef DBUG_OFF void dbug_dump(int indent, bool verbose) override; #endif bool is_agg_distinct() { return have_agg_distinct; } bool loose_scan_is_scanning() { return is_index_scan; } Explain_quick_select *get_explain(MEM_ROOT *alloc) override; }; class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT { public: QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q, uint used_key_parts); QUICK_RANGE_SELECT *clone(bool *create_error) override { DBUG_ASSERT(0); return new QUICK_SELECT_DESC(this, used_key_parts); } int get_next() override; bool reverse_sorted() override { return 1; } int get_type() override { return QS_TYPE_RANGE_DESC; } QUICK_SELECT_I *make_reverse(uint used_key_parts_arg) override { return this; // is already reverse sorted } private: bool range_reads_after_key(QUICK_RANGE *range); int reset(void) override { rev_it.rewind(); return QUICK_RANGE_SELECT::reset(); } List rev_ranges; List_iterator rev_it; uint used_key_parts; }; class SQL_SELECT :public Sql_alloc { public: QUICK_SELECT_I *quick; // If quick-select used COND *cond; // where condition /* When using Index Condition Pushdown: condition that we've had before extracting and pushing index condition. In other cases, NULL. */ Item *pre_idx_push_select_cond; TABLE *head; IO_CACHE file; // Positions to used records ha_rows records; // Records in use if read from file double read_time; // Time to read rows key_map quick_keys; // Possible quick keys key_map needed_reg; // Possible quick keys after prev tables. table_map const_tables,read_tables; /* See PARAM::possible_keys */ key_map possible_keys; bool free_cond; /* Currently not used and always FALSE */ SQL_SELECT(); ~SQL_SELECT(); void cleanup(); void set_quick(QUICK_SELECT_I *new_quick) { delete quick; quick= new_quick; } /* @return true - for ERROR and IMPOSSIBLE_RANGE false - Ok */ bool check_quick(THD *thd, bool force_quick_range, ha_rows limit, Item_func::Bitmap note_unusable_keys) { key_map tmp; tmp.set_all(); return test_quick_select(thd, tmp, 0, limit, force_quick_range, FALSE, FALSE, FALSE, note_unusable_keys) != OK; } /* RETURN 0 if record must be skipped <-> (cond && cond->val_bool() == false) -1 if error 1 otherwise */ inline int skip_record(THD *thd) { int rc= MY_TEST(!cond || cond->val_bool()); if (thd->is_error()) rc= -1; return rc; } enum quick_select_return_type { IMPOSSIBLE_RANGE = -1, ERROR, OK }; enum quick_select_return_type test_quick_select(THD *thd, key_map keys, table_map prev_tables, ha_rows limit, bool force_quick_range, bool ordered_output, bool remove_false_parts_of_where, bool only_single_index_range_scan, Item_func::Bitmap note_unusable_keys); }; typedef enum SQL_SELECT::quick_select_return_type quick_select_return; class SQL_SELECT_auto { SQL_SELECT *select; public: SQL_SELECT_auto(): select(NULL) {} ~SQL_SELECT_auto() { delete select; } SQL_SELECT_auto& operator= (SQL_SELECT *_select) { select= _select; return *this; } operator SQL_SELECT * () const { return select; } SQL_SELECT * operator-> () const { return select; } operator bool () const { return select; } }; class FT_SELECT: public QUICK_RANGE_SELECT { public: FT_SELECT(THD *thd, TABLE *table, uint key, bool *create_err) : QUICK_RANGE_SELECT (thd, table, key, 1, NULL, create_err) { (void) init(); } ~FT_SELECT() { file->ft_end(); } QUICK_RANGE_SELECT *clone(bool *create_error) override { DBUG_ASSERT(0); return new FT_SELECT(thd, head, index, create_error); } int init() override { return file->ft_init(); } int reset() override { return 0; } int get_next() override { return file->ha_ft_read(record); } int get_type() override { return QS_TYPE_FULLTEXT; } }; FT_SELECT *get_ft_select(THD *thd, TABLE *table, uint key); QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, struct st_table_ref *ref, ha_rows records); SQL_SELECT *make_select(TABLE *head, table_map const_tables, table_map read_tables, COND *conds, SORT_INFO* filesort, bool allow_null_cond, int *error); bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond); bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param, uint limit); #ifdef WITH_PARTITION_STORAGE_ENGINE bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond); #endif void store_key_image_to_rec(Field *field, uchar *ptr, uint len); extern String null_string; /* check this number of rows (default value) */ #define SELECTIVITY_SAMPLING_LIMIT 100 /* but no more then this part of table (10%) */ #define SELECTIVITY_SAMPLING_SHARE 0.10 /* do not check if we are going check less then this number of records */ #define SELECTIVITY_SAMPLING_THRESHOLD 10 #endif server/private/my_bitmap.h000064400000013372151031265040011661 0ustar00/* Copyright (c) 2001, 2011, Oracle and/or its affiliates. Copyright (c) 2009, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_bitmap_h_ #define _my_bitmap_h_ #define MY_BIT_NONE (~(uint) 0) #include #include typedef ulonglong my_bitmap_map; typedef struct st_bitmap { my_bitmap_map *bitmap; my_bitmap_map *last_word_ptr; /* mutex will be acquired for the duration of each bitmap operation if thread_safe flag in bitmap_init was set. Otherwise, we optimize by not acquiring the mutex */ mysql_mutex_t *mutex; my_bitmap_map last_bit_mask; uint32 n_bits; /* number of bits occupied by the above */ my_bool bitmap_allocated; } MY_BITMAP; #ifdef __cplusplus extern "C" { #endif /* Reset memory. Faster then doing a full bzero */ #define my_bitmap_clear(A) ((A)->bitmap= 0) extern void create_last_bit_mask(MY_BITMAP *map); extern my_bool my_bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits, my_bool thread_safe); extern my_bool bitmap_is_clear_all(const MY_BITMAP *map); extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size); extern my_bool bitmap_is_set_all(const MY_BITMAP *map); extern my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2); extern my_bool bitmap_is_overlapping(const MY_BITMAP *map1, const MY_BITMAP *map2); extern my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit); extern my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit); extern my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit); extern my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit); extern my_bool bitmap_union_is_set_all(const MY_BITMAP *map1, const MY_BITMAP *map2); extern my_bool bitmap_exists_intersection(MY_BITMAP **bitmap_array, uint bitmap_count, uint start_bit, uint end_bit); extern uint bitmap_set_next(MY_BITMAP *map); extern uint bitmap_get_first_clear(const MY_BITMAP *map); extern uint bitmap_get_first_set(const MY_BITMAP *map); extern uint bitmap_bits_set(const MY_BITMAP *map); extern uint bitmap_get_next_set(const MY_BITMAP *map, uint bitmap_bit); extern void my_bitmap_free(MY_BITMAP *map); extern void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit); extern void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size); extern void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2); extern void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2); extern void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2); extern void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2); extern void bitmap_invert(MY_BITMAP *map); extern void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2); /* Functions to export/import bitmaps to an architecture independent format */ extern void bitmap_export(uchar *to, MY_BITMAP *map); extern void bitmap_import(MY_BITMAP *map, uchar *from); extern uint bitmap_lock_set_next(MY_BITMAP *map); extern void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit); #define my_bitmap_map_bytes sizeof(my_bitmap_map) #define my_bitmap_map_bits (my_bitmap_map_bytes*8) /* Size in bytes to store 'bits' number of bits */ #define bitmap_buffer_size(bits) (MY_ALIGN((bits), my_bitmap_map_bits)/8) #define my_bitmap_buffer_size(map) bitmap_buffer_size((map)->n_bits) #define no_bytes_in_export_map(map) (((map)->n_bits + 7)/8) #define no_words_in_map(map) (((map)->n_bits + (my_bitmap_map_bits-1))/my_bitmap_map_bits) /* Fast, not thread safe, bitmap functions */ /* The following functions must be compatible with create_last_bit_mask()! */ static inline void bitmap_set_bit(MY_BITMAP *map,uint bit) { DBUG_ASSERT(bit < map->n_bits); map->bitmap[bit/my_bitmap_map_bits]|= (1ULL << (bit & (my_bitmap_map_bits-1))); } static inline void bitmap_flip_bit(MY_BITMAP *map,uint bit) { DBUG_ASSERT(bit < map->n_bits); map->bitmap[bit/my_bitmap_map_bits]^= (1ULL << (bit & (my_bitmap_map_bits-1))); } static inline void bitmap_clear_bit(MY_BITMAP *map,uint bit) { DBUG_ASSERT(bit < map->n_bits); map->bitmap[bit/my_bitmap_map_bits]&= ~(1ULL << (bit & (my_bitmap_map_bits-1))); } static inline uint bitmap_is_set(const MY_BITMAP *map,uint bit) { DBUG_ASSERT(bit < map->n_bits); return (!!(map->bitmap[bit/my_bitmap_map_bits] & (1ULL << (bit & (my_bitmap_map_bits-1))))); } /* Return true if bitmaps are equal */ static inline my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2) { DBUG_ASSERT(map1->n_bits == map2->n_bits); return (memcmp(map1->bitmap, map2->bitmap, my_bitmap_buffer_size(map1)) == 0); } #define bitmap_clear_all(MAP) \ { memset((MAP)->bitmap, 0, my_bitmap_buffer_size(MAP)); } static inline void bitmap_set_all(const MY_BITMAP *map) { if (map->n_bits) { memset(map->bitmap, 0xFF, my_bitmap_map_bytes * (no_words_in_map(map)-1)); DBUG_ASSERT(map->bitmap + no_words_in_map(map)-1 == map->last_word_ptr); *map->last_word_ptr= ~map->last_bit_mask; } } #ifdef __cplusplus } #endif #endif /* _my_bitmap_h_ */ server/private/ha_partition.h000064400000175541151031265040012370 0ustar00#ifndef HA_PARTITION_INCLUDED #define HA_PARTITION_INCLUDED /* Copyright (c) 2005, 2012, Oracle and/or its affiliates. Copyright (c) 2009, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "sql_partition.h" /* part_id_range, partition_element */ #include "queues.h" /* QUEUE */ struct Ordered_blob_storage { String blob; bool set_read_value; Ordered_blob_storage() : set_read_value(false) {} }; #define PAR_EXT ".par" #define PARTITION_BYTES_IN_POS 2 #define ORDERED_PART_NUM_OFFSET sizeof(Ordered_blob_storage **) #define ORDERED_REC_OFFSET (ORDERED_PART_NUM_OFFSET + PARTITION_BYTES_IN_POS) /** Struct used for partition_name_hash */ typedef struct st_part_name_def { uchar *partition_name; uint length; uint32 part_id; my_bool is_subpart; } PART_NAME_DEF; /** class where to save partitions Handler_share's */ class Parts_share_refs { public: uint num_parts; /**< Size of ha_share array */ Handler_share **ha_shares; /**< Storage for each part */ Parts_share_refs() { num_parts= 0; ha_shares= NULL; } ~Parts_share_refs() { uint i; for (i= 0; i < num_parts; i++) delete ha_shares[i]; delete[] ha_shares; } bool init(uint arg_num_parts) { DBUG_ASSERT(!num_parts && !ha_shares); num_parts= arg_num_parts; /* Allocate an array of Handler_share pointers */ ha_shares= new Handler_share *[num_parts]; if (!ha_shares) { num_parts= 0; return true; } memset(ha_shares, 0, sizeof(Handler_share*) * num_parts); return false; } }; class ha_partition; /* Partition Full Text Search info */ struct st_partition_ft_info { struct _ft_vft *please; st_partition_ft_info *next; ha_partition *file; FT_INFO **part_ft_info; }; #ifdef HAVE_PSI_MUTEX_INTERFACE extern PSI_mutex_key key_partition_auto_inc_mutex; #endif /** Partition specific Handler_share. */ class Partition_share : public Handler_share { public: bool auto_inc_initialized; mysql_mutex_t auto_inc_mutex; /**< protecting auto_inc val */ ulonglong next_auto_inc_val; /**< first non reserved value */ /** Hash of partition names. Initialized in the first ha_partition::open() for the table_share. After that it is read-only, i.e. no locking required. */ bool partition_name_hash_initialized; HASH partition_name_hash; const char *partition_engine_name; /** Storage for each partitions Handler_share */ Parts_share_refs partitions_share_refs; Partition_share() : auto_inc_initialized(false), next_auto_inc_val(0), partition_name_hash_initialized(false), partition_engine_name(NULL), partition_names(NULL) { mysql_mutex_init(key_partition_auto_inc_mutex, &auto_inc_mutex, MY_MUTEX_INIT_FAST); } ~Partition_share() { mysql_mutex_destroy(&auto_inc_mutex); if (partition_names) { my_free(partition_names); } if (partition_name_hash_initialized) { my_hash_free(&partition_name_hash); } } bool init(uint num_parts); /** Release reserved auto increment values not used. @param thd Thread. @param table_share Table Share @param next_insert_id Next insert id (first non used auto inc value). @param max_reserved End of reserved auto inc range. */ void release_auto_inc_if_possible(THD *thd, TABLE_SHARE *table_share, const ulonglong next_insert_id, const ulonglong max_reserved); /** lock mutex protecting auto increment value next_auto_inc_val. */ inline void lock_auto_inc() { mysql_mutex_lock(&auto_inc_mutex); } /** unlock mutex protecting auto increment value next_auto_inc_val. */ inline void unlock_auto_inc() { mysql_mutex_unlock(&auto_inc_mutex); } /** Populate partition_name_hash with partition and subpartition names from part_info. @param part_info Partition info containing all partitions metadata. @return Operation status. @retval false Success. @retval true Failure. */ bool populate_partition_name_hash(partition_info *part_info); /** Get partition name. @param part_id Partition id (for subpartitioned table only subpartition names will be returned.) @return partition name or NULL if error. */ const char *get_partition_name(size_t part_id) const; private: const uchar **partition_names; /** Insert [sub]partition name into partition_name_hash @param name Partition name. @param part_id Partition id. @param is_subpart True if subpartition else partition. @return Operation status. @retval false Success. @retval true Failure. */ bool insert_partition_name_in_hash(const char *name, uint part_id, bool is_subpart); }; /* List of ranges to be scanned by ha_partition's MRR implementation This object is - A KEY_MULTI_RANGE structure (the MRR range) - Storage for the range endpoints that the KEY_MULTI_RANGE has pointers to - list of such ranges (connected through the "next" pointer). */ typedef struct st_partition_key_multi_range { /* Number of the range. The ranges are numbered in the order RANGE_SEQ_IF has emitted them, starting from 1. The numbering in used by ordered MRR scans. */ uint id; uchar *key[2]; /* Sizes of allocated memory in key[]. These may be larger then the actual values as this structure is reused across MRR scans */ uint length[2]; /* The range. key_multi_range.ptr is a pointer to the this PARTITION_KEY_MULTI_RANGE object */ KEY_MULTI_RANGE key_multi_range; // Range id from the SQL layer range_id_t ptr; // The next element in the list of MRR ranges. st_partition_key_multi_range *next; } PARTITION_KEY_MULTI_RANGE; /* List of ranges to be scanned in a certain [sub]partition The idea is that there's a list of ranges to be scanned in the table (formed by PARTITION_KEY_MULTI_RANGE structures), and for each [sub]partition, we only need to scan a subset of that list. PKMR1 --> PKMR2 --> PKMR3 -->... // list of PARTITION_KEY_MULTI_RANGE ^ ^ | | PPKMR1 ----------> PPKMR2 -->... // list of PARTITION_PART_KEY_MULTI_RANGE This way, per-partition lists of PARTITION_PART_KEY_MULTI_RANGE have pointers to the elements of the global list of PARTITION_KEY_MULTI_RANGE. */ typedef struct st_partition_part_key_multi_range { PARTITION_KEY_MULTI_RANGE *partition_key_multi_range; st_partition_part_key_multi_range *next; } PARTITION_PART_KEY_MULTI_RANGE; class ha_partition; /* The structure holding information about range sequence to be used with one partition. (pointer to this is used as seq_init_param for RANGE_SEQ_IF structure when invoking MRR for an individual partition) */ typedef struct st_partition_part_key_multi_range_hld { /* Owner object */ ha_partition *partition; /* id of the the partition this structure is for */ uint32 part_id; /* Current range we're iterating through */ PARTITION_PART_KEY_MULTI_RANGE *partition_part_key_multi_range; } PARTITION_PART_KEY_MULTI_RANGE_HLD; extern "C" int cmp_key_part_id(void *key_p, const void *ref1, const void *ref2); extern "C" int cmp_key_rowid_part_id(void *ptr, const void *ref1, const void *ref2); class ha_partition final :public handler { private: enum partition_index_scan_type { partition_index_read= 0, partition_index_first= 1, partition_index_last= 3, partition_index_read_last= 4, partition_read_range = 5, partition_no_index_scan= 6, partition_read_multi_range = 7, partition_ft_read= 8 }; /* Data for the partition handler */ int m_mode; // Open mode uint m_open_test_lock; // Open test_if_locked uchar *m_file_buffer; // Content of the .par file char *m_name_buffer_ptr; // Pointer to first partition name MEM_ROOT m_mem_root; plugin_ref *m_engine_array; // Array of types of the handlers handler **m_file; // Array of references to handler inst. uint m_file_tot_parts; // Debug handler **m_new_file; // Array of references to new handlers handler **m_reorged_file; // Reorganised partitions handler **m_added_file; // Added parts kept for errors LEX_CSTRING *m_connect_string; partition_info *m_part_info; // local reference to partition Field **m_part_field_array; // Part field array locally to save acc uchar *m_ordered_rec_buffer; // Row and key buffer for ord. idx scan st_partition_ft_info *ft_first; st_partition_ft_info *ft_current; /* Current index. When used in key_rec_cmp: If clustered pk, index compare must compare pk if given index is same for two rows. So normally m_curr_key_info[0]= current index and m_curr_key[1]= NULL, and if clustered pk, [0]= current index, [1]= pk, [2]= NULL */ KEY *m_curr_key_info[3]; // Current index const uchar *m_err_rec; // record which gave error QUEUE m_queue; // Prio queue used by sorted read /* Length of an element in m_ordered_rec_buffer. The elements are composed of [part_no] [table->record copy] [underlying_table_rowid] underlying_table_rowid is only stored when the table has no extended keys. */ size_t m_priority_queue_rec_len; /* If true, then sorting records by key value also sorts them by their underlying_table_rowid. */ bool m_using_extended_keys; /* Since the partition handler is a handler on top of other handlers, it is necessary to keep information about what the underlying handler characteristics is. It is not possible to keep any handler instances for this since the MySQL Server sometimes allocating the handler object without freeing them. */ enum enum_handler_status { handler_not_initialized= 0, handler_initialized, handler_opened, handler_closed }; enum_handler_status m_handler_status; uint m_reorged_parts; // Number of reorganised parts uint m_tot_parts; // Total number of partitions; uint m_num_locks; // For engines like ha_blackhole, which needs no locks uint m_last_part; // Last file that we update,write,read part_id_range m_part_spec; // Which parts to scan uint m_scan_value; // Value passed in rnd_init // call uint m_ref_length; // Length of position in this // handler object key_range m_start_key; // index read key range enum partition_index_scan_type m_index_scan_type;// What type of index // scan uint m_top_entry; // Which partition is to // deliver next result uint m_rec_length; // Local copy of record length bool m_ordered; // Ordered/Unordered index scan bool m_create_handler; // Handler used to create table bool m_is_sub_partitioned; // Is subpartitioned bool m_ordered_scan_ongoing; bool m_rnd_init_and_first; bool m_ft_init_and_first; /* If set, this object was created with ha_partition::clone and doesn't "own" the m_part_info structure. */ ha_partition *m_is_clone_of; MEM_ROOT *m_clone_mem_root; /* We keep track if all underlying handlers are MyISAM since MyISAM has a great number of extra flags not needed by other handlers. */ bool m_myisam; // Are all underlying handlers // MyISAM /* We keep track of InnoDB handlers below since it requires proper setting of query_id in fields at index_init and index_read calls. */ bool m_innodb; // Are all underlying handlers // InnoDB bool m_myisammrg; // Are any of the handlers of type MERGE /* When calling extra(HA_EXTRA_CACHE) we do not pass this to the underlying handlers immediately. Instead we cache it and call the underlying immediately before starting the scan on the partition. This is to prevent allocating a READ CACHE for each partition in parallel when performing a full table scan on MyISAM partitioned table. This state is cleared by extra(HA_EXTRA_NO_CACHE). */ bool m_extra_cache; uint m_extra_cache_size; /* The same goes for HA_EXTRA_PREPARE_FOR_UPDATE */ bool m_extra_prepare_for_update; /* Which partition has active cache */ uint m_extra_cache_part_id; void init_handler_variables(); /* Variables for lock structures. */ bool auto_increment_lock; /**< lock reading/updating auto_inc */ /** Flag to keep the auto_increment lock through out the statement. This to ensure it will work with statement based replication. */ bool auto_increment_safe_stmt_log_lock; /** For optimizing ha_start_bulk_insert calls */ MY_BITMAP m_bulk_insert_started; ha_rows m_bulk_inserted_rows; /** used for prediction of start_bulk_insert rows */ enum_monotonicity_info m_part_func_monotonicity_info; part_id_range m_direct_update_part_spec; bool m_pre_calling; bool m_pre_call_use_parallel; /* Keep track of bulk access requests */ bool bulk_access_executing; /** keep track of locked partitions */ MY_BITMAP m_locked_partitions; /** Stores shared auto_increment etc. */ Partition_share *part_share; void sum_copy_info(handler *file); void sum_copy_infos(); void reset_copy_info() override; /** Temporary storage for new partitions Handler_shares during ALTER */ List m_new_partitions_share_refs; /** Sorted array of partition ids in descending order of number of rows. */ uint32 *m_part_ids_sorted_by_num_of_records; /* Compare function for my_qsort2, for reversed order. */ static int compare_number_of_records(void *me, const void *a, const void *b); /** keep track of partitions to call ha_reset */ MY_BITMAP m_partitions_to_reset; /** partitions that returned HA_ERR_KEY_NOT_FOUND. */ MY_BITMAP m_key_not_found_partitions; bool m_key_not_found; List *m_partitions_to_open; MY_BITMAP m_opened_partitions; /** This is one of the m_file-s that it guaranteed to be opened. */ /** It is set in open_read_partitions() */ handler *m_file_sample; public: handler **get_child_handlers() { return m_file; } ha_partition *get_clone_source() { return m_is_clone_of; } virtual part_id_range *get_part_spec() { return &m_part_spec; } virtual uint get_no_current_part_id() { return NO_CURRENT_PART_ID; } Partition_share *get_part_share() { return part_share; } handler *clone(const char *name, MEM_ROOT *mem_root) override; void set_part_info(partition_info *part_info) override { m_part_info= part_info; m_is_sub_partitioned= part_info->is_sub_partitioned(); } Compare_keys compare_key_parts( const Field &old_field, const Column_definition &new_field, const KEY_PART_INFO &old_part, const KEY_PART_INFO &new_part) const override; void return_record_by_parent() override; bool vers_can_native(THD *thd) override { if (thd->lex->part_info) { // PARTITION BY SYSTEM_TIME is not supported for now return thd->lex->part_info->part_type != VERSIONING_PARTITION; } else { bool can= true; for (uint i= 0; i < m_tot_parts && can; i++) can= can && m_file[i]->vers_can_native(thd); return can; } } /* ------------------------------------------------------------------------- MODULE create/delete handler object ------------------------------------------------------------------------- Object create/delete method. Normally called when a table object exists. There is also a method to create the handler object with only partition information. This is used from mysql_create_table when the table is to be created and the engine type is deduced to be the partition handler. ------------------------------------------------------------------------- */ ha_partition(handlerton *hton, TABLE_SHARE * table); ha_partition(handlerton *hton, partition_info * part_info); ha_partition(handlerton *hton, TABLE_SHARE *share, partition_info *part_info_arg, ha_partition *clone_arg, MEM_ROOT *clone_mem_root_arg); ~ha_partition(); void ha_partition_init(); /* A partition handler has no characteristics in itself. It only inherits those from the underlying handlers. Here we set-up those constants to enable later calls of the methods to retrieve constants from the under- lying handlers. Returns false if not successful. */ bool initialize_partition(MEM_ROOT *mem_root); /* ------------------------------------------------------------------------- MODULE meta data changes ------------------------------------------------------------------------- Meta data routines to CREATE, DROP, RENAME table and often used at ALTER TABLE (update_create_info used from ALTER TABLE and SHOW ..). create_partitioning_metadata is called before opening a new handler object with openfrm to call create. It is used to create any local handler object needed in opening the object in openfrm ------------------------------------------------------------------------- */ int delete_table(const char *from) override; int rename_table(const char *from, const char *to) override; int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info) override; int create_partitioning_metadata(const char *name, const char *old_name, chf_create_flags action_flag) override; bool check_if_updates_are_ignored(const char *op) const override; void update_create_info(HA_CREATE_INFO *create_info) override; int change_partitions(HA_CREATE_INFO *create_info, const char *path, ulonglong * const copied, ulonglong * const deleted, const uchar *pack_frm_data, size_t pack_frm_len) override; int drop_partitions(const char *path) override; int rename_partitions(const char *path) override; bool get_no_parts(const char *, uint *num_parts) override { DBUG_ENTER("ha_partition::get_no_parts"); *num_parts= m_tot_parts; DBUG_RETURN(0); } void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share) override; bool check_if_incompatible_data(HA_CREATE_INFO *create_info, uint table_changes) override; void update_part_create_info(HA_CREATE_INFO *create_info, uint part_id) { m_file[part_id]->update_create_info(create_info); } private: int copy_partitions(ulonglong * const copied, ulonglong * const deleted); void cleanup_new_partition(uint part_count); int prepare_new_partition(TABLE *table, HA_CREATE_INFO *create_info, handler *file, const char *part_name, partition_element *p_elem); /* delete_table and rename_table uses very similar logic which is packed into this routine. */ uint del_ren_table(const char *from, const char *to); /* One method to create the table_name.par file containing the names of the underlying partitions, their engine and the number of partitions. And one method to read it in. */ bool create_handler_file(const char *name); bool setup_engine_array(MEM_ROOT *mem_root, handlerton *first_engine); int read_par_file(const char *name); handlerton *get_def_part_engine(const char *name); bool get_from_handler_file(const char *name, MEM_ROOT *mem_root, bool is_clone); bool re_create_par_file(const char *name); bool new_handlers_from_part_info(MEM_ROOT *mem_root); bool create_handlers(MEM_ROOT *mem_root); void clear_handler_file(); int set_up_table_before_create(TABLE *table_arg, const char *partition_name_with_path, HA_CREATE_INFO *info, partition_element *p_elem); partition_element *find_partition_element(uint part_id); bool insert_partition_name_in_hash(const char *name, uint part_id, bool is_subpart); bool populate_partition_name_hash(); Partition_share *get_share(); bool set_ha_share_ref(Handler_share **ha_share) override; void fix_data_dir(char* path); bool init_partition_bitmaps(); void free_partition_bitmaps(); public: /* ------------------------------------------------------------------------- MODULE open/close object ------------------------------------------------------------------------- Open and close handler object to ensure all underlying files and objects allocated and deallocated for query handling is handled properly. ------------------------------------------------------------------------- A handler object is opened as part of its initialisation and before being used for normal queries (not before meta-data changes always. If the object was opened it will also be closed before being deleted. */ int open(const char *name, int mode, uint test_if_locked) override; int close() override; /* ------------------------------------------------------------------------- MODULE start/end statement ------------------------------------------------------------------------- This module contains methods that are used to understand start/end of statements, transaction boundaries, and aid for proper concurrency control. The partition handler need not implement abort and commit since this will be handled by any underlying handlers implementing transactions. There is only one call to each handler type involved per transaction and these go directly to the handlers supporting transactions ------------------------------------------------------------------------- */ THR_LOCK_DATA **store_lock(THD * thd, THR_LOCK_DATA ** to, enum thr_lock_type lock_type) override; int external_lock(THD * thd, int lock_type) override; LEX_CSTRING *engine_name() override { return hton_name(partition_ht()); } /* When table is locked a statement is started by calling start_stmt instead of external_lock */ int start_stmt(THD * thd, thr_lock_type lock_type) override; /* Lock count is number of locked underlying handlers (I assume) */ uint lock_count() const override; /* Call to unlock rows not to be updated in transaction */ void unlock_row() override; /* Check if semi consistent read */ bool was_semi_consistent_read() override; /* Call to hint about semi consistent read */ void try_semi_consistent_read(bool) override; /* NOTE: due to performance and resource issues with many partitions, we only use the m_psi on the ha_partition handler, excluding all partitions m_psi. */ #ifdef HAVE_M_PSI_PER_PARTITION /* Bind the table/handler thread to track table i/o. */ virtual void unbind_psi(); virtual int rebind(); #endif int discover_check_version() override; /* ------------------------------------------------------------------------- MODULE change record ------------------------------------------------------------------------- This part of the handler interface is used to change the records after INSERT, DELETE, UPDATE, REPLACE method calls but also other special meta-data operations as ALTER TABLE, LOAD DATA, TRUNCATE. ------------------------------------------------------------------------- These methods are used for insert (write_row), update (update_row) and delete (delete_row). All methods to change data always work on one row at a time. update_row and delete_row also contains the old row. delete_all_rows will delete all rows in the table in one call as a special optimisation for DELETE from table; Bulk inserts are supported if all underlying handlers support it. start_bulk_insert and end_bulk_insert is called before and after a number of calls to write_row. */ int write_row(const uchar * buf) override; bool start_bulk_update() override; int exec_bulk_update(ha_rows *dup_key_found) override; int end_bulk_update() override; int bulk_update_row(const uchar *old_data, const uchar *new_data, ha_rows *dup_key_found) override; int update_row(const uchar * old_data, const uchar * new_data) override; int direct_update_rows_init(List *update_fields) override; int pre_direct_update_rows_init(List *update_fields) override; int direct_update_rows(ha_rows *update_rows, ha_rows *found_rows) override; int pre_direct_update_rows() override; bool start_bulk_delete() override; int end_bulk_delete() override; int delete_row(const uchar * buf) override; int direct_delete_rows_init() override; int pre_direct_delete_rows_init() override; int direct_delete_rows(ha_rows *delete_rows) override; int pre_direct_delete_rows() override; int delete_all_rows() override; int truncate() override; void start_bulk_insert(ha_rows rows, uint flags) override; int end_bulk_insert() override; private: ha_rows guess_bulk_insert_rows(); void start_part_bulk_insert(THD *thd, uint part_id); long estimate_read_buffer_size(long original_size); public: /* Method for truncating a specific partition. (i.e. ALTER TABLE t1 TRUNCATE PARTITION p). @remark This method is a partitioning-specific hook and thus not a member of the general SE API. */ int truncate_partition(Alter_info *, bool *binlog_stmt); bool is_fatal_error(int error, uint flags) override { if (!handler::is_fatal_error(error, flags) || error == HA_ERR_NO_PARTITION_FOUND || error == HA_ERR_NOT_IN_LOCK_PARTITIONS) return FALSE; return TRUE; } /* ------------------------------------------------------------------------- MODULE full table scan ------------------------------------------------------------------------- This module is used for the most basic access method for any table handler. This is to fetch all data through a full table scan. No indexes are needed to implement this part. It contains one method to start the scan (rnd_init) that can also be called multiple times (typical in a nested loop join). Then proceeding to the next record (rnd_next) and closing the scan (rnd_end). To remember a record for later access there is a method (position) and there is a method used to retrieve the record based on the stored position. The position can be a file position, a primary key, a ROWID dependent on the handler below. ------------------------------------------------------------------------- */ /* unlike index_init(), rnd_init() can be called two times without rnd_end() in between (it only makes sense if scan=1). then the second call should prepare for the new table scan (e.g if rnd_init allocates the cursor, second call should position it to the start of the table, no need to deallocate and allocate it again */ int rnd_init(bool scan) override; int rnd_end() override; int rnd_next(uchar * buf) override; int rnd_pos(uchar * buf, uchar * pos) override; int rnd_pos_by_record(uchar *record) override; void position(const uchar * record) override; /* ------------------------------------------------------------------------- MODULE index scan ------------------------------------------------------------------------- This part of the handler interface is used to perform access through indexes. The interface is defined as a scan interface but the handler can also use key lookup if the index is a unique index or a primary key index. Index scans are mostly useful for SELECT queries but are an important part also of UPDATE, DELETE, REPLACE and CREATE TABLE table AS SELECT and so forth. Naturally an index is needed for an index scan and indexes can either be ordered, hash based. Some ordered indexes can return data in order but not necessarily all of them. There are many flags that define the behavior of indexes in the various handlers. These methods are found in the optimizer module. ------------------------------------------------------------------------- index_read is called to start a scan of an index. The find_flag defines the semantics of the scan. These flags are defined in include/my_base.h index_read_idx is the same but also initializes index before calling doing the same thing as index_read. Thus it is similar to index_init followed by index_read. This is also how we implement it. index_read/index_read_idx does also return the first row. Thus for key lookups, the index_read will be the only call to the handler in the index scan. index_init initializes an index before using it and index_end does any end processing needed. */ int index_read_map(uchar * buf, const uchar * key, key_part_map keypart_map, enum ha_rkey_function find_flag) override; int index_init(uint idx, bool sorted) override; int index_end() override; /** @breif Positions an index cursor to the index specified in the handle. Fetches the row if available. If the key value is null, begin at first key of the index. */ int index_read_idx_map(uchar *buf, uint index, const uchar *key, key_part_map keypart_map, enum ha_rkey_function find_flag) override; /* These methods are used to jump to next or previous entry in the index scan. There are also methods to jump to first and last entry. */ int index_next(uchar * buf) override; int index_prev(uchar * buf) override; int index_first(uchar * buf) override; int index_last(uchar * buf) override; int index_next_same(uchar * buf, const uchar * key, uint keylen) override; int index_read_last_map(uchar *buf, const uchar *key, key_part_map keypart_map) override; /* read_first_row is virtual method but is only implemented by handler.cc, no storage engine has implemented it so neither will the partition handler. int read_first_row(uchar *buf, uint primary_key) override; */ int read_range_first(const key_range * start_key, const key_range * end_key, bool eq_range, bool sorted) override; int read_range_next() override; HANDLER_BUFFER *m_mrr_buffer; uint *m_mrr_buffer_size; uchar *m_mrr_full_buffer; uint m_mrr_full_buffer_size; uint m_mrr_new_full_buffer_size; MY_BITMAP m_mrr_used_partitions; uint *m_stock_range_seq; /* not used: uint m_current_range_seq; */ /* Value of mrr_mode passed to ha_partition::multi_range_read_init */ uint m_mrr_mode; /* Value of n_ranges passed to ha_partition::multi_range_read_init */ uint m_mrr_n_ranges; /* Ordered MRR mode: m_range_info[N] has the range_id of the last record that we've got from partition N */ range_id_t *m_range_info; /* TRUE <=> This ha_partition::multi_range_read_next() call is the first one */ bool m_multi_range_read_first; /* not used: uint m_mrr_range_init_flags; */ /* Number of elements in the list pointed by m_mrr_range_first. Not used */ uint m_mrr_range_length; /* Linked list of ranges to scan */ PARTITION_KEY_MULTI_RANGE *m_mrr_range_first; PARTITION_KEY_MULTI_RANGE *m_mrr_range_current; /* For each partition: number of ranges MRR scan will scan in the partition */ uint *m_part_mrr_range_length; /* For each partition: List of ranges to scan in this partition */ PARTITION_PART_KEY_MULTI_RANGE **m_part_mrr_range_first; PARTITION_PART_KEY_MULTI_RANGE **m_part_mrr_range_current; PARTITION_PART_KEY_MULTI_RANGE_HLD *m_partition_part_key_multi_range_hld; /* Sequence of ranges to be scanned (TODO: why not store this in handler::mrr_{iter,funcs}?) */ range_seq_t m_seq; RANGE_SEQ_IF *m_seq_if; /* Range iterator structure to be supplied to partitions */ RANGE_SEQ_IF m_part_seq_if; virtual int multi_range_key_create_key( RANGE_SEQ_IF *seq, range_seq_t seq_it ); ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, uint *mrr_mode, Cost_estimate *cost) override; ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, uint key_parts, uint *bufsz, uint *mrr_mode, Cost_estimate *cost) override; int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint mrr_mode, HANDLER_BUFFER *buf) override; int multi_range_read_next(range_id_t *range_info) override; int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size) override; uint last_part() { return m_last_part; } private: bool init_record_priority_queue(); void destroy_record_priority_queue(); int common_index_read(uchar * buf, bool have_start_key); int common_first_last(uchar * buf); int partition_scan_set_up(uchar * buf, bool idx_read_flag); bool check_parallel_search(); int handle_pre_scan(bool reverse_order, bool use_parallel); int handle_unordered_next(uchar * buf, bool next_same); int handle_unordered_scan_next_partition(uchar * buf); int handle_ordered_index_scan(uchar * buf, bool reverse_order); int handle_ordered_index_scan_key_not_found(); int handle_ordered_next(uchar * buf, bool next_same); int handle_ordered_prev(uchar * buf); void return_top_record(uchar * buf); void swap_blobs(uchar* rec_buf, Ordered_blob_storage ** storage, bool restore); public: /* ------------------------------------------------------------------------- MODULE information calls ------------------------------------------------------------------------- This calls are used to inform the handler of specifics of the ongoing scans and other actions. Most of these are used for optimisation purposes. ------------------------------------------------------------------------- */ int info(uint) override; void get_dynamic_partition_info(PARTITION_STATS *stat_info, uint part_id) override; void set_partitions_to_open(List *partition_names) override; int change_partitions_to_open(List *partition_names) override; int open_read_partitions(char *name_buff, size_t name_buff_size); int extra(enum ha_extra_function operation) override; int extra_opt(enum ha_extra_function operation, ulong arg) override; int reset() override; uint count_query_cache_dependant_tables(uint8 *tables_type) override; my_bool register_query_cache_dependant_tables(THD *thd, Query_cache *cache, Query_cache_block_table **block, uint *n) override; private: typedef int handler_callback(handler *, void *); my_bool reg_query_cache_dependant_table(THD *thd, char *engine_key, uint engine_key_len, char *query_key, uint query_key_len, uint8 type, Query_cache *cache, Query_cache_block_table **block_table, handler *file, uint *n); static const uint NO_CURRENT_PART_ID= NOT_A_PARTITION_ID; int loop_partitions(handler_callback callback, void *param); int loop_partitions_over_map(const MY_BITMAP *map, handler_callback callback, void *param); int loop_read_partitions(handler_callback callback, void *param); int loop_extra_alter(enum ha_extra_function operations); void late_extra_cache(uint partition_id); void late_extra_no_cache(uint partition_id); void prepare_extra_cache(uint cachesize); handler *get_open_file_sample() const { return m_file_sample; } public: /* ------------------------------------------------------------------------- MODULE optimiser support ------------------------------------------------------------------------- ------------------------------------------------------------------------- */ /* NOTE !!!!!! ------------------------------------------------------------------------- ------------------------------------------------------------------------- One important part of the public handler interface that is not depicted in the methods is the attribute records which is defined in the base class. This is looked upon directly and is set by calling info(HA_STATUS_INFO) ? ------------------------------------------------------------------------- */ private: /* Helper functions for optimizer hints. */ ha_rows min_rows_for_estimate(); uint get_biggest_used_partition(uint *part_index); public: /* keys_to_use_for_scanning can probably be implemented as the intersection of all underlying handlers if mixed handlers are used. This method is used to derive whether an index can be used for index-only scanning when performing an ORDER BY query. Only called from one place in sql_select.cc */ const key_map *keys_to_use_for_scanning() override; /* Called in test_quick_select to determine if indexes should be used. */ double scan_time() override; double key_scan_time(uint inx) override; double keyread_time(uint inx, uint ranges, ha_rows rows) override; /* The next method will never be called if you do not implement indexes. */ double read_time(uint index, uint ranges, ha_rows rows) override; /* For the given range how many records are estimated to be in this range. Used by optimiser to calculate cost of using a particular index. */ ha_rows records_in_range(uint inx, const key_range * min_key, const key_range * max_key, page_range *pages) override; /* Upper bound of number records returned in scan is sum of all underlying handlers. */ ha_rows estimate_rows_upper_bound() override; /* table_cache_type is implemented by the underlying handler but all underlying handlers must have the same implementation for it to work. */ uint8 table_cache_type() override; ha_rows records() override; /* Calculate hash value for PARTITION BY KEY tables. */ static uint32 calculate_key_hash_value(Field **field_array); /* ------------------------------------------------------------------------- MODULE print messages ------------------------------------------------------------------------- This module contains various methods that returns text messages for table types, index type and error messages. ------------------------------------------------------------------------- */ /* The name of the index type that will be used for display Here we must ensure that all handlers use the same index type for each index created. */ const char *index_type(uint inx) override; /* The name of the table type that will be used for display purposes */ const char *real_table_type() const override; /* The name of the row type used for the underlying tables. */ enum row_type get_row_type() const override; /* Handler specific error messages */ void print_error(int error, myf errflag) override; bool get_error_message(int error, String * buf) override; /* ------------------------------------------------------------------------- MODULE handler characteristics ------------------------------------------------------------------------- This module contains a number of methods defining limitations and characteristics of the handler. The partition handler will calculate this characteristics based on underlying handler characteristics. ------------------------------------------------------------------------- This is a list of flags that says what the storage engine implements. The current table flags are documented in handler.h The partition handler will support whatever the underlying handlers support except when specifically mentioned below about exceptions to this rule. NOTE: This cannot be cached since it can depend on TRANSACTION ISOLATION LEVEL which is dynamic, see bug#39084. HA_TABLE_SCAN_ON_INDEX: Used to avoid scanning full tables on an index. If this flag is set then the handler always has a primary key (hidden if not defined) and this index is used for scanning rather than a full table scan in all situations. (InnoDB, Federated) HA_REC_NOT_IN_SEQ: This flag is set for handlers that cannot guarantee that the rows are returned according to incremental positions (0, 1, 2, 3...). This also means that rnd_next() should return HA_ERR_RECORD_DELETED if it finds a deleted row. (MyISAM (not fixed length row), HEAP, InnoDB) HA_CAN_GEOMETRY: Can the storage engine handle spatial data. Used to check that no spatial attributes are declared unless the storage engine is capable of handling it. (MyISAM) HA_FAST_KEY_READ: Setting this flag indicates that the handler is equally fast in finding a row by key as by position. This flag is used in a very special situation in conjunction with filesort's. For further explanation see intro to init_read_record. (HEAP, InnoDB) HA_NULL_IN_KEY: Is NULL values allowed in indexes. If this is not allowed then it is not possible to use an index on a NULLable field. (HEAP, MyISAM, InnoDB) HA_DUPLICATE_POS: Tells that we can the position for the conflicting duplicate key record is stored in table->file->dupp_ref. (insert uses rnd_pos() on this to find the duplicated row) (MyISAM) HA_CAN_INDEX_BLOBS: Is the storage engine capable of defining an index of a prefix on a BLOB attribute. (Federated, MyISAM, InnoDB) HA_AUTO_PART_KEY: Auto increment fields can be part of a multi-part key. For second part auto-increment keys, the auto_incrementing is done in handler.cc (Federated, MyISAM) HA_REQUIRE_PRIMARY_KEY: Can't define a table without primary key (and cannot handle a table with hidden primary key) (No handler has this limitation currently) HA_STATS_RECORDS_IS_EXACT: Does the counter of records after the info call specify an exact value or not. If it does this flag is set. Only MyISAM and HEAP uses exact count. HA_CAN_INSERT_DELAYED: Can the storage engine support delayed inserts. To start with the partition handler will not support delayed inserts. Further investigation needed. (HEAP, MyISAM) HA_PRIMARY_KEY_IN_READ_INDEX: This parameter is set when the handler will also return the primary key when doing read-only-key on another index. HA_NOT_DELETE_WITH_CACHE: Seems to be an old MyISAM feature that is no longer used. No handler has it defined but it is checked in init_read_record. Further investigation needed. (No handler defines it) HA_NO_PREFIX_CHAR_KEYS: Indexes on prefixes of character fields is not allowed. (Federated) HA_CAN_FULLTEXT: Does the storage engine support fulltext indexes The partition handler will start by not supporting fulltext indexes. (MyISAM) HA_CAN_SQL_HANDLER: Can the HANDLER interface in the MySQL API be used towards this storage engine. (MyISAM, InnoDB) HA_NO_AUTO_INCREMENT: Set if the storage engine does not support auto increment fields. (Currently not set by any handler) HA_HAS_CHECKSUM: Special MyISAM feature. Has special SQL support in CREATE TABLE. No special handling needed by partition handler. (MyISAM) HA_FILE_BASED: Should file names always be in lower case (used by engines that map table names to file names. Since partition handler has a local file this flag is set. (Federated, MyISAM) HA_CAN_BIT_FIELD: Is the storage engine capable of handling bit fields? (MyISAM) HA_NEED_READ_RANGE_BUFFER: Is Read Multi-Range supported => need multi read range buffer This parameter specifies whether a buffer for read multi range is needed by the handler. Whether the handler supports this feature or not is dependent of whether the handler implements read_multi_range* calls or not. The only handler currently supporting this feature is NDB so the partition handler need not handle this call. There are methods in handler.cc that will transfer those calls into index_read and other calls in the index scan module. (No handler defines it) HA_PRIMARY_KEY_REQUIRED_FOR_POSITION: Does the storage engine need a PK for position? (InnoDB) HA_FILE_BASED is always set for partition handler since we use a special file for handling names of partitions, engine types. HA_REC_NOT_IN_SEQ is always set for partition handler since we cannot guarantee that the records will be returned in sequence. HA_DUPLICATE_POS, HA_CAN_INSERT_DELAYED, HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is disabled until further investigated. */ Table_flags table_flags() const override; /* This is a bitmap of flags that says how the storage engine implements indexes. The current index flags are documented in handler.h. If you do not implement indexes, just return zero here. part is the key part to check. First key part is 0 If all_parts it's set, MySQL want to know the flags for the combined index up to and including 'part'. HA_READ_NEXT: Does the index support read next, this is assumed in the server code and never checked so all indexes must support this. Note that the handler can be used even if it doesn't have any index. (HEAP, MyISAM, Federated, InnoDB) HA_READ_PREV: Can the index be used to scan backwards. (HEAP, MyISAM, InnoDB) HA_READ_ORDER: Can the index deliver its record in index order. Typically true for all ordered indexes and not true for hash indexes. In first step this is not true for partition handler until a merge sort has been implemented in partition handler. Used to set keymap part_of_sortkey This keymap is only used to find indexes usable for resolving an ORDER BY in the query. Thus in most cases index_read will work just fine without order in result production. When this flag is set it is however safe to order all output started by index_read since most engines do this. With read_multi_range calls there is a specific flag setting order or not order so in those cases ordering of index output can be avoided. (InnoDB, HEAP, MyISAM) HA_READ_RANGE: Specify whether index can handle ranges, typically true for all ordered indexes and not true for hash indexes. Used by optimiser to check if ranges (as key >= 5) can be optimised by index. (InnoDB, MyISAM, HEAP) HA_ONLY_WHOLE_INDEX: Can't use part key searches. This is typically true for hash indexes and typically not true for ordered indexes. (Federated, HEAP) HA_KEYREAD_ONLY: Does the storage engine support index-only scans on this index. Enables use of HA_EXTRA_KEYREAD and HA_EXTRA_NO_KEYREAD Used to set key_map keys_for_keyread and to check in optimiser for index-only scans. When doing a read under HA_EXTRA_KEYREAD the handler only have to fill in the columns the key covers. If HA_PRIMARY_KEY_IN_READ_INDEX is set then also the PRIMARY KEY columns must be updated in the row. (InnoDB, MyISAM) */ ulong index_flags(uint inx, uint part, bool all_parts) const override { /* The following code is not safe if you are using different storage engines or different index types per partition. */ ulong part_flags= m_file[0]->index_flags(inx, part, all_parts); /* The underlying storage engine might support Rowid Filtering. But ha_partition does not forward the needed SE API calls, so the feature will not be used. Note: It's the same with IndexConditionPushdown, except for its variant of IndexConditionPushdown+BatchedKeyAccess (that one works). Because of that, we do not clear HA_DO_INDEX_COND_PUSHDOWN here. */ return part_flags & ~HA_DO_RANGE_FILTER_PUSHDOWN; } /** wrapper function for handlerton alter_table_flags, since the ha_partition_hton cannot know all its capabilities */ alter_table_operations alter_table_flags(alter_table_operations flags) override; /* unireg.cc will call the following to make sure that the storage engine can handle the data it is about to send. The maximum supported values is the minimum of all handlers in the table */ uint min_of_the_max_uint(uint (handler::*operator_func)(void) const) const; uint max_supported_record_length() const override; uint max_supported_keys() const override; uint max_supported_key_parts() const override; uint max_supported_key_length() const override; uint max_supported_key_part_length() const override; uint min_record_length(uint options) const override; /* ------------------------------------------------------------------------- MODULE compare records ------------------------------------------------------------------------- cmp_ref checks if two references are the same. For most handlers this is a simple memcmp of the reference. However some handlers use primary key as reference and this can be the same even if memcmp says they are different. This is due to character sets and end spaces and so forth. For the partition handler the reference is first two bytes providing the partition identity of the referred record and then the reference of the underlying handler. Thus cmp_ref for the partition handler always returns FALSE for records not in the same partition and uses cmp_ref on the underlying handler to check whether the rest of the reference part is also the same. ------------------------------------------------------------------------- */ int cmp_ref(const uchar * ref1, const uchar * ref2) override; /* ------------------------------------------------------------------------- MODULE auto increment ------------------------------------------------------------------------- This module is used to handle the support of auto increments. This variable in the handler is used as part of the handler interface It is maintained by the parent handler object and should not be touched by child handler objects (see handler.cc for its use). auto_increment_column_changed ------------------------------------------------------------------------- */ bool need_info_for_auto_inc() override; bool can_use_for_auto_inc_init() override; void get_auto_increment(ulonglong offset, ulonglong increment, ulonglong nb_desired_values, ulonglong *first_value, ulonglong *nb_reserved_values) override; void release_auto_increment() override; private: int reset_auto_increment(ulonglong value) override; int update_next_auto_inc_val(); virtual void lock_auto_increment() { /* lock already taken */ if (auto_increment_safe_stmt_log_lock) return; if (table_share->tmp_table == NO_TMP_TABLE) { part_share->lock_auto_inc(); DBUG_ASSERT(!auto_increment_lock); auto_increment_lock= TRUE; } } virtual void unlock_auto_increment() { /* If auto_increment_safe_stmt_log_lock is true, we have to keep the lock. It will be set to false and thus unlocked at the end of the statement by ha_partition::release_auto_increment. */ if (auto_increment_lock && !auto_increment_safe_stmt_log_lock) { auto_increment_lock= FALSE; part_share->unlock_auto_inc(); } } virtual void set_auto_increment_if_higher(Field *field) { ulonglong nr= (((Field_num*) field)->unsigned_flag || field->val_int() > 0) ? field->val_int() : 0; update_next_auto_inc_val(); lock_auto_increment(); /* must check when the mutex is taken */ if (nr >= part_share->next_auto_inc_val) part_share->next_auto_inc_val= nr + 1; unlock_auto_increment(); } void check_insert_or_replace_autoincrement() { /* If we INSERT or REPLACE into the table having the AUTO_INCREMENT column, we have to read all partitions for the next autoincrement value unless we already did it. */ if (!part_share->auto_inc_initialized && (ha_thd()->lex->sql_command == SQLCOM_INSERT || ha_thd()->lex->sql_command == SQLCOM_INSERT_SELECT || ha_thd()->lex->sql_command == SQLCOM_REPLACE || ha_thd()->lex->sql_command == SQLCOM_REPLACE_SELECT) && table->found_next_number_field) bitmap_set_all(&m_part_info->read_partitions); } public: /* ------------------------------------------------------------------------- MODULE initialize handler for HANDLER call ------------------------------------------------------------------------- This method is a special InnoDB method called before a HANDLER query. ------------------------------------------------------------------------- */ void init_table_handle_for_HANDLER() override; /* The remainder of this file defines the handler methods not implemented by the partition handler */ /* ------------------------------------------------------------------------- MODULE foreign key support ------------------------------------------------------------------------- The following methods are used to implement foreign keys as supported by InnoDB. Implement this ?? get_foreign_key_create_info is used by SHOW CREATE TABLE to get a textual description of how the CREATE TABLE part to define FOREIGN KEY's is done. free_foreign_key_create_info is used to free the memory area that provided this description. can_switch_engines checks if it is ok to switch to a new engine based on the foreign key info in the table. ------------------------------------------------------------------------- virtual char* get_foreign_key_create_info() virtual void free_foreign_key_create_info(char* str) virtual int get_foreign_key_list(THD *thd, List *f_key_list) bool referenced_by_foreign_key() const noexcept override */ bool can_switch_engines() override; /* ------------------------------------------------------------------------- MODULE fulltext index ------------------------------------------------------------------------- */ void ft_close_search(FT_INFO *handler); int ft_init() override; int pre_ft_init() override; void ft_end() override; int pre_ft_end() override; FT_INFO *ft_init_ext(uint flags, uint inx, String *key) override; int ft_read(uchar *buf) override; int pre_ft_read(bool use_parallel) override; /* ------------------------------------------------------------------------- MODULE restart full table scan at position (MyISAM) ------------------------------------------------------------------------- The following method is only used by MyISAM when used as temporary tables in a join. int restart_rnd_next(uchar *buf, uchar *pos) override; */ /* ------------------------------------------------------------------------- MODULE in-place ALTER TABLE ------------------------------------------------------------------------- These methods are in the handler interface. (used by innodb-plugin) They are used for in-place alter table: ------------------------------------------------------------------------- */ enum_alter_inplace_result check_if_supported_inplace_alter(TABLE *altered_table, Alter_inplace_info *ha_alter_info) override; bool prepare_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info) override; bool inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info) override; bool commit_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info, bool commit) override; /* ------------------------------------------------------------------------- MODULE tablespace support ------------------------------------------------------------------------- Admin of table spaces is not applicable to the partition handler (InnoDB) This means that the following method is not implemented: ------------------------------------------------------------------------- virtual int discard_or_import_tablespace(my_bool discard) */ /* ------------------------------------------------------------------------- MODULE admin MyISAM ------------------------------------------------------------------------- ------------------------------------------------------------------------- OPTIMIZE TABLE, CHECK TABLE, ANALYZE TABLE and REPAIR TABLE are mapped to a routine that handles looping over a given set of partitions and those routines send a flag indicating to execute on all partitions. ------------------------------------------------------------------------- */ int optimize(THD* thd, HA_CHECK_OPT *check_opt) override; int analyze(THD* thd, HA_CHECK_OPT *check_opt) override; int check(THD* thd, HA_CHECK_OPT *check_opt) override; int repair(THD* thd, HA_CHECK_OPT *check_opt) override; bool check_and_repair(THD *thd) override; bool auto_repair(int error) const override; bool is_crashed() const override; int check_for_upgrade(HA_CHECK_OPT *check_opt) override; /* ------------------------------------------------------------------------- MODULE condition pushdown ------------------------------------------------------------------------- */ const COND *cond_push(const COND *cond) override; void cond_pop() override; int info_push(uint info_type, void *info) override; private: int handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, uint flags); int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, uint part_id, uint flag); /** Check if the rows are placed in the correct partition. If the given argument is true, then move the rows to the correct partition. */ int check_misplaced_rows(uint read_part_id, bool repair); void append_row_to_str(String &str); public: int pre_calculate_checksum() override; int calculate_checksum() override; /* Enabled keycache for performance reasons, WL#4571 */ int assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt) override; int preload_keys(THD* thd, HA_CHECK_OPT* check_opt) override; TABLE_LIST *get_next_global_for_child() override; /* ------------------------------------------------------------------------- MODULE enable/disable indexes ------------------------------------------------------------------------- Enable/Disable Indexes are only supported by HEAP and MyISAM. ------------------------------------------------------------------------- */ int disable_indexes(key_map map, bool persist) override; int enable_indexes(key_map map, bool persist) override; int indexes_are_disabled() override; /* ------------------------------------------------------------------------- MODULE append_create_info ------------------------------------------------------------------------- append_create_info is only used by MyISAM MERGE tables and the partition handler will not support this handler as underlying handler. Implement this?? ------------------------------------------------------------------------- virtual void append_create_info(String *packet) */ /* the following heavily relies on the fact that all partitions are in the same storage engine. When this limitation is lifted, the following hack should go away, and a proper interface for engines needs to be introduced: an PARTITION_SHARE structure that has a pointer to the TABLE_SHARE. is given to engines everywhere where TABLE_SHARE is used now has members like option_struct, ha_data perhaps TABLE needs to be split the same way too... this can also be done before partition will support a mix of engines, but preferably together with other incompatible API changes. */ handlerton *partition_ht() const override { handlerton *h= m_file[0]->ht; for (uint i=1; i < m_tot_parts; i++) DBUG_ASSERT(h == m_file[i]->ht); return h; } bool partition_engine() override { return 1;} ha_rows part_records(partition_element *part_elem) { DBUG_ASSERT(m_part_info); uint32 sub_factor= m_part_info->num_subparts ? m_part_info->num_subparts : 1; uint32 part_id= part_elem->id * sub_factor; uint32 part_id_end= part_id + sub_factor; DBUG_ASSERT(part_id_end <= m_tot_parts); ha_rows part_recs= 0; for (; part_id < part_id_end; ++part_id) { handler *file= m_file[part_id]; file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_OPEN); part_recs+= file->stats.records; } return part_recs; } int notify_tabledef_changed(LEX_CSTRING *db, LEX_CSTRING *table, LEX_CUSTRING *frm, LEX_CUSTRING *version); friend int cmp_key_rowid_part_id(void *ptr, const void *ref1, const void *ref2); friend int cmp_key_part_id(void *key_p, const void *ref1, const void *ref2); bool can_convert_nocopy(const Field &field, const Column_definition &new_field) const override; void handler_stats_updated() override; }; #endif /* HA_PARTITION_INCLUDED */ server/private/rpl_utility.h000064400000022636151031265040012263 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef RPL_UTILITY_H #define RPL_UTILITY_H #ifndef __cplusplus #error "Don't include this C++ header file from a non-C++ file!" #endif #include "sql_priv.h" #include "m_string.h" /* bzero, memcpy */ #ifdef MYSQL_SERVER #include "table.h" /* TABLE_LIST */ #endif #include "mysql_com.h" class Relay_log_info; class Log_event; struct rpl_group_info; /** A table definition from the master. The responsibilities of this class is: - Extract and decode table definition data from the table map event - Check if table definition in table map is compatible with table definition on slave */ class table_def { public: /** Constructor. @param types Array of types, each stored as a byte @param size Number of elements in array 'types' @param field_metadata Array of extra information about fields @param metadata_size Size of the field_metadata array @param null_bitmap The bitmap of fields that can be null */ table_def(unsigned char *types, ulong size, uchar *field_metadata, int metadata_size, uchar *null_bitmap, uint16 flags); ~table_def(); /** Return the number of fields there is type data for. @return The number of fields that there is type data for. */ ulong size() const { return m_size; } /** Returns internal binlog type code for one field, without translation to real types. */ enum_field_types binlog_type(ulong index) const { return static_cast(m_type[index]); } /* Return a representation of the type data for one field. @param index Field index to return data for @return Will return a representation of the type data for field index. Currently, only the type identifier is returned. */ enum_field_types type(ulong index) const { DBUG_ASSERT(index < m_size); /* If the source type is MYSQL_TYPE_STRING, it can in reality be either MYSQL_TYPE_STRING, MYSQL_TYPE_ENUM, or MYSQL_TYPE_SET, so we might need to modify the type to get the real type. */ enum_field_types source_type= binlog_type(index); uint16 source_metadata= m_field_metadata[index]; switch (source_type) { case MYSQL_TYPE_STRING: { int real_type= source_metadata >> 8; if (real_type == MYSQL_TYPE_ENUM || real_type == MYSQL_TYPE_SET) source_type= static_cast(real_type); break; } /* This type has not been used since before row-based replication, so we can safely assume that it really is MYSQL_TYPE_NEWDATE. */ case MYSQL_TYPE_DATE: source_type= MYSQL_TYPE_NEWDATE; break; default: /* Do nothing */ break; } return source_type; } #ifdef MYSQL_SERVER const Type_handler *field_type_handler(uint index) const; #endif /* This function allows callers to get the extra field data from the table map for a given field. If there is no metadata for that field or there is no extra metadata at all, the function returns 0. The function returns the value for the field metadata for column at position indicated by index. As mentioned, if the field was a type that stores field metadata, that value is returned else zero (0) is returned. This method is used in the unpack() methods of the corresponding fields to properly extract the data from the binary log in the event that the master's field is smaller than the slave. */ uint16 field_metadata(uint index) const { DBUG_ASSERT(index < m_size); if (m_field_metadata_size) return m_field_metadata[index]; else return 0; } /* This function returns whether the field on the master can be null. This value is derived from field->maybe_null(). */ my_bool maybe_null(uint index) const { DBUG_ASSERT(index < m_size); return ((m_null_bits[(index / 8)] & (1 << (index % 8))) == (1 << (index %8))); } /* This function returns the field size in raw bytes based on the type and the encoded field data from the master's raw data. This method can be used for situations where the slave needs to skip a column (e.g., WL#3915) or needs to advance the pointer for the fields in the raw data from the master to a specific column. */ uint32 calc_field_size(uint col, uchar *master_data) const; /** Decide if the table definition is compatible with a table. Compare the definition with a table to see if it is compatible with it. A table definition is compatible with a table if: - The columns types of the table definition is a (not necessarily proper) prefix of the column type of the table. - The other way around. - Each column on the master that also exists on the slave can be converted according to the current settings of @c SLAVE_TYPE_CONVERSIONS. @param thd @param rli Pointer to relay log info @param table Pointer to table to compare with. @param[out] tmp_table_var Pointer to temporary table for holding conversion table. @retval 1 if the table definition is not compatible with @c table @retval 0 if the table definition is compatible with @c table */ #ifndef MYSQL_CLIENT bool compatible_with(THD *thd, rpl_group_info *rgi, TABLE *table, TABLE **conv_table_var) const; /** Create a virtual in-memory temporary table structure. The table structure has records and field array so that a row can be unpacked into the record for further processing. In the virtual table, each field that requires conversion will have a non-NULL value, while fields that do not require conversion will have a NULL value. Some information that is missing in the events, such as the character set for string types, are taken from the table that the field is going to be pushed into, so the target table that the data eventually need to be pushed into need to be supplied. @param thd Thread to allocate memory from. @param rli Relay log info structure, for error reporting. @param target_table Target table for fields. @return A pointer to a temporary table with memory allocated in the thread's memroot, NULL if the table could not be created */ TABLE *create_conversion_table(THD *thd, rpl_group_info *rgi, TABLE *target_table) const; #endif private: ulong m_size; // Number of elements in the types array unsigned char *m_type; // Array of type descriptors uint m_field_metadata_size; uint16 *m_field_metadata; uchar *m_null_bits; uint16 m_flags; // Table flags uchar *m_memory; }; #ifndef MYSQL_CLIENT /** Extend the normal table list with a few new fields needed by the slave thread, but nowhere else. */ struct RPL_TABLE_LIST : public TABLE_LIST { bool m_tabledef_valid; table_def m_tabledef; TABLE *m_conv_table; bool master_had_triggers; }; /* Anonymous namespace for template functions/classes */ CPP_UNNAMED_NS_START /* Smart pointer that will automatically call my_afree (a macro) when the pointer goes out of scope. This is used so that I do not have to remember to call my_afree() before each return. There is no overhead associated with this, since all functions are inline. I (Matz) would prefer to use the free function as a template parameter, but that is not possible when the "function" is a macro. */ template class auto_afree_ptr { Obj* m_ptr; public: auto_afree_ptr(Obj* ptr) : m_ptr(ptr) { } ~auto_afree_ptr() { if (m_ptr) my_afree(m_ptr); } void assign(Obj* ptr) { /* Only to be called if it hasn't been given a value before. */ DBUG_ASSERT(m_ptr == NULL); m_ptr= ptr; } Obj* get() { return m_ptr; } }; CPP_UNNAMED_NS_END class Deferred_log_events { private: DYNAMIC_ARRAY array; Log_event *last_added; public: Deferred_log_events(Relay_log_info *rli); ~Deferred_log_events(); /* queue for exection at Query-log-event time prior the Query */ int add(Log_event *ev); bool is_empty(); bool execute(struct rpl_group_info *rgi); void rewind(); bool is_last(Log_event *ev) { return ev == last_added; }; }; #endif // NB. number of printed bit values is limited to sizeof(buf) - 1 #define DBUG_PRINT_BITSET(N,FRM,BS) \ do { \ char buf[256]; \ uint i; \ for (i = 0 ; i < MY_MIN(sizeof(buf) - 1, (BS)->n_bits) ; i++) \ buf[i] = bitmap_is_set((BS), i) ? '1' : '0'; \ buf[i] = '\0'; \ DBUG_PRINT((N), ((FRM), buf)); \ } while (0) #endif /* RPL_UTILITY_H */ server/private/sql_signal.h000064400000006442151031265040012034 0ustar00/* Copyright (c) 2008 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_SIGNAL_H #define SQL_SIGNAL_H /** Sql_cmd_common_signal represents the common properties of the SIGNAL and RESIGNAL statements. */ class Sql_cmd_common_signal : public Sql_cmd { protected: /** Constructor. @param cond the condition signaled if any, or NULL. @param set collection of signal condition item assignments. */ Sql_cmd_common_signal(const sp_condition_value *cond, const Set_signal_information& set) : Sql_cmd(), m_cond(cond), m_set_signal_information(set) {} virtual ~Sql_cmd_common_signal() = default; /** Evaluate each signal condition items for this statement. @param thd the current thread. @param cond the condition to update. @return 0 on success. */ int eval_signal_informations(THD *thd, Sql_condition *cond); /** Raise a SQL condition. @param thd the current thread. @param cond the condition to raise. @return false on success. */ bool raise_condition(THD *thd, Sql_condition *cond); /** The condition to signal or resignal. This member is optional and can be NULL (RESIGNAL). */ const sp_condition_value *m_cond; /** Collection of 'SET item = value' assignments in the SIGNAL/RESIGNAL statement. */ Set_signal_information m_set_signal_information; }; /** Sql_cmd_signal represents a SIGNAL statement. */ class Sql_cmd_signal : public Sql_cmd_common_signal { public: /** Constructor, used to represent a SIGNAL statement. @param cond the SQL condition to signal (required). @param set the collection of signal information to signal. */ Sql_cmd_signal(const sp_condition_value *cond, const Set_signal_information& set) : Sql_cmd_common_signal(cond, set) {} virtual ~Sql_cmd_signal() = default; enum_sql_command sql_command_code() const override { return SQLCOM_SIGNAL; } bool execute(THD *thd) override; }; /** Sql_cmd_resignal represents a RESIGNAL statement. */ class Sql_cmd_resignal : public Sql_cmd_common_signal { public: /** Constructor, used to represent a RESIGNAL statement. @param cond the SQL condition to resignal (optional, may be NULL). @param set the collection of signal information to resignal. */ Sql_cmd_resignal(const sp_condition_value *cond, const Set_signal_information& set) : Sql_cmd_common_signal(cond, set) {} virtual ~Sql_cmd_resignal() = default; enum_sql_command sql_command_code() const override { return SQLCOM_RESIGNAL; } bool execute(THD *thd) override; }; #endif server/private/client_settings.h000064400000003617151031265040013077 0ustar00/* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef CLIENT_SETTINGS_INCLUDED #define CLIENT_SETTINGS_INCLUDED #else #error You have already included an client_settings.h and it should not be included twice #endif /* CLIENT_SETTINGS_INCLUDED */ #include #include /* Note: CLIENT_CAPABILITIES is also defined in libmysql/client_settings.h. When adding capabilities here, consider if they should be also added to the libmysql version. */ #define CLIENT_CAPABILITIES (CLIENT_MYSQL | \ CLIENT_LONG_FLAG | \ CLIENT_TRANSACTIONS | \ CLIENT_PROTOCOL_41 | \ CLIENT_SECURE_CONNECTION | \ CLIENT_PLUGIN_AUTH | \ CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \ CLIENT_CONNECT_ATTRS) #define read_user_name(A) A[0]= 0 #undef _CUSTOMCONFIG_ #define mysql_server_init(a,b,c) mysql_client_plugin_init() #define mysql_server_end() mysql_client_plugin_deinit() #ifdef HAVE_REPLICATION C_MODE_START void slave_io_thread_detach_vio(); C_MODE_END #else #define slave_io_thread_detach_vio() #endif server/private/mem_root_array.h000064400000015702151031265040012716 0ustar00/* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MEM_ROOT_ARRAY_INCLUDED #define MEM_ROOT_ARRAY_INCLUDED #include /** A typesafe replacement for DYNAMIC_ARRAY. We use MEM_ROOT for allocating storage, rather than the C++ heap. The interface is chosen to be similar to std::vector. @remark Unlike DYNAMIC_ARRAY, elements are properly copied (rather than memcpy()d) if the underlying array needs to be expanded. @remark Depending on has_trivial_destructor, we destroy objects which are removed from the array (including when the array object itself is destroyed). @remark Note that MEM_ROOT has no facility for reusing free space, so don't use this if multiple re-expansions are likely to happen. @param Element_type The type of the elements of the container. Elements must be copyable. @param has_trivial_destructor If true, we don't destroy elements. We could have used type traits to determine this. __has_trivial_destructor is supported by some (but not all) compilers we use. */ template class Mem_root_array { public: /// Convenience typedef, same typedef name as std::vector typedef Element_type value_type; Mem_root_array(MEM_ROOT *root) : m_root(root), m_array(NULL), m_size(0), m_capacity(0) { DBUG_ASSERT(m_root != NULL); } Mem_root_array(MEM_ROOT *root, size_t n, const value_type &val= value_type()) : m_root(root), m_array(NULL), m_size(0), m_capacity(0) { resize(n, val); } ~Mem_root_array() { clear(); } Element_type &at(size_t n) { DBUG_ASSERT(n < size()); return m_array[n]; } const Element_type &at(size_t n) const { DBUG_ASSERT(n < size()); return m_array[n]; } Element_type &operator[](size_t n) { return at(n); } const Element_type &operator[](size_t n) const { return at(n); } Element_type &back() { return at(size() - 1); } const Element_type &back() const { return at(size() - 1); } // Returns a pointer to the first element in the array. Element_type *begin() { return &m_array[0]; } const Element_type *begin() const { return &m_array[0]; } // Returns a pointer to the past-the-end element in the array. Element_type *end() { return &m_array[size()]; } const Element_type *end() const { return &m_array[size()]; } // Erases all of the elements. void clear() { if (!empty()) chop(0); } /* Chops the tail off the array, erasing all tail elements. @param pos Index of first element to erase. */ void chop(const size_t pos) { DBUG_ASSERT(pos < m_size); if (!has_trivial_destructor) { for (size_t ix= pos; ix < m_size; ++ix) { Element_type *p= &m_array[ix]; p->~Element_type(); // Destroy discarded element. } } m_size= pos; } /* Reserves space for array elements. Copies over existing elements, in case we are re-expanding the array. @param n number of elements. @retval true if out-of-memory, false otherwise. */ bool reserve(size_t n) { if (n <= m_capacity) return false; void *mem= alloc_root(m_root, n * element_size()); if (!mem) return true; Element_type *array= static_cast(mem); // Copy all the existing elements into the new array. for (size_t ix= 0; ix < m_size; ++ix) { Element_type *new_p= &array[ix]; Element_type *old_p= &m_array[ix]; new (new_p) Element_type(*old_p); // Copy into new location. if (!has_trivial_destructor) old_p->~Element_type(); // Destroy the old element. } // Forget the old array. m_array= array; m_capacity= n; return false; } /* Adds a new element at the end of the array, after its current last element. The content of this new element is initialized to a copy of the input argument. @param element Object to copy. @retval true if out-of-memory, false otherwise. */ bool push_back(const Element_type &element) { const size_t min_capacity= 20; const size_t expansion_factor= 2; if (0 == m_capacity && reserve(min_capacity)) return true; if (m_size == m_capacity && reserve(m_capacity * expansion_factor)) return true; Element_type *p= &m_array[m_size++]; new (p) Element_type(element); return false; } /** Removes the last element in the array, effectively reducing the container size by one. This destroys the removed element. */ void pop_back() { DBUG_ASSERT(!empty()); if (!has_trivial_destructor) back().~Element_type(); m_size-= 1; } /** Resizes the container so that it contains n elements. If n is smaller than the current container size, the content is reduced to its first n elements, removing those beyond (and destroying them). If n is greater than the current container size, the content is expanded by inserting at the end as many elements as needed to reach a size of n. If val is specified, the new elements are initialized as copies of val, otherwise, they are value-initialized. If n is also greater than the current container capacity, an automatic reallocation of the allocated storage space takes place. Notice that this function changes the actual content of the container by inserting or erasing elements from it. */ void resize(size_t n, const value_type &val= value_type()) { if (n == m_size) return; if (n > m_size) { if (!reserve(n)) { while (n != m_size) push_back(val); } return; } if (!has_trivial_destructor) { while (n != m_size) pop_back(); } m_size= n; } size_t capacity() const { return m_capacity; } size_t element_size() const { return sizeof(Element_type); } bool empty() const { return size() == 0; } size_t size() const { return m_size; } const MEM_ROOT *mem_root() const { return m_root; } private: MEM_ROOT *const m_root; Element_type *m_array; size_t m_size; size_t m_capacity; // Not (yet) implemented. Mem_root_array(const Mem_root_array&); Mem_root_array &operator=(const Mem_root_array&); }; #endif // MEM_ROOT_ARRAY_INCLUDED server/private/sql_udf.h000064400000011362151031265040011332 0ustar00#ifndef SQL_UDF_INCLUDED #define SQL_UDF_INCLUDED /* Copyright (c) 2000, 2003-2007 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file defines structures needed by udf functions */ #ifdef USE_PRAGMA_INTERFACE #pragma interface #endif enum Item_udftype {UDFTYPE_FUNCTION=1,UDFTYPE_AGGREGATE}; typedef void (*Udf_func_clear)(UDF_INIT *, uchar *, uchar *); typedef void (*Udf_func_add)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *); typedef void (*Udf_func_deinit)(UDF_INIT*); typedef my_bool (*Udf_func_init)(UDF_INIT *, UDF_ARGS *, char *); typedef void *Udf_func_any; typedef double (*Udf_func_double)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *); typedef longlong (*Udf_func_longlong)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *); typedef struct st_udf_func { LEX_CSTRING name; Item_result returns; Item_udftype type; const char *dl; void *dlhandle; Udf_func_any func; Udf_func_init func_init; Udf_func_deinit func_deinit; Udf_func_clear func_clear; Udf_func_add func_add; Udf_func_add func_remove; ulong usage_count; } udf_func; class Item_result_field; class udf_handler :public Sql_alloc { protected: udf_func *u_d; String *buffers; UDF_ARGS f_args; UDF_INIT initid; char *num_buffer; uchar error, is_null; bool initialized; Item **args; public: bool not_original; udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0), is_null(0), initialized(0), not_original(0) {} ~udf_handler(); const char *name() const { return u_d ? u_d->name.str : "?"; } Item_result result_type () const { return u_d ? u_d->returns : STRING_RESULT;} bool get_arguments(); bool fix_fields(THD *thd, Item_func_or_sum *item, uint arg_count, Item **args); void cleanup(); double val(my_bool *null_value) { is_null= 0; if (get_arguments()) { *null_value=1; return 0.0; } Udf_func_double func= (Udf_func_double) u_d->func; double tmp=func(&initid, &f_args, &is_null, &error); if (is_null || error) { *null_value=1; return 0.0; } *null_value=0; return tmp; } longlong val_int(my_bool *null_value) { is_null= 0; if (get_arguments()) { *null_value=1; return 0; } Udf_func_longlong func= (Udf_func_longlong) u_d->func; longlong tmp=func(&initid, &f_args, &is_null, &error); if (is_null || error) { *null_value=1; return 0; } *null_value=0; return tmp; } my_decimal *val_decimal(my_bool *null_value, my_decimal *dec_buf); void clear() { is_null= 0; Udf_func_clear func= u_d->func_clear; func(&initid, &is_null, &error); } void add(my_bool *null_value) { if (get_arguments()) { *null_value=1; return; } Udf_func_add func= u_d->func_add; func(&initid, &f_args, &is_null, &error); *null_value= (my_bool) (is_null || error); } bool supports_removal() const { return MY_TEST(u_d->func_remove); } void remove(my_bool *null_value) { DBUG_ASSERT(u_d->func_remove); if (get_arguments()) { *null_value=1; return; } Udf_func_add func= u_d->func_remove; func(&initid, &f_args, &is_null, &error); *null_value= (my_bool) (is_null || error); } String *val_str(String *str,String *save_str); udf_handler(const udf_handler &orig) { u_d = orig.u_d; buffers = orig.buffers; f_args = orig.f_args; initid = orig.initid; num_buffer = orig.num_buffer; error = orig.error; is_null = orig.is_null; initialized = orig.initialized; args = orig.args; not_original = true; } }; #ifdef HAVE_DLOPEN void udf_init(void),udf_free(void); udf_func *find_udf(const char *name, size_t size, bool mark_used=0); void free_udf(udf_func *udf); int mysql_create_function(THD *thd,udf_func *udf); enum drop_udf_result { UDF_DEL_RESULT_ABSENT, UDF_DEL_RESULT_DELETED, UDF_DEL_RESULT_ERROR }; enum drop_udf_result mysql_drop_function(THD *thd, const LEX_CSTRING *name); #else static inline void udf_init(void) { } static inline void udf_free(void) { } #endif #endif /* SQL_UDF_INCLUDED */ server/private/message.h000064400000002253151031265040011320 0ustar00/* To change or add messages mysqld writes to the Windows error log, run mc.exe message.mc and checkin generated messages.h, messages.rc and msg000001.bin under the source control. mc.exe can be installed with Windows SDK, some Visual Studio distributions do not include it. */ // // Values are 32 bit values laid out as follows: // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // +---+-+-+-----------------------+-------------------------------+ // |Sev|C|R| Facility | Code | // +---+-+-+-----------------------+-------------------------------+ // // where // // Sev - is the severity code // // 00 - Success // 01 - Informational // 10 - Warning // 11 - Error // // C - is the Customer code flag // // R - is a reserved bit // // Facility - is the facility code // // Code - is the facility's status code // // // Define the facility codes // // // Define the severity codes // // // MessageId: MSG_DEFAULT // // MessageText: // // %1 // // #define MSG_DEFAULT 0xC0000064L server/private/sql_manager.h000064400000001700151031265040012161 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_MANAGER_INCLUDED #define SQL_MANAGER_INCLUDED void start_handle_manager(); void stop_handle_manager(); bool mysql_manager_submit(void (*action)(void *), void *data); #endif /* SQL_MANAGER_INCLUDED */ server/private/sql_tvc.h000064400000004562151031265040011354 0ustar00/* Copyright (c) 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_TVC_INCLUDED #define SQL_TVC_INCLUDED #include "sql_type.h" typedef List List_item; typedef bool (Item::*Item_processor) (void *arg); class select_result; class Explain_select; class Explain_query; class Item_func_in; class st_select_lex_unit; typedef class st_select_lex SELECT_LEX; class Type_holder; /** @class table_value_constr @brief Definition of a Table Value Construction(TVC) It contains a list of lists of values which this TVC is defined by and reference on SELECT where this TVC is defined. */ class table_value_constr : public Sql_alloc { public: List lists_of_values; select_result *result; SELECT_LEX *select_lex; Type_holder *type_holders; enum { QEP_NOT_PRESENT_YET, QEP_AVAILABLE} have_query_plan; Explain_select *explain; ulonglong select_options; table_value_constr(List tvc_values, SELECT_LEX *sl, ulonglong select_options_arg) : lists_of_values(tvc_values), result(0), select_lex(sl), type_holders(0), have_query_plan(QEP_NOT_PRESENT_YET), explain(0), select_options(select_options_arg) { }; ha_rows get_records() { return lists_of_values.elements; } bool prepare(THD *thd_arg, SELECT_LEX *sl, select_result *tmp_result, st_select_lex_unit *unit_arg); bool to_be_wrapped_as_with_tail(); int save_explain_data_intern(THD *thd_arg, Explain_query *output); bool optimize(THD *thd_arg); bool exec(SELECT_LEX *sl); void print(THD *thd_arg, String *str, enum_query_type query_type); bool walk_values(Item_processor processor, bool walk_subquery, void *arg); }; st_select_lex *wrap_tvc_with_tail(THD *thd, st_select_lex *tvc_sl); #endif /* SQL_TVC_INCLUDED */ server/private/thread_cache.h000064400000013421151031265040012265 0ustar00/* Copyright (C) 2020 MariaDB Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** MariaDB thread cache for "one thread per connection" scheduler. Thread cache allows to re-use threads (as well as THD objects) for subsequent connections. */ class Thread_cache { mutable mysql_cond_t COND_thread_cache; mutable mysql_cond_t COND_flush_thread_cache; mutable mysql_mutex_t LOCK_thread_cache; /** Queue of new connection requests. */ I_List list; /** Number of threads parked in the cache. */ ulong cached_thread_count; /** Number of active flush requests. */ uint32_t kill_cached_threads; /** PFS stuff, only used during initialization. Unfortunately needs to survive till destruction. */ PSI_cond_key key_COND_thread_cache, key_COND_flush_thread_cache; PSI_mutex_key key_LOCK_thread_cache; public: void init() { #ifdef HAVE_PSI_INTERFACE PSI_cond_info conds[]= { { &key_COND_thread_cache, "COND_thread_cache", PSI_FLAG_GLOBAL }, { &key_COND_flush_thread_cache, "COND_flush_thread_cache", PSI_FLAG_GLOBAL } }; PSI_mutex_info mutexes[]= { { &key_LOCK_thread_cache, "LOCK_thread_cache", PSI_FLAG_GLOBAL } }; mysql_mutex_register("sql", mutexes, array_elements(mutexes)); mysql_cond_register("sql", conds, array_elements(conds)); #endif mysql_mutex_init(key_LOCK_thread_cache, &LOCK_thread_cache, MY_MUTEX_INIT_FAST); mysql_cond_init(key_COND_thread_cache, &COND_thread_cache, 0); mysql_cond_init(key_COND_flush_thread_cache, &COND_flush_thread_cache, 0); list.empty(); kill_cached_threads= 0; cached_thread_count= 0; } void destroy() { DBUG_ASSERT(cached_thread_count == 0); DBUG_ASSERT(list.is_empty()); mysql_cond_destroy(&COND_flush_thread_cache); mysql_cond_destroy(&COND_thread_cache); mysql_mutex_destroy(&LOCK_thread_cache); } /** Flushes thread cache. Awakes parked threads and requests them to shutdown. Waits until last parked thread leaves the cache. */ void flush() { mysql_mutex_lock(&LOCK_thread_cache); kill_cached_threads++; while (cached_thread_count) { mysql_cond_broadcast(&COND_thread_cache); mysql_cond_wait(&COND_flush_thread_cache, &LOCK_thread_cache); } kill_cached_threads--; mysql_mutex_unlock(&LOCK_thread_cache); } /** Flushes thread cache and forbids threads parking in the cache. This is a pre-shutdown hook. */ void final_flush() { kill_cached_threads++; flush(); } /** Requests parked thread to serve new connection. @return @retval true connection is enqueued and parked thread is about to serve it @retval false thread cache is empty */ bool enqueue(CONNECT *connect) { mysql_mutex_lock(&LOCK_thread_cache); if (cached_thread_count) { list.push_back(connect); cached_thread_count--; mysql_mutex_unlock(&LOCK_thread_cache); mysql_cond_signal(&COND_thread_cache); return true; } mysql_mutex_unlock(&LOCK_thread_cache); return false; } /** Parks thread in the cache. Thread execution is suspended until either of the following occurs: - thread is requested to serve new connection; - thread cache is flushed; - THREAD_CACHE_TIMEOUT elapsed. @return @retval pointer to CONNECT if requested to serve new connection @retval 0 if thread cache is flushed or on timeout */ CONNECT *park() { struct timespec abstime; CONNECT *connect; bool flushed= false; DBUG_ENTER("Thread_cache::park"); set_timespec(abstime, THREAD_CACHE_TIMEOUT); /* Delete the instrumentation for the job that just completed, before parking this pthread in the cache (blocked on COND_thread_cache). */ PSI_CALL_delete_current_thread(); #ifndef DBUG_OFF while (_db_is_pushed_()) _db_pop_(); #endif mysql_mutex_lock(&LOCK_thread_cache); if ((connect= list.get())) cached_thread_count++; else if (cached_thread_count < thread_cache_size && !kill_cached_threads) { /* Don't kill the thread, just put it in cache for reuse */ DBUG_PRINT("info", ("Adding thread to cache")); cached_thread_count++; for (;;) { int error= mysql_cond_timedwait(&COND_thread_cache, &LOCK_thread_cache, &abstime); flushed= kill_cached_threads; if ((connect= list.get())) break; else if (flushed || error == ETIMEDOUT || error == ETIME) { /* If timeout, end thread. If a new thread is requested, we will handle the call, even if we got a timeout (as we are already awake and free) */ cached_thread_count--; break; } } } mysql_mutex_unlock(&LOCK_thread_cache); if (flushed) mysql_cond_signal(&COND_flush_thread_cache); DBUG_RETURN(connect); } /** Returns the number of parked threads. */ ulong size() const { mysql_mutex_lock(&LOCK_thread_cache); ulong r= cached_thread_count; mysql_mutex_unlock(&LOCK_thread_cache); return r; } }; extern Thread_cache thread_cache; server/private/group_by_handler.h000064400000006716151031265040013227 0ustar00/* Copyright (c) 2014, 2015 SkySQL Ab & MariaDB Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef GROUP_BY_HANDLER_INCLUDED #define GROUP_BY_HANDLER_INCLUDED class Select_limit_counters; /* This file implements the group_by_handler interface. This interface can be used by storage handlers that can intercept summary or GROUP BY queries from MariaDB and itself return the result to the user or upper level. It is part of the Storage Engine API Both main and sub queries are supported. Here are some examples of what the storage engine could intersept: SELECT count(*) FROM t1; SELECT a,count(*) FROM t1 group by a; SELECT a,count(*) as sum FROM t1 where b > 10 group by a, order by sum; SELECT a,count(*) FROM t1,t2; SELECT a, (select sum(*) from t2 where t1.a=t2.a) from t2; */ /** The structure describing various parts of the query The engine is supposed to take out parts that it can do internally. For example, if the engine can return results sorted according to the specified order_by clause, it sets Query::order_by=NULL before returning. At the moment the engine must take group_by (or return an error), and optionally can take distinct, where, order_by, and having. The engine should not modify the select list. It is the extended SELECT clause (extended, because it has more items than the original user-specified SELECT clause) and it contains all aggregate functions, used in the query. */ struct Query { List *select; /* Number of auxiliary fields. */ int n_aux; bool distinct; TABLE_LIST *from; Item *where; ORDER *group_by; ORDER *order_by; Item *having; // LIMIT Select_limit_counters *limit; }; class group_by_handler { public: THD *thd; handlerton *ht; /* Temporary table where all results should be stored in record[0] The table has a field for every item from the Query::select list, except for const items and some other exceptions, see Create_tmp_table::add_fields() for which items are included and which are skipped. */ TABLE *table; group_by_handler(THD *thd_arg, handlerton *ht_arg) : thd(thd_arg), ht(ht_arg), table(0) {} virtual ~group_by_handler() = default; /* Functions to scan data. All these returns 0 if ok, error code in case of error */ /* Initialize group_by scan, prepare for next_row(). If this is a sub query with group by, this can be called many times for a query. */ virtual int init_scan()= 0; /* Return next group by result in table->record[0]. Return 0 if row found, HA_ERR_END_OF_FILE if last row and other error number in case of fatal error. */ virtual int next_row()= 0; /* End scanning */ virtual int end_scan()=0; /* Report errors */ virtual void print_error(int error, myf errflag); }; #endif //GROUP_BY_HANDLER_INCLUDED server/private/source_revision.h000064400000000103151031265040013102 0ustar00#define SOURCE_REVISION "fe8047caf26d20e98ea7f6ec1dce3924e696703f" server/private/partition_info.h000064400000045544151031265040012732 0ustar00#ifndef PARTITION_INFO_INCLUDED #define PARTITION_INFO_INCLUDED /* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_class.h" #include "partition_element.h" #include "sql_partition.h" class partition_info; struct TABLE_LIST; /* Some function typedefs */ typedef int (*get_part_id_func)(partition_info *part_info, uint32 *part_id, longlong *func_value); typedef int (*get_subpart_id_func)(partition_info *part_info, uint32 *part_id); typedef bool (*check_constants_func)(THD *thd, partition_info *part_info); struct st_ddl_log_memory_entry; #define MAX_PART_NAME_SIZE 8 struct Vers_part_info : public Sql_alloc { Vers_part_info() : limit(0), now_part(NULL), hist_part(NULL) { interval.type= INTERVAL_LAST; } Vers_part_info(Vers_part_info &src) : interval(src.interval), limit(src.limit), now_part(NULL), hist_part(NULL) { } bool initialized() { if (now_part) { DBUG_ASSERT(now_part->id != UINT_MAX32); DBUG_ASSERT(now_part->type == partition_element::CURRENT); if (hist_part) { DBUG_ASSERT(hist_part->id != UINT_MAX32); DBUG_ASSERT(hist_part->type == partition_element::HISTORY); } return true; } return false; } struct { my_time_t start; INTERVAL step; enum interval_type type; bool is_set() { return type < INTERVAL_LAST; } } interval; ulonglong limit; partition_element *now_part; partition_element *hist_part; }; /* See generate_partition_syntax() for details of how the data is used in partition expression. */ class partition_info : public Sql_alloc { public: /* * Here comes a set of definitions needed for partitioned table handlers. */ List partitions; List temp_partitions; /* These are mutually exclusive with part_expr/subpart_expr depending on what is specified in partitioning filter: expression or column list. */ List part_field_list; List subpart_field_list; /* If there is no subpartitioning, use only this func to get partition ids. If there is subpartitioning, use the this func to get partition id when you have both partition and subpartition fields. */ get_part_id_func get_partition_id; /* Get partition id when we don't have subpartition fields */ get_part_id_func get_part_partition_id; /* Get subpartition id when we have don't have partition fields by we do have subpartition ids. Mikael said that for given constant tuple {subpart_field1, ..., subpart_fieldN} the subpartition id will be the same in all subpartitions */ get_subpart_id_func get_subpartition_id; /* When we have various string fields we might need some preparation before and clean-up after calling the get_part_id_func's. We need one such method for get_part_partition_id and one for get_subpartition_id. */ get_part_id_func get_part_partition_id_charset; get_subpart_id_func get_subpartition_id_charset; check_constants_func check_constants; /* NULL-terminated array of fields used in partitioned expression */ Field **part_field_array; Field **subpart_field_array; Field **part_charset_field_array; Field **subpart_charset_field_array; /* Array of all fields used in partition and subpartition expression, without duplicates, NULL-terminated. */ Field **full_part_field_array; /* Set of all fields used in partition and subpartition expression. Required for testing of partition fields in write_set when updating. We need to set all bits in read_set because the row may need to be inserted in a different [sub]partition. */ MY_BITMAP full_part_field_set; /* When we have a field that requires transformation before calling the partition functions we must allocate field buffers for the field of the fields in the partition function. */ uchar **part_field_buffers; uchar **subpart_field_buffers; uchar **restore_part_field_ptrs; uchar **restore_subpart_field_ptrs; Item *part_expr; Item *subpart_expr; Item *item_free_list; struct st_ddl_log_memory_entry *first_log_entry; struct st_ddl_log_memory_entry *exec_log_entry; struct st_ddl_log_memory_entry *frm_log_entry; /* Bitmaps of partitions used by the current query. * read_partitions - partitions to be used for reading. * lock_partitions - partitions that must be locked (read or write). Usually read_partitions is the same set as lock_partitions, but in case of UPDATE the WHERE clause can limit the read_partitions set, but not neccesarily the lock_partitions set. Usage pattern: * Initialized in ha_partition::open(). * read+lock_partitions is set according to explicit PARTITION, WL#5217, in open_and_lock_tables(). * Bits in read_partitions can be cleared in prune_partitions() in the optimizing step. (WL#4443 is about allowing prune_partitions() to affect lock_partitions and be done before locking too). * When the partition enabled handler get an external_lock call it locks all partitions in lock_partitions (and remembers which partitions it locked, so that it can unlock them later). In case of LOCK TABLES it will lock all partitions, and keep them locked while lock_partitions can change for each statement under LOCK TABLES. * Freed at the same time item_free_list is freed. */ MY_BITMAP read_partitions; MY_BITMAP lock_partitions; bool bitmaps_are_initialized; union { longlong *range_int_array; LIST_PART_ENTRY *list_array; part_column_list_val *range_col_array; part_column_list_val *list_col_array; }; Vers_part_info *vers_info; /******************************************** * INTERVAL ANALYSIS ********************************************/ /* Partitioning interval analysis function for partitioning, or NULL if interval analysis is not supported for this kind of partitioning. */ get_partitions_in_range_iter get_part_iter_for_interval; /* Partitioning interval analysis function for subpartitioning, or NULL if interval analysis is not supported for this kind of partitioning. */ get_partitions_in_range_iter get_subpart_iter_for_interval; /******************************************** * INTERVAL ANALYSIS ENDS ********************************************/ longlong err_value; char* part_info_string; partition_element *curr_part_elem; // part or sub part partition_element *current_partition; // partition part_elem_value *curr_list_val; uint curr_list_object; uint num_columns; TABLE *table; /* These key_map's are used for Partitioning to enable quick decisions on whether we can derive more information about which partition to scan just by looking at what index is used. */ key_map all_fields_in_PF, all_fields_in_PPF, all_fields_in_SPF; key_map some_fields_in_PF; handlerton *default_engine_type; partition_type part_type; partition_type subpart_type; uint part_info_len; uint num_parts; uint num_subparts; uint count_curr_subparts; // used during parsing uint num_list_values; uint num_part_fields; uint num_subpart_fields; uint num_full_part_fields; uint has_null_part_id; uint32 default_partition_id; /* This variable is used to calculate the partition id when using LINEAR KEY/HASH. This functionality is kept in the MySQL Server but mainly of use to handlers supporting partitioning. */ uint16 linear_hash_mask; /* PARTITION BY KEY ALGORITHM=N Which algorithm to use for hashing the fields. N = 1 - Use 5.1 hashing (numeric fields are hashed as binary) N = 2 - Use 5.5 hashing (numeric fields are hashed like latin1 bytes) */ enum enum_key_algorithm { KEY_ALGORITHM_NONE= 0, KEY_ALGORITHM_51= 1, KEY_ALGORITHM_55= 2 }; enum_key_algorithm key_algorithm; /* Only the number of partitions defined (uses default names and options). */ bool use_default_partitions; bool use_default_num_partitions; /* Only the number of subpartitions defined (uses default names etc.). */ bool use_default_subpartitions; bool use_default_num_subpartitions; bool default_partitions_setup; bool defined_max_value; inline bool has_default_partititon() { return (part_type == LIST_PARTITION && defined_max_value); } bool list_of_part_fields; // KEY or COLUMNS PARTITIONING bool list_of_subpart_fields; // KEY SUBPARTITIONING bool linear_hash_ind; // LINEAR HASH/KEY bool fixed; bool is_auto_partitioned; bool has_null_value; bool column_list; // COLUMNS PARTITIONING, 5.5+ partition_info() : get_partition_id(NULL), get_part_partition_id(NULL), get_subpartition_id(NULL), part_field_array(NULL), subpart_field_array(NULL), part_charset_field_array(NULL), subpart_charset_field_array(NULL), full_part_field_array(NULL), part_field_buffers(NULL), subpart_field_buffers(NULL), restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL), bitmaps_are_initialized(FALSE), list_array(NULL), vers_info(NULL), err_value(0), part_info_string(NULL), curr_part_elem(NULL), current_partition(NULL), curr_list_object(0), num_columns(0), table(NULL), default_engine_type(NULL), part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION), part_info_len(0), num_parts(0), num_subparts(0), count_curr_subparts(0), num_list_values(0), num_part_fields(0), num_subpart_fields(0), num_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0), key_algorithm(KEY_ALGORITHM_NONE), use_default_partitions(TRUE), use_default_num_partitions(TRUE), use_default_subpartitions(TRUE), use_default_num_subpartitions(TRUE), default_partitions_setup(FALSE), defined_max_value(FALSE), list_of_part_fields(FALSE), list_of_subpart_fields(FALSE), linear_hash_ind(FALSE), fixed(FALSE), is_auto_partitioned(FALSE), has_null_value(FALSE), column_list(FALSE) { all_fields_in_PF.clear_all(); all_fields_in_PPF.clear_all(); all_fields_in_SPF.clear_all(); some_fields_in_PF.clear_all(); partitions.empty(); temp_partitions.empty(); part_field_list.empty(); subpart_field_list.empty(); } ~partition_info() = default; partition_info *get_clone(THD *thd, bool empty_data_and_index_file= FALSE); bool set_named_partition_bitmap(const char *part_name, size_t length); bool set_partition_bitmaps(List *partition_names); /* Answers the question if subpartitioning is used for a certain table */ bool is_sub_partitioned() { return (subpart_type == NOT_A_PARTITION ? FALSE : TRUE); } /* Returns the total number of partitions on the leaf level */ uint get_tot_partitions() { return num_parts * (is_sub_partitioned() ? num_subparts : 1); } bool set_up_defaults_for_partitioning(THD *thd, handler *file, HA_CREATE_INFO *info, uint start_no); const char *find_duplicate_field(); char *find_duplicate_name(); bool check_engine_mix(handlerton *engine_type, bool default_engine); bool check_partition_info(THD *thd, handlerton **eng_type, handler *file, HA_CREATE_INFO *info, partition_info *add_or_reorg_part= NULL); void print_no_partition_found(TABLE *table, myf errflag); void print_debug(const char *str, uint*); Item* get_column_item(Item *item, Field *field); int fix_partition_values(THD *thd, part_elem_value *val, partition_element *part_elem); bool fix_column_value_functions(THD *thd, part_elem_value *val, uint part_id); bool fix_parser_data(THD *thd); int add_max_value(THD *thd); void init_col_val(part_column_list_val *col_val, Item *item); int reorganize_into_single_field_col_val(THD *thd); part_column_list_val *add_column_value(THD *thd); bool set_part_expr(THD *thd, Item *item_ptr, bool is_subpart); bool set_up_charset_field_preps(THD *thd); bool check_partition_field_length(); bool init_column_part(THD *thd); bool add_column_list_value(THD *thd, Item *item); partition_element *get_part_elem(const char *partition_name, char *file_name, size_t file_name_size, uint32 *part_id); void report_part_expr_error(bool use_subpart_expr); bool has_same_partitioning(partition_info *new_part_info); bool error_if_requires_values() const; private: bool set_up_default_partitions(THD *thd, handler *file, HA_CREATE_INFO *info, uint start_no); bool set_up_default_subpartitions(THD *thd, handler *file, HA_CREATE_INFO *info); char *create_default_partition_names(THD *thd, uint part_no, uint num_parts, uint start_no); char *create_default_subpartition_name(THD *thd, uint subpart_no, const char *part_name); bool prune_partition_bitmaps(List *partition_names); // set_read_partitions() in 8.0 bool add_named_partition(const char *part_name, size_t length); public: bool has_unique_name(partition_element *element); bool field_in_partition_expr(Field *field) const; bool vers_init_info(THD *thd); bool vers_set_interval(THD *thd, Item *interval, interval_type int_type, Item *starts, const char *table_name); bool vers_set_limit(ulonglong limit) { DBUG_ASSERT(part_type == VERSIONING_PARTITION); vers_info->limit= limit; return !limit; } bool vers_require_hist_part(THD *thd) const { return part_type == VERSIONING_PARTITION && thd->lex->vers_history_generating(); } int vers_set_hist_part(THD *thd); void vers_check_limit(THD *thd); bool vers_fix_field_list(THD *thd); void vers_update_el_ids(); partition_element *get_partition(uint part_id) { List_iterator it(partitions); partition_element *el; while ((el= it++)) { if (el->id == part_id) return el; } return NULL; } uint next_part_no(uint new_parts) const; }; uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); bool check_partition_dirs(partition_info *part_info); /* Initialize the iterator to return a single partition with given part_id */ static inline void init_single_partition_iterator(uint32 part_id, PARTITION_ITERATOR *part_iter) { part_iter->part_nums.start= part_iter->part_nums.cur= part_id; part_iter->part_nums.end= part_id+1; part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE; part_iter->get_next= get_next_partition_id_range; } /* Initialize the iterator to enumerate all partitions */ static inline void init_all_partitions_iterator(partition_info *part_info, PARTITION_ITERATOR *part_iter) { part_iter->part_nums.start= part_iter->part_nums.cur= 0; part_iter->part_nums.end= part_info->num_parts; part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE; part_iter->get_next= get_next_partition_id_range; } /** @brief Update part_field_list by row_end field name @returns true on error; false on success */ inline bool partition_info::vers_fix_field_list(THD * thd) { if (!table->versioned()) { // frm must be corrupted, normally CREATE/ALTER TABLE checks for that my_error(ER_FILE_CORRUPT, MYF(0), table->s->path.str); return true; } DBUG_ASSERT(part_type == VERSIONING_PARTITION); DBUG_ASSERT(table->versioned(VERS_TIMESTAMP)); Field *row_end= table->vers_end_field(); // needed in handle_list_of_fields() row_end->flags|= GET_FIXED_FIELDS_FLAG; Name_resolution_context *context= &thd->lex->current_select->context; Item *row_end_item= new (thd->mem_root) Item_field(thd, context, row_end); Item *row_end_ts= new (thd->mem_root) Item_func_unix_timestamp(thd, row_end_item); set_part_expr(thd, row_end_ts, false); return false; } /** @brief Update partition_element's id @returns true on error; false on success */ inline void partition_info::vers_update_el_ids() { DBUG_ASSERT(part_type == VERSIONING_PARTITION); DBUG_ASSERT(table->versioned(VERS_TIMESTAMP)); List_iterator it(partitions); partition_element *el; for(uint32 id= 0; ((el= it++)); id++) { DBUG_ASSERT(el->type != partition_element::CONVENTIONAL); /* Newly added element is inserted before AS_OF_NOW. */ if (el->id == UINT_MAX32 || el->type == partition_element::CURRENT) { el->id= id; if (el->type == partition_element::CURRENT) break; } } } inline bool make_partition_name(char *move_ptr, uint i) { int res= snprintf(move_ptr, MAX_PART_NAME_SIZE + 1, "p%u", i); return res < 0 || res > MAX_PART_NAME_SIZE; } #ifdef WITH_PARTITION_STORAGE_ENGINE inline uint partition_info::next_part_no(uint new_parts) const { if (part_type != VERSIONING_PARTITION) return num_parts; DBUG_ASSERT(new_parts > 0); /* Choose first non-occupied name suffix */ uint32 suffix= num_parts - 1; DBUG_ASSERT(suffix > 0); char part_name[MAX_PART_NAME_SIZE + 1]; List_iterator_fast it(table->part_info->partitions); for (uint cur_part= 0; cur_part < new_parts; ++cur_part, ++suffix) { uint32 cur_suffix= suffix; if (make_partition_name(part_name, suffix)) return 0; partition_element *el; it.rewind(); while ((el= it++)) { if (0 == my_strcasecmp(&my_charset_latin1, el->partition_name, part_name)) { if (make_partition_name(part_name, ++suffix)) return 0; it.rewind(); } } if (cur_part > 0 && suffix > cur_suffix) cur_part= 0; } return suffix - new_parts; } #endif #endif /* PARTITION_INFO_INCLUDED */ server/private/aria_backup.h000064400000003013151031265040012130 0ustar00/* Copyright (C) 2018,2020 MariaDB Corporation Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ /* Interfaces for doing backups of Aria tables */ C_MODE_START typedef struct st_aria_table_capabilities { my_off_t header_size; ulong bitmap_pages_covered; uint block_size; uint keypage_header; enum data_file_type data_file_type; my_bool checksum; my_bool transactional; my_bool encrypted; /* This is true if the table can be copied without any locks */ my_bool online_backup_safe; /* s3 capabilities */ ulong s3_block_size; uint8 compression; } ARIA_TABLE_CAPABILITIES; int aria_get_capabilities(File kfile, ARIA_TABLE_CAPABILITIES *cap); int aria_read_index(File kfile, ARIA_TABLE_CAPABILITIES *cap, ulonglong block, uchar *buffer); int aria_read_data(File dfile, ARIA_TABLE_CAPABILITIES *cap, ulonglong block, uchar *buffer, size_t *bytes_read); C_MODE_END server/private/sql_view.h000064400000004646151031265040011535 0ustar00#ifndef SQL_VIEW_INCLUDED #define SQL_VIEW_INCLUDED /* -*- C++ -*- */ /* Copyright (c) 2004, 2010, Oracle and/or its affiliates. Copyright (c) 2015, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "sql_class.h" /* Required by sql_lex.h */ #include "sql_lex.h" /* enum_view_create_mode, enum_drop_mode */ /* Forward declarations */ class File_parser; /* Function declarations */ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, enum_view_create_mode mode); bool mysql_create_view(THD *thd, TABLE_LIST *view, enum_view_create_mode mode); bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, bool open_view_no_parse); bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode); bool check_key_in_view(THD *thd, TABLE_LIST * view); bool insert_view_fields(THD *thd, List *list, TABLE_LIST *view); int view_checksum(THD *thd, TABLE_LIST *view); int view_check(THD *thd, TABLE_LIST *view, HA_CHECK_OPT *check_opt); int view_repair(THD *thd, TABLE_LIST *view, HA_CHECK_OPT *check_opt); extern TYPELIB updatable_views_with_limit_typelib; bool check_duplicate_names(THD *thd, List& item_list, bool gen_unique_view_names); bool mysql_rename_view(THD *thd, const LEX_CSTRING *new_db, const LEX_CSTRING *new_name, const LEX_CSTRING *old_db, const LEX_CSTRING *old_name); void make_valid_column_names(THD *thd, List &item_list); #define VIEW_ANY_ACL (SELECT_ACL | UPDATE_ACL | INSERT_ACL | DELETE_ACL) extern const LEX_CSTRING view_type; void make_valid_column_names(List &item_list); bool mariadb_view_version_get(TABLE_SHARE *share); #endif /* SQL_VIEW_INCLUDED */ server/private/my_atomic.h000064400000016161151031265040011660 0ustar00#ifndef MY_ATOMIC_INCLUDED #define MY_ATOMIC_INCLUDED /* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2018, 2022, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This header defines five atomic operations: my_atomic_add#(&var, what) my_atomic_add#_explicit(&var, what, memory_order) 'Fetch and Add' add 'what' to *var, and return the old value of *var All memory orders are valid. my_atomic_fas#(&var, what) my_atomic_fas#_explicit(&var, what, memory_order) 'Fetch And Store' store 'what' in *var, and return the old value of *var All memory orders are valid. my_atomic_cas#(&var, &old, new) my_atomic_cas#_weak_explicit(&var, &old, new, succ, fail) my_atomic_cas#_strong_explicit(&var, &old, new, succ, fail) 'Compare And Swap' if *var is equal to *old, then store 'new' in *var, and return TRUE otherwise store *var in *old, and return FALSE succ - the memory synchronization ordering for the read-modify-write operation if the comparison succeeds. All memory orders are valid. fail - the memory synchronization ordering for the load operation if the comparison fails. Cannot be MY_MEMORY_ORDER_RELEASE or MY_MEMORY_ORDER_ACQ_REL and cannot specify stronger ordering than succ. The weak form is allowed to fail spuriously, that is, act as if *var != *old even if they are equal. When a compare-and-exchange is in a loop, the weak version will yield better performance on some platforms. When a weak compare-and-exchange would require a loop and a strong one would not, the strong one is preferable. my_atomic_load#(&var) my_atomic_load#_explicit(&var, memory_order) return *var Order must be one of MY_MEMORY_ORDER_RELAXED, MY_MEMORY_ORDER_CONSUME, MY_MEMORY_ORDER_ACQUIRE, MY_MEMORY_ORDER_SEQ_CST. my_atomic_store#(&var, what) my_atomic_store#_explicit(&var, what, memory_order) store 'what' in *var Order must be one of MY_MEMORY_ORDER_RELAXED, MY_MEMORY_ORDER_RELEASE, MY_MEMORY_ORDER_SEQ_CST. '#' is substituted by a size suffix - 8, 16, 32, 64, or ptr (e.g. my_atomic_add8, my_atomic_fas32, my_atomic_casptr). The first version orders memory accesses according to MY_MEMORY_ORDER_SEQ_CST, the second version (with _explicit suffix) orders memory accesses according to given memory order. memory_order specifies how non-atomic memory accesses are to be ordered around an atomic operation: MY_MEMORY_ORDER_RELAXED - there are no constraints on reordering of memory accesses around the atomic variable. MY_MEMORY_ORDER_CONSUME - no reads in the current thread dependent on the value currently loaded can be reordered before this load. This ensures that writes to dependent variables in other threads that release the same atomic variable are visible in the current thread. On most platforms, this affects compiler optimization only. MY_MEMORY_ORDER_ACQUIRE - no reads in the current thread can be reordered before this load. This ensures that all writes in other threads that release the same atomic variable are visible in the current thread. MY_MEMORY_ORDER_RELEASE - no writes in the current thread can be reordered after this store. This ensures that all writes in the current thread are visible in other threads that acquire the same atomic variable. MY_MEMORY_ORDER_ACQ_REL - no reads in the current thread can be reordered before this load as well as no writes in the current thread can be reordered after this store. The operation is read-modify-write operation. It is ensured that all writes in another threads that release the same atomic variable are visible before the modification and the modification is visible in other threads that acquire the same atomic variable. MY_MEMORY_ORDER_SEQ_CST - The operation has the same semantics as acquire-release operation, and additionally has sequentially-consistent operation ordering. We choose implementation as follows: on Windows using Visual C++ the native implementation should be preferable. When using gcc we prefer the Solaris implementation before the gcc because of stability preference, we choose gcc builtins if available. */ #if defined(_MSC_VER) #include "atomic/generic-msvc.h" #elif defined(HAVE_SOLARIS_ATOMIC) #include "atomic/solaris.h" #elif defined(HAVE_GCC_C11_ATOMICS) #include "atomic/gcc_builtins.h" #endif #ifndef MY_MEMORY_ORDER_SEQ_CST #define MY_MEMORY_ORDER_RELAXED #define MY_MEMORY_ORDER_CONSUME #define MY_MEMORY_ORDER_ACQUIRE #define MY_MEMORY_ORDER_RELEASE #define MY_MEMORY_ORDER_ACQ_REL #define MY_MEMORY_ORDER_SEQ_CST #define my_atomic_store32_explicit(P, D, O) my_atomic_store32((P), (D)) #define my_atomic_store64_explicit(P, D, O) my_atomic_store64((P), (D)) #define my_atomic_storeptr_explicit(P, D, O) my_atomic_storeptr((P), (D)) #define my_atomic_load32_explicit(P, O) my_atomic_load32((P)) #define my_atomic_load64_explicit(P, O) my_atomic_load64((P)) #define my_atomic_loadptr_explicit(P, O) my_atomic_loadptr((P)) #define my_atomic_fas32_explicit(P, D, O) my_atomic_fas32((P), (D)) #define my_atomic_fas64_explicit(P, D, O) my_atomic_fas64((P), (D)) #define my_atomic_fasptr_explicit(P, D, O) my_atomic_fasptr((P), (D)) #define my_atomic_add32_explicit(P, A, O) my_atomic_add32((P), (A)) #define my_atomic_add64_explicit(P, A, O) my_atomic_add64((P), (A)) #define my_atomic_addptr_explicit(P, A, O) my_atomic_addptr((P), (A)) #define my_atomic_cas32_weak_explicit(P, E, D, S, F) \ my_atomic_cas32((P), (E), (D)) #define my_atomic_cas64_weak_explicit(P, E, D, S, F) \ my_atomic_cas64((P), (E), (D)) #define my_atomic_casptr_weak_explicit(P, E, D, S, F) \ my_atomic_casptr((P), (E), (D)) #define my_atomic_cas32_strong_explicit(P, E, D, S, F) \ my_atomic_cas32((P), (E), (D)) #define my_atomic_cas64_strong_explicit(P, E, D, S, F) \ my_atomic_cas64((P), (E), (D)) #define my_atomic_casptr_strong_explicit(P, E, D, S, F) \ my_atomic_casptr((P), (E), (D)) #endif #endif /* MY_ATOMIC_INCLUDED */ server/private/win_tzname_data.h000064400000014552151031265040013045 0ustar00/* This file was generated using gen_win_tzname_data.ps1 */ {L"Dateline Standard Time","Etc/GMT+12"}, {L"UTC-11","Etc/GMT+11"}, {L"Aleutian Standard Time","America/Adak"}, {L"Hawaiian Standard Time","Pacific/Honolulu"}, {L"Marquesas Standard Time","Pacific/Marquesas"}, {L"Alaskan Standard Time","America/Anchorage"}, {L"UTC-09","Etc/GMT+9"}, {L"Pacific Standard Time (Mexico)","America/Tijuana"}, {L"UTC-08","Etc/GMT+8"}, {L"Pacific Standard Time","America/Los_Angeles"}, {L"US Mountain Standard Time","America/Phoenix"}, {L"Mountain Standard Time (Mexico)","America/Mazatlan"}, {L"Mountain Standard Time","America/Denver"}, {L"Yukon Standard Time","America/Whitehorse"}, {L"Central America Standard Time","America/Guatemala"}, {L"Central Standard Time","America/Chicago"}, {L"Easter Island Standard Time","Pacific/Easter"}, {L"Central Standard Time (Mexico)","America/Mexico_City"}, {L"Canada Central Standard Time","America/Regina"}, {L"SA Pacific Standard Time","America/Bogota"}, {L"Eastern Standard Time (Mexico)","America/Cancun"}, {L"Eastern Standard Time","America/New_York"}, {L"Haiti Standard Time","America/Port-au-Prince"}, {L"Cuba Standard Time","America/Havana"}, {L"US Eastern Standard Time","America/Indianapolis"}, {L"Turks And Caicos Standard Time","America/Grand_Turk"}, {L"Paraguay Standard Time","America/Asuncion"}, {L"Atlantic Standard Time","America/Halifax"}, {L"Venezuela Standard Time","America/Caracas"}, {L"Central Brazilian Standard Time","America/Cuiaba"}, {L"SA Western Standard Time","America/La_Paz"}, {L"Pacific SA Standard Time","America/Santiago"}, {L"Newfoundland Standard Time","America/St_Johns"}, {L"Tocantins Standard Time","America/Araguaina"}, {L"E. South America Standard Time","America/Sao_Paulo"}, {L"SA Eastern Standard Time","America/Cayenne"}, {L"Argentina Standard Time","America/Buenos_Aires"}, {L"Greenland Standard Time","America/Godthab"}, {L"Montevideo Standard Time","America/Montevideo"}, {L"Magallanes Standard Time","America/Punta_Arenas"}, {L"Saint Pierre Standard Time","America/Miquelon"}, {L"Bahia Standard Time","America/Bahia"}, {L"UTC-02","Etc/GMT+2"}, {L"Azores Standard Time","Atlantic/Azores"}, {L"Cape Verde Standard Time","Atlantic/Cape_Verde"}, {L"UTC","Etc/UTC"}, {L"GMT Standard Time","Europe/London"}, {L"Greenwich Standard Time","Atlantic/Reykjavik"}, {L"Sao Tome Standard Time","Africa/Sao_Tome"}, {L"Morocco Standard Time","Africa/Casablanca"}, {L"W. Europe Standard Time","Europe/Berlin"}, {L"Central Europe Standard Time","Europe/Budapest"}, {L"Romance Standard Time","Europe/Paris"}, {L"Central European Standard Time","Europe/Warsaw"}, {L"W. Central Africa Standard Time","Africa/Lagos"}, {L"Jordan Standard Time","Asia/Amman"}, {L"GTB Standard Time","Europe/Bucharest"}, {L"Middle East Standard Time","Asia/Beirut"}, {L"Egypt Standard Time","Africa/Cairo"}, {L"E. Europe Standard Time","Europe/Chisinau"}, {L"Syria Standard Time","Asia/Damascus"}, {L"West Bank Standard Time","Asia/Hebron"}, {L"South Africa Standard Time","Africa/Johannesburg"}, {L"FLE Standard Time","Europe/Kiev"}, {L"Israel Standard Time","Asia/Jerusalem"}, {L"South Sudan Standard Time","Africa/Juba"}, {L"Kaliningrad Standard Time","Europe/Kaliningrad"}, {L"Sudan Standard Time","Africa/Khartoum"}, {L"Libya Standard Time","Africa/Tripoli"}, {L"Namibia Standard Time","Africa/Windhoek"}, {L"Arabic Standard Time","Asia/Baghdad"}, {L"Turkey Standard Time","Europe/Istanbul"}, {L"Arab Standard Time","Asia/Riyadh"}, {L"Belarus Standard Time","Europe/Minsk"}, {L"Russian Standard Time","Europe/Moscow"}, {L"E. Africa Standard Time","Africa/Nairobi"}, {L"Iran Standard Time","Asia/Tehran"}, {L"Arabian Standard Time","Asia/Dubai"}, {L"Astrakhan Standard Time","Europe/Astrakhan"}, {L"Azerbaijan Standard Time","Asia/Baku"}, {L"Russia Time Zone 3","Europe/Samara"}, {L"Mauritius Standard Time","Indian/Mauritius"}, {L"Saratov Standard Time","Europe/Saratov"}, {L"Georgian Standard Time","Asia/Tbilisi"}, {L"Volgograd Standard Time","Europe/Volgograd"}, {L"Caucasus Standard Time","Asia/Yerevan"}, {L"Afghanistan Standard Time","Asia/Kabul"}, {L"West Asia Standard Time","Asia/Tashkent"}, {L"Ekaterinburg Standard Time","Asia/Yekaterinburg"}, {L"Pakistan Standard Time","Asia/Karachi"}, {L"Qyzylorda Standard Time","Asia/Qyzylorda"}, {L"India Standard Time","Asia/Calcutta"}, {L"Sri Lanka Standard Time","Asia/Colombo"}, {L"Nepal Standard Time","Asia/Katmandu"}, {L"Central Asia Standard Time","Asia/Bishkek"}, {L"Bangladesh Standard Time","Asia/Dhaka"}, {L"Omsk Standard Time","Asia/Omsk"}, {L"Myanmar Standard Time","Asia/Rangoon"}, {L"SE Asia Standard Time","Asia/Bangkok"}, {L"Altai Standard Time","Asia/Barnaul"}, {L"W. Mongolia Standard Time","Asia/Hovd"}, {L"North Asia Standard Time","Asia/Krasnoyarsk"}, {L"N. Central Asia Standard Time","Asia/Novosibirsk"}, {L"Tomsk Standard Time","Asia/Tomsk"}, {L"China Standard Time","Asia/Shanghai"}, {L"North Asia East Standard Time","Asia/Irkutsk"}, {L"Singapore Standard Time","Asia/Singapore"}, {L"W. Australia Standard Time","Australia/Perth"}, {L"Taipei Standard Time","Asia/Taipei"}, {L"Ulaanbaatar Standard Time","Asia/Ulaanbaatar"}, {L"Aus Central W. Standard Time","Australia/Eucla"}, {L"Transbaikal Standard Time","Asia/Chita"}, {L"Tokyo Standard Time","Asia/Tokyo"}, {L"North Korea Standard Time","Asia/Pyongyang"}, {L"Korea Standard Time","Asia/Seoul"}, {L"Yakutsk Standard Time","Asia/Yakutsk"}, {L"Cen. Australia Standard Time","Australia/Adelaide"}, {L"AUS Central Standard Time","Australia/Darwin"}, {L"E. Australia Standard Time","Australia/Brisbane"}, {L"AUS Eastern Standard Time","Australia/Sydney"}, {L"West Pacific Standard Time","Pacific/Port_Moresby"}, {L"Tasmania Standard Time","Australia/Hobart"}, {L"Vladivostok Standard Time","Asia/Vladivostok"}, {L"Lord Howe Standard Time","Australia/Lord_Howe"}, {L"Bougainville Standard Time","Pacific/Bougainville"}, {L"Russia Time Zone 10","Asia/Srednekolymsk"}, {L"Magadan Standard Time","Asia/Magadan"}, {L"Norfolk Standard Time","Pacific/Norfolk"}, {L"Sakhalin Standard Time","Asia/Sakhalin"}, {L"Central Pacific Standard Time","Pacific/Guadalcanal"}, {L"Russia Time Zone 11","Asia/Kamchatka"}, {L"New Zealand Standard Time","Pacific/Auckland"}, {L"UTC+12","Etc/GMT-12"}, {L"Fiji Standard Time","Pacific/Fiji"}, {L"Chatham Islands Standard Time","Pacific/Chatham"}, {L"UTC+13","Etc/GMT-13"}, {L"Tonga Standard Time","Pacific/Tongatapu"}, {L"Samoa Standard Time","Pacific/Apia"}, {L"Line Islands Standard Time","Pacific/Kiritimati"}, server/private/sql_digest_stream.h000064400000003037151031265040013406 0ustar00/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_DIGEST_STREAM_H #define SQL_DIGEST_STREAM_H #include "sql_digest.h" /** State data storage for @c digest_start, @c digest_add_token. This structure extends the @c sql_digest_storage structure with temporary state used only during parsing. */ struct sql_digest_state { /** Index, in the digest token array, of the last identifier seen. Reduce rules used in the digest computation can not apply to tokens seen before an identifier. @sa digest_add_token */ int m_last_id_index; sql_digest_storage m_digest_storage; inline void reset(unsigned char *token_array, uint length) { m_last_id_index= 0; m_digest_storage.reset(token_array, length); } inline bool is_empty() { return m_digest_storage.is_empty(); } }; typedef struct sql_digest_state sql_digest_state; #endif server/private/password.h000064400000002222151031265040011532 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef PASSWORD_INCLUDED #define PASSWORD_INCLUDED C_MODE_START void my_make_scrambled_password_323(char *to, const char *password, size_t pass_len); void my_make_scrambled_password(char *to, const char *password, size_t pass_len); void hash_password(ulong *result, const char *password, uint password_len); C_MODE_END #endif /* PASSWORD_INCLUDED */ server/private/set_var.h000064400000040247151031265040011344 0ustar00#ifndef SET_VAR_INCLUDED #define SET_VAR_INCLUDED /* Copyright (c) 2002, 2013, Oracle and/or its affiliates. Copyright (c) 2009, 2020, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file "public" interface to sys_var - server configuration variables. */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include #include class sys_var; class set_var; class sys_var_pluginvar; class PolyLock; class Item_func_set_user_var; // This include needs to be here since item.h requires enum_var_type :-P #include "item.h" /* Item */ #include "sql_class.h" /* THD */ extern TYPELIB bool_typelib; struct sys_var_chain { sys_var *first; sys_var *last; }; int mysql_add_sys_var_chain(sys_var *chain); int mysql_del_sys_var_chain(sys_var *chain); /** A class representing one system variable - that is something that can be accessed as @@global.variable_name or @@session.variable_name, visible in SHOW xxx VARIABLES and in INFORMATION_SCHEMA.xxx_VARIABLES, optionally it can be assigned to, optionally it can have a command-line counterpart with the same name. */ class sys_var: protected Value_source // for double_from_string_with_check { public: sys_var *next; LEX_CSTRING name; bool *test_load; enum flag_enum { GLOBAL, SESSION, ONLY_SESSION, SCOPE_MASK=1023, READONLY=1024, ALLOCATED=2048, PARSE_EARLY=4096, NO_SET_STATEMENT=8192, AUTO_SET=16384}; enum { NO_GETOPT=-1, GETOPT_ONLY_HELP=-2 }; enum where { CONFIG, COMMAND_LINE, AUTO, SQL, COMPILE_TIME, ENV }; /** Enumeration type to indicate for a system variable whether it will be written to the binlog or not. */ enum binlog_status_enum { VARIABLE_NOT_IN_BINLOG, SESSION_VARIABLE_IN_BINLOG } binlog_status; my_option option; ///< min, max, default values are stored here enum where value_origin; const char *origin_filename; protected: typedef bool (*on_check_function)(sys_var *self, THD *thd, set_var *var); typedef bool (*on_update_function)(sys_var *self, THD *thd, enum_var_type type); int flags; ///< or'ed flag_enum values const SHOW_TYPE show_val_type; ///< what value_ptr() returns for sql_show.cc PolyLock *guard; ///< *second* lock that protects the variable ptrdiff_t offset; ///< offset to the value from global_system_variables on_check_function on_check; on_update_function on_update; const char *const deprecation_substitute; public: sys_var(sys_var_chain *chain, const char *name_arg, const char *comment, int flag_args, ptrdiff_t off, int getopt_id, enum get_opt_arg_type getopt_arg_type, SHOW_TYPE show_val_type_arg, longlong def_val, PolyLock *lock, enum binlog_status_enum binlog_status_arg, on_check_function on_check_func, on_update_function on_update_func, const char *substitute); virtual ~sys_var() = default; /** All the cleanup procedures should be performed here */ virtual void cleanup() {} /** downcast for sys_var_pluginvar. Returns this if it's an instance of sys_var_pluginvar, and 0 otherwise. */ virtual sys_var_pluginvar *cast_pluginvar() { return 0; } bool check(THD *thd, set_var *var); const uchar *value_ptr(THD *thd, enum_var_type type, const LEX_CSTRING *base) const; /** Update the system variable with the default value from either session or global scope. The default value is stored in the 'var' argument. Return false when successful. */ bool set_default(THD *thd, set_var *var); bool update(THD *thd, set_var *var); String *val_str_nolock(String *str, THD *thd, const uchar *value); longlong val_int(bool *is_null, THD *thd, enum_var_type type, const LEX_CSTRING *base); String *val_str(String *str, THD *thd, enum_var_type type, const LEX_CSTRING *base); double val_real(bool *is_null, THD *thd, enum_var_type type, const LEX_CSTRING *base); SHOW_TYPE show_type() const { return show_val_type; } int scope() const { return flags & SCOPE_MASK; } virtual CHARSET_INFO *charset(THD *thd) const { return system_charset_info; } bool is_readonly() const { return flags & READONLY; } /** the following is only true for keycache variables, that support the syntax @@keycache_name.variable_name */ bool is_struct() { return option.var_type & GET_ASK_ADDR; } bool is_set_stmt_ok() const { return !(flags & NO_SET_STATEMENT); } bool is_written_to_binlog(enum_var_type type) { return type != OPT_GLOBAL && binlog_status == SESSION_VARIABLE_IN_BINLOG; } bool check_update_type(const Item *item) { Item_result type= item->result_type(); switch (option.var_type & GET_TYPE_MASK) { case GET_INT: case GET_UINT: case GET_LONG: case GET_ULONG: case GET_LL: case GET_ULL: return type != INT_RESULT && (type != DECIMAL_RESULT || item->decimals != 0); case GET_STR: case GET_STR_ALLOC: return type != STRING_RESULT; case GET_ENUM: case GET_BOOL: case GET_SET: case GET_FLAGSET: case GET_BIT: return type != STRING_RESULT && type != INT_RESULT; case GET_DOUBLE: return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT; default: return true; } } bool check_type(enum_var_type type) { switch (scope()) { case GLOBAL: return type != OPT_GLOBAL; case SESSION: return false; // always ok case ONLY_SESSION: return type == OPT_GLOBAL; } return true; // keep gcc happy } bool register_option(DYNAMIC_ARRAY *array, int parse_flags) { DBUG_ASSERT(parse_flags == GETOPT_ONLY_HELP || parse_flags == PARSE_EARLY || parse_flags == 0); if (option.id == NO_GETOPT) return 0; if (parse_flags == GETOPT_ONLY_HELP) { if (option.id != GETOPT_ONLY_HELP) return 0; } else { if (option.id == GETOPT_ONLY_HELP) return 0; if ((flags & PARSE_EARLY) != parse_flags) return 0; } return insert_dynamic(array, (uchar*)&option); } void do_deprecated_warning(THD *thd); /** whether session value of a sysvar is a default one. in this simple implementation we don't distinguish between default and non-default values. for most variables it's ok, they don't treat default values specially. this method is overwritten in descendant classes as necessary. */ virtual bool session_is_default(THD *thd) { return false; } virtual const uchar *default_value_ptr(THD *thd) const { return (uchar*)&option.def_value; } virtual bool on_check_access_global(THD *thd) const; virtual bool on_check_access_session(THD *thd) const { return false; } private: virtual bool do_check(THD *thd, set_var *var) = 0; /** save the session default value of the variable in var */ virtual void session_save_default(THD *thd, set_var *var) = 0; /** save the global default value of the variable in var */ virtual void global_save_default(THD *thd, set_var *var) = 0; virtual bool session_update(THD *thd, set_var *var) = 0; virtual bool global_update(THD *thd, set_var *var) = 0; protected: /** A pointer to a value of the variable for SHOW. It must be of show_val_type type (my_bool for SHOW_MY_BOOL, int for SHOW_INT, longlong for SHOW_LONGLONG, etc). */ virtual const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const; virtual const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const; /** A pointer to a storage area of the variable, to the raw data. Typically it's the same as session_value_ptr(), but it's different, for example, for ENUM, that is printed as a string, but stored as a number. */ ATTRIBUTE_NO_UBSAN uchar *session_var_ptr(THD *thd) const { return ((uchar*)&(thd->variables)) + offset; } ATTRIBUTE_NO_UBSAN uchar *global_var_ptr() const { return ((uchar*)&global_system_variables) + offset; } void *max_var_ptr() { return scope() == SESSION ? (((uchar*)&max_system_variables) + offset) : 0; } friend class Session_sysvars_tracker; friend class Session_tracker; }; #include "sql_plugin.h" /* SHOW_HA_ROWS, SHOW_MY_BOOL */ /**************************************************************************** Classes for parsing of the SET command ****************************************************************************/ /** A base class for everything that can be set with SET command. It's similar to Items, an instance of this is created by the parser for every assigmnent in SET (or elsewhere, e.g. in SELECT). */ class set_var_base :public Sql_alloc { public: set_var_base() = default; virtual ~set_var_base() = default; virtual int check(THD *thd)=0; /* To check privileges etc. */ virtual int update(THD *thd)=0; /* To set the value */ virtual int light_check(THD *thd) { return check(thd); } /* for PS */ virtual bool is_system() { return FALSE; } /** @returns whether this variable is @@@@optimizer_trace. */ virtual bool is_var_optimizer_trace() const { return false; } }; /** Structure for holding unix timestamp and high precision second part. */ typedef struct my_time_t_hires { my_time_t unix_time; ulong second_part; } my_time_t_hires; /** set_var_base descendant for assignments to the system variables. */ class set_var :public set_var_base { public: sys_var *var; ///< system variable to be updated Item *value; ///< the expression that provides the new value of the variable enum_var_type type; union ///< temp storage to hold a value between sys_var::check and ::update { ulonglong ulonglong_value; ///< for unsigned integer, set, enum sysvars longlong longlong_value; ///< for signed integer double double_value; ///< for Sys_var_double plugin_ref plugin; ///< for Sys_var_plugin plugin_ref *plugins; ///< for Sys_var_pluginlist Time_zone *time_zone; ///< for Sys_var_tz LEX_STRING string_value; ///< for Sys_var_charptr and others my_time_t_hires timestamp; ///< for Sys_var_vers_asof const void *ptr; ///< for Sys_var_struct } save_result; LEX_CSTRING base; /**< for structured variables, like keycache_name.variable_name */ set_var(THD *thd, enum_var_type type_arg, sys_var *var_arg, const LEX_CSTRING *base_name_arg, Item *value_arg); bool is_system() override { return 1; } int check(THD *thd) override; int update(THD *thd) override; int light_check(THD *thd) override; bool is_var_optimizer_trace() const override { extern sys_var *Sys_optimizer_trace_ptr; return var == Sys_optimizer_trace_ptr; } }; /* User variables like @my_own_variable */ class set_var_user: public set_var_base { Item_func_set_user_var *user_var_item; public: set_var_user(Item_func_set_user_var *item) :user_var_item(item) {} int check(THD *thd) override; int update(THD *thd) override; int light_check(THD *thd) override; }; /* For SET PASSWORD */ class set_var_password: public set_var_base { LEX_USER *user; public: set_var_password(LEX_USER *user_arg) :user(user_arg) {} int check(THD *thd) override; int update(THD *thd) override; }; /* For SET ROLE */ class set_var_role: public set_var_base { LEX_CSTRING role; privilege_t access; public: set_var_role(LEX_CSTRING role_arg) : role(role_arg), access(NO_ACL) {} int check(THD *thd) override; int update(THD *thd) override; }; /* For SET DEFAULT ROLE */ class set_var_default_role: public set_var_base { LEX_USER *user, *real_user; LEX_CSTRING role; const char *real_role; public: set_var_default_role(LEX_USER *user_arg, LEX_CSTRING role_arg) : user(user_arg), role(role_arg) {} int check(THD *thd) override; int update(THD *thd) override; }; /* For SET NAMES and SET CHARACTER SET */ class set_var_collation_client: public set_var_base { CHARSET_INFO *character_set_client; CHARSET_INFO *character_set_results; CHARSET_INFO *collation_connection; public: set_var_collation_client(CHARSET_INFO *client_coll_arg, CHARSET_INFO *connection_coll_arg, CHARSET_INFO *result_coll_arg) :character_set_client(client_coll_arg), character_set_results(result_coll_arg), collation_connection(connection_coll_arg) {} int check(THD *thd) override; int update(THD *thd) override; }; /* optional things, have_* variables */ extern SHOW_COMP_OPTION have_csv, have_innodb; extern SHOW_COMP_OPTION have_ndbcluster, have_partitioning; extern SHOW_COMP_OPTION have_profiling; extern SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen; extern SHOW_COMP_OPTION have_query_cache; extern SHOW_COMP_OPTION have_geometry, have_rtree_keys; extern SHOW_COMP_OPTION have_crypt; extern SHOW_COMP_OPTION have_compress; extern SHOW_COMP_OPTION have_openssl; /* Prototypes for helper functions */ ulong get_system_variable_hash_records(void); ulonglong get_system_variable_hash_version(void); SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type); int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond); sys_var *find_sys_var(THD *thd, const char *str, size_t length= 0, bool throw_error= false); int sql_set_variables(THD *thd, List *var_list, bool free); #define SYSVAR_AUTOSIZE(VAR,VAL) \ do { \ VAR= (VAL); \ set_sys_var_value_origin(&VAR, sys_var::AUTO); \ } while(0) #define SYSVAR_AUTOSIZE_IF_CHANGED(VAR,VAL,TYPE) \ do { \ TYPE tmp= (VAL); \ if (VAR != tmp) \ { \ VAR= (VAL); \ set_sys_var_value_origin(&VAR, sys_var::AUTO); \ } \ } while(0) void set_sys_var_value_origin(void *ptr, enum sys_var::where here, const char *filename= NULL); enum sys_var::where get_sys_var_value_origin(void *ptr); inline bool IS_SYSVAR_AUTOSIZE(void *ptr) { enum sys_var::where res= get_sys_var_value_origin(ptr); return (res == sys_var::AUTO || res == sys_var::COMPILE_TIME); } bool fix_delay_key_write(sys_var *self, THD *thd, enum_var_type type); sql_mode_t expand_sql_mode(sql_mode_t sql_mode); const char *sql_mode_string_representation(uint bit_number); bool sql_mode_string_representation(THD *thd, sql_mode_t sql_mode, LEX_CSTRING *ls); int default_regex_flags_pcre(THD *thd); extern sys_var *Sys_autocommit_ptr, *Sys_last_gtid_ptr, *Sys_character_set_client_ptr, *Sys_character_set_connection_ptr, *Sys_character_set_results_ptr; CHARSET_INFO *get_old_charset_by_name(const char *old_name); int sys_var_init(); uint sys_var_elements(); int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags); void sys_var_end(void); bool check_has_super(sys_var *self, THD *thd, set_var *var); plugin_ref *resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len, bool error_on_unknown_engine, bool temp_copy); void free_engine_list(plugin_ref *list); plugin_ref *copy_engine_list(plugin_ref *list); plugin_ref *temp_copy_engine_list(THD *thd, plugin_ref *list); char *pretty_print_engine_list(THD *thd, plugin_ref *list); #endif server/private/my_service_manager.h000064400000004002151031265040013525 0ustar00/* Copyright (c) 2015 Daniel Black. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MY_SERVICE_MANAGER_INCLUDED #define MY_SERVICE_MANAGER_INCLUDED #if defined(HAVE_SYSTEMD) && !defined(EMBEDDED_LIBRARY) /* sd-daemon.h may include inttypes.h. Explicitly request format macros before the first inclusion of inttypes.h. */ #if !defined(__STDC_FORMAT_MACROS) #define __STDC_FORMAT_MACROS #endif // !defined(__STDC_FORMAT_MACROS) #include /** INTERVAL in seconds followed by printf style status */ #define service_manager_extend_timeout(INTERVAL, FMTSTR, ...) \ sd_notifyf(0, "STATUS=" FMTSTR "\nEXTEND_TIMEOUT_USEC=%u\n", ##__VA_ARGS__, INTERVAL * 1000000) /* sd_listen_fds_with_names added v227 however RHEL/Centos7 has v219, fallback to sd_listen_fds */ #ifndef HAVE_SYSTEMD_SD_LISTEN_FDS_WITH_NAMES #define sd_listen_fds_with_names(FD, NAMES) sd_listen_fds(FD) #endif #else #define sd_listen_fds_with_names(FD, NAMES) (0) #define sd_is_socket_unix(FD, TYPE, LISTENING, PATH, SIZE) (0) #define sd_is_socket_inet(FD, FAMILY, TYPE, LISTENING, PORT) (0) #define SD_LISTEN_FDS_START (0) #define sd_notify(X, Y) #define sd_notifyf(E, F, ...) #ifdef _WIN32 #define service_manager_extend_timeout(I, F, ...) \ mysqld_win_extend_service_timeout(I) #else #define service_manager_extend_timeout(I, FMTSTR, ...) #endif #endif #endif /* MY_SERVICE_MANAGER_INCLUDED */ server/private/wsrep_server_service.h000064400000007057151031265040014151 0ustar00/* Copyright 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WSREP_SERVER_SERVICE_H #define WSREP_SERVER_SERVICE_H /* wsrep-lib */ #include "wsrep/server_service.hpp" #include "wsrep/exception.hpp" // not_impemented_error(), remove when finished #include "wsrep/storage_service.hpp" class Wsrep_server_state; /* wsrep::server_service interface implementation */ class Wsrep_server_service : public wsrep::server_service { public: Wsrep_server_service(Wsrep_server_state& server_state) : m_server_state(server_state) { } wsrep::storage_service* storage_service(wsrep::client_service&) override; wsrep::storage_service* storage_service(wsrep::high_priority_service&) override; void release_storage_service(wsrep::storage_service*) override; wsrep::high_priority_service* streaming_applier_service(wsrep::client_service&) override; wsrep::high_priority_service* streaming_applier_service(wsrep::high_priority_service&) override; void release_high_priority_service(wsrep::high_priority_service*) override; void background_rollback(wsrep::unique_lock &, wsrep::client_state &) override; void bootstrap() override; void log_message(enum wsrep::log::level, const char*) override; void log_dummy_write_set(wsrep::client_state&, const wsrep::ws_meta&) override { throw wsrep::not_implemented_error(); } void log_view(wsrep::high_priority_service*, const wsrep::view&) override; void recover_streaming_appliers(wsrep::client_service&) override; void recover_streaming_appliers(wsrep::high_priority_service&) override; wsrep::view get_view(wsrep::client_service&, const wsrep::id& own_id) override; wsrep::gtid get_position(wsrep::client_service&) override; void set_position(wsrep::client_service&, const wsrep::gtid&) override; void log_state_change(enum wsrep::server_state::state, enum wsrep::server_state::state) override; bool sst_before_init() const override; std::string sst_request() override; int start_sst(const std::string&, const wsrep::gtid&, bool) override; int wait_committing_transactions(int) override; void debug_sync(const char*) override; private: Wsrep_server_state& m_server_state; }; /** Helper method to create new streaming applier. @param orig_thd Original thd context to copy operation context from. @param ctx Context string for debug logging. */ class Wsrep_applier_service; Wsrep_applier_service* wsrep_create_streaming_applier(THD *orig_thd, const char *ctx); /** Helper method to create new storage service. @param orig_thd Original thd context to copy operation context from. @param ctx Context string for debug logging. */ class Wsrep_storage_service; Wsrep_storage_service* wsrep_create_storage_service(THD *orig_thd, const char *ctx); /** Suppress all error logging from wsrep/Galera library. */ void wsrep_suppress_error_logging(); #endif /* WSREP_SERVER_SERVICE */ server/private/aligned.h000064400000002160151031265040011274 0ustar00/* Copyright (c) 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #if defined __linux__ # include #endif inline void *aligned_malloc(size_t size, size_t alignment) { #ifdef _WIN32 return _aligned_malloc(size, alignment); #elif defined __linux__ return memalign(alignment, size); #else void *result; if (posix_memalign(&result, alignment, size)) result= NULL; return result; #endif } inline void aligned_free(void *ptr) { IF_WIN(_aligned_free,free)(ptr); } server/private/thr_lock.h000064400000016266151031265040011512 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* For use with thr_lock:s */ #ifndef _thr_lock_h #define _thr_lock_h #ifdef __cplusplus extern "C" { #endif #include #include struct st_thr_lock; extern ulong locks_immediate,locks_waited ; /* Important: if a new lock type is added, a matching lock description must be added to sql_test.cc's lock_descriptions array. */ enum thr_lock_type { TL_IGNORE=-1, TL_UNLOCK, /* UNLOCK ANY LOCK */ /* Parser only! At open_tables() becomes TL_READ or TL_READ_NO_INSERT depending on the binary log format (SBR/RBR) and on the table category (log table). Used for tables that are read by statements which modify tables. */ TL_READ_DEFAULT, TL_READ, /* Read lock */ TL_READ_WITH_SHARED_LOCKS, /* High prior. than TL_WRITE. Allow concurrent insert */ TL_READ_HIGH_PRIORITY, /* READ, Don't allow concurrent insert */ TL_READ_NO_INSERT, /* READ, but skip locks if found */ TL_READ_SKIP_LOCKED, /* Write lock, but allow other threads to read / write. Used by BDB tables in MySQL to mark that someone is reading/writing to the table. */ TL_WRITE_ALLOW_WRITE, /* WRITE lock used by concurrent insert. Will allow READ, if one could use concurrent insert on table. */ TL_WRITE_CONCURRENT_INSERT, /* Write used by INSERT DELAYED. Allows READ locks */ TL_WRITE_DELAYED, /* parser only! Late bound low_priority flag. At open_tables() becomes thd->update_lock_default. */ TL_WRITE_DEFAULT, /* WRITE lock that has lower priority than TL_READ */ TL_WRITE_LOW_PRIORITY, /* WRITE, but skip locks if found */ TL_WRITE_SKIP_LOCKED, /* Normal WRITE lock */ TL_WRITE, /* Abort new lock request with an error */ TL_WRITE_ONLY}; /* TL_FIRST_WRITE is here to impose some consistency in the sql layer on determining read/write transactions and to provide some API compatibility if additional transactions are added. Above or equal to TL_FIRST_WRITE is a write transaction while < TL_FIRST_WRITE is a read transaction. */ #define TL_FIRST_WRITE TL_WRITE_ALLOW_WRITE enum enum_thr_lock_result { THR_LOCK_SUCCESS= 0, THR_LOCK_ABORTED= 1, THR_LOCK_WAIT_TIMEOUT= 2, THR_LOCK_DEADLOCK= 3 }; /* Priority for locks */ #define THR_LOCK_LATE_PRIV 1U /* For locks to be merged with org lock */ #define THR_LOCK_MERGE_PRIV 2U /* For merge tables */ #define THR_UNLOCK_UPDATE_STATUS 1U extern ulong max_write_lock_count; extern my_bool thr_lock_inited; extern enum thr_lock_type thr_upgraded_concurrent_insert_lock; /* A description of the thread which owns the lock. The address of an instance of this structure is used to uniquely identify the thread. */ typedef struct st_thr_lock_info { pthread_t thread; my_thread_id thread_id; void *mysql_thd; // THD pointer } THR_LOCK_INFO; typedef struct st_thr_lock_data { THR_LOCK_INFO *owner; struct st_thr_lock_data *next,**prev; struct st_thr_lock *lock; mysql_cond_t *cond; void *status_param; /* Param to status functions */ void *debug_print_param; /* For error messages */ struct PSI_table *m_psi; enum thr_lock_type type; enum thr_lock_type org_type; /* Cache for MariaDB */ uint priority; } THR_LOCK_DATA; struct st_lock_list { THR_LOCK_DATA *data,**last; }; typedef struct st_thr_lock { LIST list; mysql_mutex_t mutex; struct st_lock_list read_wait; struct st_lock_list read; struct st_lock_list write_wait; struct st_lock_list write; /* write_lock_count is incremented for write locks and reset on read locks */ ulong write_lock_count; uint read_no_write_count; my_bool (*get_status)(void*, my_bool);/* Called when one gets a lock */ void (*copy_status)(void*,void*); void (*update_status)(void*); /* Before release of write */ void (*restore_status)(void*); /* Before release of read */ my_bool (*start_trans)(void*); /* When all locks are taken */ my_bool (*check_status)(void *); void (*fix_status)(void *, void *);/* For thr_merge_locks() */ const char *name; /* Used for error reporting */ my_bool allow_multiple_concurrent_insert; } THR_LOCK; extern LIST *thr_lock_thread_list; extern mysql_mutex_t THR_LOCK_lock; struct st_my_thread_var; my_bool init_thr_lock(void); /* Must be called once/thread */ void thr_lock_info_init(THR_LOCK_INFO *info, struct st_my_thread_var *tmp); void thr_lock_init(THR_LOCK *lock); void thr_lock_delete(THR_LOCK *lock); void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *status_param); void thr_unlock(THR_LOCK_DATA *data, uint unlock_flags); enum enum_thr_lock_result thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_INFO *owner, ulong lock_wait_timeout); void thr_multi_unlock(THR_LOCK_DATA **data,uint count, uint unlock_flags); void thr_merge_locks(THR_LOCK_DATA **data, uint org_count, uint new_count); void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock); my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread); void thr_print_locks(void); /* For debugging */ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data, enum thr_lock_type new_lock_type, ulong lock_wait_timeout); void thr_downgrade_write_lock(THR_LOCK_DATA *data, enum thr_lock_type new_lock_type); my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data, ulong lock_wait_timeout); void thr_set_lock_wait_callback(void (*before_wait)(void), void (*after_wait)(void)); #ifdef WITH_WSREP typedef my_bool (* wsrep_thd_is_brute_force_fun)(const MYSQL_THD, my_bool); typedef my_bool(* wsrep_abort_thd_fun)(MYSQL_THD, MYSQL_THD, my_bool); typedef my_bool (* wsrep_on_fun)(const MYSQL_THD); void wsrep_thr_lock_init( wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun, my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun); #endif #ifdef __cplusplus } #endif #endif /* _thr_lock_h */ server/private/socketpair.h000064400000001512151031265040012035 0ustar00/* Copyright (c) 2023, MariaDB Plc This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef _WIN32 C_MODE_START int create_socketpair(SOCKET socks[2]); void close_socketpair(SOCKET socks[2]); C_MODE_END #endif /* _WIN32 */ server/private/sql_reload.h000064400000002014151031265040012014 0ustar00#ifndef SQL_RELOAD_INCLUDED #define SQL_RELOAD_INCLUDED /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ class THD; struct TABLE_LIST; bool reload_acl_and_cache(THD *thd, unsigned long long options, TABLE_LIST *tables, int *write_to_binlog); bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables); #endif server/private/item_geofunc.h000064400000113770151031265040012347 0ustar00#ifndef ITEM_GEOFUNC_INCLUDED #define ITEM_GEOFUNC_INCLUDED /* Copyright (c) 2000, 2016 Oracle and/or its affiliates. Copyright (C) 2011, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file defines all spatial functions */ #ifdef HAVE_SPATIAL #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_type_geom.h" #include "item.h" #include "gstream.h" #include "spatial.h" #include "gcalc_slicescan.h" #include "gcalc_tools.h" class Item_geometry_func: public Item_str_func { public: Item_geometry_func(THD *thd): Item_str_func(thd) {} Item_geometry_func(THD *thd, Item *a): Item_str_func(thd, a) {} Item_geometry_func(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} Item_geometry_func(THD *thd, Item *a, Item *b, Item *c): Item_str_func(thd, a, b, c) {} Item_geometry_func(THD *thd, List &list): Item_str_func(thd, list) {} bool fix_length_and_dec() override; const Type_handler *type_handler() const override { return &type_handler_geometry; } }; /* Functions returning REAL measurements of a single GEOMETRY argument */ class Item_real_func_args_geometry: public Item_real_func { protected: String value; bool check_arguments() const override { DBUG_ASSERT(arg_count == 1); return Type_handler_geometry::check_type_geom_or_binary(func_name_cstring(), args[0]); } public: Item_real_func_args_geometry(THD *thd, Item *a) :Item_real_func(thd, a) {} }; /* Functions returning INT measurements of a single GEOMETRY argument */ class Item_long_func_args_geometry: public Item_long_func { bool check_arguments() const override { DBUG_ASSERT(arg_count == 1); return Type_handler_geometry::check_type_geom_or_binary(func_name_cstring(), args[0]); } protected: String value; public: Item_long_func_args_geometry(THD *thd, Item *a) :Item_long_func(thd, a) {} }; /* Functions returning BOOL measurements of a single GEOMETRY argument */ class Item_bool_func_args_geometry: public Item_bool_func { protected: String value; bool check_arguments() const override { DBUG_ASSERT(arg_count == 1); return Type_handler_geometry::check_type_geom_or_binary(func_name_cstring(), args[0]); } public: Item_bool_func_args_geometry(THD *thd, Item *a) :Item_bool_func(thd, a) {} }; /* Functions returning ASCII string measurements of a single GEOMETRY argument */ class Item_str_ascii_func_args_geometry: public Item_str_ascii_func { protected: bool check_arguments() const override { DBUG_ASSERT(arg_count >= 1); return Type_handler_geometry::check_type_geom_or_binary(func_name_cstring(), args[0]); } public: Item_str_ascii_func_args_geometry(THD *thd, Item *a) :Item_str_ascii_func(thd, a) {} Item_str_ascii_func_args_geometry(THD *thd, Item *a, Item *b) :Item_str_ascii_func(thd, a, b) {} Item_str_ascii_func_args_geometry(THD *thd, Item *a, Item *b, Item *c) :Item_str_ascii_func(thd, a, b, c) {} }; /* Functions returning binary string measurements of a single GEOMETRY argument */ class Item_binary_func_args_geometry: public Item_str_func { protected: bool check_arguments() const override { DBUG_ASSERT(arg_count >= 1); return Type_handler_geometry::check_type_geom_or_binary(func_name_cstring(), args[0]); } public: Item_binary_func_args_geometry(THD *thd, Item *a) :Item_str_func(thd, a) {} }; /* Functions returning GEOMETRY measurements of a single GEOEMETRY argument */ class Item_geometry_func_args_geometry: public Item_geometry_func { protected: bool check_arguments() const override { DBUG_ASSERT(arg_count >= 1); return Type_handler_geometry::check_type_geom_or_binary(func_name_cstring(), args[0]); } public: Item_geometry_func_args_geometry(THD *thd, Item *a) :Item_geometry_func(thd, a) {} Item_geometry_func_args_geometry(THD *thd, Item *a, Item *b) :Item_geometry_func(thd, a, b) {} }; /* Functions returning REAL result relationships between two GEOMETRY arguments */ class Item_real_func_args_geometry_geometry: public Item_real_func { protected: bool check_arguments() const override { DBUG_ASSERT(arg_count >= 2); return Type_handler_geometry::check_types_geom_or_binary(func_name_cstring(), args, 0, 2); } public: Item_real_func_args_geometry_geometry(THD *thd, Item *a, Item *b) :Item_real_func(thd, a, b) {} }; /* Functions returning BOOL result relationships between two GEOMETRY arguments */ class Item_bool_func_args_geometry_geometry: public Item_bool_func { protected: String value; bool check_arguments() const override { DBUG_ASSERT(arg_count >= 2); return Type_handler_geometry::check_types_geom_or_binary(func_name_cstring(), args, 0, 2); } public: Item_bool_func_args_geometry_geometry(THD *thd, Item *a, Item *b, Item *c) :Item_bool_func(thd, a, b, c) {} }; class Item_func_geometry_from_text: public Item_geometry_func { bool check_arguments() const override { return args[0]->check_type_general_purpose_string(func_name_cstring()) || check_argument_types_can_return_int(1, MY_MIN(2, arg_count)); } public: Item_func_geometry_from_text(THD *thd, Item *a): Item_geometry_func(thd, a) {} Item_func_geometry_from_text(THD *thd, Item *a, Item *srid): Item_geometry_func(thd, a, srid) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_geometryfromtext") }; return name; } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_geometry_from_wkb: public Item_geometry_func { bool check_arguments() const override { return Type_handler_geometry::check_type_geom_or_binary(func_name_cstring(), args[0]) || check_argument_types_can_return_int(1, MY_MIN(2, arg_count)); } public: Item_func_geometry_from_wkb(THD *thd, Item *a): Item_geometry_func(thd, a) {} Item_func_geometry_from_wkb(THD *thd, Item *a, Item *srid): Item_geometry_func(thd, a, srid) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_geometryfromwkb") }; return name; } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_geometry_from_json: public Item_geometry_func { String tmp_js; bool check_arguments() const override { // TODO: check with Alexey, for better args[1] and args[2] type control return args[0]->check_type_general_purpose_string(func_name_cstring()) || check_argument_types_traditional_scalar(1, MY_MIN(3, arg_count)); } public: Item_func_geometry_from_json(THD *thd, Item *js): Item_geometry_func(thd, js) {} Item_func_geometry_from_json(THD *thd, Item *js, Item *opt): Item_geometry_func(thd, js, opt) {} Item_func_geometry_from_json(THD *thd, Item *js, Item *opt, Item *srid): Item_geometry_func(thd, js, opt, srid) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_geomfromgeojson") }; return name; } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_as_wkt: public Item_str_ascii_func_args_geometry { public: Item_func_as_wkt(THD *thd, Item *a) :Item_str_ascii_func_args_geometry(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_astext") }; return name; } String *val_str_ascii(String *) override; bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_as_wkb: public Item_binary_func_args_geometry { public: Item_func_as_wkb(THD *thd, Item *a) :Item_binary_func_args_geometry(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_aswkb") }; return name; } String *val_str(String *) override; const Type_handler *type_handler() const override { return &type_handler_long_blob; } bool fix_length_and_dec() override { collation.set(&my_charset_bin); decimals=0; max_length= (uint32) UINT_MAX32; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_as_geojson: public Item_str_ascii_func_args_geometry { bool check_arguments() const override { // TODO: check with Alexey, for better args[1] and args[2] type control return Item_str_ascii_func_args_geometry::check_arguments() || check_argument_types_traditional_scalar(1, MY_MIN(3, arg_count)); } public: Item_func_as_geojson(THD *thd, Item *js) :Item_str_ascii_func_args_geometry(thd, js) {} Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits) :Item_str_ascii_func_args_geometry(thd, js, max_dec_digits) {} Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits, Item *opt) :Item_str_ascii_func_args_geometry(thd, js, max_dec_digits, opt) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_asgeojson") }; return name; } bool fix_length_and_dec() override; String *val_str_ascii(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_geometry_type: public Item_str_ascii_func_args_geometry { public: Item_func_geometry_type(THD *thd, Item *a) :Item_str_ascii_func_args_geometry(thd, a) {} String *val_str_ascii(String *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_geometrytype") }; return name; } bool fix_length_and_dec() override { // "GeometryCollection" is the longest fix_length_and_charset(20, default_charset()); set_maybe_null(); return FALSE; }; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; // #define HEAVY_CONVEX_HULL class Item_func_convexhull: public Item_geometry_func_args_geometry { class ch_node: public Gcalc_dyn_list::Item { public: const Gcalc_heap::Info *pi; ch_node *prev; Gcalc_dyn_list::Item *next; ch_node *get_next() { return (ch_node *) next; } }; Gcalc_heap collector; Gcalc_function func; Gcalc_dyn_list res_heap; Gcalc_result_receiver res_receiver; String tmp_value; #ifdef HEAVY_CONVEX_HULL Gcalc_scan_iterator scan_it; #endif /*HEAVY_CONVEX_HULL*/ ch_node *new_ch_node() { return (ch_node *) res_heap.new_item(); } int add_node_to_line(ch_node **p_cur, int dir, const Gcalc_heap::Info *pi); public: Item_func_convexhull(THD *thd, Item *a) :Item_geometry_func_args_geometry(thd, a), res_heap(8192, sizeof(ch_node)) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_convexhull") }; return name; } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_centroid: public Item_geometry_func_args_geometry { public: Item_func_centroid(THD *thd, Item *a) :Item_geometry_func_args_geometry(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_centroid") }; return name; } String *val_str(String *) override; const Type_handler *type_handler() const override { return &type_handler_point; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_envelope: public Item_geometry_func_args_geometry { public: Item_func_envelope(THD *thd, Item *a) :Item_geometry_func_args_geometry(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_envelope") }; return name; } String *val_str(String *) override; const Type_handler *type_handler() const override { return &type_handler_polygon; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_boundary: public Item_geometry_func_args_geometry { class Transporter : public Gcalc_shape_transporter { Gcalc_result_receiver *m_receiver; uint n_points; Gcalc_function::shape_type current_type; double last_x, last_y; public: Transporter(Gcalc_result_receiver *receiver) : Gcalc_shape_transporter(NULL), m_receiver(receiver) {} int single_point(double x, double y) override; int start_line() override; int complete_line() override; int start_poly() override; int complete_poly() override; int start_ring() override; int complete_ring() override; int add_point(double x, double y) override; int start_collection(int n_objects) override; }; Gcalc_result_receiver res_receiver; public: Item_func_boundary(THD *thd, Item *a) :Item_geometry_func_args_geometry(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_boundary") }; return name; } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_point: public Item_geometry_func { bool check_arguments() const override { return check_argument_types_can_return_real(0, 2); } public: Item_func_point(THD *thd, Item *a, Item *b): Item_geometry_func(thd, a, b) {} Item_func_point(THD *thd, Item *a, Item *b, Item *srid): Item_geometry_func(thd, a, b, srid) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("point") }; return name; } String *val_str(String *) override; const Type_handler *type_handler() const override { return &type_handler_point; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_spatial_decomp: public Item_geometry_func_args_geometry { enum Functype decomp_func; public: Item_func_spatial_decomp(THD *thd, Item *a, Item_func::Functype ft): Item_geometry_func_args_geometry(thd, a) { decomp_func = ft; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING startpoint= {STRING_WITH_LEN("st_startpoint") }; static LEX_CSTRING endpoint= {STRING_WITH_LEN("st_endpoint") }; static LEX_CSTRING exteriorring= {STRING_WITH_LEN("st_exteriorring") }; static LEX_CSTRING unknown= {STRING_WITH_LEN("spatial_decomp_unknown") }; switch (decomp_func) { case SP_STARTPOINT: return startpoint; case SP_ENDPOINT: return endpoint; case SP_EXTERIORRING: return exteriorring; default: DBUG_ASSERT(0); // Should never happened return unknown; } } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_spatial_decomp_n: public Item_geometry_func_args_geometry { enum Functype decomp_func_n; bool check_arguments() const override { return Item_geometry_func_args_geometry::check_arguments() || args[1]->check_type_can_return_int(func_name_cstring()); } public: Item_func_spatial_decomp_n(THD *thd, Item *a, Item *b, Item_func::Functype ft) :Item_geometry_func_args_geometry(thd, a, b), decomp_func_n(ft) { } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING pointn= {STRING_WITH_LEN("st_pointn") }; static LEX_CSTRING geometryn= {STRING_WITH_LEN("st_geometryn") }; static LEX_CSTRING interiorringn= {STRING_WITH_LEN("st_interiorringn") }; static LEX_CSTRING unknown= {STRING_WITH_LEN("spatial_decomp_unknown") }; switch (decomp_func_n) { case SP_POINTN: return pointn; case SP_GEOMETRYN: return geometryn; case SP_INTERIORRINGN: return interiorringn; default: DBUG_ASSERT(0); // Should never happened return unknown; } } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_spatial_collection: public Item_geometry_func { bool check_arguments() const override { return Type_handler_geometry::check_types_geom_or_binary(func_name_cstring(), args, 0, arg_count); } enum Geometry::wkbType coll_type; enum Geometry::wkbType item_type; public: Item_func_spatial_collection(THD *thd, List &list, enum Geometry::wkbType ct, enum Geometry::wkbType it): Item_geometry_func(thd, list) { coll_type=ct; item_type=it; } String *val_str(String *) override; bool fix_length_and_dec() override { if (Item_geometry_func::fix_length_and_dec()) return TRUE; for (unsigned int i= 0; i < arg_count; ++i) { if (args[i]->fixed() && args[i]->field_type() != MYSQL_TYPE_GEOMETRY) { String str; args[i]->print(&str, QT_NO_DATA_EXPANSION); str.append('\0'); my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "non geometric", str.ptr()); return TRUE; } } return FALSE; } }; class Item_func_geometrycollection: public Item_func_spatial_collection { public: Item_func_geometrycollection(THD *thd, List &list) :Item_func_spatial_collection(thd, list, Geometry::wkb_geometrycollection, Geometry::wkb_point) { } const Type_handler *type_handler() const override { return &type_handler_geometrycollection; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("geometrycollection") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_linestring: public Item_func_spatial_collection { public: Item_func_linestring(THD *thd, List &list) :Item_func_spatial_collection(thd, list, Geometry::wkb_linestring, Geometry::wkb_point) { } const Type_handler *type_handler() const override { return &type_handler_linestring; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("linestring") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_polygon: public Item_func_spatial_collection { public: Item_func_polygon(THD *thd, List &list) :Item_func_spatial_collection(thd, list, Geometry::wkb_polygon, Geometry::wkb_linestring) { } const Type_handler *type_handler() const override { return &type_handler_polygon; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("polygon") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_multilinestring: public Item_func_spatial_collection { public: Item_func_multilinestring(THD *thd, List &list) :Item_func_spatial_collection(thd, list, Geometry::wkb_multilinestring, Geometry::wkb_linestring) { } const Type_handler *type_handler() const override { return &type_handler_multilinestring; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("multilinestring") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_multipoint: public Item_func_spatial_collection { public: Item_func_multipoint(THD *thd, List &list) :Item_func_spatial_collection(thd, list, Geometry::wkb_multipoint, Geometry::wkb_point) { } const Type_handler *type_handler() const override { return &type_handler_multipoint; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("multipoint") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_multipolygon: public Item_func_spatial_collection { public: Item_func_multipolygon(THD *thd, List &list) :Item_func_spatial_collection(thd, list, Geometry::wkb_multipolygon, Geometry::wkb_polygon) { } const Type_handler *type_handler() const override { return &type_handler_multipolygon; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("multipolygon") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Spatial relations */ class Item_func_spatial_rel: public Item_bool_func2_with_rev { protected: enum Functype spatial_rel; String tmp_value1, tmp_value2; SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, Field *field, KEY_PART *key_part, Item_func::Functype type, Item *value) override; bool check_arguments() const override { DBUG_ASSERT(arg_count >= 2); return Type_handler_geometry::check_types_geom_or_binary(func_name_cstring(), args, 0, 2); } public: Item_func_spatial_rel(THD *thd, Item *a, Item *b, enum Functype sp_rel): Item_bool_func2_with_rev(thd, a, b), spatial_rel(sp_rel) { set_maybe_null(); } enum Functype functype() const override { return spatial_rel; } enum Functype rev_functype() const override { switch (spatial_rel) { case SP_CONTAINS_FUNC: return SP_WITHIN_FUNC; case SP_WITHIN_FUNC: return SP_CONTAINS_FUNC; default: return spatial_rel; } } bool is_null() override { (void) val_int(); return null_value; } void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override { return add_key_fields_optimize_op(join, key_fields, and_level, usable_tables, sargables, false); } bool need_parentheses_in_default() override { return false; } Item *do_build_clone(THD *thd) const override { return nullptr; } }; class Item_func_spatial_mbr_rel: public Item_func_spatial_rel { public: Item_func_spatial_mbr_rel(THD *thd, Item *a, Item *b, enum Functype sp_rel): Item_func_spatial_rel(thd, a, b, sp_rel) { } bool val_bool() override; LEX_CSTRING func_name_cstring() const override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_spatial_precise_rel: public Item_func_spatial_rel { Gcalc_heap collector; Gcalc_scan_iterator scan_it; Gcalc_function func; public: Item_func_spatial_precise_rel(THD *thd, Item *a, Item *b, enum Functype sp_rel): Item_func_spatial_rel(thd, a, b, sp_rel), collector() { } bool val_bool() override; LEX_CSTRING func_name_cstring() const override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_spatial_relate: public Item_bool_func_args_geometry_geometry { Gcalc_heap collector; Gcalc_scan_iterator scan_it; Gcalc_function func; String tmp_value1, tmp_value2, tmp_matrix; bool check_arguments() const override { return Item_bool_func_args_geometry_geometry::check_arguments() || args[2]->check_type_general_purpose_string(func_name_cstring()); } public: Item_func_spatial_relate(THD *thd, Item *a, Item *b, Item *matrix): Item_bool_func_args_geometry_geometry(thd, a, b, matrix) { } bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_relate") }; return name; } bool need_parentheses_in_default() override { return false; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Spatial operations */ class Item_func_spatial_operation final: public Item_geometry_func { bool check_arguments() const override { DBUG_ASSERT(arg_count >= 2); return Type_handler_geometry::check_types_geom_or_binary(func_name_cstring(), args, 0, 2); } public: Gcalc_function::op_type spatial_op; Gcalc_heap collector; Gcalc_function func; Gcalc_result_receiver res_receiver; Gcalc_operation_reducer operation; String tmp_value1,tmp_value2; public: Item_func_spatial_operation(THD *thd, Item *a,Item *b, Gcalc_function::op_type sp_op): Item_geometry_func(thd, a, b), spatial_op(sp_op) {} virtual ~Item_func_spatial_operation(); String *val_str(String *) override; LEX_CSTRING func_name_cstring() const override; void print(String *str, enum_query_type query_type) override { Item_func::print(str, query_type); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_buffer final : public Item_geometry_func_args_geometry { bool check_arguments() const override { return Item_geometry_func_args_geometry::check_arguments() || args[1]->check_type_can_return_real(func_name_cstring()); } protected: class Transporter : public Gcalc_operation_transporter { int m_npoints; double m_d; double x1,y1,x2,y2; double x00,y00,x01,y01; int add_edge_buffer(double x3, double y3, bool round_p1, bool round_p2); int add_last_edge_buffer(); int add_point_buffer(double x, double y); int complete(); int m_nshapes; Gcalc_function::op_type buffer_op; int last_shape_pos; bool skip_line; public: Transporter(Gcalc_function *fn, Gcalc_heap *heap, double d) : Gcalc_operation_transporter(fn, heap), m_npoints(0), m_d(d), m_nshapes(0), buffer_op((d > 0.0) ? Gcalc_function::op_union : Gcalc_function::op_difference), skip_line(FALSE) {} int single_point(double x, double y) override; int start_line() override; int complete_line() override; int start_poly() override; int complete_poly() override; int start_ring() override; int complete_ring() override; int add_point(double x, double y) override; int start_collection(int n_objects) override; }; Gcalc_heap collector; Gcalc_function func; Gcalc_result_receiver res_receiver; Gcalc_operation_reducer operation; public: Item_func_buffer(THD *thd, Item *obj, Item *distance) :Item_geometry_func_args_geometry(thd, obj, distance) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_buffer") }; return name; } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_isempty: public Item_bool_func_args_geometry { public: Item_func_isempty(THD *thd, Item *a) :Item_bool_func_args_geometry(thd, a) {} bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_isempty") }; return name; } bool fix_length_and_dec() override { set_maybe_null(); return FALSE; } bool need_parentheses_in_default() override { return false; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_issimple: public Item_long_func_args_geometry { Gcalc_heap collector; Gcalc_function func; Gcalc_scan_iterator scan_it; String tmp; public: Item_func_issimple(THD *thd, Item *a) :Item_long_func_args_geometry(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_issimple") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=2; return FALSE; } decimal_digits_t decimal_precision() const override { return 1; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_isclosed: public Item_long_func_args_geometry { public: Item_func_isclosed(THD *thd, Item *a) :Item_long_func_args_geometry(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_isclosed") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=2; return FALSE; } decimal_digits_t decimal_precision() const override { return 1; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_isring: public Item_func_issimple { public: Item_func_isring(THD *thd, Item *a): Item_func_issimple(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_isring") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_dimension: public Item_long_func_args_geometry { public: Item_func_dimension(THD *thd, Item *a) :Item_long_func_args_geometry(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_dimension") }; return name; } bool fix_length_and_dec() override { max_length= 10; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_x: public Item_real_func_args_geometry { public: Item_func_x(THD *thd, Item *a): Item_real_func_args_geometry(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_x") }; return name; } bool fix_length_and_dec() override { if (Item_real_func::fix_length_and_dec()) return TRUE; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_y: public Item_real_func_args_geometry { public: Item_func_y(THD *thd, Item *a): Item_real_func_args_geometry(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_y") }; return name; } bool fix_length_and_dec() override { if (Item_real_func::fix_length_and_dec()) return TRUE; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_numgeometries: public Item_long_func_args_geometry { public: Item_func_numgeometries(THD *thd, Item *a) :Item_long_func_args_geometry(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_numgeometries") }; return name; } bool fix_length_and_dec() override { max_length= 10; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_numinteriorring: public Item_long_func_args_geometry { public: Item_func_numinteriorring(THD *thd, Item *a) :Item_long_func_args_geometry(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_numinteriorrings") }; return name; } bool fix_length_and_dec() override { max_length= 10; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_numpoints: public Item_long_func_args_geometry { public: Item_func_numpoints(THD *thd, Item *a) :Item_long_func_args_geometry(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_numpoints") }; return name; } bool fix_length_and_dec() override { max_length= 10; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_area: public Item_real_func_args_geometry { public: Item_func_area(THD *thd, Item *a): Item_real_func_args_geometry(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_area") }; return name; } bool fix_length_and_dec() override { if (Item_real_func::fix_length_and_dec()) return TRUE; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_glength: public Item_real_func_args_geometry { String value; public: Item_func_glength(THD *thd, Item *a) :Item_real_func_args_geometry(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_length") }; return name; } bool fix_length_and_dec() override { if (Item_real_func::fix_length_and_dec()) return TRUE; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_srid: public Item_long_func_args_geometry { public: Item_func_srid(THD *thd, Item *a) :Item_long_func_args_geometry(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("srid") }; return name; } bool fix_length_and_dec() override { max_length= 10; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_distance: public Item_real_func_args_geometry_geometry { String tmp_value1; String tmp_value2; Gcalc_heap collector; Gcalc_function func; Gcalc_scan_iterator scan_it; public: Item_func_distance(THD *thd, Item *a, Item *b) :Item_real_func_args_geometry_geometry(thd, a, b) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_distance") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_sphere_distance: public Item_real_func { double spherical_distance_points(Geometry *g1, Geometry *g2, const double sphere_r); public: Item_func_sphere_distance(THD *thd, List &list): Item_real_func(thd, list) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_distance_sphere") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_pointonsurface: public Item_geometry_func_args_geometry { String tmp_value; Gcalc_heap collector; Gcalc_function func; Gcalc_scan_iterator scan_it; public: Item_func_pointonsurface(THD *thd, Item *a) :Item_geometry_func_args_geometry(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_pointonsurface") }; return name; } String *val_str(String *) override; const Type_handler *type_handler() const override { return &type_handler_point; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #ifndef DBUG_OFF class Item_func_gis_debug: public Item_long_func { public: Item_func_gis_debug(THD *thd, Item *a): Item_long_func(thd, a) { null_value= false; } bool fix_length_and_dec() override { fix_char_length(10); return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_gis_debug") }; return name; } longlong val_int() override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #endif #define GEOM_NEW(thd, obj_constructor) new (thd->mem_root) obj_constructor #define GEOM_TYPE(x) (x) #else /*HAVE_SPATIAL*/ #define GEOM_NEW(thd, obj_constructor) NULL #define GEOM_TYPE(x) NULL #endif /*HAVE_SPATIAL*/ #endif /* ITEM_GEOFUNC_INCLUDED */ server/private/semisync_master_ack_receiver.h000064400000021005151031265040015577 0ustar00/* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SEMISYNC_MASTER_ACK_RECEIVER_DEFINED #define SEMISYNC_MASTER_ACK_RECEIVER_DEFINED #include "my_global.h" #include "my_pthread.h" #include "sql_class.h" #include "semisync.h" #include "socketpair.h" #include struct Slave :public ilink { THD *thd; Vio vio; #ifdef HAVE_POLL uint m_fds_index; #endif bool active; my_socket sock_fd() const { return vio.mysql_socket.fd; } uint server_id() const { return thd->variables.server_id; } }; typedef I_List Slave_ilist; typedef I_List_iterator Slave_ilist_iterator; /** Ack_receiver is responsible to control ack receive thread and maintain slave information used by ack receive thread. There are mainly four operations on ack receive thread: start: start ack receive thread stop: stop ack receive thread add_slave: maintain a new semisync slave's information remove_slave: remove a semisync slave's information */ class Ack_receiver : public Repl_semi_sync_base { public: Ack_receiver(); ~Ack_receiver() = default; void cleanup(); /** Notify ack receiver to receive acks on the dump session. It adds the given dump thread into the slave list and wakes up ack thread if it is waiting for any slave coming. @param[in] thd THD of a dump thread. @return it return false if succeeds, otherwise true is returned. */ bool add_slave(THD *thd); /** Notify ack receiver not to receive ack on the dump session. it removes the given dump thread from slave list. @param[in] thd THD of a dump thread. */ void remove_slave(THD *thd); /** Start ack receive thread @return it return false if succeeds, otherwise true is returned. */ bool start(); /** Stop ack receive thread */ void stop(); /** The core of ack receive thread. It monitors all slaves' sockets and receives acks when they come. */ void run(); void set_trace_level(unsigned long trace_level) { m_trace_level= trace_level; } bool running() { return m_status != ST_DOWN; } private: enum status {ST_UP, ST_DOWN, ST_STOPPING}; enum status m_status; /* Protect m_status, m_slaves_changed and m_slaves. ack thread and other session may access the variables at the same time. */ mysql_mutex_t m_mutex; mysql_cond_t m_cond, m_cond_reply; /* If slave list is updated(add or remove). */ bool m_slaves_changed; Slave_ilist m_slaves; pthread_t m_pid; /* Declare them private, so no one can copy the object. */ Ack_receiver(const Ack_receiver &ack_receiver); Ack_receiver& operator=(const Ack_receiver &ack_receiver); void set_stage_info(const PSI_stage_info &stage); void wait_for_slave_connection(THD *thd); }; extern my_socket global_ack_signal_fd; class Ack_listener { public: my_socket local_read_signal; const Slave_ilist &m_slaves; int error; Ack_listener(const Slave_ilist &slaves) :local_read_signal(-1), m_slaves(slaves), error(0) { my_socket pipes[2]; #ifdef _WIN32 error= create_socketpair(pipes); #else if (!pipe(pipes)) { fcntl(pipes[0], F_SETFL, O_NONBLOCK); fcntl(pipes[1], F_SETFL, O_NONBLOCK); } else { pipes[0]= pipes[1]= -1; } #endif /* _WIN32 */ local_read_signal= pipes[0]; global_ack_signal_fd= pipes[1]; } virtual ~Ack_listener() { #ifdef _WIN32 my_socket pipes[2]; pipes[0]= local_read_signal; pipes[1]= global_ack_signal_fd; close_socketpair(pipes); #else if (global_ack_signal_fd >= 0) close(global_ack_signal_fd); if (local_read_signal >= 0) close(local_read_signal); #endif /* _WIN32 */ global_ack_signal_fd= local_read_signal= -1; } int got_error() { return error; } virtual bool has_signal_data()= 0; /* Clear data sent by signal_listener() to abort read */ void clear_signal() { if (has_signal_data()) { char buff[100]; /* Clear the signal message */ #ifndef _WIN32 (void) !read(local_read_signal, buff, sizeof(buff)); #else recv(local_read_signal, buff, sizeof(buff), 0); #endif /* _WIN32 */ } } }; static inline void signal_listener() { #ifndef _WIN32 my_write(global_ack_signal_fd, (uchar*) "a", 1, MYF(0)); #else send(global_ack_signal_fd, "a", 1, 0); #endif /* _WIN32 */ } #ifdef HAVE_POLL #include class Poll_socket_listener final : public Ack_listener { private: std::vector m_fds; public: Poll_socket_listener(const Slave_ilist &slaves) :Ack_listener(slaves) {} virtual ~Poll_socket_listener() = default; bool listen_on_sockets() { return poll(m_fds.data(), m_fds.size(), -1); } bool is_socket_active(const Slave *slave) { return m_fds[slave->m_fds_index].revents & POLLIN; } bool is_socket_hangup(const Slave *slave) { return m_fds[slave->m_fds_index].revents & POLLHUP; } void clear_socket_info(const Slave *slave) { m_fds[slave->m_fds_index].fd= -1; m_fds[slave->m_fds_index].events= 0; } bool has_signal_data() override { /* The signal fd is always first */ return (m_fds[0].revents & POLLIN); } int init_slave_sockets() { Slave_ilist_iterator it(const_cast(m_slaves)); Slave *slave; uint fds_index= 0; pollfd poll_fd; m_fds.clear(); /* First put in the signal socket */ poll_fd.fd= local_read_signal; poll_fd.events= POLLIN; m_fds.push_back(poll_fd); fds_index++; while ((slave= it++)) { slave->active= 1; pollfd poll_fd; poll_fd.fd= slave->sock_fd(); poll_fd.events= POLLIN; m_fds.push_back(poll_fd); slave->m_fds_index= fds_index++; } return fds_index; } }; #else //NO POLL class Select_socket_listener final : public Ack_listener { private: my_socket m_max_fd; fd_set m_init_fds; fd_set m_fds; public: Select_socket_listener(const Slave_ilist &slaves) :Ack_listener(slaves), m_max_fd(INVALID_SOCKET) {} virtual ~Select_socket_listener() = default; bool listen_on_sockets() { /* Reinitialize the fds with active fds before calling select */ m_fds= m_init_fds; /* select requires max fd + 1 for the first argument */ return select((int) m_max_fd+1, &m_fds, NULL, NULL, NULL); } bool is_socket_active(const Slave *slave) { return FD_ISSET(slave->sock_fd(), &m_fds); } bool is_socket_hangup(const Slave *slave) { return 0; } bool has_signal_data() override { return FD_ISSET(local_read_signal, &m_fds); } void clear_socket_info(const Slave *slave) { FD_CLR(slave->sock_fd(), &m_init_fds); } int init_slave_sockets() { Slave_ilist_iterator it(const_cast(m_slaves)); Slave *slave; uint fds_index= 0; FD_ZERO(&m_init_fds); m_max_fd= -1; /* First put in the signal socket */ FD_SET(local_read_signal, &m_init_fds); fds_index++; set_if_bigger(m_max_fd, local_read_signal); #ifndef _WIN32 if (local_read_signal > FD_SETSIZE) { int socket_id= local_read_signal; sql_print_error("Semisync slave socket fd is %u. " "select() cannot handle if the socket fd is " "greater than %u (FD_SETSIZE).", socket_id, FD_SETSIZE); return -1; } #endif while ((slave= it++)) { my_socket socket_id= slave->sock_fd(); set_if_bigger(m_max_fd, socket_id); #ifndef _WIN32 if (socket_id > FD_SETSIZE) { sql_print_error("Semisync slave socket fd is %u. " "select() cannot handle if the socket fd is " "greater than %u (FD_SETSIZE).", socket_id, FD_SETSIZE); it.remove(); continue; } #endif //_WIN32 FD_SET(socket_id, &m_init_fds); fds_index++; slave->active= 1; } return fds_index; } my_socket get_max_fd() { return m_max_fd; } }; #endif //HAVE_POLL extern Ack_receiver ack_receiver; #endif server/private/sql_type_fixedbin.h000064400000175500151031265040013412 0ustar00#ifndef SQL_TYPE_FIXEDBIN_H #define SQL_TYPE_FIXEDBIN_H /* Copyright (c) 2019,2021 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This is a common code for plugin (?) types that are generally handled like strings, but have their own fixed size on-disk binary storage format and their own (variable size) canonical string representation. Examples are INET6 and UUID types. */ #define MYSQL_SERVER #include "sql_class.h" // THD, SORT_FIELD_ATTR #include "opt_range.h" // SEL_ARG, null_element #include "sql_type_fixedbin_storage.h" /***********************************************************************/ template class Type_collection_fbt; template > class Type_handler_fbt: public Type_handler { /* =[ internal helper classes ]=============================== */ public: class Fbt: public FbtImpl { protected: using FbtImpl::m_buffer; bool make_from_item(Item *item, bool warn) { if (item->type_handler() == singleton()) { Native tmp(m_buffer, sizeof(m_buffer)); bool rc= item->val_native(current_thd, &tmp); if (rc) return true; DBUG_ASSERT(tmp.length() == sizeof(m_buffer)); if (tmp.ptr() != m_buffer) memcpy(m_buffer, tmp.ptr(), sizeof(m_buffer)); return false; } StringBuffer tmp; String *str= item->val_str(&tmp); return str ? make_from_character_or_binary_string(str, warn) : true; } bool character_string_to_fbt(const char *str, size_t str_length, CHARSET_INFO *cs) { if (cs->state & MY_CS_NONASCII) { char tmp[FbtImpl::max_char_length()+1]; String_copier copier; uint length= copier.well_formed_copy(&my_charset_latin1, tmp, sizeof(tmp), cs, str, str_length); return FbtImpl::ascii_to_fbt(tmp, length); } return FbtImpl::ascii_to_fbt(str, str_length); } bool make_from_character_or_binary_string(const String *str, bool warn) { if (str->charset() != &my_charset_bin) { bool rc= character_string_to_fbt(str->ptr(), str->length(), str->charset()); if (rc && warn) current_thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, singleton()->name().ptr(), ErrConvString(str).ptr()); return rc; } if (str->length() != sizeof(m_buffer)) { if (warn) current_thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, singleton()->name().ptr(), ErrConvString(str).ptr()); return true; } DBUG_ASSERT(str->ptr() != m_buffer); memcpy(m_buffer, str->ptr(), sizeof(m_buffer)); return false; } bool binary_to_fbt(const char *str, size_t length) { if (length != sizeof(m_buffer)) return true; memcpy(m_buffer, str, length); return false; } Fbt() { } public: static Fbt zero() { Fbt fbt; fbt.set_zero(); return fbt; } static Fbt record_to_memory(const char *ptr) { Fbt fbt; FbtImpl::record_to_memory(fbt.m_buffer, ptr); return fbt; } /* Check at Item's fix_fields() time if "item" can return a nullable value on conversion to Fbt, or conversion produces a NOT NULL Fbt value. */ static bool fix_fields_maybe_null_on_conversion_to_fbt(Item *item) { if (item->maybe_null()) return true; if (item->type_handler() == singleton()) return false; if (!item->const_item() || item->is_expensive()) return true; return Fbt_null(item, false).is_null(); } /* Check at fix_fields() time if any of the items can return a nullable value on conversion to Fbt. */ static bool fix_fields_maybe_null_on_conversion_to_fbt(Item **items, uint count) { for (uint i= 0; i < count; i++) { if (Fbt::fix_fields_maybe_null_on_conversion_to_fbt(items[i])) return true; } return false; } public: Fbt(Item *item, bool *error, bool warn= true) { *error= make_from_item(item, warn); } void to_record(char *str, size_t str_size) const { DBUG_ASSERT(str_size >= sizeof(m_buffer)); FbtImpl::memory_to_record(str, m_buffer); } bool to_binary(String *to) const { return to->copy(m_buffer, sizeof(m_buffer), &my_charset_bin); } bool to_native(Native *to) const { return to->copy(m_buffer, sizeof(m_buffer)); } bool to_string(String *to) const { to->set_charset(&my_charset_latin1); if (to->alloc(FbtImpl::max_char_length()+1)) return true; to->length((uint32) FbtImpl::to_string(const_cast(to->ptr()), FbtImpl::max_char_length()+1)); return false; } int cmp(const Binary_string &other) const { return FbtImpl::cmp(FbtImpl::to_lex_cstring(), other.to_lex_cstring()); } int cmp(const Fbt &other) const { return FbtImpl::cmp(FbtImpl::to_lex_cstring(), other.to_lex_cstring()); } }; class Fbt_null: public Fbt, public Null_flag { public: // Initialize from a text representation Fbt_null(const char *str, size_t length, CHARSET_INFO *cs) :Null_flag(Fbt::character_string_to_fbt(str, length, cs)) { } Fbt_null(const String &str) :Fbt_null(str.ptr(), str.length(), str.charset()) { } // Initialize from a binary representation Fbt_null(const char *str, size_t length) :Null_flag(Fbt::binary_to_fbt(str, length)) { } Fbt_null(const Binary_string &str) :Fbt_null(str.ptr(), str.length()) { } // Initialize from an Item Fbt_null(Item *item, bool warn= true) :Null_flag(Fbt::make_from_item(item, warn)) { } public: const Fbt& to_fbt() const { DBUG_ASSERT(!is_null()); return *this; } void to_record(char *str, size_t str_size) const { to_fbt().to_record(str, str_size); } bool to_binary(String *to) const { return to_fbt().to_binary(to); } bool to_string(String *to) const { return to_fbt().to_string(to); } }; /* =[ API classes ]=========================================== */ class Type_std_attributes_fbt: public Type_std_attributes { public: Type_std_attributes_fbt() :Type_std_attributes( Type_numeric_attributes(FbtImpl::max_char_length(), 0, true), DTCollation_numeric()) { } }; class Item_literal_fbt: public Item_literal { Fbt m_value; public: Item_literal_fbt(THD *thd) :Item_literal(thd), m_value(Fbt::zero()) { } Item_literal_fbt(THD *thd, const Fbt &value) :Item_literal(thd), m_value(value) { } const Type_handler *type_handler() const override { return singleton(); } bool val_bool() override { return m_value.to_bool(); } longlong val_int() override { return 0; } double val_real() override { return 0; } String *val_str(String *to) override { return m_value.to_string(to) ? NULL : to; } my_decimal *val_decimal(my_decimal *to) override { my_decimal_set_zero(to); return to; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); return false; } bool val_native(THD *thd, Native *to) override { return m_value.to_native(to); } void print(String *str, enum_query_type query_type) override { StringBuffer tmp; tmp.append(singleton()->name().lex_cstring()); my_caseup_str(&my_charset_latin1, tmp.c_ptr()); str->append(tmp); str->append('\''); m_value.to_string(&tmp); str->append(tmp); str->append('\''); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } // Non-overriding methods void set_value(const Fbt &value) { m_value= value; } }; class Field_fbt: public Field { static void set_min_value(char *ptr) { memset(ptr, 0, FbtImpl::binary_length()); } static void set_max_value(char *ptr) { memset(ptr, 0xFF, FbtImpl::binary_length()); } void store_warning(const ErrConv &str, Sql_condition::enum_warning_level level) { if (get_thd()->count_cuted_fields <= CHECK_FIELD_EXPRESSION) return; const TABLE_SHARE *s= table->s; static const Name type_name= singleton()->name(); get_thd()->push_warning_truncated_value_for_field(level, type_name.ptr(), str.ptr(), s ? s->db.str : nullptr, s ? s->table_name.str : nullptr, field_name.str); } int set_null_with_warn(const ErrConv &str) { store_warning(str, Sql_condition::WARN_LEVEL_WARN); set_null(); return 1; } int set_min_value_with_warn(const ErrConv &str) { store_warning(str, Sql_condition::WARN_LEVEL_WARN); set_min_value((char*) ptr); return 1; } int set_max_value_with_warn(const ErrConv &str) { store_warning(str, Sql_condition::WARN_LEVEL_WARN); set_max_value((char*) ptr); return 1; } int store_fbt_null_with_warn(const Fbt_null &fbt, const ErrConvString &err) { DBUG_ASSERT(marked_for_write_or_computed()); if (fbt.is_null()) return maybe_null() ? set_null_with_warn(err) : set_min_value_with_warn(err); fbt.to_record((char *) ptr, FbtImpl::binary_length()); return 0; } public: Field_fbt(const LEX_CSTRING *field_name_arg, const Record_addr &rec) :Field(rec.ptr(), FbtImpl::max_char_length(), rec.null_ptr(), rec.null_bit(), Field::NONE, field_name_arg) { flags|= BINARY_FLAG | UNSIGNED_FLAG; } const Type_handler *type_handler() const override { return singleton(); } uint32 max_display_length() const override { return field_length; } bool str_needs_quotes() const override { return true; } const DTCollation &dtcollation() const override { static DTCollation_numeric c; return c; } CHARSET_INFO *charset(void) const override { return &my_charset_numeric; } const CHARSET_INFO *sort_charset(void) const override { return &my_charset_bin; } /** This makes client-server protocol convert the value according to @@character_set_client. */ bool binary() const override { return false; } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; } bool is_equal(const Column_definition &new_field) const override { return new_field.type_handler() == type_handler(); } bool eq_def(const Field *field) const override { return Field::eq_def(field); } double pos_in_interval(Field *min, Field *max) override { return pos_in_interval_val_str(min, max, 0); } int cmp(const uchar *a, const uchar *b) const override { return memcmp(a, b, pack_length()); } void sort_string(uchar *to, uint length) override { DBUG_ASSERT(length == pack_length()); memcpy(to, ptr, length); } uint32 pack_length() const override { return FbtImpl::binary_length(); } uint pack_length_from_metadata(uint field_metadata) const override { return FbtImpl::binary_length(); } void sql_type(String &str) const override { static Name name= singleton()->name(); str.set_ascii(name.ptr(), name.length()); } void make_send_field(Send_field *to) override { Field::make_send_field(to); to->set_data_type_name(singleton()->name().lex_cstring()); } bool validate_value_in_record(THD *thd, const uchar *record) const override { return false; } bool val_native(Native *to) override { DBUG_ASSERT(marked_for_read()); if (to->alloc(FbtImpl::binary_length())) return true; to->length(FbtImpl::binary_length()); FbtImpl::record_to_memory((char*) to->ptr(), (const char*) ptr); return false; } Fbt to_fbt() const { DBUG_ASSERT(marked_for_read()); return Fbt::record_to_memory((const char*) ptr); } String *val_str(String *val_buffer, String *) override { return to_fbt().to_string(val_buffer) ? NULL : val_buffer; } my_decimal *val_decimal(my_decimal *to) override { DBUG_ASSERT(marked_for_read()); my_decimal_set_zero(to); return to; } longlong val_int() override { DBUG_ASSERT(marked_for_read()); return 0; } double val_real() override { DBUG_ASSERT(marked_for_read()); return 0; } bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override { DBUG_ASSERT(marked_for_read()); set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); return false; } bool val_bool(void) override { DBUG_ASSERT(marked_for_read()); return !Fbt::only_zero_bytes((const char *) ptr, FbtImpl::binary_length()); } int store_native(const Native &value) override { DBUG_ASSERT(marked_for_write_or_computed()); DBUG_ASSERT(value.length() == FbtImpl::binary_length()); FbtImpl::memory_to_record((char*) ptr, value.ptr()); return 0; } int store(const char *str, size_t length, CHARSET_INFO *cs) override { return cs == &my_charset_bin ? store_binary(str, length) : store_text(str, length, cs); } int store_text(const char *str, size_t length, CHARSET_INFO *cs) override { return store_fbt_null_with_warn(Fbt_null(str, length, cs), ErrConvString(str, length, cs)); } int store_binary(const char *str, size_t length) override { return store_fbt_null_with_warn(Fbt_null(str, length), ErrConvString(str, length, &my_charset_bin)); } int store_hex_hybrid(const char *str, size_t length) override { return Field_fbt::store_binary(str, length); } int store_decimal(const my_decimal *num) override { DBUG_ASSERT(marked_for_write_or_computed()); return set_min_value_with_warn(ErrConvDecimal(num)); } int store(longlong nr, bool unsigned_flag) override { DBUG_ASSERT(marked_for_write_or_computed()); return set_min_value_with_warn( ErrConvInteger(Longlong_hybrid(nr, unsigned_flag))); } int store(double nr) override { DBUG_ASSERT(marked_for_write_or_computed()); return set_min_value_with_warn(ErrConvDouble(nr)); } int store_time_dec(const MYSQL_TIME *ltime, uint dec) override { DBUG_ASSERT(marked_for_write_or_computed()); return set_min_value_with_warn(ErrConvTime(ltime)); } /*** Field conversion routines ***/ int store_field(Field *from) override { // INSERT INTO t1 (fbt_field) SELECT different_field_type FROM t2; return from->save_in_field(this); } int save_in_field(Field *to) override { // INSERT INTO t2 (different_field_type) SELECT fbt_field FROM t1; if (to->charset() == &my_charset_bin && dynamic_cast (to->type_handler())) { NativeBuffer res; val_native(&res); return to->store(res.ptr(), res.length(), &my_charset_bin); } return save_in_field_str(to); } Copy_func *get_copy_func(const Field *from) const override { // ALTER to FBT from another field return do_field_string; } Copy_func *get_copy_func_to(const Field *to) const override { if (type_handler() == to->type_handler()) { // ALTER from FBT to FBT DBUG_ASSERT(pack_length() == to->pack_length()); DBUG_ASSERT(charset() == to->charset()); DBUG_ASSERT(sort_charset() == to->sort_charset()); return Field::do_field_eq; } // ALTER from FBT to another fbt type if (to->charset() == &my_charset_bin && dynamic_cast (to->type_handler())) { /* ALTER from FBT to a binary string type, e.g.: BINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB */ return do_field_fbt_native_to_binary; } return do_field_string; } static void do_field_fbt_native_to_binary(Copy_field *copy) { NativeBuffer res; copy->from_field->val_native(&res); copy->to_field->store(res.ptr(), res.length(), &my_charset_bin); } bool memcpy_field_possible(const Field *from) const override { // INSERT INTO t1 (fbt_field) SELECT field2 FROM t2; return type_handler() == from->type_handler(); } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override { if (type_handler() == source.type_handler() || (source.type_handler() == &type_handler_string && source.type_handler()->max_display_length_for_field(source) == FbtImpl::binary_length())) return rpl_conv_type_from_same_data_type(source.metadata(), rli, param); return CONV_TYPE_IMPOSSIBLE; } /*** Optimizer routines ***/ bool test_if_equality_guarantees_uniqueness(const Item *const_item) const override { /* This condition: WHERE fbt_field=const should return a single distinct value only, as comparison is done according to FBT. */ return true; } bool can_be_substituted_to_equal_item(const Context &ctx, const Item_equal *item_equal) override { switch (ctx.subst_constraint()) { case ANY_SUBST: return ctx.compare_type_handler() == item_equal->compare_type_handler(); case IDENTITY_SUBST: return true; } return false; } Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) override { Fbt_null tmp(const_item); if (tmp.is_null()) return NULL; return new (thd->mem_root) Item_literal_fbt(thd, tmp); } Data_type_compatibility can_optimize_keypart_ref(const Item_bool_func *cond, const Item *item) const override { /* Mixing of two different non-traditional types is currently prevented. This may change in the future. */ DBUG_ASSERT(item->type_handler()->type_handler_base_or_self()-> is_traditional_scalar_type() || item->type_handler() == type_handler()); return Data_type_compatibility::OK; } /** Test if Field can use range optimizer for a standard comparison operation: <=, <, =, <=>, >, >= Note, this method does not cover spatial operations. */ Data_type_compatibility can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const override { // See the DBUG_ASSERT comment in can_optimize_keypart_ref() DBUG_ASSERT(item->type_handler()->type_handler_base_or_self()-> is_traditional_scalar_type() || item->type_handler() == type_handler()); return Data_type_compatibility::OK; } void hash_not_null(Hasher *hasher) override { FbtImpl::hash_record(ptr, hasher); } SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part, const Item_bool_func *cond, scalar_comparison_op op, Item *value) override { DBUG_ENTER("Field_fbt::get_mm_leaf"); if (can_optimize_scalar_range(prm, key_part, cond, op, value) != Data_type_compatibility::OK) DBUG_RETURN(0); int err= value->save_in_field_no_warnings(this, 1); if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0) DBUG_RETURN(&null_element); if (err > 0) { if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL) DBUG_RETURN(new (prm->mem_root) SEL_ARG_IMPOSSIBLE(this)); DBUG_RETURN(NULL); /* Cannot infer anything */ } DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value)); } Data_type_compatibility can_optimize_hash_join(const Item_bool_func *cond, const Item *item) const override { return can_optimize_keypart_ref(cond, item); } Data_type_compatibility can_optimize_group_min_max( const Item_bool_func *cond, const Item *const_item) const override { return Data_type_compatibility::OK; } uint row_pack_length() const override { return pack_length(); } Binlog_type_info binlog_type_info() const override { DBUG_ASSERT(type() == binlog_type()); return Binlog_type_info_fixed_string(Field_fbt::binlog_type(), FbtImpl::binary_length(), &my_charset_bin); } uchar *pack(uchar *to, const uchar *from, uint max_length) override { DBUG_PRINT("debug", ("Packing field '%s'", field_name.str)); return FbtImpl::pack(to, from, max_length); } const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end, uint param_data) override { return FbtImpl::unpack(to, from, from_end, param_data); } uint max_packed_col_length(uint max_length) override { return StringPack::max_packed_col_length(max_length); } uint packed_col_length(const uchar *fbt_ptr, uint length) override { return StringPack::packed_col_length(fbt_ptr, length); } uint size_of() const override { return sizeof(*this); } }; class cmp_item_fbt: public cmp_item_scalar { Fbt m_native; public: cmp_item_fbt() :cmp_item_scalar(), m_native(Fbt::zero()) { } void store_value(Item *item) override { m_native= Fbt(item, &m_null_value); } int cmp_not_null(const Value *val) override { DBUG_ASSERT(!val->is_null()); DBUG_ASSERT(val->is_string()); Fbt_null tmp(val->m_string); DBUG_ASSERT(!tmp.is_null()); return m_native.cmp(tmp); } int cmp(Item *arg) override { Fbt_null tmp(arg); return m_null_value || tmp.is_null() ? UNKNOWN : m_native.cmp(tmp) != 0; } int compare(const cmp_item *ci) const override { const cmp_item_fbt *tmp= static_cast(ci); DBUG_ASSERT(!m_null_value); DBUG_ASSERT(!tmp->m_null_value); return m_native.cmp(tmp->m_native); } cmp_item *make_same(THD *thd) override { return new (thd->mem_root) cmp_item_fbt(); } }; class in_fbt :public in_vector { Fbt m_value; static int cmp_fbt(void *cmp_arg, const void *a, const void *b) { return static_cast(a)->cmp(*static_cast(b)); } public: in_fbt(THD *thd, uint elements) :in_vector(thd, elements, sizeof(Fbt), cmp_fbt, 0), m_value(Fbt::zero()) { } const Type_handler *type_handler() const override { return singleton(); } bool set(uint pos, Item *item) override { Fbt *buff= &((Fbt *) base)[pos]; Fbt_null value(item); if (value.is_null()) { *buff= Fbt::zero(); return true; } *buff= value; return false; } uchar *get_value(Item *item) override { Fbt_null value(item); if (value.is_null()) return 0; m_value= value; return (uchar *) &m_value; } Item* create_item(THD *thd) override { return new (thd->mem_root) Item_literal_fbt(thd); } void value_to_item(uint pos, Item *item) override { const Fbt &buff= (((Fbt*) base)[pos]); static_cast(item)->set_value(buff); } }; class Item_copy_fbt: public Item_copy { NativeBuffer m_value; public: Item_copy_fbt(THD *thd, Item *item_arg): Item_copy(thd, item_arg) {} bool val_native(THD *thd, Native *to) override { if (null_value) return true; return to->copy(m_value.ptr(), m_value.length()); } String *val_str(String *to) override { if (null_value) return NULL; Fbt_null tmp(m_value.ptr(), m_value.length()); return tmp.is_null() || tmp.to_string(to) ? NULL : to; } my_decimal *val_decimal(my_decimal *to) override { my_decimal_set_zero(to); return to; } double val_real() override { return 0; } longlong val_int() override { return 0; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); return null_value; } void copy() override { null_value= item->val_native(current_thd, &m_value); DBUG_ASSERT(null_value == item->null_value); } int save_in_field(Field *field, bool no_conversions) override { return Item::save_in_field(field, no_conversions); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_char_typecast_func_handler_fbt_to_binary: public Item_handled_func::Handler_str { public: const Type_handler *return_type_handler(const Item_handled_func *item) const override { if (item->max_length > MAX_FIELD_VARCHARLENGTH) return Type_handler::blob_type_handler(item->max_length); if (item->max_length > 255) return &type_handler_varchar; return &type_handler_string; } bool fix_length_and_dec(Item_handled_func *xitem) const override { return false; } String *val_str(Item_handled_func *item, String *to) const override { DBUG_ASSERT(dynamic_cast(item)); return static_cast(item)-> val_str_binary_from_native(to); } }; class Item_typecast_fbt: public Item_func { public: Item_typecast_fbt(THD *thd, Item *a) :Item_func(thd, a) {} const Type_handler *type_handler() const override { return singleton(); } enum Functype functype() const override { return CHAR_TYPECAST_FUNC; } bool eq(const Item *item, bool binary_cmp) const override { if (this == item) return true; if (item->type() != FUNC_ITEM || functype() != ((Item_func*)item)->functype()) return false; if (type_handler() != item->type_handler()) return false; Item_typecast_fbt *cast= (Item_typecast_fbt*) item; return args[0]->eq(cast->args[0], binary_cmp); } LEX_CSTRING func_name_cstring() const override { static Name name= singleton()->name(); size_t len= 9+name.length()+1; char *buf= (char*)current_thd->alloc(len); strmov(strmov(buf, "cast_as_"), name.ptr()); return { buf, len }; } void print(String *str, enum_query_type query_type) override { str->append(STRING_WITH_LEN("cast(")); args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as ")); str->append(singleton()->name().lex_cstring()); str->append(')'); } bool fix_length_and_dec() override { Type_std_attributes::operator=(Type_std_attributes_fbt()); if (Fbt::fix_fields_maybe_null_on_conversion_to_fbt(args[0])) set_maybe_null(); return false; } String *val_str(String *to) override { Fbt_null tmp(args[0]); return (null_value= tmp.is_null() || tmp.to_string(to)) ? NULL : to; } longlong val_int() override { return 0; } double val_real() override { return 0; } my_decimal *val_decimal(my_decimal *to) override { my_decimal_set_zero(to); return to; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); return false; } bool val_native(THD *thd, Native *to) override { Fbt_null tmp(args[0]); return null_value= tmp.is_null() || tmp.to_native(to); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_cache_fbt: public Item_cache { NativeBuffer m_value; public: Item_cache_fbt(THD *thd) :Item_cache(thd, singleton()) { } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } bool cache_value() override { if (!example) return false; value_cached= true; null_value_inside= null_value= example->val_native_with_conversion_result(current_thd, &m_value, type_handler()); return true; } String* val_str(String *to) override { if (!has_value()) return NULL; Fbt_null tmp(m_value.ptr(), m_value.length()); return tmp.is_null() || tmp.to_string(to) ? NULL : to; } my_decimal *val_decimal(my_decimal *to) override { if (!has_value()) return NULL; my_decimal_set_zero(to); return to; } longlong val_int() override { if (!has_value()) return 0; return 0; } double val_real() override { if (!has_value()) return 0; return 0; } longlong val_datetime_packed(THD *) override { DBUG_ASSERT(0); if (!has_value()) return 0; return 0; } longlong val_time_packed(THD *) override { DBUG_ASSERT(0); if (!has_value()) return 0; return 0; } bool get_date(THD *, MYSQL_TIME *ltime, date_mode_t) override { if (!has_value()) return true; set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); return false; } bool val_native(THD *, Native *to) override { if (!has_value()) return true; return to->copy(m_value.ptr(), m_value.length()); } }; /* =[ methods ]=============================================== */ private: bool character_or_binary_string_to_native(THD *thd, const String *str, Native *to) const { if (str->charset() == &my_charset_bin) { // Convert from a binary string if (str->length() != FbtImpl::binary_length() || to->copy(str->ptr(), str->length())) { thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, name().ptr(), ErrConvString(str).ptr()); return true; } return false; } // Convert from a character string Fbt_null tmp(*str); if (tmp.is_null()) thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, name().ptr(), ErrConvString(str).ptr()); return tmp.is_null() || tmp.to_native(to); } public: ~Type_handler_fbt() override {} const Type_collection *type_collection() const override { return TypeCollectionImpl::singleton(); } const Name &default_value() const override { return FbtImpl::default_value(); } ulong KEY_pack_flags(uint column_nr) const override { return FbtImpl::KEY_pack_flags(column_nr); } protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_STRING; } bool Item_append_extended_type_info(Send_field_extended_metadata *to, const Item *item) const override { return to->set_data_type_name(name().lex_cstring()); } enum_field_types field_type() const override { return MYSQL_TYPE_STRING; } Item_result result_type() const override { return STRING_RESULT; } Item_result cmp_type() const override { return STRING_RESULT; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const override { return DYN_COL_STRING; } uint32 max_display_length_for_field(const Conv_source &src) const override { return FbtImpl::max_char_length(); } const Type_handler *type_handler_for_comparison() const override { return this; } int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override { DBUG_ASSERT(field->type_handler() == this); Fbt_null ni(item); // Convert Item to Fbt if (ni.is_null()) return 0; NativeBuffer tmp; if (field->val_native(&tmp)) { DBUG_ASSERT(0); return 0; } return -ni.cmp(tmp); } CHARSET_INFO *charset_for_protocol(const Item *item) const override { return item->collation.collation; } bool is_scalar_type() const override { return true; } bool is_val_native_ready() const override { return true; } bool can_return_int() const override { return false; } bool can_return_decimal() const override { return false; } bool can_return_real() const override { return false; } bool can_return_str() const override { return true; } bool can_return_text() const override { return true; } bool can_return_date() const override { return false; } bool can_return_time() const override { return false; } bool convert_to_binary_using_val_native() const override { return true; } decimal_digits_t Item_time_precision(THD *thd, Item *item) const override { return 0; } decimal_digits_t Item_datetime_precision(THD *thd, Item *item) const override { return 0; } decimal_digits_t Item_decimal_scale(const Item *item) const override { return 0; } decimal_digits_t Item_decimal_precision(const Item *item) const override { /* This will be needed if we ever allow cast from Fbt to DECIMAL. */ return (FbtImpl::binary_length()*8+7)/10*3; // = bytes to decimal digits } /* Returns how many digits a divisor adds into a division result. See Item::divisor_precision_increment() in item.h for more comments. */ decimal_digits_t Item_divisor_precision_increment(const Item *) const override { return 0; } /** Makes a temporary table Field to handle numeric aggregate functions, e.g. SUM(DISTINCT expr), AVG(DISTINCT expr), etc. */ Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override { DBUG_ASSERT(0); return 0; } Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override { const Record_addr tmp(NULL, Bit_addr(true)); return new (table->in_use->mem_root) Field_fbt(&empty_clex_str, tmp); } // Fix attributes after the parser bool Column_definition_fix_attributes(Column_definition *c) const override { c->length= FbtImpl::max_char_length(); return false; } bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *def, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const override { def->prepare_stage1_simple(&my_charset_numeric); return false; } bool Column_definition_redefine_stage1(Column_definition *def, const Column_definition *dup, const handler *file) const override { def->redefine_stage1_common(dup, file); def->set_compression_method(dup->compression_method()); def->create_length_to_internal_length_string(); return false; } bool Column_definition_prepare_stage2(Column_definition *def, handler *file, ulonglong table_flags) const override { def->pack_flag= FIELDFLAG_BINARY; return false; } bool partition_field_check(const LEX_CSTRING &field_name, Item *item_expr) const override { if (item_expr->cmp_type() != STRING_RESULT) { my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); return true; } return false; } bool partition_field_append_value(String *to, Item *item_expr, CHARSET_INFO *field_cs, partition_value_print_mode_t mode) const override { StringBuffer fbtstr; Fbt_null fbt(item_expr); if (fbt.is_null()) { my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); return true; } return fbt.to_string(&fbtstr) || to->append('\'') || to->append(fbtstr) || to->append('\''); } Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *table) const override { return new (root) Field_fbt(name, addr); } Field * make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override { return new (mem_root) Field_fbt(name, addr); } void Column_definition_attributes_frm_pack(const Column_definition_attributes *def, uchar *buff) const override { def->frm_pack_basic(buff); def->frm_pack_charset(buff); } bool Column_definition_attributes_frm_unpack(Column_definition_attributes *def, TABLE_SHARE *share, const uchar *buffer, LEX_CUSTRING *gis_options) const override { def->frm_unpack_basic(buffer); return def->frm_unpack_charset(share, buffer); } void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *) const override { DBUG_ASSERT(item->type_handler() == this); NativeBuffer tmp; item->val_native_result(current_thd, &tmp); if (item->maybe_null()) { if (item->null_value) { memset(to, 0, FbtImpl::binary_length() + 1); return; } *to++= 1; } DBUG_ASSERT(!item->null_value); DBUG_ASSERT(FbtImpl::binary_length() == tmp.length()); DBUG_ASSERT(FbtImpl::binary_length() == sort_field->length); FbtImpl::memory_to_record((char*) to, tmp.ptr()); } uint make_packed_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *) const override { DBUG_ASSERT(item->type_handler() == this); NativeBuffer tmp; item->val_native_result(current_thd, &tmp); if (item->maybe_null()) { if (item->null_value) { *to++=0; return 0; } *to++= 1; } DBUG_ASSERT(!item->null_value); DBUG_ASSERT(FbtImpl::binary_length() == tmp.length()); DBUG_ASSERT(FbtImpl::binary_length() == sort_field->length); FbtImpl::memory_to_record((char*) to, tmp.ptr()); return tmp.length(); } void sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override { attr->original_length= attr->length= FbtImpl::binary_length(); attr->suffix_length= 0; } uint32 max_display_length(const Item *item) const override { return FbtImpl::max_char_length(); } uint32 calc_pack_length(uint32 length) const override { return FbtImpl::binary_length(); } void Item_update_null_value(Item *item) const override { NativeBuffer tmp; item->val_native(current_thd, &tmp); } bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override { value->m_type= DYN_COL_STRING; String *str= item->val_str(&value->m_string); if (str != &value->m_string && !item->null_value) { // "item" returned a non-NULL value if (Fbt_null(*str).is_null()) { /* The value was not-null, but conversion to FBT failed: SELECT a, DECODE_ORACLE(fbtcol, 'garbage', '', '::01', '01') FROM t1; */ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, name().ptr(), ErrConvString(str).ptr()); value->m_type= DYN_COL_NULL; return true; } // "item" returned a non-NULL value, and it was a valid FBT value->m_string.set(str->ptr(), str->length(), str->charset()); } return check_null(item, value); } void Item_param_setup_conversion(THD *thd, Item_param *param) const override { param->setup_conversion_string(thd, thd->variables.character_set_client); } void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override { param->set_param_str(pos, len); } bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *val) const override { param->unsigned_flag= false; param->setup_conversion_string(thd, attr->collation.collation); /* Exact value of max_length is not known unless fbt is converted to charset of connection, so we have to set it later. */ return param->set_str(val->m_string.ptr(), val->m_string.length(), attr->collation.collation, attr->collation.collation); } bool Item_param_val_native(THD *thd, Item_param *item, Native *to) const override { StringBuffer buffer; String *str= item->val_str(&buffer); if (!str) return true; Fbt_null tmp(*str); return tmp.is_null() || tmp.to_native(to); } bool Item_send(Item *item, Protocol *p, st_value *buf) const override { return Item_send_str(item, p, buf); } int Item_save_in_field(Item *item, Field *field, bool no_conversions) const override { if (field->type_handler() == this) { NativeBuffer tmp; bool rc= item->val_native(current_thd, &tmp); if (rc || item->null_value) return set_field_to_null_with_conversions(field, no_conversions); field->set_notnull(); return field->store_native(tmp); } return item->save_str_in_field(field, no_conversions); } String *print_item_value(THD *thd, Item *item, String *str) const override { StringBuffer buf; String *result= item->val_str(&buf); /* TODO: This should eventually use one of these notations: 1. CAST('xxx' AS Fbt) Problem: CAST is not supported as a NAME_CONST() argument. 2. Fbt'xxx' Problem: This syntax is not supported by the parser yet. */ return !result || str->realloc(result->length() + 2) || str->append(STRING_WITH_LEN("'")) || str->append(result->ptr(), result->length()) || str->append(STRING_WITH_LEN("'")) ? nullptr : str; } /** Check if WHERE expr=value AND expr=const can be rewritten as: WHERE const=value AND expr=const "this" is the comparison handler that is used by "target". @param target - the predicate expr=value, whose "expr" argument will be replaced to "const". @param target_expr - the target's "expr" which will be replaced to "const". @param target_value - the target's second argument, it will remain unchanged. @param source - the equality predicate expr=const (or expr<=>const) that can be used to rewrite the "target" part (under certain conditions, see the code). @param source_expr - the source's "expr". It should be exactly equal to the target's "expr" to make condition rewrite possible. @param source_const - the source's "const" argument, it will be inserted into "target" instead of "expr". */ bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const override { /* WHERE COALESCE(col)='xxx' AND COALESCE(col)=CONCAT(a); --> WHERE COALESCE(col)='xxx' AND 'xxx'=CONCAT(a); */ return target->compare_type_handler() == source->compare_type_handler(); } bool subquery_type_allows_materialization(const Item *inner, const Item *outer, bool) const override { /* Example: SELECT * FROM t1 WHERE a IN (SELECT col FROM t1 GROUP BY col); Allow materialization only if the outer column is also FBT. This can be changed for more relaxed rules in the future. */ DBUG_ASSERT(inner->type_handler() == this); return outer->type_handler() == this; } /** Make a simple constant replacement item for a constant "src", so the new item can futher be used for comparison with "cmp", e.g.: src = cmp -> replacement = cmp "this" is the type handler that is used to compare "src" and "cmp". @param thd - current thread, for mem_root @param src - The item that we want to replace. It's a const item, but it can be complex enough to calculate on every row. @param cmp - The src's comparand. @retval - a pointer to the created replacement Item @retval - NULL, if could not create a replacement (e.g. on EOM). NULL is also returned for ROWs, because instead of replacing a Item_row to a new Item_row, Type_handler_row just replaces its elements. */ Item *make_const_item_for_comparison(THD *thd, Item *src, const Item *cmp) const override { Fbt_null tmp(src); if (tmp.is_null()) return new (thd->mem_root) Item_null(thd, src->name.str); return new (thd->mem_root) Item_literal_fbt(thd, tmp); } Item_cache *Item_get_cache(THD *thd, const Item *item) const override { return new (thd->mem_root) Item_cache_fbt(thd); } Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override { return new (thd->mem_root) Item_typecast_fbt(thd, item); } Item_copy *create_item_copy(THD *thd, Item *item) const override { return new (thd->mem_root) Item_copy_fbt(thd, item); } int cmp_native(const Native &a, const Native &b) const override { return FbtImpl::cmp(a.to_lex_cstring(), b.to_lex_cstring()); } bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override { return cmp->set_cmp_func_native(thd); } bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const override { return false; } bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const override { Fbt_null na(a), nb(b); return !na.is_null() && !nb.is_null() && !na.cmp(nb); } bool Item_bool_rowready_func2_fix_length_and_dec(THD *thd, Item_bool_rowready_func2 *func) const override { if (Type_handler::Item_bool_rowready_func2_fix_length_and_dec(thd, func)) return true; if (!func->maybe_null() && Fbt::fix_fields_maybe_null_on_conversion_to_fbt(func->arguments(), 2)) func->set_maybe_null(); return false; } bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *h, Type_all_attributes *attr, Item **items, uint nitems) const override { attr->Type_std_attributes::operator=(Type_std_attributes_fbt()); h->set_handler(this); /* If some of the arguments cannot be safely converted to "FBT NOT NULL", then mark the entire function nullability as NULL-able. Otherwise, keep the generic nullability calculated by earlier stages: - either by the most generic way in Item_func::fix_fields() - or by Item_func_xxx::fix_length_and_dec() before the call of Item_hybrid_func_fix_attributes() IFNULL() is special. It does not need to test args[0]. */ uint first= dynamic_cast(attr) ? 1 : 0; for (uint i= first; i < nitems; i++) { if (Fbt::fix_fields_maybe_null_on_conversion_to_fbt(items[i])) { attr->set_type_maybe_null(true); break; } } return false; } bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func, Item **items, uint nitems) const override { return Item_hybrid_func_fix_attributes(thd, func->func_name_cstring(), func, func, items, nitems); } bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override { func->Type_std_attributes::operator=(Type_std_attributes_fbt()); func->set_handler(this); return false; } bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *func) const override { return Item_func_or_sum_illegal_param(func); } bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *func) const override { return Item_func_or_sum_illegal_param(func); } bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *func) const override { return Item_func_or_sum_illegal_param(func); } bool Item_val_native_with_conversion(THD *thd, Item *item, Native *to) const override { if (item->type_handler() == this) return item->val_native(thd, to); // No conversion needed StringBuffer buffer; String *str= item->val_str(&buffer); return str ? character_or_binary_string_to_native(thd, str, to) : true; } bool Item_val_native_with_conversion_result(THD *thd, Item *item, Native *to) const override { if (item->type_handler() == this) return item->val_native_result(thd, to); // No conversion needed StringBuffer buffer; String *str= item->str_result(&buffer); return str ? character_or_binary_string_to_native(thd, str, to) : true; } bool Item_val_bool(Item *item) const override { NativeBuffer tmp; if (item->val_native(current_thd, &tmp)) return false; return !Fbt::only_zero_bytes(tmp.ptr(), tmp.length()); } void Item_get_date(THD *thd, Item *item, Temporal::Warn *buff, MYSQL_TIME *ltime, date_mode_t fuzzydate) const override { set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); } longlong Item_val_int_signed_typecast(Item *item) const override { DBUG_ASSERT(0); return 0; } longlong Item_val_int_unsigned_typecast(Item *item) const override { DBUG_ASSERT(0); return 0; } String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const override { NativeBuffer tmp; if ((item->null_value= item->arguments()[0]->val_native(current_thd, &tmp))) return nullptr; DBUG_ASSERT(tmp.length() == FbtImpl::binary_length()); if (str->set_hex(tmp.ptr(), tmp.length())) { str->length(0); str->set_charset(item->collation.collation); } return str; } String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *item, String *str) const override { NativeBuffer native; if (item->val_native(current_thd, &native)) { DBUG_ASSERT(item->null_value); return nullptr; } DBUG_ASSERT(native.length() == FbtImpl::binary_length()); Fbt_null tmp(native.ptr(), native.length()); return tmp.is_null() || tmp.to_string(str) ? nullptr : str; } double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) const override { return 0; } longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) const override { return 0; } my_decimal * Item_func_hybrid_field_type_val_decimal(Item_func_hybrid_field_type *, my_decimal *to) const override { my_decimal_set_zero(to); return to; } void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, Temporal::Warn *, MYSQL_TIME *to, date_mode_t fuzzydate) const override { set_zero_time(to, MYSQL_TIMESTAMP_TIME); } // WHERE is Item_func_min_max_val_native??? String *Item_func_min_max_val_str(Item_func_min_max *func, String *str) const override { Fbt_null tmp(func); return tmp.is_null() || tmp.to_string(str) ? nullptr : str; } double Item_func_min_max_val_real(Item_func_min_max *) const override { return 0; } longlong Item_func_min_max_val_int(Item_func_min_max *) const override { return 0; } my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *to) const override { my_decimal_set_zero(to); return to; } bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *to, date_mode_t fuzzydate) const override { set_zero_time(to, MYSQL_TIMESTAMP_TIME); return false; } bool Item_func_between_fix_length_and_dec(Item_func_between *func) const override { if (!func->maybe_null() && Fbt::fix_fields_maybe_null_on_conversion_to_fbt(func->arguments(), 3)) func->set_maybe_null(); return false; } longlong Item_func_between_val_int(Item_func_between *func) const override { return func->val_int_cmp_native(); } cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override { return new (thd->mem_root) cmp_item_fbt; } in_vector *make_in_vector(THD *thd, const Item_func_in *func, uint nargs) const override { return new (thd->mem_root) in_fbt(thd, nargs); } bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *func) const override { if (!func->maybe_null() && Fbt::fix_fields_maybe_null_on_conversion_to_fbt(func->arguments(), func->argument_count())) func->set_maybe_null(); if (func->compatible_types_scalar_bisection_possible()) { return func->value_list_convert_const_to_int(thd) || func->fix_for_scalar_comparison_using_bisection(thd); } return func->fix_for_scalar_comparison_using_cmp_items(thd, 1U << (uint) STRING_RESULT); } bool Item_func_round_fix_length_and_dec(Item_func_round *func) const override { return Item_func_or_sum_illegal_param(func); } bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *func) const override { return Item_func_or_sum_illegal_param(func); } bool Item_func_abs_fix_length_and_dec(Item_func_abs *func) const override { return Item_func_or_sum_illegal_param(func); } bool Item_func_neg_fix_length_and_dec(Item_func_neg *func) const override { return Item_func_or_sum_illegal_param(func); } bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const override { if (item->cast_charset() == &my_charset_bin) { static Item_char_typecast_func_handler_fbt_to_binary item_char_typecast_func_handler_fbt_to_binary; item->fix_length_and_dec_native_to_binary(FbtImpl::binary_length()); item->set_func_handler(&item_char_typecast_func_handler_fbt_to_binary); return false; } item->fix_length_and_dec_str(); return false; } bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_func_plus_fix_length_and_dec(Item_func_plus *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_func_minus_fix_length_and_dec(Item_func_minus *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_func_mul_fix_length_and_dec(Item_func_mul *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_func_div_fix_length_and_dec(Item_func_div *item) const override { return Item_func_or_sum_illegal_param(item); } bool Item_func_mod_fix_length_and_dec(Item_func_mod *item) const override { return Item_func_or_sum_illegal_param(item); } static Type_handler_fbt *singleton() { static Type_handler_fbt th; return &th; } }; template class Type_collection_fbt: public Type_collection { const Type_handler *aggregate_common(const Type_handler *a, const Type_handler *b) const { if (a == b) return a; return NULL; } const Type_handler *aggregate_if_string(const Type_handler *a, const Type_handler *b) const { static const Type_aggregator::Pair agg[]= { {Type_handler_fbt::singleton(), &type_handler_null, Type_handler_fbt::singleton()}, {Type_handler_fbt::singleton(), &type_handler_varchar, Type_handler_fbt::singleton()}, {Type_handler_fbt::singleton(), &type_handler_string, Type_handler_fbt::singleton()}, {Type_handler_fbt::singleton(), &type_handler_tiny_blob, Type_handler_fbt::singleton()}, {Type_handler_fbt::singleton(), &type_handler_blob, Type_handler_fbt::singleton()}, {Type_handler_fbt::singleton(), &type_handler_medium_blob, Type_handler_fbt::singleton()}, {Type_handler_fbt::singleton(), &type_handler_long_blob, Type_handler_fbt::singleton()}, {Type_handler_fbt::singleton(), &type_handler_hex_hybrid, Type_handler_fbt::singleton()}, {NULL,NULL,NULL} }; return Type_aggregator::find_handler_in_array(agg, a, b, true); } public: const Type_handler *aggregate_for_result(const Type_handler *a, const Type_handler *b) const override { const Type_handler *h; if ((h= aggregate_common(a, b)) || (h= aggregate_if_string(a, b))) return h; return NULL; } const Type_handler *aggregate_for_min_max(const Type_handler *a, const Type_handler *b) const override { return aggregate_for_result(a, b); } const Type_handler *aggregate_for_comparison(const Type_handler *a, const Type_handler *b) const override { if (const Type_handler *h= aggregate_common(a, b)) return h; static const Type_aggregator::Pair agg[]= { {Type_handler_fbt::singleton(), &type_handler_null, Type_handler_fbt::singleton()}, {Type_handler_fbt::singleton(), &type_handler_long_blob, Type_handler_fbt::singleton()}, {NULL,NULL,NULL} }; return Type_aggregator::find_handler_in_array(agg, a, b, true); } const Type_handler *aggregate_for_num_op(const Type_handler *a, const Type_handler *b) const override { return NULL; } static Type_collection_fbt *singleton() { static Type_collection_fbt tc; return &tc; } }; #endif /* SQL_TYPE_FIXEDBIN_H */ server/private/sql_priv.h000064400000044241151031265040011536 0ustar00/* Copyright (c) 2000, 2018, Oracle and/or its affiliates. Copyright (c) 2010, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file @details Mostly this file is used in the server. But a little part of it is used in mysqlbinlog too (definition of SELECT_DISTINCT and others). The consequence is that 90% of the file is wrapped in \#ifndef MYSQL_CLIENT, except the part which must be in the server and in the client. */ #ifndef SQL_PRIV_INCLUDED #define SQL_PRIV_INCLUDED #ifndef MYSQL_CLIENT /* Generates a warning that a feature is deprecated. After a specified version asserts that the feature is removed. Using it as WARN_DEPRECATED(thd, 6,2, "BAD", "'GOOD'"); Will result in a warning "The syntax 'BAD' is deprecated and will be removed in MySQL 6.2. Please use 'GOOD' instead" Note that in macro arguments BAD is not quoted, while 'GOOD' is. Note that the version is TWO numbers, separated with a comma (two macro arguments, that is) */ #define WARN_DEPRECATED(Thd,VerHi,VerLo,Old,New) \ do { \ compile_time_assert(MYSQL_VERSION_ID < VerHi * 10000 + VerLo * 100); \ if (((THD *) Thd) != NULL) \ push_warning_printf(((THD *) Thd), Sql_condition::WARN_LEVEL_WARN, \ ER_WARN_DEPRECATED_SYNTAX, \ ER_THD(((THD *) Thd), ER_WARN_DEPRECATED_SYNTAX), \ (Old), (New)); \ else \ sql_print_warning("The syntax '%s' is deprecated and will be removed " \ "in a future release. Please use %s instead.", \ (Old), (New)); \ } while(0) /* Generates a warning that a feature is deprecated and there is no replacement. Using it as WARN_DEPRECATED_NO_REPLACEMENT(thd, "BAD"); Will result in a warning "'BAD' is deprecated and will be removed in a future release." Note that in macro arguments BAD is not quoted. */ #define WARN_DEPRECATED_NO_REPLACEMENT(Thd,Old) \ do { \ THD *thd_= ((THD*) Thd); \ if (thd_ != NULL) \ push_warning_printf(thd_, Sql_condition::WARN_LEVEL_WARN, \ ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT, \ ER_THD(thd_, ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT), \ (Old)); \ else \ sql_print_warning("'%s' is deprecated and will be removed " \ "in a future release.", (Old)); \ } while(0) /*************************************************************************/ #endif /* This is included in the server and in the client. Options for select set by the yacc parser (stored in lex->options). NOTE log_event.h defines OPTIONS_WRITTEN_TO_BIN_LOG to specify what THD options list are written into binlog. These options can NOT change their values, or it will break replication between version. context is encoded as following: SELECT - SELECT_LEX_NODE::options THD - THD::options intern - neither. used only as func(..., select_node->options | thd->options | OPTION_XXX, ...) TODO: separate three contexts above, move them to separate bitfields. */ #define SELECT_DISTINCT (1ULL << 0) // SELECT, user #define SELECT_STRAIGHT_JOIN (1ULL << 1) // SELECT, user #define SELECT_DESCRIBE (1ULL << 2) // SELECT, user #define SELECT_SMALL_RESULT (1ULL << 3) // SELECT, user #define SELECT_BIG_RESULT (1ULL << 4) // SELECT, user #define OPTION_FOUND_ROWS (1ULL << 5) // SELECT, user #define OPTION_TO_QUERY_CACHE (1ULL << 6) // SELECT, user #define SELECT_NO_JOIN_CACHE (1ULL << 7) // intern /** always the opposite of OPTION_NOT_AUTOCOMMIT except when in fix_autocommit() */ #define OPTION_AUTOCOMMIT (1ULL << 8) // THD, user #define OPTION_BIG_SELECTS (1ULL << 9) // THD, user #define OPTION_LOG_OFF (1ULL << 10) // THD, user #define OPTION_QUOTE_SHOW_CREATE (1ULL << 11) // THD, user #define TMP_TABLE_ALL_COLUMNS (1ULL << 12) // SELECT, intern #define OPTION_WARNINGS (1ULL << 13) // THD, user #define OPTION_AUTO_IS_NULL (1ULL << 14) // THD, user, binlog #define OPTION_NO_CHECK_CONSTRAINT_CHECKS (1ULL << 15) #define OPTION_SAFE_UPDATES (1ULL << 16) // THD, user #define OPTION_BUFFER_RESULT (1ULL << 17) // SELECT, user #define OPTION_BIN_LOG (1ULL << 18) // THD, user #define OPTION_NOT_AUTOCOMMIT (1ULL << 19) // THD, user #define OPTION_BEGIN (1ULL << 20) // THD, intern #define OPTION_TABLE_LOCK (1ULL << 21) // THD, intern #define OPTION_QUICK (1ULL << 22) // SELECT (for DELETE) #define OPTION_KEEP_LOG (1ULL << 23) // THD, user #define OPTION_EXPLICIT_DEF_TIMESTAMP (1ULL << 24) // THD, user #define OPTION_GTID_BEGIN (1ULL << 25) // GTID BEGIN found in log /** The following can be set when importing tables in a 'wrong order' to suppress foreign key checks */ #define OPTION_NO_FOREIGN_KEY_CHECKS (1ULL << 26) // THD, user, binlog /** The following speeds up inserts to InnoDB tables by suppressing unique key checks in some cases */ #define OPTION_RELAXED_UNIQUE_CHECKS (1ULL << 27) // THD, user, binlog #define OPTION_IF_EXISTS (1ULL << 28) // binlog #define OPTION_SCHEMA_TABLE (1ULL << 29) // SELECT, intern /** Flag set if setup_tables already done */ #define OPTION_SETUP_TABLES_DONE (1ULL << 30) // intern /** If not set then the thread will ignore all warnings with level notes. */ #define OPTION_SQL_NOTES (1ULL << 31) // THD, user /** Force the used temporary table to be a MyISAM table (because we will use fulltext functions when reading from it. */ #define TMP_TABLE_FORCE_MYISAM (1ULL << 32) #define OPTION_PROFILING (1ULL << 33) /** Indicates that this is a HIGH_PRIORITY SELECT. Currently used only for printing of such selects. Type of locks to be acquired is specified directly. */ #define SELECT_HIGH_PRIORITY (1ULL << 34) // SELECT, user /** Is set in slave SQL thread when there was an error on master, which, when is not reproducible on slave (i.e. the query succeeds on slave), is not terminal to the state of repliation, and should be ignored. The slave SQL thread, however, needs to rollback the effects of the succeeded statement to keep replication consistent. */ #define OPTION_MASTER_SQL_ERROR (1ULL << 35) #define OPTION_SKIP_REPLICATION (1ULL << 37) // THD, user #define OPTION_RPL_SKIP_PARALLEL (1ULL << 38) #define OPTION_NO_QUERY_CACHE (1ULL << 39) // SELECT, user #define OPTION_PROCEDURE_CLAUSE (1ULL << 40) // Internal usage #define SELECT_NO_UNLOCK (1ULL << 41) // SELECT, intern #define OPTION_BIN_TMP_LOG_OFF (1ULL << 42) // disable binlog, intern /* Disable commit of binlog. Used to combine many DDL's and DML's as one */ #define OPTION_BIN_COMMIT_OFF (1ULL << 43) /* The following is used to detect a conflict with DISTINCT */ #define SELECT_ALL (1ULL << 44) // SELECT, user, parser #define OPTION_LEX_FOUND_COMMENT (1ULL << 0) // intern, parser /* The rest of the file is included in the server only */ #ifndef MYSQL_CLIENT /* @@optimizer_switch flags. These must be in sync with optimizer_switch_names */ #define OPTIMIZER_SWITCH_INDEX_MERGE (1ULL << 0) #define OPTIMIZER_SWITCH_INDEX_MERGE_UNION (1ULL << 1) #define OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION (1ULL << 2) #define OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT (1ULL << 3) #define OPTIMIZER_SWITCH_INDEX_MERGE_SORT_INTERSECT (1ULL << 4) #define deprecated_ENGINE_CONDITION_PUSHDOWN (1ULL << 5) #define OPTIMIZER_SWITCH_INDEX_COND_PUSHDOWN (1ULL << 6) #define OPTIMIZER_SWITCH_DERIVED_MERGE (1ULL << 7) #define OPTIMIZER_SWITCH_DERIVED_WITH_KEYS (1ULL << 8) #define OPTIMIZER_SWITCH_FIRSTMATCH (1ULL << 9) #define OPTIMIZER_SWITCH_LOOSE_SCAN (1ULL << 10) #define OPTIMIZER_SWITCH_MATERIALIZATION (1ULL << 11) #define OPTIMIZER_SWITCH_IN_TO_EXISTS (1ULL << 12) #define OPTIMIZER_SWITCH_SEMIJOIN (1ULL << 13) #define OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE (1ULL << 14) #define OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN (1ULL << 15) #define OPTIMIZER_SWITCH_SUBQUERY_CACHE (1ULL << 16) /** If this is off, MRR is never used. */ #define OPTIMIZER_SWITCH_MRR (1ULL << 17) /** If OPTIMIZER_SWITCH_MRR is on and this is on, MRR is used depending on a cost-based choice ("automatic"). If OPTIMIZER_SWITCH_MRR is on and this is off, MRR is "forced" (i.e. used as long as the storage engine is capable of doing it). */ #define OPTIMIZER_SWITCH_MRR_COST_BASED (1ULL << 18) #define OPTIMIZER_SWITCH_MRR_SORT_KEYS (1ULL << 19) #define OPTIMIZER_SWITCH_OUTER_JOIN_WITH_CACHE (1ULL << 20) #define OPTIMIZER_SWITCH_SEMIJOIN_WITH_CACHE (1ULL << 21) #define OPTIMIZER_SWITCH_JOIN_CACHE_INCREMENTAL (1ULL << 22) #define OPTIMIZER_SWITCH_JOIN_CACHE_HASHED (1ULL << 23) #define OPTIMIZER_SWITCH_JOIN_CACHE_BKA (1ULL << 24) #define OPTIMIZER_SWITCH_OPTIMIZE_JOIN_BUFFER_SIZE (1ULL << 25) #define OPTIMIZER_SWITCH_TABLE_ELIMINATION (1ULL << 26) #define OPTIMIZER_SWITCH_EXTENDED_KEYS (1ULL << 27) #define OPTIMIZER_SWITCH_EXISTS_TO_IN (1ULL << 28) #define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 29) #define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 30) #define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 31) #define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY (1ULL << 32) #define OPTIMIZER_SWITCH_USE_ROWID_FILTER (1ULL << 33) #define OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING (1ULL << 34) #define OPTIMIZER_SWITCH_NOT_NULL_RANGE_SCAN (1ULL << 35) #define OPTIMIZER_SWITCH_HASH_JOIN_CARDINALITY (1ULL << 36) #define OPTIMIZER_SWITCH_CSET_NARROWING (1ULL << 37) #define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \ OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \ OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION | \ OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT | \ OPTIMIZER_SWITCH_INDEX_COND_PUSHDOWN | \ OPTIMIZER_SWITCH_DERIVED_MERGE | \ OPTIMIZER_SWITCH_DERIVED_WITH_KEYS | \ OPTIMIZER_SWITCH_TABLE_ELIMINATION | \ OPTIMIZER_SWITCH_EXTENDED_KEYS | \ OPTIMIZER_SWITCH_IN_TO_EXISTS | \ OPTIMIZER_SWITCH_MATERIALIZATION | \ OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE|\ OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN|\ OPTIMIZER_SWITCH_OUTER_JOIN_WITH_CACHE | \ OPTIMIZER_SWITCH_SEMIJOIN_WITH_CACHE | \ OPTIMIZER_SWITCH_JOIN_CACHE_INCREMENTAL | \ OPTIMIZER_SWITCH_JOIN_CACHE_HASHED | \ OPTIMIZER_SWITCH_JOIN_CACHE_BKA | \ OPTIMIZER_SWITCH_SUBQUERY_CACHE | \ OPTIMIZER_SWITCH_SEMIJOIN | \ OPTIMIZER_SWITCH_FIRSTMATCH | \ OPTIMIZER_SWITCH_LOOSE_SCAN | \ OPTIMIZER_SWITCH_EXISTS_TO_IN | \ OPTIMIZER_SWITCH_ORDERBY_EQ_PROP | \ OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED | \ OPTIMIZER_SWITCH_SPLIT_MATERIALIZED | \ OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY | \ OPTIMIZER_SWITCH_USE_ROWID_FILTER | \ OPTIMIZER_SWITCH_COND_PUSHDOWN_FROM_HAVING | \ OPTIMIZER_SWITCH_OPTIMIZE_JOIN_BUFFER_SIZE) /* See adjust_secondary_key_cost in sys_vars.cc for symbolic names. */ #define OPTIMIZER_ADJ_SEC_KEY_COST (1) #define OPTIMIZER_ADJ_DISABLE_MAX_SEEKS (2) #define OPTIMIZER_ADJ_DISABLE_FORCE_INDEX_GROUP_BY (4) #define OPTIMIZER_FIX_INNODB_CARDINALITY (8) #define OPTIMIZER_ADJ_FIX_REUSE_RANGE_FOR_REF (16) #define OPTIMIZER_ADJ_FIX_CARD_MULT (32) #define OPTIMIZER_ADJ_DEFAULT (OPTIMIZER_ADJ_FIX_REUSE_RANGE_FOR_REF | \ OPTIMIZER_ADJ_FIX_CARD_MULT) /* Replication uses 8 bytes to store SQL_MODE in the binary log. The day you use strictly more than 64 bits by adding one more define above, you should contact the replication team because the replication code should then be updated (to store more bytes on disk). NOTE: When adding new SQL_MODE types, make sure to also add them to the scripts used for creating the MySQL system tables in scripts/mysql_system_tables.sql and scripts/mysql_system_tables_fix.sql */ /* Flags below are set when we perform context analysis of the statement and make subqueries non-const. It prevents subquery evaluation at context analysis stage. */ /* Don't evaluate this subquery during statement prepare even if it's a constant one. The flag is switched off in the end of mysqld_stmt_prepare. */ #define CONTEXT_ANALYSIS_ONLY_PREPARE 1 /* Special JOIN::prepare mode: changing of query is prohibited. When creating a view, we need to just check its syntax omitting any optimizations: afterwards definition of the view will be reconstructed by means of ::print() methods and written to to an .frm file. We need this definition to stay untouched. */ #define CONTEXT_ANALYSIS_ONLY_VIEW 2 /* Don't evaluate this subquery during derived table prepare even if it's a constant one. */ #define CONTEXT_ANALYSIS_ONLY_DERIVED 4 /* Don't evaluate constant sub-expressions of virtual column expressions when opening tables */ #define CONTEXT_ANALYSIS_ONLY_VCOL_EXPR 8 /* Uncachable causes: */ /* This subquery has fields from outer query (put by user) */ #define UNCACHEABLE_DEPENDENT_GENERATED 1 /* This subquery contains functions with random result. Something that is uncacheable is by default unmergeable. */ #define UNCACHEABLE_RAND 2 /* This subquery contains functions with side effect */ #define UNCACHEABLE_SIDEEFFECT 4 /* Forcing to save JOIN tables for explain */ #define UNCACHEABLE_EXPLAIN 8 /* For uncorrelated SELECT in an UNION with some correlated SELECTs */ #define UNCACHEABLE_UNITED 16 #define UNCACHEABLE_CHECKOPTION 32 /* This subquery has fields from outer query injected during transformation process */ #define UNCACHEABLE_DEPENDENT_INJECTED 64 /* This subquery has fields from outer query (any nature) */ #define UNCACHEABLE_DEPENDENT (UNCACHEABLE_DEPENDENT_GENERATED | \ UNCACHEABLE_DEPENDENT_INJECTED) /* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */ #define UNDEF_POS (-1) #define IN_SUBQUERY_CONVERSION_THRESHOLD 1000 #endif /* !MYSQL_CLIENT */ /* BINLOG_DUMP options */ #define BINLOG_DUMP_NON_BLOCK 1 #define BINLOG_SEND_ANNOTATE_ROWS_EVENT 2 #ifndef MYSQL_CLIENT /* Field::is_equal() return codes. */ #define IS_EQUAL_NO 0 #define IS_EQUAL_YES 1 /** new_field has compatible packed representation with old type, so it is theoretically possible to perform change by only updating data dictionary without changing table rows */ #define IS_EQUAL_PACK_LENGTH 2 enum enum_parsing_place { NO_MATTER, IN_HAVING, SELECT_LIST, IN_WHERE, IN_ON, IN_GROUP_BY, IN_ORDER_BY, IN_UPDATE_ON_DUP_KEY, IN_PART_FUNC, BEFORE_OPT_LIST, AFTER_LIST, FOR_LOOP_BOUND, IN_RETURNING, PARSING_PLACE_SIZE /* always should be the last */ }; class sys_var; enum enum_yes_no_unknown { TVL_YES, TVL_NO, TVL_UNKNOWN }; #ifdef MYSQL_SERVER /* External variables */ /* yy_*.cc */ #ifndef DBUG_OFF extern void turn_parser_debug_on_MYSQLparse(); extern void turn_parser_debug_on_ORAparse(); #endif /** convert a hex digit into number. */ inline int hexchar_to_int(char c) { if (c <= '9' && c >= '0') return c-'0'; c|=32; if (c <= 'f' && c >= 'a') return c-'a'+10; return -1; } /* This must match the path length limit in the ER_NOT_RW_DIR error msg. */ #define ER_NOT_RW_DIR_PATHSIZE 200 #define IS_TABLESPACES_TABLESPACE_NAME 0 #define IS_TABLESPACES_ENGINE 1 #define IS_TABLESPACES_TABLESPACE_TYPE 2 #define IS_TABLESPACES_LOGFILE_GROUP_NAME 3 #define IS_TABLESPACES_EXTENT_SIZE 4 #define IS_TABLESPACES_AUTOEXTEND_SIZE 5 #define IS_TABLESPACES_MAXIMUM_SIZE 6 #define IS_TABLESPACES_NODEGROUP_ID 7 #define IS_TABLESPACES_TABLESPACE_COMMENT 8 bool db_name_is_in_ignore_db_dirs_list(const char *dbase); #endif /* MYSQL_SERVER */ #endif /* MYSQL_CLIENT */ #endif /* SQL_PRIV_INCLUDED */ server/private/threadpool_generic.h000064400000007601151031265040013533 0ustar00/* Copyright(C) 2019, 2020, MariaDB * * This program is free software; you can redistribute itand /or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 - 1301 USA*/ #if defined (HAVE_POOL_OF_THREADS) #include #include #include #include #include #include #ifdef _WIN32 #include #include "threadpool_winsockets.h" /* AIX may define this, too ?*/ #define HAVE_IOCP #endif #ifdef _WIN32 typedef HANDLE TP_file_handle; #else typedef int TP_file_handle; #define INVALID_HANDLE_VALUE -1 #endif #ifdef __linux__ #include typedef struct epoll_event native_event; #elif defined(HAVE_KQUEUE) #include typedef struct kevent native_event; #elif defined (__sun) #include typedef port_event_t native_event; #elif defined (HAVE_IOCP) typedef OVERLAPPED_ENTRY native_event; #else #error threadpool is not available on this platform #endif struct thread_group_t; /* Per-thread structure for workers */ struct worker_thread_t { ulonglong event_count; /* number of request handled by this thread */ thread_group_t* thread_group; worker_thread_t* next_in_list; worker_thread_t** prev_in_list; mysql_cond_t cond; bool woken; }; typedef I_P_List, I_P_List_counter > worker_list_t; struct TP_connection_generic :public TP_connection { TP_connection_generic(CONNECT* c); ~TP_connection_generic(); int init() override { return 0; } void set_io_timeout(int sec) override; int start_io() override; void wait_begin(int type) override; void wait_end() override; thread_group_t* thread_group; TP_connection_generic* next_in_queue; TP_connection_generic** prev_in_queue; ulonglong abs_wait_timeout; ulonglong enqueue_time; TP_file_handle fd; bool bound_to_poll_descriptor; int waiting; bool fix_group; #ifdef _WIN32 win_aiosocket win_sock{}; void init_vio(st_vio *vio) override { win_sock.init(vio);} #endif }; typedef I_P_List, I_P_List_counter, I_P_List_fast_push_back > connection_queue_t; const int NQUEUES = 2; /* We have high and low priority queues*/ enum class operation_origin { WORKER, LISTENER }; struct thread_group_counters_t { ulonglong thread_creations; ulonglong thread_creations_due_to_stall; ulonglong wakes; ulonglong wakes_due_to_stall; ulonglong throttles; ulonglong stalls; ulonglong dequeues[2]; ulonglong polls[2]; }; struct thread_group_t { mysql_mutex_t mutex; connection_queue_t queues[NQUEUES]; worker_list_t waiting_threads; worker_thread_t* listener; pthread_attr_t* pthread_attr; TP_file_handle pollfd; int thread_count; int active_thread_count; int connection_count; /* Stats for the deadlock detection timer routine.*/ int io_event_count; int queue_event_count; ulonglong last_thread_creation_time; int shutdown_pipe[2]; bool shutdown; bool stalled; thread_group_counters_t counters; char pad[CPU_LEVEL1_DCACHE_LINESIZE]; }; #define TP_INCREMENT_GROUP_COUNTER(group,var) do {group->counters.var++;}while(0) extern thread_group_t* all_groups; #endif server/private/my_crypt.h000064400000001610151031265040011536 0ustar00/* Copyright (c) 2014 Google Inc. Copyright (c) 2014, 2015 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MY_CRYPT_INCLUDED #define MY_CRYPT_INCLUDED #include /* HAVE_EncryptAes128{Ctr,Gcm} */ #include #endif /* MY_CRYPT_INCLUDED */ server/private/sql_window.h000064400000015236151031265040012067 0ustar00/* Copyright (c) 2016, 2022 MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_WINDOW_INCLUDED #define SQL_WINDOW_INCLUDED #include "filesort.h" class Item_window_func; /* Window functions module. Each instance of window function has its own element in SELECT_LEX::window_specs. */ class Window_frame_bound : public Sql_alloc { public: enum Bound_precedence_type { PRECEDING, CURRENT, // Used for CURRENT ROW window frame bounds FOLLOWING }; Bound_precedence_type precedence_type; /* For UNBOUNDED PRECEDING / UNBOUNDED FOLLOWING window frame bounds precedence type is seto to PRECEDING / FOLLOWING and offset is set to NULL. The offset is not meaningful with precedence type CURRENT */ Item *offset; Window_frame_bound(Bound_precedence_type prec_type, Item *offset_val) : precedence_type(prec_type), offset(offset_val) {} bool is_unbounded() { return offset == NULL; } void print(String *str, enum_query_type query_type); }; class Window_frame : public Sql_alloc { public: enum Frame_units { UNITS_ROWS, UNITS_RANGE }; enum Frame_exclusion { EXCL_NONE, EXCL_CURRENT_ROW, EXCL_GROUP, EXCL_TIES }; Frame_units units; Window_frame_bound *top_bound; Window_frame_bound *bottom_bound; Frame_exclusion exclusion; Window_frame(Frame_units win_frame_units, Window_frame_bound *win_frame_top_bound, Window_frame_bound *win_frame_bottom_bound, Frame_exclusion win_frame_exclusion) : units(win_frame_units), top_bound(win_frame_top_bound), bottom_bound(win_frame_bottom_bound), exclusion(win_frame_exclusion) {} bool check_frame_bounds(); void print(String *str, enum_query_type query_type); }; class Window_spec : public Sql_alloc { bool window_names_are_checked; public: virtual ~Window_spec() = default; LEX_CSTRING *window_ref; SQL_I_List *partition_list; SQL_I_List *save_partition_list; SQL_I_List *order_list; SQL_I_List *save_order_list; Window_frame *window_frame; Window_spec *referenced_win_spec; /* Window_spec objects are numbered by the number of their appearance in the query. This is used by compare_order_elements() to provide a predictable ordering of PARTITION/ORDER BY clauses. */ int win_spec_number; Window_spec(LEX_CSTRING *win_ref, SQL_I_List *part_list, SQL_I_List *ord_list, Window_frame *win_frame) : window_names_are_checked(false), window_ref(win_ref), partition_list(part_list), save_partition_list(NULL), order_list(ord_list), save_order_list(NULL), window_frame(win_frame), referenced_win_spec(NULL) {} virtual const char *name() { return NULL; } bool check_window_names(List_iterator_fast &it); const char *window_reference() { return window_ref ? window_ref->str : NULL; } void join_partition_and_order_lists() { *(partition_list->next)= order_list->first; } void disjoin_partition_and_order_lists() { *(partition_list->next)= NULL; } void print(String *str, enum_query_type query_type); void print_order(String *str, enum_query_type query_type); void print_partition(String *str, enum_query_type query_type); }; class Window_def : public Window_spec { public: LEX_CSTRING *window_name; Window_def(LEX_CSTRING *win_name, LEX_CSTRING *win_ref, SQL_I_List *part_list, SQL_I_List *ord_list, Window_frame *win_frame) : Window_spec(win_ref, part_list, ord_list, win_frame), window_name(win_name) {} const char *name() override { return window_name->str; } }; int setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, List &win_specs, List &win_funcs); ////////////////////////////////////////////////////////////////////////////// // Classes that make window functions computation a part of SELECT's query plan ////////////////////////////////////////////////////////////////////////////// class Frame_cursor; /* This handles computation of one window function. Currently, we make a spearate filesort() call for each window function. */ class Window_func_runner : public Sql_alloc { public: /* Add the function to be computed during the execution pass */ bool add_function_to_run(Item_window_func *win_func); /* Compute and fill the fields in the table. */ bool exec(THD *thd, TABLE *tbl, SORT_INFO *filesort_result); private: /* A list of window functions for which this Window_func_runner will compute values during the execution phase. */ List window_functions; }; /* Represents a group of window functions that require the same sorting of rows and so share the filesort() call. */ class Window_funcs_sort : public Sql_alloc { public: bool setup(THD *thd, SQL_SELECT *sel, List_iterator &it, st_join_table *join_tab); bool exec(JOIN *join, bool keep_filesort_result); void cleanup() { delete filesort; } friend class Window_funcs_computation; private: Window_func_runner runner; /* Window functions can be computed over this sorting */ Filesort *filesort; }; struct st_join_table; class Explain_aggr_window_funcs; /* This is a "window function computation phase": a single object of this class takes care of computing all window functions in a SELECT. - JOIN optimizer is exected to call setup() during query optimization. - JOIN::exec() should call exec() once it has collected join output in a temporary table. */ class Window_funcs_computation : public Sql_alloc { List win_func_sorts; public: bool setup(THD *thd, List *window_funcs, st_join_table *tab); bool exec(JOIN *join, bool keep_last_filesort_result); Explain_aggr_window_funcs *save_explain_plan(MEM_ROOT *mem_root, bool is_analyze); void cleanup(); }; #endif /* SQL_WINDOW_INCLUDED */ server/private/wsrep_mysqld_c.h000064400000002313151031265040012724 0ustar00/* Copyright 2018-2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef WSREP_MYSQLD_C_H #define WSREP_MYSQLD_C_H enum enum_wsrep_certification_rules { WSREP_CERTIFICATION_RULES_STRICT, WSREP_CERTIFICATION_RULES_OPTIMIZED }; /* This is intentionally declared as a weak global symbol, so that the same ha_innodb.so can be used with the embedded server (which does not link to the definition of this variable) and with the regular server built WITH_WSREP. */ extern ulong wsrep_certification_rules __attribute__((weak)); #endif /* WSREP_MYSQLD_C_H */ server/private/my_rnd.h000064400000002050151031265040011157 0ustar00/* Copyright (C) 2013 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 or later of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_rnd_h #define _my_rnd_h C_MODE_START struct my_rnd_struct { unsigned long seed1,seed2,max_value; double max_value_dbl; }; void my_rnd_init(struct my_rnd_struct *rand_st, ulong seed1, ulong seed2); double my_rnd(struct my_rnd_struct *rand_st); double my_rnd_ssl(struct my_rnd_struct *rand_st); C_MODE_END #endif /* _my_rnd_h */ server/private/opt_subselect.h000064400000034327151031265040012556 0ustar00/* Copyright (c) 2010, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Semi-join subquery optimization code definitions */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif int check_and_do_in_subquery_rewrites(JOIN *join); bool convert_join_subqueries_to_semijoins(JOIN *join); int pull_out_semijoin_tables(JOIN *join); bool optimize_semijoin_nests(JOIN *join, table_map all_table_map); bool setup_degenerate_jtbm_semi_joins(JOIN *join, List *join_list, List &eq_list); bool setup_jtbm_semi_joins(JOIN *join, List *join_list, List &eq_list); void cleanup_empty_jtbm_semi_joins(JOIN *join, List *join_list); // used by Loose_scan_opt ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest, table_map remaining_tables); /* This is a class for considering possible loose index scan optimizations. It's usage pattern is as follows: best_access_path() { Loose_scan_opt opt; opt.init() for each index we can do ref access with { opt.next_ref_key(); for each keyuse opt.add_keyuse(); opt.check_ref_access(); } if (some criteria for range scans) opt.check_range_access(); opt.get_best_option(); } */ class Loose_scan_opt { /* All methods must check this before doing anything else */ bool try_loosescan; /* If we consider (oe1, .. oeN) IN (SELECT ie1, .. ieN) then ieK=oeK is called sj-equality. If oeK depends only on preceding tables then such equality is called 'bound'. */ ulonglong bound_sj_equalities; /* Accumulated properties of ref access we're now considering: */ ulonglong handled_sj_equalities; key_part_map loose_scan_keyparts; uint max_loose_keypart; bool part1_conds_met; /* Use of quick select is a special case. Some of its properties: */ uint quick_uses_applicable_index; uint quick_max_loose_keypart; /* Best loose scan method so far */ uint best_loose_scan_key; double best_loose_scan_cost; double best_loose_scan_records; KEYUSE *best_loose_scan_start_key; uint best_max_loose_keypart; table_map best_ref_depend_map; public: Loose_scan_opt(): try_loosescan(false), bound_sj_equalities(0), quick_uses_applicable_index(0), quick_max_loose_keypart(0), best_loose_scan_key(0), best_loose_scan_cost(0), best_loose_scan_records(0), best_loose_scan_start_key(NULL), best_max_loose_keypart(0), best_ref_depend_map(0) { } void init(JOIN *join, JOIN_TAB *s, table_map remaining_tables) { /* Discover the bound equalities. We need to do this if 1. The next table is an SJ-inner table, and 2. It is the first table from that semijoin, and 3. We're not within a semi-join range (i.e. all semi-joins either have all or none of their tables in join_table_map), except s->emb_sj_nest (which we've just entered, see #2). 4. All non-IN-equality correlation references from this sj-nest are bound 5. But some of the IN-equalities aren't (so this can't be handled by FirstMatch strategy) */ best_loose_scan_cost= DBL_MAX; if (!join->emb_sjm_nest && s->emb_sj_nest && // (1) s->emb_sj_nest->sj_in_exprs < 64 && ((remaining_tables & s->emb_sj_nest->sj_inner_tables) == // (2) s->emb_sj_nest->sj_inner_tables) && // (2) join->cur_sj_inner_tables == 0 && // (3) !(remaining_tables & s->emb_sj_nest->nested_join->sj_corr_tables) && // (4) remaining_tables & s->emb_sj_nest->nested_join->sj_depends_on &&// (5) optimizer_flag(join->thd, OPTIMIZER_SWITCH_LOOSE_SCAN)) { /* This table is an LooseScan scan candidate */ bound_sj_equalities= get_bound_sj_equalities(s->emb_sj_nest, remaining_tables); try_loosescan= TRUE; DBUG_PRINT("info", ("Will try LooseScan scan, bound_map=%llx", (longlong)bound_sj_equalities)); } } void next_ref_key() { handled_sj_equalities=0; loose_scan_keyparts= 0; max_loose_keypart= 0; part1_conds_met= FALSE; } void add_keyuse(table_map remaining_tables, KEYUSE *keyuse) { if (try_loosescan && keyuse->sj_pred_no != UINT_MAX && (keyuse->table->file->index_flags(keyuse->key, 0, 1 ) & HA_READ_ORDER)) { if (!(remaining_tables & keyuse->used_tables)) { /* This allows to use equality propagation to infer that some sj-equalities are bound. */ bound_sj_equalities |= 1ULL << keyuse->sj_pred_no; } else { handled_sj_equalities |= 1ULL << keyuse->sj_pred_no; loose_scan_keyparts |= ((key_part_map)1) << keyuse->keypart; set_if_bigger(max_loose_keypart, keyuse->keypart); } } } bool have_a_case() { return MY_TEST(handled_sj_equalities); } void check_ref_access_part1(JOIN_TAB *s, uint key, KEYUSE *start_key, table_map found_part) { /* Check if we can use LooseScan semi-join strategy. We can if 1. This is the right table at right location 2. All IN-equalities are either - "bound", ie. the outer_expr part refers to the preceding tables - "handled", ie. covered by the index we're considering 3. Index order allows to enumerate subquery's duplicate groups in order. This happens when the index definition matches this pattern: (handled_col|bound_col)* (other_col|bound_col) */ if (try_loosescan && // (1) (handled_sj_equalities | bound_sj_equalities) == // (2) PREV_BITS(ulonglong, s->emb_sj_nest->sj_in_exprs) && // (2) (PREV_BITS(key_part_map, max_loose_keypart+1) & // (3) (found_part | loose_scan_keyparts)) == // (3) PREV_BITS(key_part_map, max_loose_keypart+1) && // (3) !key_uses_partial_cols(s->table->s, key)) { if (s->quick && s->quick->index == key && s->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE) { quick_uses_applicable_index= TRUE; quick_max_loose_keypart= max_loose_keypart; } DBUG_PRINT("info", ("Can use LooseScan scan")); if (found_part & 1) { /* Can use LooseScan on ref access if the first key part is bound */ part1_conds_met= TRUE; } /* Check if this is a special case where there are no usable bound IN-equalities, i.e. we have outer_expr IN (SELECT innertbl.key FROM ...) and outer_expr cannot be evaluated yet, so it's actually full index scan and not a ref access. We can do full index scan if it uses index-only. */ if (!(found_part & 1 ) && /* no usable ref access for 1st key part */ s->table->covering_keys.is_set(key)) { part1_conds_met= TRUE; DBUG_PRINT("info", ("Can use full index scan for LooseScan")); /* Calculate the cost of complete loose index scan. */ double records= rows2double(s->table->file->stats.records); /* The cost is entire index scan cost (divided by 2) */ double read_time= s->table->file->keyread_time(key, 1, (ha_rows) records); /* Now find out how many different keys we will get (for now we ignore the fact that we have "keypart_i=const" restriction for some key components, that may make us think think that loose scan will produce more distinct records than it actually will) */ ulong rpc; if ((rpc= s->table->key_info[key].rec_per_key[max_loose_keypart])) records= records / rpc; // TODO: previous version also did /2 if (read_time < best_loose_scan_cost) { best_loose_scan_key= key; best_loose_scan_cost= read_time; best_loose_scan_records= records; best_max_loose_keypart= max_loose_keypart; best_loose_scan_start_key= start_key; best_ref_depend_map= 0; } } } } void check_ref_access_part2(uint key, KEYUSE *start_key, double records, double read_time, table_map ref_depend_map_arg) { if (part1_conds_met && read_time < best_loose_scan_cost) { /* TODO use rec-per-key-based fanout calculations */ best_loose_scan_key= key; best_loose_scan_cost= read_time; best_loose_scan_records= records; best_max_loose_keypart= max_loose_keypart; best_loose_scan_start_key= start_key; best_ref_depend_map= ref_depend_map_arg; } } void check_range_access(JOIN *join, uint idx, QUICK_SELECT_I *quick) { /* TODO: this the right part restriction: */ if (quick_uses_applicable_index && idx == join->const_tables && quick->read_time < best_loose_scan_cost) { best_loose_scan_key= quick->index; best_loose_scan_cost= quick->read_time; /* this is ok because idx == join->const_tables */ best_loose_scan_records= rows2double(quick->records); best_max_loose_keypart= quick_max_loose_keypart; best_loose_scan_start_key= NULL; best_ref_depend_map= 0; } } void save_to_position(JOIN_TAB *tab, POSITION *pos) { pos->read_time= best_loose_scan_cost; if (best_loose_scan_cost != DBL_MAX) { pos->records_read= best_loose_scan_records; pos->key= best_loose_scan_start_key; pos->cond_selectivity= 1.0; pos->loosescan_picker.loosescan_key= best_loose_scan_key; pos->loosescan_picker.loosescan_parts= best_max_loose_keypart + 1; pos->use_join_buffer= FALSE; pos->table= tab; pos->range_rowid_filter_info= tab->range_rowid_filter_info; pos->ref_depend_map= best_ref_depend_map; DBUG_PRINT("info", ("Produced a LooseScan plan, key %s, %s", tab->table->key_info[best_loose_scan_key].name.str, best_loose_scan_start_key? "(ref access)": "(range/index access)")); } } }; void optimize_semi_joins(JOIN *join, table_map remaining_tables, uint idx, double *current_record_count, double *current_read_time, POSITION *loose_scan_pos); void update_sj_state(JOIN *join, const JOIN_TAB *new_tab, uint idx, table_map remaining_tables); void restore_prev_sj_state(const table_map remaining_tables, const JOIN_TAB *tab, uint idx); void fix_semijoin_strategies_for_picked_join_order(JOIN *join); bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab); bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab); uint get_number_of_tables_at_top_level(JOIN *join); /* Temporary table used by semi-join DuplicateElimination strategy This consists of the temptable itself and data needed to put records into it. The table's DDL is as follows: CREATE TABLE tmptable (col VARCHAR(n) BINARY, PRIMARY KEY(col)); where the primary key can be replaced with unique constraint if n exceeds the limit (as it is always done for query execution-time temptables). The record value is a concatenation of rowids of tables from the join we're executing. If a join table is on the inner side of the outer join, we assume that its rowid can be NULL and provide means to store this rowid in the tuple. */ class SJ_TMP_TABLE : public Sql_alloc { public: /* Array of pointers to tables whose rowids compose the temporary table record. */ class TAB { public: JOIN_TAB *join_tab; uint rowid_offset; ushort null_byte; uchar null_bit; }; TAB *tabs; TAB *tabs_end; /* is_degenerate==TRUE means this is a special case where the temptable record has zero length (and presence of a unique key means that the temptable can have either 0 or 1 records). In this case we don't create the physical temptable but instead record its state in SJ_TMP_TABLE::have_degenerate_row. */ bool is_degenerate; /* When is_degenerate==TRUE: the contents of the table (whether it has the record or not). */ bool have_degenerate_row; /* table record parameters */ uint null_bits; uint null_bytes; uint rowid_len; /* The temporary table itself (NULL means not created yet) */ TABLE *tmp_table; /* These are the members we got from temptable creation code. We'll need them if we'll need to convert table from HEAP to MyISAM/Maria. */ TMP_ENGINE_COLUMNDEF *start_recinfo; TMP_ENGINE_COLUMNDEF *recinfo; SJ_TMP_TABLE *next_flush_table; int sj_weedout_delete_rows(); int sj_weedout_check_row(THD *thd); bool create_sj_weedout_tmp_table(THD *thd); }; int setup_semijoin_loosescan(JOIN *join); int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, uint no_jbuf_after); void destroy_sj_tmp_tables(JOIN *join); int clear_sj_tmp_tables(JOIN *join); int rewrite_to_index_subquery_engine(JOIN *join); void get_delayed_table_estimates(TABLE *table, ha_rows *out_rows, double *scan_time, double *startup_cost); enum_nested_loop_state join_tab_execution_startup(JOIN_TAB *tab); server/private/sql_array.h000064400000015333151031265040011674 0ustar00#ifndef SQL_ARRAY_INCLUDED #define SQL_ARRAY_INCLUDED /* Copyright (c) 2003, 2005-2007 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include /** A wrapper class which provides array bounds checking. We do *not* own the array, we simply have a pointer to the first element, and a length. @remark We want the compiler-generated versions of: - the copy CTOR (memberwise initialization) - the assignment operator (memberwise assignment) @param Element_type The type of the elements of the container. */ template class Bounds_checked_array { public: Bounds_checked_array()= default; Bounds_checked_array(Element_type *el, size_t size_arg) : m_array(el), m_size(size_arg) {} void reset() { m_array= NULL; m_size= 0; } void reset(Element_type *array_arg, size_t size_arg) { m_array= array_arg; m_size= size_arg; } /** Set a new bound on the array. Does not resize the underlying array, so the new size must be smaller than or equal to the current size. */ void resize(size_t new_size) { DBUG_ASSERT(new_size <= m_size); m_size= new_size; } Element_type &operator[](size_t n) { DBUG_ASSERT(n < m_size); return m_array[n]; } const Element_type &operator[](size_t n) const { DBUG_ASSERT(n < m_size); return m_array[n]; } size_t element_size() const { return sizeof(Element_type); } size_t size() const { return m_size; } bool is_null() const { return m_array == NULL; } void pop_front() { DBUG_ASSERT(m_size > 0); m_array+= 1; m_size-= 1; } Element_type *array() const { return m_array; } Element_type *begin() const { return array(); } Element_type *end() const { return array() + m_size; } bool operator==(const Bounds_checked_array&rhs) const { return m_array == rhs.m_array && m_size == rhs.m_size; } bool operator!=(const Bounds_checked_array&rhs) const { return m_array != rhs.m_array || m_size != rhs.m_size; } private: Element_type *m_array= nullptr; size_t m_size= 0; }; /* A typesafe wrapper around DYNAMIC_ARRAY TODO: Change creator to take a THREAD_SPECIFIC option. */ template class Dynamic_array { DYNAMIC_ARRAY array; public: Dynamic_array(PSI_memory_key psi_key, uint prealloc=16, uint increment=16) { init(psi_key, prealloc, increment); } Dynamic_array(MEM_ROOT *root, uint prealloc=16, uint increment=16) { void *init_buffer= alloc_root(root, sizeof(Elem) * prealloc); init_dynamic_array2(root->m_psi_key, &array, sizeof(Elem), init_buffer, prealloc, increment, MYF(0)); } void init(PSI_memory_key psi_key, uint prealloc=16, uint increment=16) { init_dynamic_array2(psi_key, &array, sizeof(Elem), 0, prealloc, increment, MYF(0)); } /** @note Though formally this could be declared "const" it would be misleading at it returns a non-const pointer to array's data. */ Elem& at(size_t idx) { DBUG_ASSERT(idx < array.elements); return *(((Elem*)array.buffer) + idx); } /// Const variant of at(), which cannot change data const Elem& at(size_t idx) const { return *(((Elem*)array.buffer) + idx); } Elem& operator[](size_t idx) { return at(idx); } /// Const variant of operator[] const Elem& operator[](size_t idx) const { return at(idx); } /// @returns pointer to first element Elem *front() { return (Elem*)array.buffer; } /// @returns pointer to first element const Elem *front() const { return (const Elem*)array.buffer; } /// @returns pointer to last element Elem *back() { return ((Elem*)array.buffer) + array.elements - 1; } /// @returns pointer to last element const Elem *back() const { return ((const Elem*)array.buffer) + array.elements - 1; } size_t size() const { return array.elements; } const Elem *end() const { return back() + 1; } /// @returns pointer to n-th element Elem *get_pos(size_t idx) { return ((Elem*)array.buffer) + idx; } /// @returns pointer to n-th element const Elem *get_pos(size_t idx) const { return ((const Elem*)array.buffer) + idx; } /** @retval false ok @retval true OOM, @c my_error() has been called. */ bool append(const Elem &el) { return insert_dynamic(&array, &el); } bool append_val(Elem el) { return (insert_dynamic(&array, (uchar*)&el)); } bool push(Elem &el) { return append(el); } /// Pops the last element. Does nothing if array is empty. Elem& pop() { return *((Elem*)pop_dynamic(&array)); } void del(size_t idx) { DBUG_ASSERT(idx <= array.max_element); delete_dynamic_element(&array, (uint)idx); } size_t elements() const { return array.elements; } void elements(size_t num_elements) { DBUG_ASSERT(num_elements <= array.max_element); array.elements= (uint)num_elements; } void clear() { elements(0); } void set(uint idx, const Elem &el) { set_dynamic(&array, &el, idx); } void freeze() { freeze_size(&array); } bool reserve(size_t new_size) { return allocate_dynamic(&array, (uint)new_size); } bool resize(size_t new_size, Elem default_val) { size_t old_size= elements(); if (reserve(new_size)) return true; if (new_size > old_size) { set_dynamic(&array, (uchar*)&default_val, (uint)(new_size - 1)); /*for (size_t i= old_size; i != new_size; i++) { at(i)= default_val; }*/ } return false; } ~Dynamic_array() { delete_dynamic(&array); } void free_memory() { delete_dynamic(&array); } void sort(int (*cmp_func)(const void *, const void *)) { my_qsort(array.buffer, array.elements, sizeof(Elem), cmp_func); } void sort(qsort_cmp2 cmp_func, void *data) { my_qsort2(array.buffer, array.elements, sizeof(Elem), cmp_func, data); } }; typedef Bounds_checked_array Ref_ptr_array; #endif /* SQL_ARRAY_INCLUDED */ server/private/my_bit.h000064400000014064151031265040011162 0ustar00/* Copyright (c) 2007, 2011, Oracle and/or its affiliates. Copyright (c) 2009, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MY_BIT_INCLUDED #define MY_BIT_INCLUDED /* Some useful bit functions */ C_MODE_START extern const uchar _my_bits_reverse_table[256]; /* my_bit_log2_xxx() In the given value, find the highest bit set, which is the smallest X that satisfies the condition: (2^X >= value). Can be used as a reverse operation for (1<> 4)) + 4: my_bit_log2_hex_digit(value); } static inline CONSTEXPR uint my_bit_log2_uint16(uint16 value) { return value & 0xFF00 ? my_bit_log2_uint8((uint8) (value >> 8)) + 8 : my_bit_log2_uint8((uint8) value); } static inline CONSTEXPR uint my_bit_log2_uint32(uint32 value) { return value & 0xFFFF0000UL ? my_bit_log2_uint16((uint16) (value >> 16)) + 16 : my_bit_log2_uint16((uint16) value); } static inline CONSTEXPR uint my_bit_log2_uint64(ulonglong value) { return value & 0xFFFFFFFF00000000ULL ? my_bit_log2_uint32((uint32) (value >> 32)) + 32 : my_bit_log2_uint32((uint32) value); } static inline CONSTEXPR uint my_bit_log2_size_t(size_t value) { #ifdef __cplusplus static_assert(sizeof(size_t) <= sizeof(ulonglong), "size_t <= ulonglong is an assumption that needs to be fixed " "for this architecture. Please create an issue on " "https://jira.mariadb.org"); #endif return my_bit_log2_uint64((ulonglong) value); } /* Count bits in 32bit integer Algorithm by Sean Anderson, according to: http://graphics.stanford.edu/~seander/bithacks.html under "Counting bits set, in parallel" (Original code public domain). */ static inline uint my_count_bits_uint32(uint32 v) { v = v - ((v >> 1) & 0x55555555); v = (v & 0x33333333) + ((v >> 2) & 0x33333333); return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; } static inline uint my_count_bits(ulonglong x) { return my_count_bits_uint32((uint32)x) + my_count_bits_uint32((uint32)(x >> 32)); } /* Next highest power of two SYNOPSIS my_round_up_to_next_power() v Value to check RETURN Next or equal power of 2 Note: 0 will return 0 NOTES Algorithm by Sean Anderson, according to: http://graphics.stanford.edu/~seander/bithacks.html (Original code public domain) Comments shows how this works with 01100000000000000000000000001011 */ static inline uint32 my_round_up_to_next_power(uint32 v) { v--; /* 01100000000000000000000000001010 */ v|= v >> 1; /* 01110000000000000000000000001111 */ v|= v >> 2; /* 01111100000000000000000000001111 */ v|= v >> 4; /* 01111111110000000000000000001111 */ v|= v >> 8; /* 01111111111111111100000000001111 */ v|= v >> 16; /* 01111111111111111111111111111111 */ return v+1; /* 10000000000000000000000000000000 */ } static inline uint32 my_clear_highest_bit(uint32 v) { uint32 w=v >> 1; w|= w >> 1; w|= w >> 2; w|= w >> 4; w|= w >> 8; w|= w >> 16; return v & w; } static inline uint32 my_reverse_bits(uint32 key) { return ((uint32)_my_bits_reverse_table[ key & 255] << 24) | ((uint32)_my_bits_reverse_table[(key>> 8) & 255] << 16) | ((uint32)_my_bits_reverse_table[(key>>16) & 255] << 8) | (uint32)_my_bits_reverse_table[(key>>24) ]; } /* a number with the n lowest bits set an overflow-safe version of (1 << n) - 1 */ static inline uint64 my_set_bits(int n) { return (((1ULL << (n - 1)) - 1) << 1) | 1; } /* Create a mask of the significant bits for the last byte (1,3,7,..255) */ static inline uchar last_byte_mask(uint bits) { /* Get the number of used bits-1 (0..7) in the last byte */ unsigned int const used = (bits - 1U) & 7U; /* Return bitmask for the significant bits */ return (uchar) ((2U << used) - 1); } static inline uint my_bits_in_bytes(uint n) { return ((n + 7) / 8); } #ifdef _MSC_VER #include #endif /* Find the position of the first(least significant) bit set in the argument. Returns 64 if the argument was 0. */ static inline uint my_find_first_bit(ulonglong n) { if(!n) return 64; #if defined(__GNUC__) return __builtin_ctzll(n); #elif defined(_MSC_VER) #if defined(_M_IX86) unsigned long bit; if( _BitScanForward(&bit, (uint)n)) return bit; _BitScanForward(&bit, (uint)(n>>32)); return bit + 32; #else unsigned long bit; _BitScanForward64(&bit, n); return bit; #endif #else /* Generic case */ uint shift= 0; static const uchar last_bit[16] = { 32, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0}; uint bit; while ((bit = last_bit[(n >> shift) & 0xF]) == 32) shift+= 4; return shift+bit; #endif } C_MODE_END #endif /* MY_BIT_INCLUDED */ server/private/my_check_opt.h000064400000005072151031265040012342 0ustar00/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_check_opt_h #define _my_check_opt_h #ifdef __cplusplus extern "C" { #endif /* All given definitions needed for MyISAM storage engine: myisamchk.c or/and ha_myisam.cc or/and micheck.c Some definitions are needed by the MySQL parser. */ #define T_AUTO_INC (1UL << 0) #define T_AUTO_REPAIR (1UL << 1) #define T_BACKUP_DATA (1UL << 2) #define T_CALC_CHECKSUM (1UL << 3) #define T_CHECK (1UL << 4) #define T_CHECK_ONLY_CHANGED (1UL << 5) #define T_CREATE_MISSING_KEYS (1UL << 6) #define T_DESCRIPT (1UL << 7) #define T_DONT_CHECK_CHECKSUM (1UL << 8) #define T_EXTEND (1UL << 9) #define T_FAST (1UL << 10) #define T_FORCE_CREATE (1UL << 11) #define T_FORCE_UNIQUENESS (1UL << 12) #define T_INFO (1UL << 13) /** CHECK TABLE...MEDIUM (the default) */ #define T_MEDIUM (1UL << 14) /** CHECK TABLE...QUICK */ #define T_QUICK (1UL << 15) #define T_READONLY (1UL << 16) #define T_REP (1UL << 17) #define T_REP_BY_SORT (1UL << 18) #define T_REP_PARALLEL (1UL << 19) #define T_RETRY_WITHOUT_QUICK (1UL << 20) #define T_SAFE_REPAIR (1UL << 21) #define T_SILENT (1UL << 22) #define T_SORT_INDEX (1UL << 23) #define T_SORT_RECORDS (1UL << 24) #define T_STATISTICS (1UL << 25) #define T_UNPACK (1UL << 26) #define T_UPDATE_STATE (1UL << 27) #define T_VERBOSE (1UL << 28) #define T_VERY_SILENT (1UL << 29) #define T_WAIT_FOREVER (1UL << 30) #define T_WRITE_LOOP (1UL << 31) #define T_ZEROFILL (1ULL << 32) #define T_ZEROFILL_KEEP_LSN (1ULL << 33) /** If repair should not bump create_rename_lsn */ #define T_NO_CREATE_RENAME_LSN (1ULL << 34) /** If repair shouldn't do any locks */ #define T_NO_LOCKS (1ULL << 35) #define T_CREATE_UNIQUE_BY_SORT (1ULL << 36) #define T_SUPPRESS_ERR_HANDLING (1ULL << 37) #define T_FORCE_SORT_MEMORY (1ULL << 38) #define T_REP_ANY (T_REP | T_REP_BY_SORT | T_REP_PARALLEL) #ifdef __cplusplus } #endif #endif server/private/sql_db.h000064400000004610151031265040011137 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_DB_INCLUDED #define SQL_DB_INCLUDED #include "hash.h" /* HASH */ class THD; int mysql_create_db(THD *thd, const LEX_CSTRING *db, DDL_options_st options, const Schema_specification_st *create); bool mysql_alter_db(THD *thd, const LEX_CSTRING *db, const Schema_specification_st *create); bool mysql_rm_db(THD *thd, const LEX_CSTRING *db, bool if_exists); bool mysql_upgrade_db(THD *thd, const LEX_CSTRING *old_db); uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name, bool force_switch); bool mysql_opt_change_db(THD *thd, const LEX_CSTRING *new_db_name, LEX_STRING *saved_db_name, bool force_switch, bool *cur_db_changed); bool my_dboptions_cache_init(void); void my_dboptions_cache_free(void); bool check_db_dir_existence(const char *db_name); bool load_db_opt(THD *thd, const char *path, Schema_specification_st *create); bool load_db_opt_by_name(THD *thd, const char *db_name, Schema_specification_st *db_create_info); CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name); bool my_dbopt_init(void); void my_dbopt_cleanup(void); const char *normalize_db_name(const char *db, char *buffer, size_t buffer_size); void drop_database_objects(THD *thd, const LEX_CSTRING *path, const LEX_CSTRING *db, bool rm_mysql_schema); my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error); #define MY_DB_OPT_FILE "db.opt" #endif /* SQL_DB_INCLUDED */ server/private/lex_token.h000064400000123006151031265040011664 0ustar00/* Copyright (c) 2011, 2018, Oracle, MariaDB Corporation Ab and others. */ /* This file is generated, do not edit. See file sql/gen_lex_token.cc. */ struct lex_token_string { const char *m_token_string; int m_token_length; bool m_append_space; bool m_start_expr; }; typedef struct lex_token_string lex_token_string; #ifdef LEX_TOKEN_WITH_DEFINITION lex_token_string lex_token_array[]= { /* PART 1: character tokens. */ /* 000 */ { "\x00", 1, true, false}, /* 001 */ { "\x01", 1, true, false}, /* 002 */ { "\x02", 1, true, false}, /* 003 */ { "\x03", 1, true, false}, /* 004 */ { "\x04", 1, true, false}, /* 005 */ { "\x05", 1, true, false}, /* 006 */ { "\x06", 1, true, false}, /* 007 */ { "\x07", 1, true, false}, /* 008 */ { "\x08", 1, true, false}, /* 009 */ { "\x09", 1, true, false}, /* 010 */ { "\x0a", 1, true, false}, /* 011 */ { "\x0b", 1, true, false}, /* 012 */ { "\x0c", 1, true, false}, /* 013 */ { "\x0d", 1, true, false}, /* 014 */ { "\x0e", 1, true, false}, /* 015 */ { "\x0f", 1, true, false}, /* 016 */ { "\x10", 1, true, false}, /* 017 */ { "\x11", 1, true, false}, /* 018 */ { "\x12", 1, true, false}, /* 019 */ { "\x13", 1, true, false}, /* 020 */ { "\x14", 1, true, false}, /* 021 */ { "\x15", 1, true, false}, /* 022 */ { "\x16", 1, true, false}, /* 023 */ { "\x17", 1, true, false}, /* 024 */ { "\x18", 1, true, false}, /* 025 */ { "\x19", 1, true, false}, /* 026 */ { "\x1a", 1, true, false}, /* 027 */ { "\x1b", 1, true, false}, /* 028 */ { "\x1c", 1, true, false}, /* 029 */ { "\x1d", 1, true, false}, /* 030 */ { "\x1e", 1, true, false}, /* 031 */ { "\x1f", 1, true, false}, /* 032 */ { "\x20", 1, true, false}, /* 033 */ { "\x21", 1, true, false}, /* 034 */ { "\x22", 1, true, false}, /* 035 */ { "\x23", 1, true, false}, /* 036 */ { "\x24", 1, true, false}, /* 037 */ { "\x25", 1, true, true}, /* 038 */ { "\x26", 1, true, true}, /* 039 */ { "\x27", 1, true, false}, /* 040 */ { "\x28", 1, true, true}, /* 041 */ { "\x29", 1, true, false}, /* 042 */ { "\x2a", 1, true, true}, /* 043 */ { "\x2b", 1, true, true}, /* 044 */ { "\x2c", 1, true, true}, /* 045 */ { "\x2d", 1, true, true}, /* 046 */ { "\x2e", 1, true, false}, /* 047 */ { "\x2f", 1, true, true}, /* 048 */ { "\x30", 1, true, false}, /* 049 */ { "\x31", 1, true, false}, /* 050 */ { "\x32", 1, true, false}, /* 051 */ { "\x33", 1, true, false}, /* 052 */ { "\x34", 1, true, false}, /* 053 */ { "\x35", 1, true, false}, /* 054 */ { "\x36", 1, true, false}, /* 055 */ { "\x37", 1, true, false}, /* 056 */ { "\x38", 1, true, false}, /* 057 */ { "\x39", 1, true, false}, /* 058 */ { "\x3a", 1, true, false}, /* 059 */ { "\x3b", 1, true, false}, /* 060 */ { "\x3c", 1, true, false}, /* 061 */ { "\x3d", 1, true, false}, /* 062 */ { "\x3e", 1, true, false}, /* 063 */ { "\x3f", 1, true, false}, /* 064 */ { "\x40", 1, false, false}, /* 065 */ { "\x41", 1, true, false}, /* 066 */ { "\x42", 1, true, false}, /* 067 */ { "\x43", 1, true, false}, /* 068 */ { "\x44", 1, true, false}, /* 069 */ { "\x45", 1, true, false}, /* 070 */ { "\x46", 1, true, false}, /* 071 */ { "\x47", 1, true, false}, /* 072 */ { "\x48", 1, true, false}, /* 073 */ { "\x49", 1, true, false}, /* 074 */ { "\x4a", 1, true, false}, /* 075 */ { "\x4b", 1, true, false}, /* 076 */ { "\x4c", 1, true, false}, /* 077 */ { "\x4d", 1, true, false}, /* 078 */ { "\x4e", 1, true, false}, /* 079 */ { "\x4f", 1, true, false}, /* 080 */ { "\x50", 1, true, false}, /* 081 */ { "\x51", 1, true, false}, /* 082 */ { "\x52", 1, true, false}, /* 083 */ { "\x53", 1, true, false}, /* 084 */ { "\x54", 1, true, false}, /* 085 */ { "\x55", 1, true, false}, /* 086 */ { "\x56", 1, true, false}, /* 087 */ { "\x57", 1, true, false}, /* 088 */ { "\x58", 1, true, false}, /* 089 */ { "\x59", 1, true, false}, /* 090 */ { "\x5a", 1, true, false}, /* 091 */ { "\x5b", 1, true, false}, /* 092 */ { "\x5c", 1, true, false}, /* 093 */ { "\x5d", 1, true, false}, /* 094 */ { "\x5e", 1, true, true}, /* 095 */ { "\x5f", 1, true, false}, /* 096 */ { "\x60", 1, true, false}, /* 097 */ { "\x61", 1, true, false}, /* 098 */ { "\x62", 1, true, false}, /* 099 */ { "\x63", 1, true, false}, /* 100 */ { "\x64", 1, true, false}, /* 101 */ { "\x65", 1, true, false}, /* 102 */ { "\x66", 1, true, false}, /* 103 */ { "\x67", 1, true, false}, /* 104 */ { "\x68", 1, true, false}, /* 105 */ { "\x69", 1, true, false}, /* 106 */ { "\x6a", 1, true, false}, /* 107 */ { "\x6b", 1, true, false}, /* 108 */ { "\x6c", 1, true, false}, /* 109 */ { "\x6d", 1, true, false}, /* 110 */ { "\x6e", 1, true, false}, /* 111 */ { "\x6f", 1, true, false}, /* 112 */ { "\x70", 1, true, false}, /* 113 */ { "\x71", 1, true, false}, /* 114 */ { "\x72", 1, true, false}, /* 115 */ { "\x73", 1, true, false}, /* 116 */ { "\x74", 1, true, false}, /* 117 */ { "\x75", 1, true, false}, /* 118 */ { "\x76", 1, true, false}, /* 119 */ { "\x77", 1, true, false}, /* 120 */ { "\x78", 1, true, false}, /* 121 */ { "\x79", 1, true, false}, /* 122 */ { "\x7a", 1, true, false}, /* 123 */ { "\x7b", 1, true, false}, /* 124 */ { "\x7c", 1, true, true}, /* 125 */ { "\x7d", 1, true, false}, /* 126 */ { "\x7e", 1, true, false}, /* 127 */ { "\x7f", 1, true, false}, /* 128 */ { "\x80", 1, true, false}, /* 129 */ { "\x81", 1, true, false}, /* 130 */ { "\x82", 1, true, false}, /* 131 */ { "\x83", 1, true, false}, /* 132 */ { "\x84", 1, true, false}, /* 133 */ { "\x85", 1, true, false}, /* 134 */ { "\x86", 1, true, false}, /* 135 */ { "\x87", 1, true, false}, /* 136 */ { "\x88", 1, true, false}, /* 137 */ { "\x89", 1, true, false}, /* 138 */ { "\x8a", 1, true, false}, /* 139 */ { "\x8b", 1, true, false}, /* 140 */ { "\x8c", 1, true, false}, /* 141 */ { "\x8d", 1, true, false}, /* 142 */ { "\x8e", 1, true, false}, /* 143 */ { "\x8f", 1, true, false}, /* 144 */ { "\x90", 1, true, false}, /* 145 */ { "\x91", 1, true, false}, /* 146 */ { "\x92", 1, true, false}, /* 147 */ { "\x93", 1, true, false}, /* 148 */ { "\x94", 1, true, false}, /* 149 */ { "\x95", 1, true, false}, /* 150 */ { "\x96", 1, true, false}, /* 151 */ { "\x97", 1, true, false}, /* 152 */ { "\x98", 1, true, false}, /* 153 */ { "\x99", 1, true, false}, /* 154 */ { "\x9a", 1, true, false}, /* 155 */ { "\x9b", 1, true, false}, /* 156 */ { "\x9c", 1, true, false}, /* 157 */ { "\x9d", 1, true, false}, /* 158 */ { "\x9e", 1, true, false}, /* 159 */ { "\x9f", 1, true, false}, /* 160 */ { "\xa0", 1, true, false}, /* 161 */ { "\xa1", 1, true, false}, /* 162 */ { "\xa2", 1, true, false}, /* 163 */ { "\xa3", 1, true, false}, /* 164 */ { "\xa4", 1, true, false}, /* 165 */ { "\xa5", 1, true, false}, /* 166 */ { "\xa6", 1, true, false}, /* 167 */ { "\xa7", 1, true, false}, /* 168 */ { "\xa8", 1, true, false}, /* 169 */ { "\xa9", 1, true, false}, /* 170 */ { "\xaa", 1, true, false}, /* 171 */ { "\xab", 1, true, false}, /* 172 */ { "\xac", 1, true, false}, /* 173 */ { "\xad", 1, true, false}, /* 174 */ { "\xae", 1, true, false}, /* 175 */ { "\xaf", 1, true, false}, /* 176 */ { "\xb0", 1, true, false}, /* 177 */ { "\xb1", 1, true, false}, /* 178 */ { "\xb2", 1, true, false}, /* 179 */ { "\xb3", 1, true, false}, /* 180 */ { "\xb4", 1, true, false}, /* 181 */ { "\xb5", 1, true, false}, /* 182 */ { "\xb6", 1, true, false}, /* 183 */ { "\xb7", 1, true, false}, /* 184 */ { "\xb8", 1, true, false}, /* 185 */ { "\xb9", 1, true, false}, /* 186 */ { "\xba", 1, true, false}, /* 187 */ { "\xbb", 1, true, false}, /* 188 */ { "\xbc", 1, true, false}, /* 189 */ { "\xbd", 1, true, false}, /* 190 */ { "\xbe", 1, true, false}, /* 191 */ { "\xbf", 1, true, false}, /* 192 */ { "\xc0", 1, true, false}, /* 193 */ { "\xc1", 1, true, false}, /* 194 */ { "\xc2", 1, true, false}, /* 195 */ { "\xc3", 1, true, false}, /* 196 */ { "\xc4", 1, true, false}, /* 197 */ { "\xc5", 1, true, false}, /* 198 */ { "\xc6", 1, true, false}, /* 199 */ { "\xc7", 1, true, false}, /* 200 */ { "\xc8", 1, true, false}, /* 201 */ { "\xc9", 1, true, false}, /* 202 */ { "\xca", 1, true, false}, /* 203 */ { "\xcb", 1, true, false}, /* 204 */ { "\xcc", 1, true, false}, /* 205 */ { "\xcd", 1, true, false}, /* 206 */ { "\xce", 1, true, false}, /* 207 */ { "\xcf", 1, true, false}, /* 208 */ { "\xd0", 1, true, false}, /* 209 */ { "\xd1", 1, true, false}, /* 210 */ { "\xd2", 1, true, false}, /* 211 */ { "\xd3", 1, true, false}, /* 212 */ { "\xd4", 1, true, false}, /* 213 */ { "\xd5", 1, true, false}, /* 214 */ { "\xd6", 1, true, false}, /* 215 */ { "\xd7", 1, true, false}, /* 216 */ { "\xd8", 1, true, false}, /* 217 */ { "\xd9", 1, true, false}, /* 218 */ { "\xda", 1, true, false}, /* 219 */ { "\xdb", 1, true, false}, /* 220 */ { "\xdc", 1, true, false}, /* 221 */ { "\xdd", 1, true, false}, /* 222 */ { "\xde", 1, true, false}, /* 223 */ { "\xdf", 1, true, false}, /* 224 */ { "\xe0", 1, true, false}, /* 225 */ { "\xe1", 1, true, false}, /* 226 */ { "\xe2", 1, true, false}, /* 227 */ { "\xe3", 1, true, false}, /* 228 */ { "\xe4", 1, true, false}, /* 229 */ { "\xe5", 1, true, false}, /* 230 */ { "\xe6", 1, true, false}, /* 231 */ { "\xe7", 1, true, false}, /* 232 */ { "\xe8", 1, true, false}, /* 233 */ { "\xe9", 1, true, false}, /* 234 */ { "\xea", 1, true, false}, /* 235 */ { "\xeb", 1, true, false}, /* 236 */ { "\xec", 1, true, false}, /* 237 */ { "\xed", 1, true, false}, /* 238 */ { "\xee", 1, true, false}, /* 239 */ { "\xef", 1, true, false}, /* 240 */ { "\xf0", 1, true, false}, /* 241 */ { "\xf1", 1, true, false}, /* 242 */ { "\xf2", 1, true, false}, /* 243 */ { "\xf3", 1, true, false}, /* 244 */ { "\xf4", 1, true, false}, /* 245 */ { "\xf5", 1, true, false}, /* 246 */ { "\xf6", 1, true, false}, /* 247 */ { "\xf7", 1, true, false}, /* 248 */ { "\xf8", 1, true, false}, /* 249 */ { "\xf9", 1, true, false}, /* 250 */ { "\xfa", 1, true, false}, /* 251 */ { "\xfb", 1, true, false}, /* 252 */ { "\xfc", 1, true, false}, /* 253 */ { "\xfd", 1, true, false}, /* 254 */ { "\xfe", 1, true, false}, /* 255 */ { "\xff", 1, true, false}, /* PART 2: named tokens. */ /* 256 */ { "(unknown)", 9, true, false}, /* 257 */ { "(unknown)", 9, true, false}, /* 258 */ { "(unknown)", 9, true, false}, /* 259 */ { "(unknown)", 9, true, false}, /* 260 */ { "(unknown)", 9, true, false}, /* 261 */ { "", 0, true, false}, /* 262 */ { "(unknown)", 9, true, false}, /* 263 */ { "?", 1, true, false}, /* 264 */ { "FOR SYSTEM_TIME", 15, true, false}, /* 265 */ { "(unknown)", 9, true, false}, /* 266 */ { "(unknown)", 9, true, false}, /* 267 */ { "(unknown)", 9, true, false}, /* 268 */ { "(unknown)", 9, true, false}, /* 269 */ { "(unknown)", 9, true, false}, /* 270 */ { "WITH CUBE", 9, true, false}, /* 271 */ { "WITH ROLLUP", 11, true, false}, /* 272 */ { "WITH SYSTEM", 11, true, false}, /* 273 */ { "(id)", 4, true, false}, /* 274 */ { "(id_quoted)", 11, true, false}, /* 275 */ { "(hostname)", 10, true, false}, /* 276 */ { "(_charset)", 10, true, false}, /* 277 */ { "(bin)", 5, true, false}, /* 278 */ { "(decimal)", 9, true, false}, /* 279 */ { "(float)", 7, true, false}, /* 280 */ { "(hex)", 5, true, false}, /* 281 */ { "(unknown)", 9, true, false}, /* 282 */ { "(long)", 6, true, false}, /* 283 */ { "(nchar)", 7, true, false}, /* 284 */ { "(num)", 5, true, false}, /* 285 */ { "(text)", 6, true, false}, /* 286 */ { "(ulonglong)", 11, true, false}, /* 287 */ { "&&", 2, true, true}, /* 288 */ { "(unknown)", 9, true, false}, /* 289 */ { "<=>", 3, true, false}, /* 290 */ { ">=", 2, true, false}, /* 291 */ { "<=", 2, true, false}, /* 292 */ { "(unknown)", 9, true, false}, /* 293 */ { "!=", 2, true, false}, /* 294 */ { "!", 1, true, false}, /* 295 */ { "||", 2, true, true}, /* 296 */ { ":=", 2, true, false}, /* 297 */ { "<<", 2, true, true}, /* 298 */ { ">>", 2, true, true}, /* 299 */ { "ACCESSIBLE", 10, true, false}, /* 300 */ { "ADD", 3, true, false}, /* 301 */ { "ALL", 3, true, false}, /* 302 */ { "ALTER", 5, true, false}, /* 303 */ { "ANALYZE", 7, true, false}, /* 304 */ { "AND", 3, true, true}, /* 305 */ { "ASC", 3, true, false}, /* 306 */ { "ASENSITIVE", 10, true, false}, /* 307 */ { "AS", 2, true, false}, /* 308 */ { "BEFORE", 6, true, false}, /* 309 */ { "BETWEEN", 7, true, true}, /* 310 */ { "INT8", 4, true, false}, /* 311 */ { "BINARY", 6, true, false}, /* 312 */ { "BIT_AND", 7, true, false}, /* 313 */ { "BIT_OR", 6, true, false}, /* 314 */ { "BIT_XOR", 7, true, false}, /* 315 */ { "BLOB", 4, true, false}, /* 316 */ { "(unknown)", 9, true, false}, /* 317 */ { "(unknown)", 9, true, false}, /* 318 */ { "BOTH", 4, true, false}, /* 319 */ { "BY", 2, true, false}, /* 320 */ { "CALL", 4, true, false}, /* 321 */ { "CASCADE", 7, true, false}, /* 322 */ { "CASE", 4, true, true}, /* 323 */ { "CAST", 4, true, false}, /* 324 */ { "CHANGE", 6, true, false}, /* 325 */ { "CHARACTER", 9, true, false}, /* 326 */ { "CHECK", 5, true, false}, /* 327 */ { "COLLATE", 7, true, false}, /* 328 */ { "CONDITION", 9, true, false}, /* 329 */ { "CONSTRAINT", 10, true, false}, /* 330 */ { "CONTINUE", 8, true, false}, /* 331 */ { "(unknown)", 9, true, false}, /* 332 */ { "CONVERT", 7, true, false}, /* 333 */ { "COUNT", 5, true, false}, /* 334 */ { "CREATE", 6, true, false}, /* 335 */ { "CROSS", 5, true, false}, /* 336 */ { "CUME_DIST", 9, true, false}, /* 337 */ { "CURDATE", 7, true, false}, /* 338 */ { "CURRENT_ROLE", 12, true, false}, /* 339 */ { "CURRENT_USER", 12, true, false}, /* 340 */ { "CURSOR", 6, true, false}, /* 341 */ { "CURTIME", 7, true, false}, /* 342 */ { "SCHEMA", 6, true, false}, /* 343 */ { "SCHEMAS", 7, true, false}, /* 344 */ { "DATE_ADD", 8, true, false}, /* 345 */ { "DATE_SUB", 8, true, false}, /* 346 */ { "DAY_HOUR", 8, true, false}, /* 347 */ { "DAY_MICROSECOND", 15, true, false}, /* 348 */ { "DAY_MINUTE", 10, true, false}, /* 349 */ { "DAY_SECOND", 10, true, false}, /* 350 */ { "DECIMAL", 7, true, false}, /* 351 */ { "DECLARE", 7, true, false}, /* 352 */ { "(unknown)", 9, true, false}, /* 353 */ { "DEFAULT", 7, true, true}, /* 354 */ { "DELETE_DOMAIN_ID", 16, true, false}, /* 355 */ { "DELETE", 6, true, false}, /* 356 */ { "DENSE_RANK", 10, true, false}, /* 357 */ { "EXPLAIN", 7, true, false}, /* 358 */ { "DESC", 4, true, false}, /* 359 */ { "DETERMINISTIC", 13, true, false}, /* 360 */ { "DISTINCTROW", 11, true, false}, /* 361 */ { "DIV", 3, true, true}, /* 362 */ { "DO_DOMAIN_IDS", 13, true, false}, /* 363 */ { "FLOAT8", 6, true, false}, /* 364 */ { "DROP", 4, true, false}, /* 365 */ { "DUAL", 4, true, false}, /* 366 */ { "EACH", 4, true, false}, /* 367 */ { "ELSEIF", 6, true, true}, /* 368 */ { "ELSE", 4, true, false}, /* 369 */ { "(unknown)", 9, true, false}, /* 370 */ { "EMPTY", 5, true, false}, /* 371 */ { "ENCLOSED", 8, true, false}, /* 372 */ { "ESCAPED", 7, true, false}, /* 373 */ { "EXCEPT", 6, true, false}, /* 374 */ { "EXISTS", 6, true, false}, /* 375 */ { "EXTRACT", 7, true, false}, /* 376 */ { "FALSE", 5, true, false}, /* 377 */ { "FETCH", 5, true, false}, /* 378 */ { "FIRST_VALUE", 11, true, false}, /* 379 */ { "FLOAT4", 6, true, false}, /* 380 */ { "FOREIGN", 7, true, false}, /* 381 */ { "FOR", 3, true, false}, /* 382 */ { "FROM", 4, true, false}, /* 383 */ { "FULLTEXT", 8, true, false}, /* 384 */ { "(unknown)", 9, true, false}, /* 385 */ { "GRANT", 5, true, false}, /* 386 */ { "GROUP_CONCAT", 12, true, false}, /* 387 */ { "JSON_ARRAYAGG", 13, true, false}, /* 388 */ { "JSON_OBJECTAGG", 14, true, false}, /* 389 */ { "JSON_TABLE", 10, true, false}, /* 390 */ { "GROUP", 5, true, false}, /* 391 */ { "HAVING", 6, true, false}, /* 392 */ { "HOUR_MICROSECOND", 16, true, false}, /* 393 */ { "HOUR_MINUTE", 11, true, false}, /* 394 */ { "HOUR_SECOND", 11, true, false}, /* 395 */ { "IF", 2, true, true}, /* 396 */ { "IGNORE_DOMAIN_IDS", 17, true, false}, /* 397 */ { "IGNORE", 6, true, false}, /* 398 */ { "IGNORED", 7, true, false}, /* 399 */ { "INDEX", 5, true, false}, /* 400 */ { "INFILE", 6, true, false}, /* 401 */ { "INNER", 5, true, false}, /* 402 */ { "INOUT", 5, true, false}, /* 403 */ { "INSENSITIVE", 11, true, false}, /* 404 */ { "INSERT", 6, true, false}, /* 405 */ { "IN", 2, true, false}, /* 406 */ { "INTERSECT", 9, true, false}, /* 407 */ { "INTERVAL", 8, true, true}, /* 408 */ { "INTO", 4, true, false}, /* 409 */ { "INTEGER", 7, true, false}, /* 410 */ { "IS", 2, true, false}, /* 411 */ { "ITERATE", 7, true, false}, /* 412 */ { "JOIN", 4, true, false}, /* 413 */ { "KEYS", 4, true, false}, /* 414 */ { "KEY", 3, true, false}, /* 415 */ { "KILL", 4, true, false}, /* 416 */ { "LAG", 3, true, false}, /* 417 */ { "LEADING", 7, true, false}, /* 418 */ { "LEAD", 4, true, false}, /* 419 */ { "LEAVE", 5, true, false}, /* 420 */ { "LEFT", 4, true, false}, /* 421 */ { "LIKE", 4, true, true}, /* 422 */ { "LIMIT", 5, true, false}, /* 423 */ { "LINEAR", 6, true, false}, /* 424 */ { "LINES", 5, true, false}, /* 425 */ { "LOAD", 4, true, false}, /* 426 */ { "LOCATOR", 7, true, false}, /* 427 */ { "LOCK", 4, true, false}, /* 428 */ { "LONGBLOB", 8, true, false}, /* 429 */ { "LONG", 4, true, false}, /* 430 */ { "LONGTEXT", 8, true, false}, /* 431 */ { "LOOP", 4, true, false}, /* 432 */ { "LOW_PRIORITY", 12, true, false}, /* 433 */ { "MASTER_SSL_VERIFY_SERVER_CERT", 29, true, false}, /* 434 */ { "MATCH", 5, true, false}, /* 435 */ { "MAX", 3, true, false}, /* 436 */ { "MAXVALUE", 8, true, false}, /* 437 */ { "MEDIAN", 6, true, false}, /* 438 */ { "MEDIUMBLOB", 10, true, false}, /* 439 */ { "MIDDLEINT", 9, true, false}, /* 440 */ { "MEDIUMTEXT", 10, true, false}, /* 441 */ { "MIN", 3, true, false}, /* 442 */ { "MINUS", 5, true, false}, /* 443 */ { "MINUTE_MICROSECOND", 18, true, false}, /* 444 */ { "MINUTE_SECOND", 13, true, false}, /* 445 */ { "MODIFIES", 8, true, false}, /* 446 */ { "MOD", 3, true, true}, /* 447 */ { "NATURAL", 7, true, false}, /* 448 */ { "~", 1, true, false}, /* 449 */ { "NESTED", 6, true, false}, /* 450 */ { "NOT", 3, true, true}, /* 451 */ { "NO_WRITE_TO_BINLOG", 18, true, false}, /* 452 */ { "NOW", 3, true, false}, /* 453 */ { "NTH_VALUE", 9, true, false}, /* 454 */ { "NTILE", 5, true, false}, /* 455 */ { "NULL", 4, true, false}, /* 456 */ { "NUMERIC", 7, true, false}, /* 457 */ { "ON", 2, true, false}, /* 458 */ { "OPTIMIZE", 8, true, false}, /* 459 */ { "OPTIONALLY", 10, true, false}, /* 460 */ { "ORDER", 5, true, false}, /* 461 */ { "ORDINALITY", 10, true, false}, /* 462 */ { "OR", 2, true, true}, /* 463 */ { "(unknown)", 9, true, false}, /* 464 */ { "OUTER", 5, true, false}, /* 465 */ { "OUTFILE", 7, true, false}, /* 466 */ { "OUT", 3, true, false}, /* 467 */ { "OVER", 4, true, false}, /* 468 */ { "(unknown)", 9, true, false}, /* 469 */ { "PAGE_CHECKSUM", 13, true, false}, /* 470 */ { "PARSE_VCOL_EXPR", 15, true, false}, /* 471 */ { "PARTITION", 9, true, false}, /* 472 */ { "PATH", 4, true, false}, /* 473 */ { "PERCENTILE_CONT", 15, true, false}, /* 474 */ { "PERCENTILE_DISC", 15, true, false}, /* 475 */ { "PERCENT_RANK", 12, true, false}, /* 476 */ { "PORTION", 7, true, false}, /* 477 */ { "POSITION", 8, true, false}, /* 478 */ { "PRECISION", 9, true, false}, /* 479 */ { "PRIMARY", 7, true, false}, /* 480 */ { "PROCEDURE", 9, true, false}, /* 481 */ { "PURGE", 5, true, false}, /* 482 */ { "(unknown)", 9, true, false}, /* 483 */ { "RANGE", 5, true, false}, /* 484 */ { "RANK", 4, true, false}, /* 485 */ { "READS", 5, true, false}, /* 486 */ { "READ", 4, true, false}, /* 487 */ { "READ_WRITE", 10, true, false}, /* 488 */ { "REAL", 4, true, false}, /* 489 */ { "RECURSIVE", 9, true, false}, /* 490 */ { "REFERENCES", 10, true, false}, /* 491 */ { "REF_SYSTEM_ID", 13, true, false}, /* 492 */ { "RLIKE", 5, true, true}, /* 493 */ { "RELEASE", 7, true, false}, /* 494 */ { "RENAME", 6, true, false}, /* 495 */ { "REPEAT", 6, true, false}, /* 496 */ { "REQUIRE", 7, true, false}, /* 497 */ { "RESIGNAL", 8, true, false}, /* 498 */ { "RESTRICT", 8, true, false}, /* 499 */ { "RETURNING", 9, true, false}, /* 500 */ { "RETURN", 6, true, true}, /* 501 */ { "(unknown)", 9, true, true}, /* 502 */ { "REVOKE", 6, true, false}, /* 503 */ { "RIGHT", 5, true, false}, /* 504 */ { "ROW_NUMBER", 10, true, false}, /* 505 */ { "ROWS", 4, true, false}, /* 506 */ { "(unknown)", 9, true, false}, /* 507 */ { "SECOND_MICROSECOND", 18, true, false}, /* 508 */ { "SELECT", 6, true, true}, /* 509 */ { "SENSITIVE", 9, true, false}, /* 510 */ { "SEPARATOR", 9, true, false}, /* 511 */ { "SERVER_OPTIONS", 14, true, false}, /* 512 */ { "SET", 3, true, false}, /* 513 */ { "SHOW", 4, true, false}, /* 514 */ { "SIGNAL", 6, true, false}, /* 515 */ { "SMALLINT", 8, true, false}, /* 516 */ { "SPATIAL", 7, true, false}, /* 517 */ { "SPECIFIC", 8, true, false}, /* 518 */ { "SQL_BIG_RESULT", 14, true, false}, /* 519 */ { "SQLEXCEPTION", 12, true, false}, /* 520 */ { "SQL_SMALL_RESULT", 16, true, false}, /* 521 */ { "SQLSTATE", 8, true, false}, /* 522 */ { "SQL", 3, true, false}, /* 523 */ { "SQLWARNING", 10, true, false}, /* 524 */ { "SSL", 3, true, false}, /* 525 */ { "STARTING", 8, true, false}, /* 526 */ { "STATS_AUTO_RECALC", 17, true, false}, /* 527 */ { "STATS_PERSISTENT", 16, true, false}, /* 528 */ { "STATS_SAMPLE_PAGES", 18, true, false}, /* 529 */ { "STDDEV_SAMP", 11, true, false}, /* 530 */ { "STDDEV_POP", 10, true, false}, /* 531 */ { "STRAIGHT_JOIN", 13, true, false}, /* 532 */ { "SUM", 3, true, false}, /* 533 */ { "SYSDATE", 7, true, false}, /* 534 */ { "TABLE_REF_PRIORITY", 18, true, false}, /* 535 */ { "TABLE", 5, true, false}, /* 536 */ { "TERMINATED", 10, true, false}, /* 537 */ { "THEN", 4, true, false}, /* 538 */ { "TINYBLOB", 8, true, false}, /* 539 */ { "TINYINT", 7, true, false}, /* 540 */ { "TINYTEXT", 8, true, false}, /* 541 */ { "TO", 2, true, false}, /* 542 */ { "TRAILING", 8, true, false}, /* 543 */ { "TRIGGER", 7, true, false}, /* 544 */ { "TRUE", 4, true, false}, /* 545 */ { "UNDO", 4, true, false}, /* 546 */ { "UNION", 5, true, false}, /* 547 */ { "UNIQUE", 6, true, false}, /* 548 */ { "UNLOCK", 6, true, false}, /* 549 */ { "UNSIGNED", 8, true, false}, /* 550 */ { "UPDATE", 6, true, false}, /* 551 */ { "USAGE", 5, true, false}, /* 552 */ { "USE", 3, true, false}, /* 553 */ { "USING", 5, true, false}, /* 554 */ { "UTC_DATE", 8, true, false}, /* 555 */ { "UTC_TIMESTAMP", 13, true, false}, /* 556 */ { "UTC_TIME", 8, true, false}, /* 557 */ { "VALUES IN", 9, true, false}, /* 558 */ { "VALUES LESS", 11, true, false}, /* 559 */ { "VALUES", 6, true, false}, /* 560 */ { "VARBINARY", 9, true, false}, /* 561 */ { "VARCHARACTER", 12, true, false}, /* 562 */ { "VAR_POP", 7, true, false}, /* 563 */ { "VAR_SAMP", 8, true, false}, /* 564 */ { "VARYING", 7, true, false}, /* 565 */ { "WHEN", 4, true, true}, /* 566 */ { "WHERE", 5, true, false}, /* 567 */ { "WHILE", 5, true, true}, /* 568 */ { "WITH", 4, true, false}, /* 569 */ { "XOR", 3, true, true}, /* 570 */ { "YEAR_MONTH", 10, true, false}, /* 571 */ { "ZEROFILL", 8, true, false}, /* 572 */ { "BODY", 4, true, false}, /* 573 */ { "(unknown)", 9, true, true}, /* 574 */ { "ELSIF", 5, true, false}, /* 575 */ { "(unknown)", 9, true, false}, /* 576 */ { "GOTO", 4, true, false}, /* 577 */ { "OTHERS", 6, true, false}, /* 578 */ { "PACKAGE", 7, true, false}, /* 579 */ { "RAISE", 5, true, false}, /* 580 */ { "ROWTYPE", 7, true, false}, /* 581 */ { "ROWNUM", 6, true, false}, /* 582 */ { "REPLACE", 7, true, false}, /* 583 */ { "SUBSTRING", 9, true, false}, /* 584 */ { "TRIM", 4, true, false}, /* 585 */ { "ACCOUNT", 7, true, false}, /* 586 */ { "ACTION", 6, true, false}, /* 587 */ { "ADMIN", 5, true, false}, /* 588 */ { "ADDDATE", 7, true, false}, /* 589 */ { "AFTER", 5, true, false}, /* 590 */ { "AGAINST", 7, true, false}, /* 591 */ { "AGGREGATE", 9, true, false}, /* 592 */ { "ALGORITHM", 9, true, false}, /* 593 */ { "ALWAYS", 6, true, false}, /* 594 */ { "SOME", 4, true, false}, /* 595 */ { "ASCII", 5, true, false}, /* 596 */ { "AT", 2, true, true}, /* 597 */ { "ATOMIC", 6, true, false}, /* 598 */ { "AUTHORS", 7, true, false}, /* 599 */ { "AUTOEXTEND_SIZE", 15, true, false}, /* 600 */ { "AUTO_INCREMENT", 14, true, false}, /* 601 */ { "AVG_ROW_LENGTH", 14, true, false}, /* 602 */ { "AVG", 3, true, false}, /* 603 */ { "BACKUP", 6, true, false}, /* 604 */ { "BEGIN", 5, true, false}, /* 605 */ { "(unknown)", 9, true, false}, /* 606 */ { "BINLOG", 6, true, false}, /* 607 */ { "BIT", 3, true, false}, /* 608 */ { "BLOCK", 5, true, false}, /* 609 */ { "BOOL", 4, true, false}, /* 610 */ { "BOOLEAN", 7, true, false}, /* 611 */ { "BTREE", 5, true, false}, /* 612 */ { "BYTE", 4, true, false}, /* 613 */ { "CACHE", 5, true, false}, /* 614 */ { "CASCADED", 8, true, false}, /* 615 */ { "CATALOG_NAME", 12, true, false}, /* 616 */ { "CHAIN", 5, true, false}, /* 617 */ { "CHANGED", 7, true, false}, /* 618 */ { "CHARSET", 7, true, false}, /* 619 */ { "CHECKPOINT", 10, true, false}, /* 620 */ { "CHECKSUM", 8, true, false}, /* 621 */ { "CIPHER", 6, true, false}, /* 622 */ { "CLASS_ORIGIN", 12, true, false}, /* 623 */ { "CLIENT", 6, true, false}, /* 624 */ { "CLOB", 4, true, false}, /* 625 */ { "(unknown)", 9, true, false}, /* 626 */ { "CLOSE", 5, true, false}, /* 627 */ { "COALESCE", 8, true, false}, /* 628 */ { "CODE", 4, true, false}, /* 629 */ { "COLLATION", 9, true, false}, /* 630 */ { "FIELDS", 6, true, false}, /* 631 */ { "COLUMN_ADD", 10, true, false}, /* 632 */ { "COLUMN_CHECK", 12, true, false}, /* 633 */ { "COLUMN_CREATE", 13, true, false}, /* 634 */ { "COLUMN_DELETE", 13, true, false}, /* 635 */ { "COLUMN_GET", 10, true, false}, /* 636 */ { "COLUMN", 6, true, false}, /* 637 */ { "COLUMN_NAME", 11, true, false}, /* 638 */ { "COMMENT", 7, true, false}, /* 639 */ { "COMMITTED", 9, true, false}, /* 640 */ { "COMMIT", 6, true, false}, /* 641 */ { "COMPACT", 7, true, false}, /* 642 */ { "COMPLETION", 10, true, false}, /* 643 */ { "COMPRESSED", 10, true, false}, /* 644 */ { "CONCURRENT", 10, true, false}, /* 645 */ { "CONNECTION", 10, true, false}, /* 646 */ { "CONSISTENT", 10, true, false}, /* 647 */ { "CONSTRAINT_CATALOG", 18, true, false}, /* 648 */ { "CONSTRAINT_NAME", 15, true, false}, /* 649 */ { "CONSTRAINT_SCHEMA", 17, true, false}, /* 650 */ { "CONTAINS", 8, true, false}, /* 651 */ { "CONTEXT", 7, true, false}, /* 652 */ { "CONTRIBUTORS", 12, true, false}, /* 653 */ { "CPU", 3, true, false}, /* 654 */ { "CUBE", 4, true, false}, /* 655 */ { "CURRENT", 7, true, false}, /* 656 */ { "CURRENT_POS", 11, true, false}, /* 657 */ { "CURSOR_NAME", 11, true, false}, /* 658 */ { "CYCLE", 5, true, false}, /* 659 */ { "DATAFILE", 8, true, false}, /* 660 */ { "DATA", 4, true, false}, /* 661 */ { "DATETIME", 8, true, false}, /* 662 */ { "DATE", 4, true, false}, /* 663 */ { "SQL_TSI_DAY", 11, true, false}, /* 664 */ { "DEALLOCATE", 10, true, false}, /* 665 */ { "DEFINER", 7, true, false}, /* 666 */ { "DELAYED", 7, true, false}, /* 667 */ { "DELAY_KEY_WRITE", 15, true, false}, /* 668 */ { "DES_KEY_FILE", 12, true, false}, /* 669 */ { "DIAGNOSTICS", 11, true, false}, /* 670 */ { "DIRECTORY", 9, true, false}, /* 671 */ { "DISABLE", 7, true, false}, /* 672 */ { "DISCARD", 7, true, false}, /* 673 */ { "DISK", 4, true, false}, /* 674 */ { "DO", 2, true, false}, /* 675 */ { "DUMPFILE", 8, true, false}, /* 676 */ { "DUPLICATE", 9, true, false}, /* 677 */ { "DYNAMIC", 7, true, false}, /* 678 */ { "ENABLE", 6, true, false}, /* 679 */ { "END", 3, true, false}, /* 680 */ { "ENDS", 4, true, true}, /* 681 */ { "ENGINES", 7, true, false}, /* 682 */ { "ENGINE", 6, true, false}, /* 683 */ { "ENUM", 4, true, false}, /* 684 */ { "ERROR", 5, true, false}, /* 685 */ { "ERRORS", 6, true, false}, /* 686 */ { "ESCAPE", 6, true, false}, /* 687 */ { "EVENTS", 6, true, false}, /* 688 */ { "EVENT", 5, true, false}, /* 689 */ { "EVERY", 5, true, true}, /* 690 */ { "EXCHANGE", 8, true, false}, /* 691 */ { "EXAMINED", 8, true, false}, /* 692 */ { "EXCLUDE", 7, true, false}, /* 693 */ { "EXECUTE", 7, true, false}, /* 694 */ { "EXCEPTION", 9, true, false}, /* 695 */ { "EXIT", 4, true, false}, /* 696 */ { "(unknown)", 9, true, false}, /* 697 */ { "EXPANSION", 9, true, false}, /* 698 */ { "EXPIRE", 6, true, false}, /* 699 */ { "EXPORT", 6, true, false}, /* 700 */ { "EXTENDED", 8, true, false}, /* 701 */ { "EXTENT_SIZE", 11, true, false}, /* 702 */ { "FAST", 4, true, false}, /* 703 */ { "FAULTS", 6, true, false}, /* 704 */ { "FEDERATED", 9, true, false}, /* 705 */ { "FILE", 4, true, false}, /* 706 */ { "FIRST", 5, true, false}, /* 707 */ { "FIXED", 5, true, false}, /* 708 */ { "FLUSH", 5, true, false}, /* 709 */ { "FOLLOWS", 7, true, false}, /* 710 */ { "FOLLOWING", 9, true, false}, /* 711 */ { "FORCE", 5, true, false}, /* 712 */ { "FORMAT", 6, true, false}, /* 713 */ { "FOUND", 5, true, false}, /* 714 */ { "FULL", 4, true, false}, /* 715 */ { "FUNCTION", 8, true, false}, /* 716 */ { "GENERAL", 7, true, false}, /* 717 */ { "GENERATED", 9, true, false}, /* 718 */ { "GET_FORMAT", 10, true, false}, /* 719 */ { "GET", 3, true, false}, /* 720 */ { "GLOBAL", 6, true, false}, /* 721 */ { "GRANTS", 6, true, false}, /* 722 */ { "HANDLER", 7, true, false}, /* 723 */ { "HARD", 4, true, false}, /* 724 */ { "HASH", 4, true, false}, /* 725 */ { "HELP", 4, true, false}, /* 726 */ { "HIGH_PRIORITY", 13, true, false}, /* 727 */ { "HISTORY", 7, true, false}, /* 728 */ { "HOST", 4, true, false}, /* 729 */ { "HOSTS", 5, true, false}, /* 730 */ { "SQL_TSI_HOUR", 12, true, false}, /* 731 */ { "ID", 2, true, false}, /* 732 */ { "IDENTIFIED", 10, true, false}, /* 733 */ { "IGNORE_SERVER_IDS", 17, true, false}, /* 734 */ { "IMMEDIATE", 9, true, false}, /* 735 */ { "IMPORT", 6, true, false}, /* 736 */ { "INCREMENT", 9, true, false}, /* 737 */ { "INDEXES", 7, true, false}, /* 738 */ { "INITIAL_SIZE", 12, true, false}, /* 739 */ { "INSERT_METHOD", 13, true, false}, /* 740 */ { "INSTALL", 7, true, false}, /* 741 */ { "INVOKER", 7, true, false}, /* 742 */ { "IO", 2, true, false}, /* 743 */ { "IPC", 3, true, false}, /* 744 */ { "ISOLATION", 9, true, false}, /* 745 */ { "ISOPEN", 6, true, false}, /* 746 */ { "ISSUER", 6, true, false}, /* 747 */ { "INVISIBLE", 9, true, false}, /* 748 */ { "JSON", 4, true, false}, /* 749 */ { "KEY_BLOCK_SIZE", 14, true, false}, /* 750 */ { "LANGUAGE", 8, true, false}, /* 751 */ { "LAST", 4, true, false}, /* 752 */ { "LAST_VALUE", 10, true, false}, /* 753 */ { "LASTVAL", 7, true, false}, /* 754 */ { "LEAVES", 6, true, false}, /* 755 */ { "LESS", 4, true, false}, /* 756 */ { "LEVEL", 5, true, false}, /* 757 */ { "LIST", 4, true, false}, /* 758 */ { "LOCAL", 5, true, false}, /* 759 */ { "LOCKED", 6, true, false}, /* 760 */ { "LOCKS", 5, true, false}, /* 761 */ { "LOGFILE", 7, true, false}, /* 762 */ { "LOGS", 4, true, false}, /* 763 */ { "MASTER_CONNECT_RETRY", 20, true, false}, /* 764 */ { "MASTER_DELAY", 12, true, false}, /* 765 */ { "MASTER_GTID_POS", 15, true, false}, /* 766 */ { "MASTER_HOST", 11, true, false}, /* 767 */ { "MASTER_LOG_FILE", 15, true, false}, /* 768 */ { "MASTER_LOG_POS", 14, true, false}, /* 769 */ { "MASTER_PASSWORD", 15, true, false}, /* 770 */ { "MASTER_PORT", 11, true, false}, /* 771 */ { "MASTER_SERVER_ID", 16, true, false}, /* 772 */ { "MASTER_SSL_CAPATH", 17, true, false}, /* 773 */ { "MASTER_SSL_CA", 13, true, false}, /* 774 */ { "MASTER_SSL_CERT", 15, true, false}, /* 775 */ { "MASTER_SSL_CIPHER", 17, true, false}, /* 776 */ { "MASTER_SSL_CRL", 14, true, false}, /* 777 */ { "MASTER_SSL_CRLPATH", 18, true, false}, /* 778 */ { "MASTER_SSL_KEY", 14, true, false}, /* 779 */ { "MASTER_SSL", 10, true, false}, /* 780 */ { "MASTER", 6, true, false}, /* 781 */ { "MASTER_USER", 11, true, false}, /* 782 */ { "MASTER_USE_GTID", 15, true, false}, /* 783 */ { "MASTER_HEARTBEAT_PERIOD", 23, true, false}, /* 784 */ { "MAX_CONNECTIONS_PER_HOUR", 24, true, false}, /* 785 */ { "MAX_QUERIES_PER_HOUR", 20, true, false}, /* 786 */ { "MAX_ROWS", 8, true, false}, /* 787 */ { "MAX_SIZE", 8, true, false}, /* 788 */ { "MAX_UPDATES_PER_HOUR", 20, true, false}, /* 789 */ { "MAX_STATEMENT_TIME", 18, true, false}, /* 790 */ { "MAX_USER_CONNECTIONS", 20, true, false}, /* 791 */ { "MEDIUM", 6, true, false}, /* 792 */ { "MEMORY", 6, true, false}, /* 793 */ { "MERGE", 5, true, false}, /* 794 */ { "MESSAGE_TEXT", 12, true, false}, /* 795 */ { "MICROSECOND", 11, true, false}, /* 796 */ { "MIGRATE", 7, true, false}, /* 797 */ { "SQL_TSI_MINUTE", 14, true, false}, /* 798 */ { "MINVALUE", 8, true, false}, /* 799 */ { "MIN_ROWS", 8, true, false}, /* 800 */ { "MODE", 4, true, false}, /* 801 */ { "MODIFY", 6, true, false}, /* 802 */ { "MONITOR", 7, true, false}, /* 803 */ { "SQL_TSI_MONTH", 13, true, false}, /* 804 */ { "MUTEX", 5, true, false}, /* 805 */ { "MYSQL", 5, true, false}, /* 806 */ { "MYSQL_ERRNO", 11, true, false}, /* 807 */ { "NAMES", 5, true, false}, /* 808 */ { "NAME", 4, true, false}, /* 809 */ { "NATIONAL", 8, true, false}, /* 810 */ { "NCHAR", 5, true, false}, /* 811 */ { "NEVER", 5, true, false}, /* 812 */ { "NEXT", 4, true, false}, /* 813 */ { "NEXTVAL", 7, true, false}, /* 814 */ { "NOCACHE", 7, true, false}, /* 815 */ { "NOCYCLE", 7, true, false}, /* 816 */ { "NODEGROUP", 9, true, false}, /* 817 */ { "NONE", 4, true, false}, /* 818 */ { "NOTFOUND", 8, true, false}, /* 819 */ { "NO", 2, true, false}, /* 820 */ { "NOMAXVALUE", 10, true, false}, /* 821 */ { "NOMINVALUE", 10, true, false}, /* 822 */ { "NO_WAIT", 7, true, false}, /* 823 */ { "NOWAIT", 6, true, false}, /* 824 */ { "NUMBER", 6, true, false}, /* 825 */ { "(unknown)", 9, true, false}, /* 826 */ { "NVARCHAR", 8, true, false}, /* 827 */ { "OF", 2, true, false}, /* 828 */ { "OFFSET", 6, true, false}, /* 829 */ { "OLD_PASSWORD", 12, true, false}, /* 830 */ { "ONE", 3, true, false}, /* 831 */ { "ONLY", 4, true, false}, /* 832 */ { "ONLINE", 6, true, false}, /* 833 */ { "OPEN", 4, true, false}, /* 834 */ { "OPTIONS", 7, true, false}, /* 835 */ { "OPTION", 6, true, false}, /* 836 */ { "OVERLAPS", 8, true, false}, /* 837 */ { "OWNER", 5, true, false}, /* 838 */ { "PACK_KEYS", 9, true, false}, /* 839 */ { "PAGE", 4, true, false}, /* 840 */ { "PARSER", 6, true, false}, /* 841 */ { "PARTIAL", 7, true, false}, /* 842 */ { "PARTITIONS", 10, true, false}, /* 843 */ { "PARTITIONING", 12, true, false}, /* 844 */ { "PASSWORD", 8, true, false}, /* 845 */ { "PERIOD", 6, true, false}, /* 846 */ { "PERSISTENT", 10, true, false}, /* 847 */ { "PHASE", 5, true, false}, /* 848 */ { "PLUGINS", 7, true, false}, /* 849 */ { "PLUGIN", 6, true, false}, /* 850 */ { "PORT", 4, true, false}, /* 851 */ { "PRECEDES", 8, true, false}, /* 852 */ { "PRECEDING", 9, true, false}, /* 853 */ { "PREPARE", 7, true, false}, /* 854 */ { "PRESERVE", 8, true, false}, /* 855 */ { "PREV", 4, true, false}, /* 856 */ { "PREVIOUS", 8, true, false}, /* 857 */ { "PRIVILEGES", 10, true, false}, /* 858 */ { "PROCESS", 7, true, false}, /* 859 */ { "PROCESSLIST", 11, true, false}, /* 860 */ { "PROFILE", 7, true, false}, /* 861 */ { "PROFILES", 8, true, false}, /* 862 */ { "PROXY", 5, true, false}, /* 863 */ { "SQL_TSI_QUARTER", 15, true, false}, /* 864 */ { "QUERY", 5, true, false}, /* 865 */ { "QUICK", 5, true, false}, /* 866 */ { "RAW", 3, true, false}, /* 867 */ { "(unknown)", 9, true, false}, /* 868 */ { "READ_ONLY", 9, true, false}, /* 869 */ { "REBUILD", 7, true, false}, /* 870 */ { "RECOVER", 7, true, false}, /* 871 */ { "REDOFILE", 8, true, false}, /* 872 */ { "REDO_BUFFER_SIZE", 16, true, false}, /* 873 */ { "REDUNDANT", 9, true, false}, /* 874 */ { "RELAY", 5, true, false}, /* 875 */ { "RELAYLOG", 8, true, false}, /* 876 */ { "RELAY_LOG_FILE", 14, true, false}, /* 877 */ { "RELAY_LOG_POS", 13, true, false}, /* 878 */ { "RELAY_THREAD", 12, true, false}, /* 879 */ { "RELOAD", 6, true, false}, /* 880 */ { "REMOVE", 6, true, false}, /* 881 */ { "REORGANIZE", 10, true, false}, /* 882 */ { "REPAIR", 6, true, false}, /* 883 */ { "REPEATABLE", 10, true, false}, /* 884 */ { "REPLAY", 6, true, false}, /* 885 */ { "REPLICATION", 11, true, false}, /* 886 */ { "RESET", 5, true, false}, /* 887 */ { "RESTART", 7, true, false}, /* 888 */ { "USER_RESOURCES", 14, true, false}, /* 889 */ { "RESTORE", 7, true, false}, /* 890 */ { "RESUME", 6, true, false}, /* 891 */ { "RETURNED_SQLSTATE", 17, true, false}, /* 892 */ { "RETURNS", 7, true, false}, /* 893 */ { "REUSE", 5, true, false}, /* 894 */ { "REVERSE", 7, true, false}, /* 895 */ { "ROLE", 4, true, false}, /* 896 */ { "ROLLBACK", 8, true, false}, /* 897 */ { "ROLLUP", 6, true, false}, /* 898 */ { "ROUTINE", 7, true, false}, /* 899 */ { "ROWCOUNT", 8, true, false}, /* 900 */ { "ROW", 3, true, false}, /* 901 */ { "ROW_COUNT", 9, true, false}, /* 902 */ { "ROW_FORMAT", 10, true, false}, /* 903 */ { "RTREE", 5, true, false}, /* 904 */ { "SAVEPOINT", 9, true, false}, /* 905 */ { "SCHEDULE", 8, true, false}, /* 906 */ { "SCHEMA_NAME", 11, true, false}, /* 907 */ { "SQL_TSI_SECOND", 14, true, false}, /* 908 */ { "SECURITY", 8, true, false}, /* 909 */ { "SEQUENCE", 8, true, false}, /* 910 */ { "SERIALIZABLE", 12, true, false}, /* 911 */ { "SERIAL", 6, true, false}, /* 912 */ { "SESSION", 7, true, false}, /* 913 */ { "SERVER", 6, true, false}, /* 914 */ { "SETVAL", 6, true, false}, /* 915 */ { "SHARE", 5, true, false}, /* 916 */ { "SHUTDOWN", 8, true, false}, /* 917 */ { "SIGNED", 6, true, false}, /* 918 */ { "SIMPLE", 6, true, false}, /* 919 */ { "SKIP", 4, true, false}, /* 920 */ { "SLAVE", 5, true, false}, /* 921 */ { "SLAVES", 6, true, false}, /* 922 */ { "SLAVE_POS", 9, true, false}, /* 923 */ { "SLOW", 4, true, false}, /* 924 */ { "SNAPSHOT", 8, true, false}, /* 925 */ { "SOCKET", 6, true, false}, /* 926 */ { "SOFT", 4, true, false}, /* 927 */ { "SONAME", 6, true, false}, /* 928 */ { "SOUNDS", 6, true, false}, /* 929 */ { "SOURCE", 6, true, false}, /* 930 */ { "SQL_BUFFER_RESULT", 17, true, false}, /* 931 */ { "SQL_CACHE", 9, true, false}, /* 932 */ { "SQL_CALC_FOUND_ROWS", 19, true, false}, /* 933 */ { "SQL_NO_CACHE", 12, true, false}, /* 934 */ { "SQL_THREAD", 10, true, false}, /* 935 */ { "STAGE", 5, true, false}, /* 936 */ { "STARTS", 6, true, true}, /* 937 */ { "START", 5, true, false}, /* 938 */ { "STATEMENT", 9, true, false}, /* 939 */ { "STATUS", 6, true, false}, /* 940 */ { "STOP", 4, true, false}, /* 941 */ { "STORAGE", 7, true, false}, /* 942 */ { "STORED", 6, true, false}, /* 943 */ { "STRING", 6, true, false}, /* 944 */ { "SUBCLASS_ORIGIN", 15, true, false}, /* 945 */ { "SUBDATE", 7, true, false}, /* 946 */ { "SUBJECT", 7, true, false}, /* 947 */ { "SUBPARTITIONS", 13, true, false}, /* 948 */ { "SUBPARTITION", 12, true, false}, /* 949 */ { "SUPER", 5, true, false}, /* 950 */ { "SUSPEND", 7, true, false}, /* 951 */ { "SWAPS", 5, true, false}, /* 952 */ { "SWITCHES", 8, true, false}, /* 953 */ { "SYSTEM", 6, true, false}, /* 954 */ { "SYSTEM_TIME", 11, true, false}, /* 955 */ { "TABLES", 6, true, false}, /* 956 */ { "TABLESPACE", 10, true, false}, /* 957 */ { "TABLE_CHECKSUM", 14, true, false}, /* 958 */ { "TABLE_NAME", 10, true, false}, /* 959 */ { "TEMPORARY", 9, true, false}, /* 960 */ { "TEMPTABLE", 9, true, false}, /* 961 */ { "TEXT", 4, true, false}, /* 962 */ { "THAN", 4, true, false}, /* 963 */ { "TIES", 4, true, false}, /* 964 */ { "TIMESTAMP", 9, true, false}, /* 965 */ { "TIMESTAMPADD", 12, true, false}, /* 966 */ { "TIMESTAMPDIFF", 13, true, false}, /* 967 */ { "TIME", 4, true, false}, /* 968 */ { "TRANSACTION", 11, true, false}, /* 969 */ { "TRANSACTIONAL", 13, true, false}, /* 970 */ { "THREADS", 7, true, false}, /* 971 */ { "TRIGGERS", 8, true, false}, /* 972 */ { "TRIM_ORACLE", 11, true, false}, /* 973 */ { "TRUNCATE", 8, true, false}, /* 974 */ { "TYPE", 4, true, false}, /* 975 */ { "UDF_RETURNS", 11, true, false}, /* 976 */ { "UNBOUNDED", 9, true, false}, /* 977 */ { "UNCOMMITTED", 11, true, false}, /* 978 */ { "UNDEFINED", 9, true, false}, /* 979 */ { "UNDOFILE", 8, true, false}, /* 980 */ { "UNDO_BUFFER_SIZE", 16, true, false}, /* 981 */ { "UNICODE", 7, true, false}, /* 982 */ { "UNINSTALL", 9, true, false}, /* 983 */ { "UNKNOWN", 7, true, false}, /* 984 */ { "UNTIL", 5, true, true}, /* 985 */ { "UPGRADE", 7, true, false}, /* 986 */ { "SYSTEM_USER", 11, true, false}, /* 987 */ { "USE_FRM", 7, true, false}, /* 988 */ { "VALUE", 5, true, false}, /* 989 */ { "VARCHAR2", 8, true, false}, /* 990 */ { "(unknown)", 9, true, false}, /* 991 */ { "VARIABLES", 9, true, false}, /* 992 */ { "VERSIONING", 10, true, false}, /* 993 */ { "VIA", 3, true, false}, /* 994 */ { "VIEW", 4, true, false}, /* 995 */ { "VISIBLE", 7, true, false}, /* 996 */ { "VIRTUAL", 7, true, false}, /* 997 */ { "WAIT", 4, true, false}, /* 998 */ { "WARNINGS", 8, true, false}, /* 999 */ { "WEEK", 4, true, false}, /* 1000 */ { "WEIGHT_STRING", 13, true, false}, /* 1001 */ { "WINDOW", 6, true, false}, /* 1002 */ { "WITHIN", 6, true, false}, /* 1003 */ { "WITHOUT", 7, true, false}, /* 1004 */ { "WORK", 4, true, false}, /* 1005 */ { "WRAPPER", 7, true, false}, /* 1006 */ { "WRITE", 5, true, false}, /* 1007 */ { "X509", 4, true, false}, /* 1008 */ { "XA", 2, true, false}, /* 1009 */ { "XML", 3, true, false}, /* 1010 */ { "YEAR", 4, true, false}, /* 1011 */ { "?", 1, true, false}, /* 1012 */ { "?, ...", 6, true, false}, /* 1013 */ { "(?)", 3, true, false}, /* 1014 */ { "(?) /* , ... */", 15, true, false}, /* 1015 */ { "(...)", 5, true, false}, /* 1016 */ { "(...) /* , ... */", 17, true, false}, /* 1017 */ { "(tok_id)", 8, true, false}, /* 1018 */ { "UNUSED", 6, true, false}, /* DUMMY */ { "", 0, false, false} }; #endif /* LEX_TOKEN_WITH_DEFINITION */ /* DIGEST specific tokens. */ #define TOK_GENERIC_VALUE 1011 #define TOK_GENERIC_VALUE_LIST 1012 #define TOK_ROW_SINGLE_VALUE 1013 #define TOK_ROW_SINGLE_VALUE_LIST 1014 #define TOK_ROW_MULTIPLE_VALUE 1015 #define TOK_ROW_MULTIPLE_VALUE_LIST 1016 #define TOK_IDENT 1017 #define TOK_UNUSED 1018 server/private/cset_narrowing.h000064400000007600151031265040012721 0ustar00/* Copyright (c) 2023, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef CSET_NARROWING_H_INCLUDED #define CSET_NARROWING_H_INCLUDED /* A singleton class to provide "utf8mb3_from_mb4.charset()". This is a variant of utf8mb3_general_ci that one can use when they have data in MB4 and want to make index lookup keys in MB3. */ extern class Charset_utf8narrow { struct my_charset_handler_st cset_handler; struct charset_info_st cset; public: Charset_utf8narrow() : cset_handler(*my_charset_utf8mb3_general_ci.cset), cset(my_charset_utf8mb3_general_ci) /* Copy the CHARSET_INFO structure */ { /* Insert our function wc_mb */ cset_handler.wc_mb= my_wc_mb_utf8mb4_bmp_only; cset.cset=&cset_handler; /* Charsets are compared by their name, so assign a different name */ LEX_CSTRING tmp= {STRING_WITH_LEN("utf8_mb4_to_mb3")}; cset.cs_name= tmp; } CHARSET_INFO *charset() { return &cset; } } utf8mb3_from_mb4; /* A class to temporary change a field that uses utf8mb3_general_ci to enable correct lookup key construction from string value in utf8mb4_general_ci Intended usage: // can do this in advance: bool do_narrowing= Utf8_narrow::should_do_narrowing(field, value_cset); ... // This sets the field to do narrowing if necessary: Utf8_narrow narrow(field, do_narrowing); // write to 'field' here // item->save_in_field(field) or something else // Stop doing narrowing narrow.stop(); */ class Utf8_narrow { Field *field; DTCollation save_collation; public: static bool should_do_narrowing(const THD *thd, CHARSET_INFO *field_cset, CHARSET_INFO *value_cset); static bool should_do_narrowing(const Field *field, CHARSET_INFO *value_cset) { CHARSET_INFO *field_cset= field->charset(); THD *thd= field->table->in_use; return should_do_narrowing(thd, field_cset, value_cset); } Utf8_narrow(Field *field_arg, bool is_applicable) { field= NULL; if (is_applicable) { DTCollation mb3_from_mb4= utf8mb3_from_mb4.charset(); field= field_arg; save_collation= field->dtcollation(); field->change_charset(mb3_from_mb4); } } void stop() { if (field) field->change_charset(save_collation); #ifndef NDEBUG field= NULL; #endif } ~Utf8_narrow() { DBUG_ASSERT(!field); } }; /* @brief Check if two fields can participate in a multiple equality using charset narrowing. @detail Normally, check_simple_equality() checks this by calling: left_field->eq_def(right_field) This function does the same but takes into account we might use charset narrowing: - collations are not the same but rather an utf8mb{3,4}_general_ci pair - for field lengths, should compare # characters, not #bytes. */ inline bool fields_equal_using_narrowing(const THD *thd, const Field *left, const Field *right) { return dynamic_cast(left) && dynamic_cast(right) && left->real_type() == right->real_type() && (Utf8_narrow::should_do_narrowing(left, right->charset()) || Utf8_narrow::should_do_narrowing(right, left->charset())) && left->char_length() == right->char_length(); }; #endif /* CSET_NARROWING_H_INCLUDED */ server/private/sql_prepare.h000064400000026221151031265040012212 0ustar00#ifndef SQL_PREPARE_H #define SQL_PREPARE_H /* Copyright (c) 1995-2008 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "sql_error.h" #define LAST_STMT_ID 0xFFFFFFFF #define STMT_ID_MASK 0x7FFFFFFF class THD; struct LEX; /** An interface that is used to take an action when the locking module notices that a table version has changed since the last execution. "Table" here may refer to any kind of table -- a base table, a temporary table, a view or an information schema table. When we open and lock tables for execution of a prepared statement, we must verify that they did not change since statement prepare. If some table did change, the statement parse tree *may* be no longer valid, e.g. in case it contains optimizations that depend on table metadata. This class provides an interface (a method) that is invoked when such a situation takes place. The implementation of the method simply reports an error, but the exact details depend on the nature of the SQL statement. At most 1 instance of this class is active at a time, in which case THD::m_reprepare_observer is not NULL. @sa check_and_update_table_version() for details of the version tracking algorithm @sa Open_tables_state::m_reprepare_observer for the life cycle of metadata observers. */ class Reprepare_observer { public: /** Check if a change of metadata is OK. In future the signature of this method may be extended to accept the old and the new versions, but since currently the check is very simple, we only need the THD to report an error. */ bool report_error(THD *thd); bool is_invalidated() const { return m_invalidated; } void reset_reprepare_observer() { m_invalidated= FALSE; } private: bool m_invalidated; }; void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length); void mysqld_stmt_execute(THD *thd, char *packet, uint packet_length); void mysqld_stmt_execute_bulk(THD *thd, char *packet, uint packet_length); void mysqld_stmt_bulk_execute(THD *thd, char *packet, uint packet_length); void mysqld_stmt_close(THD *thd, char *packet); void mysql_sql_stmt_prepare(THD *thd); void mysql_sql_stmt_execute(THD *thd); void mysql_sql_stmt_execute_immediate(THD *thd); void mysql_sql_stmt_close(THD *thd); void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length); void mysqld_stmt_reset(THD *thd, char *packet); void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length); void reinit_stmt_before_use(THD *thd, LEX *lex); my_bool bulk_parameters_iterations(THD *thd); my_bool bulk_parameters_set(THD *thd); /** Execute a fragment of server code in an isolated context, so that it doesn't leave any effect on THD. THD must have no open tables. The code must not leave any open tables around. The result of execution (if any) is stored in Ed_result. */ class Server_runnable { public: virtual bool execute_server_code(THD *thd)= 0; virtual ~Server_runnable(); }; /** Execute direct interface. @todo Implement support for prelocked mode. */ class Ed_row; /** Ed_result_set -- a container with result set rows. @todo Implement support for result set metadata and automatic type conversion. */ class Ed_result_set { public: operator List&() { return *m_rows; } unsigned int size() const { return m_rows->elements; } Ed_result_set(List *rows_arg, size_t column_count, MEM_ROOT *mem_root_arg); /** We don't call member destructors, they all are POD types. */ ~Ed_result_set() = default; size_t get_field_count() const { return m_column_count; } static void *operator new(size_t size, MEM_ROOT *mem_root) { return alloc_root(mem_root, size); } static void operator delete(void *ptr, size_t size) throw (); static void operator delete(void *, MEM_ROOT *){} private: Ed_result_set(const Ed_result_set &); /* not implemented */ Ed_result_set &operator=(Ed_result_set &); /* not implemented */ private: MEM_ROOT m_mem_root; size_t m_column_count; List *m_rows; Ed_result_set *m_next_rset; friend class Ed_connection; }; class Ed_connection { public: /** Construct a new "execute direct" connection. The connection can be used to execute SQL statements. If the connection failed to initialize, the error will be returned on the attempt to execute a statement. @pre thd must have no open tables while the connection is used. However, Ed_connection works okay in LOCK TABLES mode. Other properties of THD, such as the current warning information, errors, etc. do not matter and are preserved by Ed_connection. One thread may have many Ed_connections created for it. */ Ed_connection(THD *thd); /** Execute one SQL statement. Until this method is executed, no other methods of Ed_connection can be used. Life cycle of Ed_connection is: Initialized -> a statement has been executed -> look at result, move to next result -> look at result, move to next result -> ... moved beyond the last result == Initialized. This method can be called repeatedly. Once it's invoked, results of the previous execution are lost. A result of execute_direct() can be either: - success, no result set rows. In this case get_field_count() returns 0. This happens after execution of INSERT, UPDATE, DELETE, DROP and similar statements. Some other methods, such as get_affected_rows() can be used to retrieve additional result information. - success, there are some result set rows (maybe 0). E.g. happens after SELECT. In this case get_field_count() returns the number of columns in a result set and store_result() can be used to retrieve a result set.. - an error, methods to retrieve error information can be used. @return execution status @retval FALSE success, use get_field_count() to determine what to do next. @retval TRUE error, use get_last_error() to see the error number. */ bool execute_direct(Protocol *p, LEX_STRING sql_text); /** Same as the previous, but takes an instance of Server_runnable instead of SQL statement text. @return execution status @retval FALSE success, use get_field_count() if your code fragment is supposed to return a result set @retval TRUE failure */ bool execute_direct(Protocol *p, Server_runnable *server_runnable); /** Get the number of affected (deleted, updated) rows for the current statement. Can be used for statements with get_field_count() == 0. @sa Documentation for C API function mysql_affected_rows(). */ ulonglong get_affected_rows() const { return m_diagnostics_area.affected_rows(); } /** Get the last insert id, if any. @sa Documentation for mysql_insert_id(). */ ulonglong get_last_insert_id() const { return m_diagnostics_area.last_insert_id(); } /** Get the total number of warnings for the last executed statement. Note, that there is only one warning list even if a statement returns multiple results. @sa Documentation for C API function mysql_num_warnings(). */ ulong get_warn_count() const { return m_diagnostics_area.warn_count(); } /** The following members are only valid if execute_direct() or move_to_next_result() returned an error. They never fail, but if they are called when there is no result, or no error, the result is not defined. */ const char *get_last_error() const { return m_diagnostics_area.message(); } unsigned int get_last_errno() const { return m_diagnostics_area.sql_errno(); } const char *get_last_sqlstate() const { return m_diagnostics_area.get_sqlstate(); } /** Provided get_field_count() is not 0, this never fails. You don't need to free the result set, this is done automatically when you advance to the next result set or destroy the connection. Not returning const because of List iterator not accepting Should be used when you would like Ed_connection to manage result set memory for you. */ Ed_result_set *use_result_set() { return m_current_rset; } /** Provided get_field_count() is not 0, this never fails. You must free the returned result set. This can be called only once after execute_direct(). Should be used when you would like to get the results and destroy the connection. */ Ed_result_set *store_result_set(); /** If the query returns multiple results, this method can be checked if there is another result beyond the next one. Never fails. */ bool has_next_result() const { return MY_TEST(m_current_rset->m_next_rset); } /** Only valid to call if has_next_result() returned true. Otherwise the result is undefined. */ bool move_to_next_result() { m_current_rset= m_current_rset->m_next_rset; return MY_TEST(m_current_rset); } ~Ed_connection() { free_old_result(); } private: Diagnostics_area m_diagnostics_area; /** Execute direct interface does not support multi-statements, only multi-results. So we never have a situation when we have a mix of result sets and OK or error packets. We either have a single result set, a single error, or a single OK, or we have a series of result sets, followed by an OK or error. */ THD *m_thd; Ed_result_set *m_rsets; Ed_result_set *m_current_rset; private: void free_old_result(); void add_result_set(Ed_result_set *ed_result_set); private: Ed_connection(const Ed_connection &); /* not implemented */ Ed_connection &operator=(Ed_connection &); /* not implemented */ }; /** One result set column. */ struct Ed_column: public LEX_STRING { /** Implementation note: destructor for this class is never called. */ }; /** One result set record. */ class Ed_row: public Sql_alloc { public: const Ed_column &operator[](const unsigned int column_index) const { return *get_column(column_index); } const Ed_column *get_column(const unsigned int column_index) const { DBUG_ASSERT(column_index < size()); return m_column_array + column_index; } size_t size() const { return m_column_count; } Ed_row(Ed_column *column_array_arg, size_t column_count_arg) :m_column_array(column_array_arg), m_column_count(column_count_arg) {} private: Ed_column *m_column_array; size_t m_column_count; /* TODO: change to point to metadata */ }; extern Atomic_counter local_connection_thread_count; #endif // SQL_PREPARE_H server/private/sql_trigger.h000064400000030054151031265040012216 0ustar00#ifndef SQL_TRIGGER_INCLUDED #define SQL_TRIGGER_INCLUDED /* Copyright (c) 2004, 2011, Oracle and/or its affiliates. Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include /* Forward declarations */ class Item_trigger_field; class sp_head; class sp_name; class Query_tables_list; struct TABLE_LIST; class Query_tables_list; typedef struct st_ddl_log_state DDL_LOG_STATE; /** Event on which trigger is invoked. */ enum trg_event_type { TRG_EVENT_INSERT= 0, TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2, TRG_EVENT_MAX }; static inline uint8 trg2bit(enum trg_event_type trg) { return static_cast(1 << static_cast(trg)); } #include "table.h" /* GRANT_INFO */ /* We need this two enums here instead of sql_lex.h because at least one of them is used by Item_trigger_field interface. Time when trigger is invoked (i.e. before or after row actually inserted/updated/deleted). */ enum trg_action_time_type { TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX }; enum trigger_order_type { TRG_ORDER_NONE= 0, TRG_ORDER_FOLLOWS= 1, TRG_ORDER_PRECEDES= 2 }; struct st_trg_execution_order { /** FOLLOWS or PRECEDES as specified in the CREATE TRIGGER statement. */ enum trigger_order_type ordering_clause; /** Trigger name referenced in the FOLLOWS/PRECEDES clause of the CREATE TRIGGER statement. */ LEX_CSTRING anchor_trigger_name; }; /* Parameter to change_table_name_in_triggers() */ class TRIGGER_RENAME_PARAM { public: TABLE table; bool upgrading50to51; bool got_error; TRIGGER_RENAME_PARAM() { upgrading50to51= got_error= 0; table.reset(); } ~TRIGGER_RENAME_PARAM() { reset(); } void reset(); }; class Table_triggers_list; /** The trigger object */ class Trigger :public Sql_alloc { public: Trigger(Table_triggers_list *base_arg, sp_head *code): base(base_arg), body(code), next(0), trigger_fields(0), action_order(0) { bzero((char *)&subject_table_grants, sizeof(subject_table_grants)); } ~Trigger(); Table_triggers_list *base; sp_head *body; Trigger *next; /* Next trigger of same type */ /** Heads of the lists linking items for all fields used in triggers grouped by event and action_time. */ Item_trigger_field *trigger_fields; LEX_CSTRING name; LEX_CSTRING on_table_name; /* Raw table name */ LEX_CSTRING definition; LEX_CSTRING definer; /* Character sets used */ LEX_CSTRING client_cs_name; LEX_CSTRING connection_cl_name; LEX_CSTRING db_cl_name; GRANT_INFO subject_table_grants; sql_mode_t sql_mode; /* Store create time. Can't be mysql_time_t as this holds also sub seconds */ my_hrtime_t hr_create_time; // Create time timestamp in microseconds trg_event_type event; trg_action_time_type action_time; uint action_order; bool is_fields_updated_in_trigger(MY_BITMAP *used_fields); void get_trigger_info(LEX_CSTRING *stmt, LEX_CSTRING *body, LEX_STRING *definer); /* Functions executed over each active trigger */ bool change_on_table_name(void* param_arg); bool change_table_name(void* param_arg); bool add_to_file_list(void* param_arg); }; typedef bool (Trigger::*Triggers_processor)(void *arg); /** This class holds all information about triggers of table. */ class Table_triggers_list: public Sql_alloc { friend class Trigger; /* Points to first trigger for a certain type */ Trigger *triggers[TRG_EVENT_MAX][TRG_ACTION_MAX]; /** Copy of TABLE::Field array which all fields made nullable (using extra_null_bitmap, if needed). Used for NEW values in BEFORE INSERT/UPDATE triggers. */ Field **record0_field; uchar *extra_null_bitmap, *extra_null_bitmap_init; /** Copy of TABLE::Field array with field pointers set to TABLE::record[1] buffer instead of TABLE::record[0] (used for OLD values in on UPDATE trigger and DELETE trigger when it is called for REPLACE). */ Field **record1_field; /** During execution of trigger new_field and old_field should point to the array of fields representing new or old version of row correspondingly (so it can point to TABLE::field or to Tale_triggers_list::record1_field) */ Field **new_field; Field **old_field; /* TABLE instance for which this triggers list object was created */ TABLE *trigger_table; /** This flag indicates that one of the triggers was not parsed successfully, and as a precaution the object has entered a state where all trigger access results in errors until all such triggers are dropped. It is not safe to add triggers since we don't know if the broken trigger has the same name or event type. Nor is it safe to invoke any trigger for the aforementioned reasons. The only safe operations are drop_trigger and drop_all_triggers. @see Table_triggers_list::set_parse_error */ bool m_has_unparseable_trigger; /** This error will be displayed when the user tries to manipulate or invoke triggers on a table that has broken triggers. It will get set only once per statement and thus will contain the first parse error encountered in the trigger file. */ char m_parse_error_message[MYSQL_ERRMSG_SIZE]; uint count; /* Number of triggers */ public: /** Field responsible for storing triggers definitions in file. It have to be public because we are using it directly from parser. */ List definitions_list; /** List of sql modes for triggers */ List definition_modes_list; /** Create times for triggers */ List hr_create_times; List definers_list; /* Character set context, used for parsing and executing triggers. */ List client_cs_names; List connection_cl_names; List db_cl_names; /* End of character ser context. */ Table_triggers_list(TABLE *table_arg) :record0_field(0), extra_null_bitmap(0), extra_null_bitmap_init(0), record1_field(0), trigger_table(table_arg), m_has_unparseable_trigger(false), count(0) { bzero((char *) triggers, sizeof(triggers)); } ~Table_triggers_list(); bool create_trigger(THD *thd, TABLE_LIST *table, String *stmt_query, DDL_LOG_STATE *ddl_log_state, DDL_LOG_STATE *ddl_log_state_tmp_file); bool drop_trigger(THD *thd, TABLE_LIST *table, LEX_CSTRING *sp_name, String *stmt_query, DDL_LOG_STATE *ddl_log_state); bool process_triggers(THD *thd, trg_event_type event, trg_action_time_type time_type, bool old_row_is_record1); void empty_lists(); bool create_lists_needed_for_files(MEM_ROOT *root); bool save_trigger_file(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table_name); static bool check_n_load(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table_name, TABLE *table, bool names_only); static bool drop_all_triggers(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table_name, myf MyFlags); static bool prepare_for_rename(THD *thd, TRIGGER_RENAME_PARAM *param, const LEX_CSTRING *db, const LEX_CSTRING *old_alias, const LEX_CSTRING *old_table, const LEX_CSTRING *new_db, const LEX_CSTRING *new_table); static bool change_table_name(THD *thd, TRIGGER_RENAME_PARAM *param, const LEX_CSTRING *db, const LEX_CSTRING *old_alias, const LEX_CSTRING *old_table, const LEX_CSTRING *new_db, const LEX_CSTRING *new_table); void add_trigger(trg_event_type event_type, trg_action_time_type action_time, trigger_order_type ordering_clause, LEX_CSTRING *anchor_trigger_name, Trigger *trigger); Trigger *get_trigger(trg_event_type event_type, trg_action_time_type action_time) { return triggers[event_type][action_time]; } /* Simpler version of the above, to avoid casts in the code */ Trigger *get_trigger(uint event_type, uint action_time) { return get_trigger((trg_event_type) event_type, (trg_action_time_type) action_time); } bool has_triggers(trg_event_type event_type, trg_action_time_type action_time) { return get_trigger(event_type,action_time) != 0; } bool has_delete_triggers() { return (has_triggers(TRG_EVENT_DELETE,TRG_ACTION_BEFORE) || has_triggers(TRG_EVENT_DELETE,TRG_ACTION_AFTER)); } void mark_fields_used(trg_event_type event); void set_parse_error_message(char *error_message); friend class Item_trigger_field; bool add_tables_and_routines_for_triggers(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list); Field **nullable_fields() { return record0_field; } void clear_extra_null_bitmap() { if (size_t null_bytes= extra_null_bitmap_init - extra_null_bitmap) bzero(extra_null_bitmap, null_bytes); } void default_extra_null_bitmap() { if (size_t null_bytes= extra_null_bitmap_init - extra_null_bitmap) memcpy(extra_null_bitmap, extra_null_bitmap_init, null_bytes); } Trigger *find_trigger(const LEX_CSTRING *name, bool remove_from_list); Trigger* for_all_triggers(Triggers_processor func, void *arg); private: bool prepare_record_accessors(TABLE *table); Trigger *change_table_name_in_trignames(const LEX_CSTRING *old_db_name, const LEX_CSTRING *new_db_name, const LEX_CSTRING *new_table_name, Trigger *trigger); bool change_table_name_in_triggers(THD *thd, const LEX_CSTRING *old_db_name, const LEX_CSTRING *new_db_name, const LEX_CSTRING *old_table_name, const LEX_CSTRING *new_table_name); bool check_for_broken_triggers() { if (m_has_unparseable_trigger) { my_message(ER_PARSE_ERROR, m_parse_error_message, MYF(0)); return true; } return false; } }; bool add_table_for_trigger(THD *thd, const sp_name *trg_name, bool continue_if_not_exist, TABLE_LIST **table); void build_trn_path(THD *thd, const sp_name *trg_name, LEX_STRING *trn_path); bool check_trn_exists(const LEX_CSTRING *trn_path); bool load_table_name_for_trigger(THD *thd, const sp_name *trg_name, const LEX_CSTRING *trn_path, LEX_CSTRING *tbl_name); bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create); bool rm_trigname_file(char *path, const LEX_CSTRING *db, const LEX_CSTRING *trigger_name, myf MyFlags); extern const char * const TRG_EXT; extern const char * const TRN_EXT; #endif /* SQL_TRIGGER_INCLUDED */ server/private/create_tmp_table.h000064400000005370151031265040013171 0ustar00#ifndef CREATE_TMP_TABLE_INCLUDED #define CREATE_TMP_TABLE_INCLUDED /* Copyright (c) 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Class for creating internal tempory tables in sql_select.cc */ class Create_tmp_table: public Data_type_statistics { protected: // The following members are initialized only in start() Field **m_from_field, **m_default_field; KEY_PART_INFO *m_key_part_info; uchar *m_group_buff, *m_bitmaps; // The following members are initialized in ctor uint m_alloced_field_count; bool m_using_unique_constraint; uint m_temp_pool_slot; ORDER *m_group; bool m_distinct; bool m_save_sum_fields; bool m_with_cycle; ulonglong m_select_options; ha_rows m_rows_limit; uint m_group_null_items; // counter for distinct/other fields uint m_field_count[2]; // counter for distinct/other fields which can be NULL uint m_null_count[2]; // counter for distinct/other blob fields uint m_blobs_count[2]; // counter for "tails" of bit fields which do not fit in a byte uint m_uneven_bit[2]; public: enum counter {distinct, other}; /* shows which field we are processing: distinct/other (set in processing cycles) */ counter current_counter; Create_tmp_table(ORDER *group, bool distinct, bool save_sum_fields, ulonglong select_options, ha_rows rows_limit); virtual ~Create_tmp_table() {} virtual bool choose_engine(THD *thd, TABLE *table, TMP_TABLE_PARAM *param); void add_field(TABLE *table, Field *field, uint fieldnr, bool force_not_null_cols); TABLE *start(THD *thd, TMP_TABLE_PARAM *param, const LEX_CSTRING *table_alias); bool add_fields(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, List &fields); bool add_schema_fields(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, const ST_SCHEMA_TABLE &schema_table); bool finalize(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, bool do_not_open, bool keep_row_order); void cleanup_on_failure(THD *thd, TABLE *table); }; #endif /* CREATE_TMP_TABLE_INCLUDED */ server/private/wsrep_utils.h000064400000022112151031265040012250 0ustar00/* Copyright (C) 2013-2015 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA. */ #ifndef WSREP_UTILS_H #define WSREP_UTILS_H #include "wsrep_priv.h" #include "wsrep_mysqld.h" unsigned int wsrep_check_ip (const char* const addr, bool *is_ipv6); size_t wsrep_guess_ip (char* buf, size_t buf_len); /* returns the length of the host part of the address string */ size_t wsrep_host_len(const char* addr, size_t addr_len); namespace wsp { class Address { public: Address() : m_address_len(0), m_family(UNSPEC), m_port(0), m_valid(false) { memset(m_address, 0, sizeof(m_address)); } Address(const char *addr_in) : m_address_len(0), m_family(UNSPEC), m_port(0), m_valid(false) { memset(m_address, 0, sizeof(m_address)); parse_addr(addr_in); } bool is_valid() { return m_valid; } bool is_ipv6() { return (m_family == INET6); } const char* get_address() { return m_address; } size_t get_address_len() { return m_address_len; } int get_port() { return m_port; } void set_port(int port) { m_port= port; } private: enum family { UNSPEC= 0, INET, /* IPv4 */ INET6, /* IPv6 */ }; char m_address[256]; size_t m_address_len; family m_family; int m_port; bool m_valid; void parse_addr(const char *addr_in) { const char *start; const char *end; const char *port; const char* open_bracket= strchr(const_cast(addr_in), '['); const char* close_bracket= strchr(const_cast(addr_in), ']'); const char* colon= strchr(const_cast(addr_in), ':'); const char* dot= strchr(const_cast(addr_in), '.'); int cc= colon_count(addr_in); if (open_bracket != NULL || dot == NULL || (colon != NULL && (dot == NULL || colon < dot))) { // This could be an IPv6 address or a hostname if (open_bracket != NULL) { /* Sanity check: Address with '[' must include ']' */ if (close_bracket == NULL && open_bracket < close_bracket) /* Error: malformed address */ { m_valid= false; return; } start= open_bracket + 1; end= close_bracket; /* Check for port */ port= strchr(close_bracket, ':'); if ((port != NULL) && parse_port(port + 1)) { return; /* Error: invalid port */ } m_family= INET6; } else { switch (cc) { case 0: /* Hostname with no port */ start= addr_in; end= addr_in + strlen(addr_in); break; case 1: /* Hostname with port (host:port) */ start= addr_in; end= colon; if (parse_port(colon + 1)) return; /* Error: invalid port */ break; default: /* IPv6 address */ start= addr_in; end= addr_in + strlen(addr_in); m_family= INET6; break; } } } else { /* IPv4 address or hostname */ start= addr_in; if (colon != NULL) { /* Port */ end= colon; if (parse_port(colon + 1)) return; /* Error: invalid port */ } else { end= addr_in + strlen(addr_in); } } size_t len= end - start; /* Safety */ if (len >= sizeof(m_address)) { // The supplied address is too large to fit into the internal buffer. m_valid= false; return; } memcpy(m_address, start, len); m_address[len]= '\0'; m_address_len= ++ len; m_valid= true; return; } int colon_count(const char *addr) { int count= 0, i= 0; while(addr[i] != '\0') { if (addr[i] == ':') ++count; ++ i; } return count; } bool parse_port(const char *port) { errno= 0; /* Reset the errno */ m_port= strtol(port, NULL, 10); if (errno == EINVAL || errno == ERANGE) { m_port= 0; /* Error: invalid port */ m_valid= false; return true; } return false; } }; class Config_state { public: Config_state() : view_(), status_(wsrep::server_state::s_disconnected) {} void set(const wsrep::view& view) { wsrep_notify_status(status_, &view); lock(); view_= view; unlock(); } void set(enum wsrep::server_state::state status) { if (status == wsrep::server_state::s_donor || status == wsrep::server_state::s_synced) wsrep_notify_status(status, &view_); else wsrep_notify_status(status); lock(); status_= status; unlock(); } const wsrep::view& get_view_info() const { return view_; } enum wsrep::server_state::state get_status() const { return status_; } int lock() { return mysql_mutex_lock(&LOCK_wsrep_config_state); } int unlock() { return mysql_mutex_unlock(&LOCK_wsrep_config_state); } private: wsrep::view view_; enum wsrep::server_state::state status_; }; } /* namespace wsp */ extern wsp::Config_state *wsrep_config_state; namespace wsp { /* a class to manage env vars array */ class env { private: size_t len_; char** env_; int errno_; bool ctor_common(char** e); void dtor(); env& operator =(env); public: explicit env(char** env); explicit env(const env&); ~env(); int append(const char* var); /* add a new env. var */ int error() const { return errno_; } char** operator()() { return env_; } }; /* A small class to run external programs. */ class process { private: const char* const str_; FILE* io_; int err_; pid_t pid_; public: /*! @arg type is a pointer to a null-terminated string which must contain either the letter 'r' for reading or the letter 'w' for writing. @arg env optional null-terminated vector of environment variables */ process (const char* cmd, const char* type, char** env); ~process (); FILE* pipe () { return io_; } int error() { return err_; } int wait (); const char* cmd() { return str_; } }; class thd { class thd_init { public: thd_init() { my_thread_init(); } ~thd_init() { my_thread_end(); } } init; thd (const thd&); thd& operator= (const thd&); public: thd(my_bool wsrep_on, bool system_thread=false); ~thd(); THD* const ptr; }; class string { public: string() : string_(0) {} explicit string(size_t s) : string_(static_cast(malloc(s))) {} char* operator()() { return string_; } void set(char* str) { if (string_) free (string_); string_= str; } ~string() { set (0); } private: char* string_; }; /* scope level lock */ class auto_lock { public: auto_lock(mysql_mutex_t* m) : m_(m) { mysql_mutex_lock(m_); } ~auto_lock() { mysql_mutex_unlock(m_); } private: mysql_mutex_t& operator =(mysql_mutex_t&); mysql_mutex_t* const m_; }; #ifdef REMOVED class lock { pthread_mutex_t* const mtx_; public: lock (pthread_mutex_t* mtx) : mtx_(mtx) { int err= pthread_mutex_lock (mtx_); if (err) { WSREP_ERROR("Mutex lock failed: %s", strerror(err)); abort(); } } virtual ~lock () { int err= pthread_mutex_unlock (mtx_); if (err) { WSREP_ERROR("Mutex unlock failed: %s", strerror(err)); abort(); } } inline void wait (pthread_cond_t* cond) { pthread_cond_wait (cond, mtx_); } private: lock (const lock&); lock& operator=(const lock&); }; class monitor { int mutable refcnt; pthread_mutex_t mutable mtx; pthread_cond_t mutable cond; public: monitor() : refcnt(0) { pthread_mutex_init (&mtx, NULL); pthread_cond_init (&cond, NULL); } ~monitor() { pthread_mutex_destroy (&mtx); pthread_cond_destroy (&cond); } void enter() const { lock l(&mtx); while (refcnt) { l.wait(&cond); } refcnt++; } void leave() const { lock l(&mtx); refcnt--; if (refcnt == 0) { pthread_cond_signal (&cond); } } private: monitor (const monitor&); monitor& operator= (const monitor&); }; class critical { const monitor& mon; public: critical(const monitor& m) : mon(m) { mon.enter(); } ~critical() { mon.leave(); } private: critical (const critical&); critical& operator= (const critical&); }; #endif } // namespace wsrep #endif /* WSREP_UTILS_H */ server/private/item_windowfunc.h000064400000103013151031265040013071 0ustar00/* Copyright (c) 2016, 2020, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ITEM_WINDOWFUNC_INCLUDED #define ITEM_WINDOWFUNC_INCLUDED #include "item.h" class Window_spec; int test_if_group_changed(List &list); /* A wrapper around test_if_group_changed */ class Group_bound_tracker { public: Group_bound_tracker(THD *thd, SQL_I_List *list) { for (ORDER *curr = list->first; curr; curr=curr->next) { Cached_item *tmp= new_Cached_item(thd, curr->item[0], TRUE); group_fields.push_back(tmp); } } void init() { first_check= true; } /* Check if the current row is in a different group than the previous row this function was called for. XXX: Side-effect: The new row's group becomes the current row's group. Returns true if there is a change between the current_group and the cached value, or if it is the first check after a call to init. */ bool check_if_next_group() { if (test_if_group_changed(group_fields) > -1 || first_check) { first_check= false; return true; } return false; } /* Check if the current row is in a different group than the previous row check_if_next_group was called for. Compares the groups without the additional side effect of updating the current cached values. */ int compare_with_cache() { List_iterator li(group_fields); Cached_item *ptr; int res; while ((ptr= li++)) { if ((res= ptr->cmp_read_only())) return res; } return 0; } ~Group_bound_tracker() { group_fields.delete_elements(); } private: List group_fields; /* During the first check_if_next_group, the list of cached_items is not initialized. The compare function will return that the items match if the field's value is the same as the Cached_item's default value (0). This flag makes sure that we always return true during the first check. XXX This is better to be implemented within test_if_group_changed, but since it is used in other parts of the codebase, we keep it here for now. */ bool first_check; }; /* ROW_NUMBER() OVER (...) @detail - This is a Window function (not just an aggregate) - It can be computed by doing one pass over select output, provided the output is sorted according to the window definition. */ class Item_sum_row_number: public Item_sum_int { longlong count; public: Item_sum_row_number(THD *thd) : Item_sum_int(thd), count(0) {} const Type_handler *type_handler() const override { return &type_handler_slonglong; } void clear() override { count= 0; } bool add() override { count++; return false; } void reset_field() override { DBUG_ASSERT(0); } void update_field() override {} enum Sumfunctype sum_func() const override { return ROW_NUMBER_FUNC; } longlong val_int() override { return count; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("row_number") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* RANK() OVER (...) Windowing function @detail - This is a Window function (not just an aggregate) - It can be computed by doing one pass over select output, provided the output is sorted according to the window definition. The function is defined as: "The rank of row R is defined as 1 (one) plus the number of rows that precede R and are not peers of R" "This implies that if two or more rows are not distinct with respect to the window ordering, then there will be one or more" */ class Item_sum_rank: public Item_sum_int { protected: longlong row_number; // just ROW_NUMBER() longlong cur_rank; // current value Group_bound_tracker *peer_tracker; public: Item_sum_rank(THD *thd) : Item_sum_int(thd), peer_tracker(NULL) {} const Type_handler *type_handler() const override { return &type_handler_slonglong; } void clear() override { /* This is called on partition start */ cur_rank= 1; row_number= 0; } bool add() override; longlong val_int() override { return cur_rank; } void reset_field() override { DBUG_ASSERT(0); } void update_field() override {} enum Sumfunctype sum_func () const override { return RANK_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("rank") }; return name; } void setup_window_func(THD *thd, Window_spec *window_spec) override; void cleanup() override { if (peer_tracker) { delete peer_tracker; peer_tracker= NULL; } Item_sum_int::cleanup(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* DENSE_RANK() OVER (...) Windowing function @detail - This is a Window function (not just an aggregate) - It can be computed by doing one pass over select output, provided the output is sorted according to the window definition. The function is defined as: "If DENSE_RANK is specified, then the rank of row R is defined as the number of rows preceding and including R that are distinct with respect to the window ordering" "This implies that there are no gaps in the sequential rank numbering of rows in each window partition." */ class Item_sum_dense_rank: public Item_sum_int { longlong dense_rank; bool first_add; Group_bound_tracker *peer_tracker; public: /* XXX(cvicentiu) This class could potentially be implemented in the rank class, with a switch for the DENSE case. */ void clear() override { dense_rank= 0; first_add= true; } bool add() override; void reset_field() override { DBUG_ASSERT(0); } void update_field() override {} longlong val_int() override { return dense_rank; } Item_sum_dense_rank(THD *thd) : Item_sum_int(thd), dense_rank(0), first_add(true), peer_tracker(NULL) {} const Type_handler *type_handler() const override { return &type_handler_slonglong; } enum Sumfunctype sum_func () const override { return DENSE_RANK_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("dense_rank") }; return name; } void setup_window_func(THD *thd, Window_spec *window_spec) override; void cleanup() override { if (peer_tracker) { delete peer_tracker; peer_tracker= NULL; } Item_sum_int::cleanup(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_sum_hybrid_simple : public Item_sum_hybrid { public: Item_sum_hybrid_simple(THD *thd, Item *arg): Item_sum_hybrid(thd, arg), value(NULL) { } Item_sum_hybrid_simple(THD *thd, Item *arg1, Item *arg2): Item_sum_hybrid(thd, arg1, arg2), value(NULL) { } bool add() override; bool fix_fields(THD *, Item **) override; bool fix_length_and_dec() override; void setup_hybrid(THD *thd, Item *item); double val_real() override; longlong val_int() override; my_decimal *val_decimal(my_decimal *) override; void reset_field() override; String *val_str(String *) override; bool val_native(THD *thd, Native *to) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } void update_field() override; Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table) override; void clear() override { value->clear(); null_value= 1; } private: Item_cache *value; }; /* This item will remember the first value added to it. It will not update the value unless it is cleared. */ class Item_sum_first_value : public Item_sum_hybrid_simple { public: Item_sum_first_value(THD* thd, Item* arg_expr) : Item_sum_hybrid_simple(thd, arg_expr) {} enum Sumfunctype sum_func () const override { return FIRST_VALUE_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("first_value") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* This item will remember the last value added to it. This item does not support removal, and can be cleared only by calling clear(). */ class Item_sum_last_value : public Item_sum_hybrid_simple { public: Item_sum_last_value(THD* thd, Item* arg_expr) : Item_sum_hybrid_simple(thd, arg_expr) {} enum Sumfunctype sum_func() const override { return LAST_VALUE_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("last_value") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_sum_nth_value : public Item_sum_hybrid_simple { public: Item_sum_nth_value(THD *thd, Item *arg_expr, Item* offset_expr) : Item_sum_hybrid_simple(thd, arg_expr, offset_expr) {} enum Sumfunctype sum_func() const override { return NTH_VALUE_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("nth_value") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_sum_lead : public Item_sum_hybrid_simple { public: Item_sum_lead(THD *thd, Item *arg_expr, Item* offset_expr) : Item_sum_hybrid_simple(thd, arg_expr, offset_expr) {} enum Sumfunctype sum_func() const override { return LEAD_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("lead") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_sum_lag : public Item_sum_hybrid_simple { public: Item_sum_lag(THD *thd, Item *arg_expr, Item* offset_expr) : Item_sum_hybrid_simple(thd, arg_expr, offset_expr) {} enum Sumfunctype sum_func() const override { return LAG_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("lag") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Partition_row_count { public: Partition_row_count() :partition_row_count_(0) { } void set_partition_row_count(ulonglong count) { partition_row_count_ = count; } double calc_val_real(bool *null_value, ulonglong current_row_count) { if ((*null_value= (partition_row_count_ == 0))) return 0; return static_cast(current_row_count) / partition_row_count_; } protected: longlong get_row_count() { return partition_row_count_; } ulonglong partition_row_count_; }; class Current_row_count { public: Current_row_count() :current_row_count_(0) { } protected: ulonglong get_row_number() { return current_row_count_ ; } ulonglong current_row_count_; }; /* @detail "The relative rank of a row R is defined as (RK-1)/(NR-1), where RK is defined to be the RANK of R and NR is defined to be the number of rows in the window partition of R." Computation of this function requires two passes: - First pass to find #rows in the partition This is held within the row_count context. - Second pass to compute rank of current row and the value of the function */ class Item_sum_percent_rank: public Item_sum_double, public Partition_row_count { public: Item_sum_percent_rank(THD *thd) : Item_sum_double(thd), cur_rank(1), peer_tracker(NULL) {} longlong val_int() override { /* Percent rank is a real value so calling the integer value should never happen. It makes no sense as it gets truncated to either 0 or 1. */ DBUG_ASSERT(0); return 0; } double val_real() override { /* We can not get the real value without knowing the number of rows in the partition. Don't divide by 0. */ ulonglong partition_rows = get_row_count(); null_value= partition_rows > 0 ? false : true; return partition_rows > 1 ? static_cast(cur_rank - 1) / (partition_rows - 1) : 0; } enum Sumfunctype sum_func () const override { return PERCENT_RANK_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("percent_rank") }; return name; } void update_field() override {} void clear() override { cur_rank= 1; row_number= 0; } bool add() override; const Type_handler *type_handler() const override { return &type_handler_double; } bool fix_length_and_dec() override { decimals = 10; // TODO-cvicentiu find out how many decimals the standard // requires. return FALSE; } void setup_window_func(THD *thd, Window_spec *window_spec) override; void reset_field() override { DBUG_ASSERT(0); } void set_partition_row_count(ulonglong count) override { Partition_row_count::set_partition_row_count(count); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } private: longlong cur_rank; // Current rank of the current row. longlong row_number; // Value if this were ROW_NUMBER() function. Group_bound_tracker *peer_tracker; void cleanup() override { if (peer_tracker) { delete peer_tracker; peer_tracker= NULL; } Item_sum_num::cleanup(); } }; /* @detail "The relative rank of a row R is defined as NP/NR, where - NP is defined to be the number of rows preceding or peer with R in the window ordering of the window partition of R - NR is defined to be the number of rows in the window partition of R. Just like with Item_sum_percent_rank, computation of this function requires two passes. */ class Item_sum_cume_dist: public Item_sum_double, public Partition_row_count, public Current_row_count { public: Item_sum_cume_dist(THD *thd) :Item_sum_double(thd) { } Item_sum_cume_dist(THD *thd, Item *arg) :Item_sum_double(thd, arg) { } double val_real() override { return calc_val_real(&null_value, current_row_count_); } bool add() override { current_row_count_++; return false; } enum Sumfunctype sum_func() const override { return CUME_DIST_FUNC; } void clear() override { current_row_count_= 0; partition_row_count_= 0; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("cume_dist") }; return name; } void update_field() override {} const Type_handler *type_handler() const override { return &type_handler_double; } bool fix_length_and_dec() override { decimals = 10; // TODO-cvicentiu find out how many decimals the standard // requires. return FALSE; } void reset_field() override { DBUG_ASSERT(0); } void set_partition_row_count(ulonglong count) override { Partition_row_count::set_partition_row_count(count); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_sum_ntile : public Item_sum_int, public Partition_row_count, public Current_row_count { public: Item_sum_ntile(THD* thd, Item* num_quantiles_expr) : Item_sum_int(thd, num_quantiles_expr), n_old_val_(0) { } longlong val_int() override { if (get_row_count() == 0) { null_value= true; return 0; } longlong num_quantiles= get_num_quantiles(); if (num_quantiles <= 0 || (static_cast(num_quantiles) != n_old_val_ && n_old_val_ > 0)) { my_error(ER_INVALID_NTILE_ARGUMENT, MYF(0)); return true; } n_old_val_= static_cast(num_quantiles); null_value= false; ulonglong quantile_size = get_row_count() / num_quantiles; ulonglong extra_rows = get_row_count() - quantile_size * num_quantiles; if (current_row_count_ <= extra_rows * (quantile_size + 1)) return (current_row_count_ - 1) / (quantile_size + 1) + 1; return (current_row_count_ - 1 - extra_rows) / quantile_size + 1; } bool add() override { current_row_count_++; return false; } enum Sumfunctype sum_func() const override { return NTILE_FUNC; } void clear() override { current_row_count_= 0; partition_row_count_= 0; n_old_val_= 0; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("ntile") }; return name; } void update_field() override {} const Type_handler *type_handler() const override { return &type_handler_slonglong; } void reset_field() override { DBUG_ASSERT(0); } void set_partition_row_count(ulonglong count) override { Partition_row_count::set_partition_row_count(count); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } private: longlong get_num_quantiles() { return args[0]->val_int(); } ulonglong n_old_val_; }; class Item_sum_percentile_disc : public Item_sum_num, public Type_handler_hybrid_field_type, public Partition_row_count, public Current_row_count { public: Item_sum_percentile_disc(THD *thd, Item* arg) : Item_sum_num(thd, arg), Type_handler_hybrid_field_type(&type_handler_slonglong), value(NULL), val_calculated(FALSE), first_call(TRUE), prev_value(0), order_item(NULL){} double val_real() override { if (get_row_count() == 0 || get_arg(0)->is_null()) { null_value= true; return 0; } null_value= false; return value->val_real(); } longlong val_int() override { if (get_row_count() == 0 || get_arg(0)->is_null()) { null_value= true; return 0; } null_value= false; return value->val_int(); } my_decimal* val_decimal(my_decimal* dec) override { if (get_row_count() == 0 || get_arg(0)->is_null()) { null_value= true; return 0; } null_value= false; return value->val_decimal(dec); } String* val_str(String *str) override { if (get_row_count() == 0 || get_arg(0)->is_null()) { null_value= true; return 0; } null_value= false; return value->val_str(str); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { if (get_row_count() == 0 || get_arg(0)->is_null()) { null_value= true; return true; } null_value= false; return value->get_date(thd, ltime, fuzzydate); } bool val_native(THD *thd, Native *to) override { if (get_row_count() == 0 || get_arg(0)->is_null()) { null_value= true; return true; } null_value= false; return value->val_native(thd, to); } bool add() override { Item *arg= get_arg(0); if (arg->is_null()) return false; if (first_call) { prev_value= arg->val_real(); if (prev_value > 1 || prev_value < 0) { my_error(ER_ARGUMENT_OUT_OF_RANGE, MYF(0), func_name()); return true; } first_call= false; } double arg_val= arg->val_real(); if (prev_value != arg_val) { my_error(ER_ARGUMENT_NOT_CONSTANT, MYF(0), func_name()); return true; } if (val_calculated) return false; value->store(order_item); value->cache_value(); if (value->null_value) return false; current_row_count_++; double val= calc_val_real(&null_value, current_row_count_); if (val >= prev_value && !val_calculated) val_calculated= true; return false; } enum Sumfunctype sum_func() const override { return PERCENTILE_DISC_FUNC; } void clear() override { val_calculated= false; first_call= true; value->clear(); partition_row_count_= 0; current_row_count_= 0; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("percentile_disc") }; return name; } void update_field() override {} const Type_handler *type_handler() const override {return Type_handler_hybrid_field_type::type_handler();} bool fix_length_and_dec() override { decimals = 10; // TODO-cvicentiu find out how many decimals the standard // requires. return FALSE; } void reset_field() override { DBUG_ASSERT(0); } void set_partition_row_count(ulonglong count) override { Partition_row_count::set_partition_row_count(count); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } void setup_window_func(THD *thd, Window_spec *window_spec) override; void setup_hybrid(THD *thd, Item *item); bool fix_fields(THD *thd, Item **ref) override; private: Item_cache *value; bool val_calculated; bool first_call; double prev_value; Item *order_item; }; class Item_sum_percentile_cont : public Item_sum_double, public Partition_row_count, public Current_row_count { public: Item_sum_percentile_cont(THD *thd, Item* arg) : Item_sum_double(thd, arg), floor_value(NULL), ceil_value(NULL), first_call(TRUE),prev_value(0), ceil_val_calculated(FALSE), floor_val_calculated(FALSE), order_item(NULL){} double val_real() override { if (get_row_count() == 0 || get_arg(0)->is_null()) { null_value= true; return 0; } null_value= false; double val= 1 + prev_value * (get_row_count()-1); /* Applying the formula to get the value If (CRN = FRN = RN) then the result is (value of expression from row at RN) Otherwise the result is (CRN - RN) * (value of expression for row at FRN) + (RN - FRN) * (value of expression for row at CRN) */ if(ceil(val) == floor(val)) return floor_value->val_real(); double ret_val= ((val - floor(val)) * ceil_value->val_real()) + ((ceil(val) - val) * floor_value->val_real()); return ret_val; } bool add() override { Item *arg= get_arg(0); if (arg->is_null()) return false; if (first_call) { first_call= false; prev_value= arg->val_real(); if (prev_value > 1 || prev_value < 0) { my_error(ER_ARGUMENT_OUT_OF_RANGE, MYF(0), func_name()); return true; } } double arg_val= arg->val_real(); if (prev_value != arg_val) { my_error(ER_ARGUMENT_NOT_CONSTANT, MYF(0), func_name()); return true; } if (!floor_val_calculated) { floor_value->store(order_item); floor_value->cache_value(); if (floor_value->null_value) return false; } if (floor_val_calculated && !ceil_val_calculated) { ceil_value->store(order_item); ceil_value->cache_value(); if (ceil_value->null_value) return false; } current_row_count_++; double val= 1 + prev_value * (get_row_count()-1); if (!floor_val_calculated && get_row_number() == floor(val)) floor_val_calculated= true; if (!ceil_val_calculated && get_row_number() == ceil(val)) ceil_val_calculated= true; return false; } enum Sumfunctype sum_func() const override { return PERCENTILE_CONT_FUNC; } void clear() override { first_call= true; floor_value->clear(); ceil_value->clear(); floor_val_calculated= false; ceil_val_calculated= false; partition_row_count_= 0; current_row_count_= 0; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("percentile_cont") }; return name; } void update_field() override {} bool fix_length_and_dec() override { decimals = 10; // TODO-cvicentiu find out how many decimals the standard // requires. return FALSE; } void reset_field() override { DBUG_ASSERT(0); } void set_partition_row_count(ulonglong count) override { Partition_row_count::set_partition_row_count(count); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } void setup_window_func(THD *thd, Window_spec *window_spec) override; void setup_hybrid(THD *thd, Item *item); bool fix_fields(THD *thd, Item **ref) override; private: Item_cache *floor_value; Item_cache *ceil_value; bool first_call; double prev_value; bool ceil_val_calculated; bool floor_val_calculated; Item *order_item; }; class Item_window_func : public Item_func_or_sum { /* Window function parameters as we've got them from the parser */ public: LEX_CSTRING *window_name; public: Window_spec *window_spec; public: Item_window_func(THD *thd, Item_sum *win_func, LEX_CSTRING *win_name) : Item_func_or_sum(thd, (Item *) win_func), window_name(win_name), window_spec(NULL), force_return_blank(true), read_value_from_result_field(false) {} Item_window_func(THD *thd, Item_sum *win_func, Window_spec *win_spec) : Item_func_or_sum(thd, (Item *) win_func), window_name(NULL), window_spec(win_spec), force_return_blank(true), read_value_from_result_field(false) {} Item_sum *window_func() const { return (Item_sum *) args[0]; } void update_used_tables() override; /* This is used by filesort to mark the columns it needs to read (because they participate in the sort criteria and/or row retrieval. Window functions can only be used in sort criteria). Sorting by window function value is only done after the window functions have been computed. In that case, window function will need to read its temp.table field. In order to allow that, mark that field in the read_set. */ bool register_field_in_read_map(void *arg) override { TABLE *table= (TABLE*) arg; if (result_field && (result_field->table == table || !table)) { bitmap_set_bit(result_field->table->read_set, result_field->field_index); } return 0; } bool is_frame_prohibited() const { switch (window_func()->sum_func()) { case Item_sum::ROW_NUMBER_FUNC: case Item_sum::RANK_FUNC: case Item_sum::DENSE_RANK_FUNC: case Item_sum::PERCENT_RANK_FUNC: case Item_sum::CUME_DIST_FUNC: case Item_sum::NTILE_FUNC: case Item_sum::PERCENTILE_CONT_FUNC: case Item_sum::PERCENTILE_DISC_FUNC: return true; default: return false; } } bool requires_special_cursors() const { switch (window_func()->sum_func()) { case Item_sum::FIRST_VALUE_FUNC: case Item_sum::LAST_VALUE_FUNC: case Item_sum::NTH_VALUE_FUNC: case Item_sum::LAG_FUNC: case Item_sum::LEAD_FUNC: return true; default: return false; } } bool requires_partition_size() const { switch (window_func()->sum_func()) { case Item_sum::PERCENT_RANK_FUNC: case Item_sum::CUME_DIST_FUNC: case Item_sum::NTILE_FUNC: case Item_sum::PERCENTILE_CONT_FUNC: case Item_sum::PERCENTILE_DISC_FUNC: return true; default: return false; } } bool requires_peer_size() const { switch (window_func()->sum_func()) { case Item_sum::CUME_DIST_FUNC: return true; default: return false; } } bool is_order_list_mandatory() const { switch (window_func()->sum_func()) { case Item_sum::RANK_FUNC: case Item_sum::DENSE_RANK_FUNC: case Item_sum::PERCENT_RANK_FUNC: case Item_sum::CUME_DIST_FUNC: case Item_sum::LAG_FUNC: case Item_sum::LEAD_FUNC: case Item_sum::PERCENTILE_CONT_FUNC: case Item_sum::PERCENTILE_DISC_FUNC: return true; default: return false; } } bool only_single_element_order_list() const { switch (window_func()->sum_func()){ case Item_sum::PERCENTILE_CONT_FUNC: case Item_sum::PERCENTILE_DISC_FUNC: return true; default: return false; } } bool check_result_type_of_order_item(); /* Computation functions. TODO: consoder merging these with class Group_bound_tracker. */ void setup_partition_border_check(THD *thd); const Type_handler *type_handler() const override { return ((Item_sum *) args[0])->type_handler(); } enum Item::Type type() const override { return Item::WINDOW_FUNC_ITEM; } private: /* Window functions are very special functions, so val_() methods have special meaning for them: - Phase#1, "Initial" we run the join and put its result into temporary table. For window functions, we write the default value (NULL?) as a placeholder. - Phase#2: "Computation": executor does the scan in {PARTITION, ORDER BY} order of this window function. It calls appropriate methods to inform the window function about rows entering/leaving the window. It calls window_func()->val_int() so that current window function value can be saved and stored in the temp.table. - Phase#3: "Retrieval" the temporary table is read and passed to query output. However, Item_window_func still remains in the select list, so item_windowfunc->val_int() will be called. During Phase#3, read_value_from_result_field= true. */ bool force_return_blank; bool read_value_from_result_field; void print_for_percentile_functions(String *str, enum_query_type query_type); public: void set_phase_to_initial() { force_return_blank= true; read_value_from_result_field= false; } void set_phase_to_computation() { force_return_blank= false; read_value_from_result_field= false; } void set_phase_to_retrieval() { force_return_blank= false; read_value_from_result_field= true; } bool is_null() override { if (force_return_blank) return true; if (read_value_from_result_field) return result_field->is_null(); return window_func()->is_null(); } double val_real() override { double res; if (force_return_blank) { res= 0.0; null_value= true; } else if (read_value_from_result_field) { res= result_field->val_real(); null_value= result_field->is_null(); } else { res= window_func()->val_real(); null_value= window_func()->null_value; } return res; } longlong val_int() override { longlong res; if (force_return_blank) { res= 0; null_value= true; } else if (read_value_from_result_field) { res= result_field->val_int(); null_value= result_field->is_null(); } else { res= window_func()->val_int(); null_value= window_func()->null_value; } return res; } String* val_str(String* str) override { String *res; if (force_return_blank) { null_value= true; res= NULL; } else if (read_value_from_result_field) { if ((null_value= result_field->is_null())) res= NULL; else res= result_field->val_str(str); } else { res= window_func()->val_str(str); null_value= window_func()->null_value; } return res; } bool val_native(THD *thd, Native *to) override { if (force_return_blank) return null_value= true; if (read_value_from_result_field) return val_native_from_field(result_field, to); return val_native_from_item(thd, window_func(), to); } my_decimal* val_decimal(my_decimal* dec) override { my_decimal *res; if (force_return_blank) { null_value= true; res= NULL; } else if (read_value_from_result_field) { if ((null_value= result_field->is_null())) res= NULL; else res= result_field->val_decimal(dec); } else { res= window_func()->val_decimal(dec); null_value= window_func()->null_value; } return res; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { bool res; if (force_return_blank) { null_value= true; res= true; } else if (read_value_from_result_field) { if ((null_value= result_field->is_null())) res= true; else res= result_field->get_date(ltime, fuzzydate); } else { res= window_func()->get_date(thd, ltime, fuzzydate); null_value= window_func()->null_value; } return res; } void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, uint flags) override; bool fix_length_and_dec() override { Type_std_attributes::set(window_func()); return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("WF") }; return name; } bool fix_fields(THD *thd, Item **ref) override; bool resolve_window_name(THD *thd); void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return 0; } }; #endif /* ITEM_WINDOWFUNC_INCLUDED */ server/private/authors.h000064400000023635151031265040011370 0ustar00#ifndef AUTHORS_INCLUDED #define AUTHORS_INCLUDED /* Copyright (c) 2005, 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Structure of the name list */ struct show_table_authors_st { const char *name; const char *location; const char *comment; }; /* Output from "SHOW AUTHORS" If you can update it, you get to be in it :) Don't be offended if your name is not in here, just add it! Active people in the MariaDB are listed first, active people in MySQL then, not active last. Names should be encoded using UTF-8. See also https://mariadb.com/kb/en/log-of-mariadb-contributions/ */ struct show_table_authors_st show_table_authors[]= { /* Active people on MariaDB */ { "Michael (Monty) Widenius", "Tusby, Finland", "Lead developer and main author" }, { "Sergei Golubchik", "Kerpen, Germany", "Architect, Full-text search, precision math, plugin framework, merges etc" }, { "Igor Babaev", "Bellevue, USA", "Optimizer, keycache, core work"}, { "Sergey Petrunia", "St. Petersburg, Russia", "Optimizer"}, { "Oleksandr Byelkin", "Lugansk, Ukraine", "Query Cache (4.0), Subqueries (4.1), Views (5.0)" }, { "Timour Katchaounov", "Sofia , Bulgaria", "Optimizer"}, { "Kristian Nielsen", "Copenhagen, Denmark", "Replication, Async client prototocol, General buildbot stuff" }, { "Alexander (Bar) Barkov", "Izhevsk, Russia", "Unicode and character sets" }, { "Alexey Botchkov (Holyfoot)", "Izhevsk, Russia", "GIS extensions, embedded server, precision math"}, { "Daniel Bartholomew", "Raleigh, USA", "MariaDB documentation, Buildbot, releases"}, { "Colin Charles", "Selangor, Malesia", "MariaDB documentation, talks at a LOT of conferences"}, { "Sergey Vojtovich", "Izhevsk, Russia", "initial implementation of plugin architecture, maintained native storage engines (MyISAM, MEMORY, ARCHIVE, etc), rewrite of table cache"}, { "Vladislav Vaintroub", "Mannheim, Germany", "MariaDB Java connector, new thread pool, Windows optimizations"}, { "Elena Stepanova", "Sankt Petersburg, Russia", "QA, test cases"}, { "Georg Richter", "Heidelberg, Germany", "New LGPL C connector, PHP connector"}, { "Jan Lindström", "Ylämylly, Finland", "Working on InnoDB"}, { "Lixun Peng", "Hangzhou, China", "Multi Source replication" }, { "Olivier Bertrand", "Paris, France", "CONNECT storage engine"}, { "Kentoku Shiba", "Tokyo, Japan", "Spider storage engine, metadata_lock_info Information schema"}, { "Percona", "CA, USA", "XtraDB, microslow patches, extensions to slow log"}, { "Vicentiu Ciorbaru", "Bucharest, Romania", "Roles"}, { "Sudheera Palihakkara", "", "PCRE Regular Expressions" }, { "Pavel Ivanov", "USA", "Some patches and bug fixes"}, { "Konstantin Osipov", "Moscow, Russia", "Prepared statements (4.1), Cursors (5.0), GET_LOCK (10.0)" }, { "Ian Gilfillan", "South Africa", "MariaDB documentation"}, { "Federico Razolli", "Italy", "MariaDB documentation Italian translation"}, { "Vinchen", "Shenzhen, China", "Instant ADD Column for InnoDB, Spider engine optimization, from Tencent Game DBA Team" }, { "Willhan", "Shenzhen, China", "Big Column Compression, Spider engine optimization, from Tencent Game DBA Team" }, { "Anders Karlsson", "Ystad, Sweden", "Replication patch for enforcing triggers on slave"}, { "Otto Kekäläinen", "Tampere, Finland", "Debian packaging, install/upgrade engineering, QA pipelines, documentation"}, { "Daniel Black", "Canberra, Australia", "Modernising large page support, systemd, and bug fixes"}, /* People working on MySQL code base (not NDB) */ { "Guilhem Bichot", "Bordeaux, France", "Replication (since 4.0)" }, { "Andrei Elkin", "Espoo, Finland", "Replication" }, { "Dmitri Lenev", "Moscow, Russia", "Time zones support (4.1), Triggers (5.0)" }, { "Marc Alff", "Denver, CO, USA", "Signal, Resignal, Performance schema" }, { "Mikael Ronström", "Stockholm, Sweden", "NDB Cluster, Partitioning, online alter table" }, { "Ingo Strüwing", "Berlin, Germany", "Bug fixing in MyISAM, Merge tables etc" }, {"Marko Mäkelä", "Helsinki, Finland", "InnoDB core developer"}, /* People not active anymore */ { "David Axmark", "London, England", "MySQL founder; Small stuff long time ago, Monty ripped it out!" }, { "Brian (Krow) Aker", "Seattle, WA, USA", "Architecture, archive, blackhole, federated, bunch of little stuff :)" }, { "Venu Anuganti", "", "Client/server protocol (4.1)" }, { "Omer BarNir", "Sunnyvale, CA, USA", "Testing (sometimes) and general QA stuff" }, { "John Birrell", "", "Emulation of pthread_mutex() for OS/2" }, { "Andreas F. Bobak", "", "AGGREGATE extension to user-defined functions" }, { "Reggie Burnett", "Nashville, TN, USA", "Windows development, Connectors" }, { "Kent Boortz", "Orebro, Sweden", "Test platform, and general build stuff" }, { "Tim Bunce", "", "mysqlhotcopy" }, { "Yves Carlier", "", "mysqlaccess" }, { "Joshua Chamas", "Cupertino, CA, USA", "Concurrent insert, extended date syntax" }, { "Petr Chardin", "Moscow, Russia", "Instance Manager (5.0), Server log tables (5.1)" }, { "Wei-Jou Chen", "", "Chinese (Big5) character set" }, { "Albert Chin-A-Young", "", "Tru64 port, large file support, better TCP wrappers support" }, { "Jorge del Conde", "Mexico City, Mexico", "Windows development" }, { "Antony T. Curtis", "Norwalk, CA, USA", "Parser, port to OS/2, storage engines and some random stuff" }, { "Yuri Dario", "", "OS/2 port" }, { "Patrick Galbraith", "Sharon, NH", "Federated Engine, mysqlslap" }, { "Lenz Grimmer", "Hamburg, Germany", "Production (build and release) engineering" }, { "Nikolay Grishakin", "Austin, TX, USA", "Testing - Server" }, { "Wei He", "", "Chinese (GBK) character set" }, { "Eric Herman", "Amsterdam, Netherlands", "Bug fixing - federated" }, { "Andrey Hristov", "Walldorf, Germany", "Event scheduler (5.1)" }, { "Alexander (Alexi) Ivanov", "St. Petersburg, Russia", "Replication" }, { "Mattias Jonsson", "Uppsala, Sweden", "Partitioning" }, { "Alexander (Salle) Keremidarski", "Sofia, Bulgaria", "Bug fixing" }, { "Mats Kindahl", "Storvreta, Sweden", "Replication" }, { "Serge Kozlov", "Velikie Luki, Russia", "Testing - Cluster" }, { "Hakan Küçükyılmaz", "Walldorf, Germany", "Testing - Server" }, { "Matthias Leich", "Berlin, Germany", "Testing - Server" }, { "Arjen Lentz", "Brisbane, Australia", "Documentation (2001-2004), Dutch error messages, LOG2()" }, { "Marc Liyanage", "", "Created Mac OS X packages" }, { "Kelly Long", "Denver, CO, USA", "Pool Of Threads" }, { "Zarko Mocnik", "", "Sorting for Slovenian language" }, { "Per-Erik Martin", "Uppsala, Sweden", "Stored Procedures (5.0)" }, { "Alexis Mikhailov", "", "User-defined functions" }, { "Sinisa Milivojevic", "Larnaca, Cyprus", "UNION (4.0), Subqueries in FROM clause (4.1), many other features" }, { "Jonathan (Jeb) Miller", "Kyle, TX, USA", "Testing - Cluster, Replication" }, { "Elliot Murphy", "Cocoa, FL, USA", "Replication and backup" }, { "Pekka Nouisiainen", "Stockholm, Sweden", "NDB Cluster: BLOB support, character set support, ordered indexes" }, { "Alexander Nozdrin", "Moscow, Russia", "Bug fixing (Stored Procedures, 5.0)" }, { "Per Eric Olsson", "", "Testing of dynamic record format" }, { "Jonas Oreland", "Stockholm, Sweden", "NDB Cluster, Online Backup, lots of other things" }, { "Alexander (Sasha) Pachev", "Provo, UT, USA", "Statement-based replication, SHOW CREATE TABLE, mysql-bench" }, { "Irena Pancirov", "", "Port to Windows with Borland compiler" }, { "Jan Pazdziora", "", "Czech sorting order" }, { "Benjamin Pflugmann", "", "Extended MERGE storage engine to handle INSERT" }, { "Igor Romanenko", "", "mysqldump" }, { "Tõnu Samuel", "Estonia", "VIO interface, other miscellaneous features" }, { "Carsten Segieth (Pino)", "Fredersdorf, Germany", "Testing - Server"}, { "Martin Sköld", "Stockholm, Sweden", "NDB Cluster: Unique indexes, integration into MySQL" }, { "Timothy Smith", "Auckland, New Zealand", "Dynamic character sets, parts of the build system, libmysqld"}, { "Miguel Solorzano", "Florianopolis, Santa Catarina, Brazil", "Windows development, Windows NT service"}, { "Punita Srivastava", "Austin, TX, USA", "Testing - Merlin"}, { "Alexey Stroganov (Ranger)", "Lugansk, Ukraine", "Testing - Benchmarks"}, { "Magnus Svensson", "Öregrund, Sweden", "NDB Cluster: Integration into MySQL, test framework" }, { "Zeev Suraski", "", "FROM_UNIXTIME(), ENCRYPT()" }, { "TAMITO", "", "The _MB character set macros and UJIS and SJIS character sets" }, { "Jani Tolonen", "Helsinki, Finland", "mysqlimport, extensions to command-line clients, PROCEDURE ANALYSE()" }, { "Lars Thalmann", "Stockholm, Sweden", "Replication and cluster development" }, { "Tomas Ulin", "Stockholm, Sweden", "NDB Cluster: Configuration, installation" }, { "Gianmassimo Vigazzola", "", "Initial Windows port" }, { "Sergey Vojtovich", "Izhevsk, Russia", "Plugins infrastructure (5.1)" }, { "Matt Wagner", "Northfield, MN, USA", "Bug fixing" }, { "Jim Winstead Jr.", "Los Angeles, CA, USA", "Bug fixing" }, { "Peter Zaitsev", "Tacoma, WA, USA", "SHA1(), AES_ENCRYPT(), AES_DECRYPT(), bug fixing" }, {"Mark Mark Callaghan", "Texas, USA", "Statistics patches"}, {NULL, NULL, NULL} }; #endif /* AUTHORS_INCLUDED */ server/private/sql_show.h000064400000022620151031265040011533 0ustar00/* Copyright (c) 2005, 2010, Oracle and/or its affiliates. Copyright (c) 2012, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_SHOW_H #define SQL_SHOW_H #include "sql_list.h" /* List */ #include "handler.h" /* enum_schema_tables */ #include "table.h" /* enum_schema_table_state */ #include "my_apc.h" /* Forward declarations */ class JOIN; class String; class THD; class sp_name; struct TABLE_LIST; typedef class st_select_lex SELECT_LEX; struct LEX; typedef struct st_mysql_show_var SHOW_VAR; typedef struct st_schema_table ST_SCHEMA_TABLE; struct TABLE; typedef struct system_status_var STATUS_VAR; /* Used by handlers to store things in schema tables */ #define IS_FILES_FILE_ID 0 #define IS_FILES_FILE_NAME 1 #define IS_FILES_FILE_TYPE 2 #define IS_FILES_TABLESPACE_NAME 3 #define IS_FILES_TABLE_CATALOG 4 #define IS_FILES_TABLE_SCHEMA 5 #define IS_FILES_TABLE_NAME 6 #define IS_FILES_LOGFILE_GROUP_NAME 7 #define IS_FILES_LOGFILE_GROUP_NUMBER 8 #define IS_FILES_ENGINE 9 #define IS_FILES_FULLTEXT_KEYS 10 #define IS_FILES_DELETED_ROWS 11 #define IS_FILES_UPDATE_COUNT 12 #define IS_FILES_FREE_EXTENTS 13 #define IS_FILES_TOTAL_EXTENTS 14 #define IS_FILES_EXTENT_SIZE 15 #define IS_FILES_INITIAL_SIZE 16 #define IS_FILES_MAXIMUM_SIZE 17 #define IS_FILES_AUTOEXTEND_SIZE 18 #define IS_FILES_CREATION_TIME 19 #define IS_FILES_LAST_UPDATE_TIME 20 #define IS_FILES_LAST_ACCESS_TIME 21 #define IS_FILES_RECOVER_TIME 22 #define IS_FILES_TRANSACTION_COUNTER 23 #define IS_FILES_VERSION 24 #define IS_FILES_ROW_FORMAT 25 #define IS_FILES_TABLE_ROWS 26 #define IS_FILES_AVG_ROW_LENGTH 27 #define IS_FILES_DATA_LENGTH 28 #define IS_FILES_MAX_DATA_LENGTH 29 #define IS_FILES_INDEX_LENGTH 30 #define IS_FILES_DATA_FREE 31 #define IS_FILES_CREATE_TIME 32 #define IS_FILES_UPDATE_TIME 33 #define IS_FILES_CHECK_TIME 34 #define IS_FILES_CHECKSUM 35 #define IS_FILES_STATUS 36 #define IS_FILES_EXTRA 37 typedef enum { WITHOUT_DB_NAME, WITH_DB_NAME } enum_with_db_name; int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond); int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, Table_specification_st *create_info_arg, enum_with_db_name with_db_name); int show_create_table_ex(THD *thd, TABLE_LIST *table_list, const char * forced_db, const char *forced_name, String *packet, Table_specification_st *create_info_arg, enum_with_db_name with_db_name); int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table); bool append_identifier(THD *thd, String *packet, const char *name, size_t length); static inline bool append_identifier(THD *thd, String *packet, const LEX_CSTRING *name) { return append_identifier(thd, packet, name->str, name->length); } void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild); int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd); bool mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list, List *field_list, String *buffer); bool mysqld_show_create(THD *thd, TABLE_LIST *table_list); void mysqld_show_create_db_get_fields(THD *thd, List *field_list); bool mysqld_show_create_db(THD *thd, LEX_CSTRING *db_name, LEX_CSTRING *orig_db_name, const DDL_options_st &options); void mysqld_list_processes(THD *thd,const char *user,bool verbose); int mysqld_show_status(THD *thd); int mysqld_show_variables(THD *thd,const char *wild); bool mysqld_show_storage_engines(THD *thd); bool mysqld_show_authors(THD *thd); bool mysqld_show_contributors(THD *thd); bool mysqld_show_privileges(THD *thd); char *make_backup_log_name(char *buff, const char *name, const char* log_ext); uint calc_sum_of_all_status(STATUS_VAR *to); bool append_definer(THD *thd, String *buffer, const LEX_CSTRING *definer_user, const LEX_CSTRING *definer_host); int add_status_vars(SHOW_VAR *list); void remove_status_vars(SHOW_VAR *list); ulonglong get_status_vars_version(void); void init_status_vars(); void free_status_vars(); void reset_status_vars(); bool show_create_trigger(THD *thd, const sp_name *trg_name); void view_store_options(THD *thd, TABLE_LIST *table, String *buff); void init_fill_schema_files_row(TABLE* table); void initialize_information_schema_acl(); ST_SCHEMA_TABLE *find_schema_table(THD *thd, const LEX_CSTRING *table_name, bool *in_plugin); static inline ST_SCHEMA_TABLE *find_schema_table(THD *thd, const LEX_CSTRING *table_name) { bool unused; return find_schema_table(thd, table_name, &unused); } ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx); int make_schema_select(THD *thd, SELECT_LEX *sel, ST_SCHEMA_TABLE *schema_table); int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list); bool get_schema_tables_result(JOIN *join, enum enum_schema_table_state executed_place); enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table); TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list); const char* get_one_variable(THD *thd, const SHOW_VAR *variable, enum_var_type value_type, SHOW_TYPE show_type, system_status_var *status_var, const CHARSET_INFO **charset, char *buff, size_t *length); /* These functions were under INNODB_COMPATIBILITY_HOOKS */ int get_quote_char_for_identifier(THD *thd, const char *name, size_t length); THD *find_thread_by_id(longlong id, bool query_id= false); class select_result_explain_buffer; /* SHOW EXPLAIN request object. */ class Show_explain_request : public Apc_target::Apc_call { public: THD *target_thd; /* thd that we're running SHOW EXPLAIN for */ THD *request_thd; /* thd that run SHOW EXPLAIN command */ /* If true, there was some error when producing EXPLAIN output. */ bool failed_to_produce; /* SHOW EXPLAIN will be stored here */ select_result_explain_buffer *explain_buf; /* Query that we've got SHOW EXPLAIN for */ String query_str; /* Overloaded virtual function */ void call_in_target_thread() override; }; /** Condition pushdown used for INFORMATION_SCHEMA / SHOW queries. This structure is to implement an optimization when accessing data dictionary data in the INFORMATION_SCHEMA or SHOW commands. When the query contain a TABLE_SCHEMA or TABLE_NAME clause, narrow the search for data based on the constraints given. */ typedef struct st_lookup_field_values { /** Value of a TABLE_SCHEMA clause. Note that this value length may exceed @c NAME_LEN. @sa wild_db_value */ LEX_CSTRING db_value; /** Value of a TABLE_NAME clause. Note that this value length may exceed @c NAME_LEN. @sa wild_table_value */ LEX_CSTRING table_value; /** True when @c db_value is a LIKE clause, false when @c db_value is an '=' clause. */ bool wild_db_value; /** True when @c table_value is a LIKE clause, false when @c table_value is an '=' clause. */ bool wild_table_value; } LOOKUP_FIELD_VALUES; /* INFORMATION_SCHEMA: Execution plan for get_all_tables() call */ class IS_table_read_plan : public Sql_alloc { public: IS_table_read_plan() : no_rows(false), trivial_show_command(FALSE) {} bool no_rows; /* For EXPLAIN only: For SHOW KEYS and SHOW COLUMNS, we know which db_name.table_name will be read, however for some reason we don't set the fields in this->lookup_field_vals. In order to not have JOIN::save_explain_data() walking over uninitialized data, we set trivial_show_command=true. */ bool trivial_show_command; LOOKUP_FIELD_VALUES lookup_field_vals; Item *partial_cond; bool has_db_lookup_value() { return (lookup_field_vals.db_value.length && !lookup_field_vals.wild_db_value); } bool has_table_lookup_value() { return (lookup_field_vals.table_value.length && !lookup_field_vals.wild_table_value); } }; bool optimize_schema_tables_reads(JOIN *join); bool optimize_schema_tables_memory_usage(List &tables); /* Handle the ignored database directories list for SHOW/I_S. */ bool ignore_db_dirs_init(); void ignore_db_dirs_free(); void ignore_db_dirs_reset(); bool ignore_db_dirs_process_additions(); bool push_ignored_db_dir(const char *path); extern char *opt_ignore_db_dirs; #endif /* SQL_SHOW_H */ server/private/grant.h000064400000005306151031265040011011 0ustar00/* Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_GRANT_INCLUDED #define SQL_GRANT_INCLUDED #include "lex_string.h" #include "privilege.h" class LEX_COLUMN; class Lex_ident_sys; class Table_ident; /* Represents the object name in this standard SQL grammar: GRANT ON */ class Grant_object_name { public: enum Type { STAR, // ON * IDENT_STAR, // ON db.* STAR_STAR, // ON *.* TABLE_IDENT // ON db.name }; Lex_cstring m_db; Table_ident *m_table_ident; Type m_type; public: Grant_object_name(Table_ident *table_ident) :m_table_ident(table_ident), m_type(TABLE_IDENT) { } Grant_object_name(const LEX_CSTRING &db, Type type) :m_db(db), m_table_ident(NULL), m_type(type) { } privilege_t all_privileges_by_type() const; }; /* Represents standard SQL statements described by: - - */ class Grant_privilege { protected: List m_columns; Lex_cstring m_db; privilege_t m_object_privilege; privilege_t m_column_privilege_total; bool m_all_privileges; public: Grant_privilege() :m_object_privilege(NO_ACL), m_column_privilege_total(NO_ACL), m_all_privileges(false) { } Grant_privilege(privilege_t privilege, bool all_privileges) :m_object_privilege(privilege), m_column_privilege_total(NO_ACL), m_all_privileges(all_privileges) { } void add_object_privilege(privilege_t privilege) { m_object_privilege|= privilege; } bool add_column_privilege(THD *thd, const Lex_ident_sys &col, privilege_t privilege); bool add_column_list_privilege(THD *thd, List &list, privilege_t privilege); bool set_object_name(THD *thd, const Grant_object_name &ident, SELECT_LEX *sel, privilege_t with_grant_option); const List & columns() const { return m_columns; } }; #endif // SQL_GRANT_INCLUDED server/private/compat56.h000064400000004350151031265040011332 0ustar00#ifndef COMPAT56_H_INCLUDED #define COMPAT56_H_INCLUDED /* Copyright (c) 2004, 2012, Oracle and/or its affiliates. Copyright (c) 2013 MariaDB Foundation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** MySQL56 routines and macros **/ /* Buffer size for a native TIMESTAMP representation, for use with NativBuffer. 4 bytes for seconds 3 bytes for microseconds 1 byte for the trailing '\0' (class Native reserves extra 1 byte for '\0') */ #define STRING_BUFFER_TIMESTAMP_BINARY_SIZE 8 /* 4 + 3 + 1 */ #define MY_PACKED_TIME_GET_INT_PART(x) ((x) >> 24) #define MY_PACKED_TIME_GET_FRAC_PART(x) ((x) % (1LL << 24)) #define MY_PACKED_TIME_MAKE(i, f) ((((ulonglong) (i)) << 24) + (f)) #define MY_PACKED_TIME_MAKE_INT(i) ((((ulonglong) (i)) << 24)) longlong TIME_to_longlong_datetime_packed(const MYSQL_TIME *); longlong TIME_to_longlong_time_packed(const MYSQL_TIME *); void TIME_from_longlong_datetime_packed(MYSQL_TIME *ltime, longlong nr); void TIME_from_longlong_time_packed(MYSQL_TIME *ltime, longlong nr); void my_datetime_packed_to_binary(longlong nr, uchar *ptr, uint dec); longlong my_datetime_packed_from_binary(const uchar *ptr, uint dec); uint my_datetime_binary_length(uint dec); void my_time_packed_to_binary(longlong nr, uchar *ptr, uint dec); longlong my_time_packed_from_binary(const uchar *ptr, uint dec); uint my_time_binary_length(uint dec); void my_timestamp_to_binary(const struct timeval *tm, uchar *ptr, uint dec); void my_timestamp_from_binary(struct timeval *tm, const uchar *ptr, uint dec); uint my_timestamp_binary_length(uint dec); /** End of MySQL routines and macros **/ #endif /* COMPAT56_H_INCLUDED */ server/private/sql_truncate.h000064400000004037151031265040012402 0ustar00#ifndef SQL_TRUNCATE_INCLUDED #define SQL_TRUNCATE_INCLUDED /* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ class THD; struct TABLE_LIST; /** Sql_cmd_truncate_table represents the TRUNCATE statement. */ class Sql_cmd_truncate_table : public Sql_cmd { private: /* Set if a lock must be downgraded after truncate is done. */ MDL_ticket *m_ticket_downgrade; public: /** Constructor, used to represent a TRUNCATE statement. */ Sql_cmd_truncate_table() = default; virtual ~Sql_cmd_truncate_table() = default; /** Execute a TRUNCATE statement at runtime. @param thd the current thread. @return false on success. */ bool execute(THD *thd) override; enum_sql_command sql_command_code() const override { return SQLCOM_TRUNCATE; } protected: enum truncate_result{ TRUNCATE_OK=0, TRUNCATE_FAILED_BUT_BINLOG, TRUNCATE_FAILED_SKIP_BINLOG }; /** Handle locking a base table for truncate. */ bool lock_table(THD *, TABLE_LIST *, bool *); /** Truncate table via the handler method. */ enum truncate_result handler_truncate(THD *, TABLE_LIST *, bool); /** Optimized delete of all rows by doing a full regenerate of the table. Depending on the storage engine, it can be accomplished through a drop and recreate or via the handler truncate method. */ bool truncate_table(THD *, TABLE_LIST *); }; #endif server/private/mdl.h000064400000113104151031265040010446 0ustar00#ifndef MDL_H #define MDL_H /* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2020, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include "sql_plist.h" #include "ilist.h" #include #include #include #include class THD; class MDL_context; class MDL_lock; class MDL_ticket; bool ok_for_lower_case_names(const char *name); typedef unsigned short mdl_bitmap_t; #define MDL_BIT(A) static_cast(1U << A) /** @def ENTER_COND(C, M, S, O) Start a wait on a condition. @param C the condition to wait on @param M the associated mutex @param S the new stage to enter @param O the previous stage @sa EXIT_COND(). */ #define ENTER_COND(C, M, S, O) enter_cond(C, M, S, O, __func__, __FILE__, __LINE__) /** @def EXIT_COND(S) End a wait on a condition @param S the new stage to enter */ #define EXIT_COND(S) exit_cond(S, __func__, __FILE__, __LINE__) /** An interface to separate the MDL module from the THD, and the rest of the server code. */ class MDL_context_owner { public: virtual ~MDL_context_owner() = default; /** Enter a condition wait. For @c enter_cond() / @c exit_cond() to work the mutex must be held before @c enter_cond(); this mutex is then released by @c exit_cond(). Usage must be: lock mutex; enter_cond(); your code; exit_cond(). @param cond the condition to wait on @param mutex the associated mutex @param [in] stage the stage to enter, or NULL @param [out] old_stage the previous stage, or NULL @param src_function function name of the caller @param src_file file name of the caller @param src_line line number of the caller @sa ENTER_COND(), THD::enter_cond() @sa EXIT_COND(), THD::exit_cond() */ virtual void enter_cond(mysql_cond_t *cond, mysql_mutex_t *mutex, const PSI_stage_info *stage, PSI_stage_info *old_stage, const char *src_function, const char *src_file, int src_line) = 0; /** @def EXIT_COND(S) End a wait on a condition @param [in] stage the new stage to enter @param src_function function name of the caller @param src_file file name of the caller @param src_line line number of the caller @sa ENTER_COND(), THD::enter_cond() @sa EXIT_COND(), THD::exit_cond() */ virtual void exit_cond(const PSI_stage_info *stage, const char *src_function, const char *src_file, int src_line) = 0; /** Has the owner thread been killed? */ virtual int is_killed() = 0; /** This one is only used for DEBUG_SYNC. (Do not use it to peek/poke into other parts of THD.) */ virtual THD* get_thd() = 0; /** @see THD::notify_shared_lock() */ virtual bool notify_shared_lock(MDL_context_owner *in_use, bool needs_thr_lock_abort) = 0; }; /** Type of metadata lock request. @sa Comments for MDL_object_lock::can_grant_lock() and MDL_scoped_lock::can_grant_lock() for details. Scoped locks are database (or schema) locks. The object locks are for tables, triggers etc. */ enum enum_mdl_type { /* This means that the MDL_request is not initialized */ MDL_NOT_INITIALIZED= -1, /* An intention exclusive metadata lock (IX). Used only for scoped locks. Owner of this type of lock can acquire upgradable exclusive locks on individual objects. Compatible with other IX locks, but is incompatible with scoped S and X locks. IX lock is taken in SCHEMA namespace when we intend to modify object metadata. Object may refer table, stored procedure, trigger, view/etc. */ MDL_INTENTION_EXCLUSIVE= 0, /* A shared metadata lock (S). To be used in cases when we are interested in object metadata only and there is no intention to access object data (e.g. for stored routines or during preparing prepared statements). We also mis-use this type of lock for open HANDLERs, since lock acquired by this statement has to be compatible with lock acquired by LOCK TABLES ... WRITE statement, i.e. SNRW (We can't get by by acquiring S lock at HANDLER ... OPEN time and upgrading it to SR lock for HANDLER ... READ as it doesn't solve problem with need to abort DML statements which wait on table level lock while having open HANDLER in the same connection). To avoid deadlock which may occur when SNRW lock is being upgraded to X lock for table on which there is an active S lock which is owned by thread which waits in its turn for table-level lock owned by thread performing upgrade we have to use thr_abort_locks_for_thread() facility in such situation. This problem does not arise for locks on stored routines as we don't use SNRW locks for them. It also does not arise when S locks are used during PREPARE calls as table-level locks are not acquired in this case. This lock is taken for global read lock, when caching a stored procedure in memory for the duration of the transaction and for tables used by prepared statements. */ MDL_SHARED, /* A high priority shared metadata lock. Used for cases when there is no intention to access object data (i.e. data in the table). "High priority" means that, unlike other shared locks, it is granted ignoring pending requests for exclusive locks. Intended for use in cases when we only need to access metadata and not data, e.g. when filling an INFORMATION_SCHEMA table. Since SH lock is compatible with SNRW lock, the connection that holds SH lock lock should not try to acquire any kind of table-level or row-level lock, as this can lead to a deadlock. Moreover, after acquiring SH lock, the connection should not wait for any other resource, as it might cause starvation for X locks and a potential deadlock during upgrade of SNW or SNRW to X lock (e.g. if the upgrading connection holds the resource that is being waited for). */ MDL_SHARED_HIGH_PRIO, /* A shared metadata lock (SR) for cases when there is an intention to read data from table. A connection holding this kind of lock can read table metadata and read table data (after acquiring appropriate table and row-level locks). This means that one can only acquire TL_READ, TL_READ_NO_INSERT, and similar table-level locks on table if one holds SR MDL lock on it. To be used for tables in SELECTs, subqueries, and LOCK TABLE ... READ statements. */ MDL_SHARED_READ, /* A shared metadata lock (SW) for cases when there is an intention to modify (and not just read) data in the table. A connection holding SW lock can read table metadata and modify or read table data (after acquiring appropriate table and row-level locks). To be used for tables to be modified by INSERT, UPDATE, DELETE statements, but not LOCK TABLE ... WRITE or DDL). Also taken by SELECT ... FOR UPDATE. */ MDL_SHARED_WRITE, /* An upgradable shared metadata lock for cases when there is an intention to modify (and not just read) data in the table. Can be upgraded to MDL_SHARED_NO_WRITE and MDL_EXCLUSIVE. A connection holding SU lock can read table metadata and modify or read table data (after acquiring appropriate table and row-level locks). To be used for the first phase of ALTER TABLE. */ MDL_SHARED_UPGRADABLE, /* A shared metadata lock for cases when we need to read data from table and block all concurrent modifications to it (for both data and metadata). Used by LOCK TABLES READ statement. */ MDL_SHARED_READ_ONLY, /* An upgradable shared metadata lock which blocks all attempts to update table data, allowing reads. A connection holding this kind of lock can read table metadata and read table data. Can be upgraded to X metadata lock. Note, that since this type of lock is not compatible with SNRW or SW lock types, acquiring appropriate engine-level locks for reading (TL_READ* for MyISAM, shared row locks in InnoDB) should be contention-free. To be used for the first phase of ALTER TABLE, when copying data between tables, to allow concurrent SELECTs from the table, but not UPDATEs. */ MDL_SHARED_NO_WRITE, /* An upgradable shared metadata lock which allows other connections to access table metadata, but not data. It blocks all attempts to read or update table data, while allowing INFORMATION_SCHEMA and SHOW queries. A connection holding this kind of lock can read table metadata modify and read table data. Can be upgraded to X metadata lock. To be used for LOCK TABLES WRITE statement. Not compatible with any other lock type except S and SH. */ MDL_SHARED_NO_READ_WRITE, /* An exclusive metadata lock (X). A connection holding this lock can modify both table's metadata and data. No other type of metadata lock can be granted while this lock is held. To be used for CREATE/DROP/RENAME TABLE statements and for execution of certain phases of other DDL statements. */ MDL_EXCLUSIVE, /* This should be the last !!! */ MDL_TYPE_END }; /** Backup locks */ /** Block concurrent backup */ #define MDL_BACKUP_START enum_mdl_type(0) /** Block new write requests to non transactional tables */ #define MDL_BACKUP_FLUSH enum_mdl_type(1) /** In addition to previous locks, blocks running requests to non trans tables Used to wait until all DML usage of on trans tables are finished */ #define MDL_BACKUP_WAIT_FLUSH enum_mdl_type(2) /** In addition to previous locks, blocks new DDL's from starting */ #define MDL_BACKUP_WAIT_DDL enum_mdl_type(3) /** In addition to previous locks, blocks commits */ #define MDL_BACKUP_WAIT_COMMIT enum_mdl_type(4) /** Blocks (or is blocked by) statements that intend to modify data. Acquired before commit lock by FLUSH TABLES WITH READ LOCK. */ #define MDL_BACKUP_FTWRL1 enum_mdl_type(5) /** Blocks (or is blocked by) commits. Acquired after global read lock by FLUSH TABLES WITH READ LOCK. */ #define MDL_BACKUP_FTWRL2 enum_mdl_type(6) #define MDL_BACKUP_DML enum_mdl_type(7) #define MDL_BACKUP_TRANS_DML enum_mdl_type(8) #define MDL_BACKUP_SYS_DML enum_mdl_type(9) /** Must be acquired by DDL statements that intend to modify data. Currently it's also used for LOCK TABLES. */ #define MDL_BACKUP_DDL enum_mdl_type(10) /** Blocks new DDL's. Used by backup code to enable DDL logging */ #define MDL_BACKUP_BLOCK_DDL enum_mdl_type(11) /* Statement is modifying data, but will not block MDL_BACKUP_DDL or earlier BACKUP stages. ALTER TABLE is started with MDL_BACKUP_DDL, but changed to MDL_BACKUP_ALTER_COPY while alter table is copying or modifing data. */ #define MDL_BACKUP_ALTER_COPY enum_mdl_type(12) /** Must be acquired during commit. */ #define MDL_BACKUP_COMMIT enum_mdl_type(13) #define MDL_BACKUP_END enum_mdl_type(14) /** Duration of metadata lock. */ enum enum_mdl_duration { /** Locks with statement duration are automatically released at the end of statement or transaction. */ MDL_STATEMENT= 0, /** Locks with transaction duration are automatically released at the end of transaction. */ MDL_TRANSACTION, /** Locks with explicit duration survive the end of statement and transaction. They have to be released explicitly by calling MDL_context::release_lock(). */ MDL_EXPLICIT, /* This should be the last ! */ MDL_DURATION_END }; /** Maximal length of key for metadata locking subsystem. */ #define MAX_MDLKEY_LENGTH (1 + NAME_LEN + 1 + NAME_LEN + 1) /** Metadata lock object key. A lock is requested or granted based on a fully qualified name and type. E.g. They key for a table consists of <0 (=table)>++. Elsewhere in the comments this triple will be referred to simply as "key" or "name". */ struct MDL_key { public: #ifdef HAVE_PSI_INTERFACE static void init_psi_keys(); #endif /** Object namespaces. Sic: when adding a new member to this enum make sure to update m_namespace_to_wait_state_name array in mdl.cc and metadata_lock_info_lock_name in metadata_lock_info.cc! Different types of objects exist in different namespaces - SCHEMA is for databases (to protect against DROP DATABASE) - TABLE is for tables and views. - BACKUP is for locking DML, DDL and COMMIT's during BACKUP STAGES - FUNCTION is for stored functions. - PROCEDURE is for stored procedures. - TRIGGER is for triggers. - EVENT is for event scheduler events Note that although there isn't metadata locking on triggers, it's necessary to have a separate namespace for them since MDL_key is also used outside of the MDL subsystem. */ enum enum_mdl_namespace { BACKUP=0, SCHEMA, TABLE, FUNCTION, PROCEDURE, PACKAGE_BODY, TRIGGER, EVENT, USER_LOCK, /* user level locks. */ /* This should be the last ! */ NAMESPACE_END }; const uchar *ptr() const { return (uchar*) m_ptr; } uint length() const { return m_length; } const char *db_name() const { return m_ptr + 1; } uint db_name_length() const { return m_db_name_length; } const char *name() const { return m_ptr + m_db_name_length + 2; } uint name_length() const { return m_length - m_db_name_length - 3; } enum_mdl_namespace mdl_namespace() const { return (enum_mdl_namespace)(m_ptr[0]); } /** Construct a metadata lock key from a triplet (mdl_namespace, database and name). @remark The key for a table is ++
@param mdl_namespace Id of namespace of object to be locked @param db Name of database to which the object belongs @param name Name of of the object @param key Where to store the the MDL key. */ void mdl_key_init(enum_mdl_namespace mdl_namespace_arg, const char *db, const char *name_arg) { m_ptr[0]= (char) mdl_namespace_arg; /* It is responsibility of caller to ensure that db and object names are not longer than NAME_LEN. Still we play safe and try to avoid buffer overruns. */ DBUG_ASSERT(strlen(db) <= NAME_LEN); DBUG_ASSERT(strlen(name_arg) <= NAME_LEN); m_db_name_length= static_cast(strmake(m_ptr + 1, db, NAME_LEN) - m_ptr - 1); m_length= static_cast(strmake(m_ptr + m_db_name_length + 2, name_arg, NAME_LEN) - m_ptr + 1); m_hash_value= my_hash_sort(&my_charset_bin, (uchar*) m_ptr + 1, m_length - 1); DBUG_SLOW_ASSERT(mdl_namespace_arg == USER_LOCK || ok_for_lower_case_names(db)); } void mdl_key_init(const MDL_key *rhs) { memcpy(m_ptr, rhs->m_ptr, rhs->m_length); m_length= rhs->m_length; m_db_name_length= rhs->m_db_name_length; m_hash_value= rhs->m_hash_value; } bool is_equal(const MDL_key *rhs) const { return (m_length == rhs->m_length && memcmp(m_ptr, rhs->m_ptr, m_length) == 0); } /** Compare two MDL keys lexicographically. */ int cmp(const MDL_key *rhs) const { /* The key buffer is always '\0'-terminated. Since key character set is utf-8, we can safely assume that no character starts with a zero byte. */ return memcmp(m_ptr, rhs->m_ptr, MY_MIN(m_length, rhs->m_length)); } MDL_key(const MDL_key *rhs) { mdl_key_init(rhs); } MDL_key(enum_mdl_namespace namespace_arg, const char *db_arg, const char *name_arg) { mdl_key_init(namespace_arg, db_arg, name_arg); } MDL_key() = default; /* To use when part of MDL_request. */ /** Get thread state name to be used in case when we have to wait on resource identified by key. */ const PSI_stage_info * get_wait_state_name() const { return & m_namespace_to_wait_state_name[(int)mdl_namespace()]; } my_hash_value_type hash_value() const { return m_hash_value + mdl_namespace(); } my_hash_value_type tc_hash_value() const { return m_hash_value; } private: uint16 m_length; uint16 m_db_name_length; my_hash_value_type m_hash_value; char m_ptr[MAX_MDLKEY_LENGTH]; static PSI_stage_info m_namespace_to_wait_state_name[NAMESPACE_END]; private: MDL_key(const MDL_key &); /* not implemented */ MDL_key &operator=(const MDL_key &); /* not implemented */ friend my_hash_value_type mdl_hash_function(CHARSET_INFO *, const uchar *, size_t); }; /** A pending metadata lock request. A lock request and a granted metadata lock are represented by different classes because they have different allocation sites and hence different lifetimes. The allocation of lock requests is controlled from outside of the MDL subsystem, while allocation of granted locks (tickets) is controlled within the MDL subsystem. MDL_request is a C structure, you don't need to call a constructor or destructor for it. */ class MDL_request { public: /** Type of metadata lock. */ enum enum_mdl_type type; /** Duration for requested lock. */ enum enum_mdl_duration duration; /** Pointers for participating in the list of lock requests for this context. */ MDL_request *next_in_list; MDL_request **prev_in_list; /** Pointer to the lock ticket object for this lock request. Valid only if this lock request is satisfied. */ MDL_ticket *ticket; /** A lock is requested based on a fully qualified name and type. */ MDL_key key; const char *m_src_file; uint m_src_line; public: static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return alloc_root(mem_root, size); } static void operator delete(void *, MEM_ROOT *) {} void init_with_source(MDL_key::enum_mdl_namespace namespace_arg, const char *db_arg, const char *name_arg, enum_mdl_type mdl_type_arg, enum_mdl_duration mdl_duration_arg, const char *src_file, uint src_line); void init_by_key_with_source(const MDL_key *key_arg, enum_mdl_type mdl_type_arg, enum_mdl_duration mdl_duration_arg, const char *src_file, uint src_line); /** Set type of lock request. Can be only applied to pending locks. */ inline void set_type(enum_mdl_type type_arg) { DBUG_ASSERT(ticket == NULL); type= type_arg; } void move_from(MDL_request &from) { type= from.type; duration= from.duration; ticket= from.ticket; next_in_list= from.next_in_list; prev_in_list= from.prev_in_list; key.mdl_key_init(&from.key); from.ticket= NULL; // that's what "move" means } /** Is this a request for a lock which allow data to be updated? @note This method returns true for MDL_SHARED_UPGRADABLE type of lock. Even though this type of lock doesn't allow updates it will always be upgraded to one that does. */ bool is_write_lock_request() const { return (type >= MDL_SHARED_WRITE && type != MDL_SHARED_READ_ONLY); } /* This is to work around the ugliness of TABLE_LIST compiler-generated assignment operator. It is currently used in several places to quickly copy "most" of the members of the table list. These places currently never assume that the mdl request is carried over to the new TABLE_LIST, or shared between lists. This method does not initialize the instance being assigned! Use of init() for initialization after this assignment operator is mandatory. Can only be used before the request has been granted. */ MDL_request& operator=(const MDL_request &) { type= MDL_NOT_INITIALIZED; ticket= NULL; /* Do nothing, in particular, don't try to copy the key. */ return *this; } /* Another piece of ugliness for TABLE_LIST constructor */ MDL_request(): type(MDL_NOT_INITIALIZED), ticket(NULL) {} MDL_request(const MDL_request *rhs) :type(rhs->type), duration(rhs->duration), ticket(NULL), key(&rhs->key) {} }; typedef void (*mdl_cached_object_release_hook)(void *); #define MDL_REQUEST_INIT(R, P1, P2, P3, P4, P5) \ (*R).init_with_source(P1, P2, P3, P4, P5, __FILE__, __LINE__) #define MDL_REQUEST_INIT_BY_KEY(R, P1, P2, P3) \ (*R).init_by_key_with_source(P1, P2, P3, __FILE__, __LINE__) /** An abstract class for inspection of a connected subgraph of the wait-for graph. */ class MDL_wait_for_graph_visitor { public: virtual bool enter_node(MDL_context *node) = 0; virtual void leave_node(MDL_context *node) = 0; virtual bool inspect_edge(MDL_context *dest) = 0; virtual ~MDL_wait_for_graph_visitor(); MDL_wait_for_graph_visitor() = default; }; /** Abstract class representing an edge in the waiters graph to be traversed by deadlock detection algorithm. */ class MDL_wait_for_subgraph { public: virtual ~MDL_wait_for_subgraph(); /** Accept a wait-for graph visitor to inspect the node this edge is leading to. */ virtual bool accept_visitor(MDL_wait_for_graph_visitor *gvisitor) = 0; enum enum_deadlock_weight { DEADLOCK_WEIGHT_FTWRL1= 0, DEADLOCK_WEIGHT_DML= 1, DEADLOCK_WEIGHT_DDL= 100 }; /* A helper used to determine which lock request should be aborted. */ virtual uint get_deadlock_weight() const = 0; }; /** A granted metadata lock. @warning MDL_ticket members are private to the MDL subsystem. @note Multiple shared locks on a same object are represented by a single ticket. The same does not apply for other lock types. @note There are two groups of MDL_ticket members: - "Externally accessible". These members can be accessed from threads/contexts different than ticket owner in cases when ticket participates in some list of granted or waiting tickets for a lock. Therefore one should change these members before including then to waiting/granted lists or while holding lock protecting those lists. - "Context private". Such members are private to thread/context owning this ticket. I.e. they should not be accessed from other threads/contexts. */ class MDL_ticket : public MDL_wait_for_subgraph, public ilist_node<> { public: /** Pointers for participating in the list of lock requests for this context. Context private. */ MDL_ticket *next_in_context; MDL_ticket **prev_in_context; public: #ifdef WITH_WSREP void wsrep_report(bool debug) const; #endif /* WITH_WSREP */ bool has_pending_conflicting_lock() const; MDL_context *get_ctx() const { return m_ctx; } bool is_upgradable_or_exclusive() const { return m_type == MDL_SHARED_UPGRADABLE || m_type == MDL_SHARED_NO_WRITE || m_type == MDL_SHARED_NO_READ_WRITE || m_type == MDL_EXCLUSIVE; } enum_mdl_type get_type() const { return m_type; } const LEX_STRING *get_type_name() const; const LEX_STRING *get_type_name(enum_mdl_type type) const; MDL_lock *get_lock() const { return m_lock; } MDL_key *get_key() const; void downgrade_lock(enum_mdl_type type); bool has_stronger_or_equal_type(enum_mdl_type type) const; bool is_incompatible_when_granted(enum_mdl_type type) const; bool is_incompatible_when_waiting(enum_mdl_type type) const; /** Implement MDL_wait_for_subgraph interface. */ bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor) override; uint get_deadlock_weight() const override; /** Status of lock request represented by the ticket as reflected in P_S. */ enum enum_psi_status { PENDING = 0, GRANTED, PRE_ACQUIRE_NOTIFY, POST_RELEASE_NOTIFY }; private: friend class MDL_context; MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg #ifndef DBUG_OFF , enum_mdl_duration duration_arg #endif ) : m_type(type_arg), #ifndef DBUG_OFF m_duration(duration_arg), #endif m_ctx(ctx_arg), m_lock(NULL), m_psi(NULL) {} virtual ~MDL_ticket() { DBUG_ASSERT(m_psi == NULL); } static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg #ifndef DBUG_OFF , enum_mdl_duration duration_arg #endif ); static void destroy(MDL_ticket *ticket); private: /** Type of metadata lock. Externally accessible. */ enum enum_mdl_type m_type; #ifndef DBUG_OFF /** Duration of lock represented by this ticket. Context private. Debug-only. */ enum_mdl_duration m_duration; #endif /** Context of the owner of the metadata lock ticket. Externally accessible. */ MDL_context *m_ctx; /** Pointer to the lock object for this lock ticket. Externally accessible. */ MDL_lock *m_lock; PSI_metadata_lock *m_psi; private: MDL_ticket(const MDL_ticket &); /* not implemented */ MDL_ticket &operator=(const MDL_ticket &); /* not implemented */ }; /** Savepoint for MDL context. Doesn't include metadata locks with explicit duration as they are not released during rollback to savepoint. */ class MDL_savepoint { public: MDL_savepoint() = default;; private: MDL_savepoint(MDL_ticket *stmt_ticket, MDL_ticket *trans_ticket) : m_stmt_ticket(stmt_ticket), m_trans_ticket(trans_ticket) {} friend class MDL_context; private: /** Pointer to last lock with statement duration which was taken before creation of savepoint. */ MDL_ticket *m_stmt_ticket; /** Pointer to last lock with transaction duration which was taken before creation of savepoint. */ MDL_ticket *m_trans_ticket; }; /** A reliable way to wait on an MDL lock. */ class MDL_wait { public: MDL_wait(); ~MDL_wait(); enum enum_wait_status { EMPTY = 0, GRANTED, VICTIM, TIMEOUT, KILLED }; bool set_status(enum_wait_status result_arg); enum_wait_status get_status(); void reset_status(); enum_wait_status timed_wait(MDL_context_owner *owner, struct timespec *abs_timeout, bool signal_timeout, const PSI_stage_info *wait_state_name); private: /** Condvar which is used for waiting until this context's pending request can be satisfied or this thread has to perform actions to resolve a potential deadlock (we subscribe to such notification by adding a ticket corresponding to the request to an appropriate queue of waiters). */ mysql_mutex_t m_LOCK_wait_status; mysql_cond_t m_COND_wait_status; enum_wait_status m_wait_status; }; typedef I_P_List, I_P_List_counter> MDL_request_list; /** Context of the owner of metadata locks. I.e. each server connection has such a context. */ class MDL_context { public: typedef I_P_List > Ticket_list; typedef Ticket_list::Iterator Ticket_iterator; MDL_context(); void destroy(); bool try_acquire_lock(MDL_request *mdl_request); bool acquire_lock(MDL_request *mdl_request, double lock_wait_timeout); bool acquire_locks(MDL_request_list *requests, double lock_wait_timeout); bool upgrade_shared_lock(MDL_ticket *mdl_ticket, enum_mdl_type new_type, double lock_wait_timeout); bool clone_ticket(MDL_request *mdl_request); void release_all_locks_for_name(MDL_ticket *ticket); void release_lock(MDL_ticket *ticket); bool is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace, const char *db, const char *name, enum_mdl_type mdl_type); unsigned long get_lock_owner(MDL_key *mdl_key); bool has_lock(const MDL_savepoint &mdl_savepoint, MDL_ticket *mdl_ticket); inline bool has_locks() const { return !(m_tickets[MDL_STATEMENT].is_empty() && m_tickets[MDL_TRANSACTION].is_empty() && m_tickets[MDL_EXPLICIT].is_empty()); } bool has_explicit_locks() const { return !m_tickets[MDL_EXPLICIT].is_empty(); } inline bool has_transactional_locks() const { return !m_tickets[MDL_TRANSACTION].is_empty(); } MDL_savepoint mdl_savepoint() { return MDL_savepoint(m_tickets[MDL_STATEMENT].front(), m_tickets[MDL_TRANSACTION].front()); } void set_explicit_duration_for_all_locks(); void set_transaction_duration_for_all_locks(); void set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration); void release_statement_locks(); void release_transactional_locks(THD *thd); void release_explicit_locks(); void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint); MDL_context_owner *get_owner() { return m_owner; } /** @pre Only valid if we started waiting for lock. */ inline uint get_deadlock_weight() const { return m_waiting_for->get_deadlock_weight() + m_deadlock_overweight; } void inc_deadlock_overweight() { m_deadlock_overweight++; } /** Post signal to the context (and wake it up if necessary). @retval FALSE - Success, signal was posted. @retval TRUE - Failure, signal was not posted since context already has received some signal or closed signal slot. */ void init(MDL_context_owner *arg) { m_owner= arg; reset(); } void reset() { m_deadlock_overweight= 0; } void set_needs_thr_lock_abort(bool needs_thr_lock_abort) { /* @note In theory, this member should be modified under protection of some lock since it can be accessed from different threads. In practice, this is not necessary as code which reads this value and so might miss the fact that value was changed will always re-try reading it after small timeout and therefore will see the new value eventually. */ m_needs_thr_lock_abort= needs_thr_lock_abort; } bool get_needs_thr_lock_abort() const { return m_needs_thr_lock_abort; } public: /** If our request for a lock is scheduled, or aborted by the deadlock detector, the result is recorded in this class. */ MDL_wait m_wait; private: /** Lists of all MDL tickets acquired by this connection. Lists of MDL tickets: --------------------- The entire set of locks acquired by a connection can be separated in three subsets according to their duration: locks released at the end of statement, at the end of transaction and locks are released explicitly. Statement and transactional locks are locks with automatic scope. They are accumulated in the course of a transaction, and released either at the end of uppermost statement (for statement locks) or on COMMIT, ROLLBACK or ROLLBACK TO SAVEPOINT (for transactional locks). They must not be (and never are) released manually, i.e. with release_lock() call. Tickets with explicit duration are taken for locks that span multiple transactions or savepoints. These are: HANDLER SQL locks (HANDLER SQL is transaction-agnostic), LOCK TABLES locks (you can COMMIT/etc under LOCK TABLES, and the locked tables stay locked), user level locks (GET_LOCK()/RELEASE_LOCK() functions) and locks implementing "global read lock". Statement/transactional locks are always prepended to the beginning of the appropriate list. In other words, they are stored in reverse temporal order. Thus, when we rollback to a savepoint, we start popping and releasing tickets from the front until we reach the last ticket acquired after the savepoint. Locks with explicit duration are not stored in any particular order, and among each other can be split into four sets: [LOCK TABLES locks] [USER locks] [HANDLER locks] [GLOBAL READ LOCK locks] The following is known about these sets: * GLOBAL READ LOCK locks are always stored last. This is because one can't say SET GLOBAL read_only=1 or FLUSH TABLES WITH READ LOCK if one has locked tables. One can, however, LOCK TABLES after having entered the read only mode. Note, that subsequent LOCK TABLES statement will unlock the previous set of tables, but not the GRL! There are no HANDLER locks after GRL locks because SET GLOBAL read_only performs a FLUSH TABLES WITH READ LOCK internally, and FLUSH TABLES, in turn, implicitly closes all open HANDLERs. However, one can open a few HANDLERs after entering the read only mode. * LOCK TABLES locks include intention exclusive locks on involved schemas and global intention exclusive lock. */ Ticket_list m_tickets[MDL_DURATION_END]; MDL_context_owner *m_owner; /** TRUE - if for this context we will break protocol and try to acquire table-level locks while having only S lock on some table. To avoid deadlocks which might occur during concurrent upgrade of SNRW lock on such object to X lock we have to abort waits for table-level locks for such connections. FALSE - Otherwise. */ bool m_needs_thr_lock_abort; /** Read-write lock protecting m_waiting_for member. @note The fact that this read-write lock prefers readers is important as deadlock detector won't work correctly otherwise. @sa Comment for MDL_lock::m_rwlock. */ mysql_prlock_t m_LOCK_waiting_for; /** Tell the deadlock detector what metadata lock or table definition cache entry this session is waiting for. In principle, this is redundant, as information can be found by inspecting waiting queues, but we'd very much like it to be readily available to the wait-for graph iterator. */ MDL_wait_for_subgraph *m_waiting_for; LF_PINS *m_pins; uint m_deadlock_overweight; private: MDL_ticket *find_ticket(MDL_request *mdl_req, enum_mdl_duration *duration); void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel); void release_lock(enum_mdl_duration duration, MDL_ticket *ticket); bool try_acquire_lock_impl(MDL_request *mdl_request, MDL_ticket **out_ticket); bool fix_pins(); public: THD *get_thd() const { return m_owner->get_thd(); } bool has_explicit_locks(); void find_deadlock(); ulong get_thread_id() const { return thd_get_thread_id(get_thd()); } bool visit_subgraph(MDL_wait_for_graph_visitor *dvisitor); /** Inform the deadlock detector there is an edge in the wait-for graph. */ void will_wait_for(MDL_wait_for_subgraph *waiting_for_arg) { mysql_prlock_wrlock(&m_LOCK_waiting_for); m_waiting_for= waiting_for_arg; mysql_prlock_unlock(&m_LOCK_waiting_for); } /** Remove the wait-for edge from the graph after we're done waiting. */ void done_waiting_for() { mysql_prlock_wrlock(&m_LOCK_waiting_for); m_waiting_for= NULL; mysql_prlock_unlock(&m_LOCK_waiting_for); } void lock_deadlock_victim() { mysql_prlock_rdlock(&m_LOCK_waiting_for); } void unlock_deadlock_victim() { mysql_prlock_unlock(&m_LOCK_waiting_for); } private: MDL_context(const MDL_context &rhs); /* not implemented */ MDL_context &operator=(MDL_context &rhs); /* not implemented */ /* metadata_lock_info plugin */ friend int i_s_metadata_lock_info_fill_row(MDL_ticket*, void*); #ifndef DBUG_OFF public: /** This is for the case when the thread opening the table does not acquire the lock itself, but utilizes a lock guarantee from another MDL context. For example, in InnoDB, MDL is acquired by the purge_coordinator_task, but the table may be opened and used in a purge_worker_task. The coordinator thread holds the lock for the duration of worker's purge job, or longer, possibly reusing shared MDL for different workers and jobs. */ MDL_context *lock_warrant= NULL; inline bool is_lock_warrantee(MDL_key::enum_mdl_namespace ns, const char *db, const char *name, enum_mdl_type mdl_type) const { return lock_warrant && lock_warrant->is_lock_owner(ns, db, name, mdl_type); } #endif }; void mdl_init(); void mdl_destroy(); extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd); /** Check if a connection in question is no longer connected. @details Replication apply thread is always connected. Otherwise, does a poll on the associated socket to check if the client is gone. */ extern "C" int thd_is_connected(MYSQL_THD thd); /* Metadata locking subsystem tries not to grant more than max_write_lock_count high-prio, strong locks successively, to avoid starving out weak, low-prio locks. */ extern "C" ulong max_write_lock_count; typedef int (*mdl_iterator_callback)(MDL_ticket *ticket, void *arg, bool granted); extern MYSQL_PLUGIN_IMPORT int mdl_iterate(mdl_iterator_callback callback, void *arg); #endif /* MDL_H */ server/private/sql_time.h000064400000020266151031265040011515 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. Copyright (c) 2011, 2020, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_TIME_INCLUDED #define SQL_TIME_INCLUDED #include "sql_basic_types.h" #include "my_time.h" #include "mysql_time.h" /* timestamp_type */ #include "sql_error.h" /* Sql_condition */ #include "structs.h" /* INTERVAL */ typedef enum enum_mysql_timestamp_type timestamp_type; typedef struct st_date_time_format DATE_TIME_FORMAT; typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT; /* Flags for calc_week() function. */ #define WEEK_MONDAY_FIRST 1 #define WEEK_YEAR 2 #define WEEK_FIRST_WEEKDAY 4 ulong convert_period_to_month(ulong period); ulong convert_month_to_period(ulong month); void set_current_date(THD *thd, MYSQL_TIME *to); bool time_to_datetime(MYSQL_TIME *ltime); bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code); bool str_to_datetime_with_warn(THD *thd, CHARSET_INFO *cs, const char *str, size_t length, MYSQL_TIME *l_time, date_mode_t flags); bool double_to_datetime_with_warn(THD *thd, double value, MYSQL_TIME *ltime, date_mode_t fuzzydate, const TABLE_SHARE *s, const char *name); bool decimal_to_datetime_with_warn(THD *thd, const my_decimal *value, MYSQL_TIME *ltime, date_mode_t fuzzydate, const TABLE_SHARE *s, const char *name); bool int_to_datetime_with_warn(THD *thd, const Longlong_hybrid &nr, MYSQL_TIME *ltime, date_mode_t fuzzydate, const TABLE_SHARE *s, const char *name); bool time_to_datetime(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt); bool time_to_datetime_with_warn(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt, date_conv_mode_t fuzzydate); inline void datetime_to_date(MYSQL_TIME *ltime) { DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE || ltime->time_type == MYSQL_TIMESTAMP_DATETIME); DBUG_ASSERT(ltime->neg == 0); ltime->second_part= ltime->hour= ltime->minute= ltime->second= 0; ltime->time_type= MYSQL_TIMESTAMP_DATE; } inline void date_to_datetime(MYSQL_TIME *ltime) { DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE || ltime->time_type == MYSQL_TIMESTAMP_DATETIME); DBUG_ASSERT(ltime->neg == 0); ltime->time_type= MYSQL_TIMESTAMP_DATETIME; } void make_truncated_value_warning(THD *thd, Sql_condition::enum_warning_level level, const ErrConv *str_val, timestamp_type time_type, const char *db_name, const char *table_name, const char *field_name); extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type, const char *format_str, uint format_length); extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format); const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, timestamp_type type); bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec); /* MYSQL_TIME operations */ bool date_add_interval(THD *thd, MYSQL_TIME *ltime, interval_type int_type, const INTERVAL &interval, bool push_warn= true); bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, int l_sign, ulonglong *seconds_out, ulong *microseconds_out); int append_interval(String *str, interval_type int_type, const INTERVAL &interval); /** Calculate time difference between two MYSQL_TIME values and store the result as an out MYSQL_TIME value in MYSQL_TIMESTAMP_TIME format. The result can be outside of the supported TIME range. For example, calc_time_diff('2002-01-01 00:00:00', '2001-01-01 00:00:00') returns '8760:00:00'. So the caller might want to do check_time_range() or adjust_time_range_with_warn() on the result of a calc_time_diff() call. @param l_time1 - the minuend (TIME/DATE/DATETIME value) @param l_time2 - the subtrahend TIME/DATE/DATETIME value @param l_sign - +1 if absolute values are to be subtracted, or -1 if absolute values are to be added. @param[out] l_time3 - the result @param fuzzydate - flags @return true - if TIME_NO_ZERO_DATE was passed in flags and the result appeared to be '00:00:00.000000'. This is important when calc_time_diff() is called when calculating DATE_ADD(TIMEDIFF(...),...) @return false - otherwise */ bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2, int lsign, MYSQL_TIME *l_time3, date_mode_t fuzzydate); int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b); void localtime_to_TIME(MYSQL_TIME *to, struct tm *from); void calc_time_from_sec(MYSQL_TIME *to, ulong seconds, ulong microseconds); uint calc_week(const MYSQL_TIME *l_time, uint week_behaviour, uint *year); int calc_weekday(long daynr,bool sunday_first_day_of_week); bool parse_date_time_format(timestamp_type format_type, const char *format, uint format_length, DATE_TIME_FORMAT *date_time_format); /* convenience wrapper */ inline bool parse_date_time_format(timestamp_type format_type, DATE_TIME_FORMAT *date_time_format) { return parse_date_time_format(format_type, date_time_format->format.str, (uint) date_time_format->format.length, date_time_format); } extern DATE_TIME_FORMAT global_date_format; extern DATE_TIME_FORMAT global_datetime_format; extern DATE_TIME_FORMAT global_time_format; extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[]; extern LEX_CSTRING interval_type_to_name[]; static inline bool non_zero_hhmmssuu(const MYSQL_TIME *ltime) { return ltime->hour || ltime->minute || ltime->second || ltime->second_part; } static inline bool non_zero_YYMMDD(const MYSQL_TIME *ltime) { return ltime->year || ltime->month || ltime->day; } static inline bool non_zero_date(const MYSQL_TIME *ltime) { return non_zero_YYMMDD(ltime) || (ltime->time_type == MYSQL_TIMESTAMP_DATETIME && non_zero_hhmmssuu(ltime)); } static inline bool check_date(const MYSQL_TIME *ltime, date_conv_mode_t flags, int *was_cut) { return check_date(ltime, non_zero_date(ltime), ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), was_cut); } bool check_date_with_warn(THD *thd, const MYSQL_TIME *ltime, date_conv_mode_t fuzzy_date, timestamp_type ts_type); static inline bool check_date_with_warn(THD *thd, const MYSQL_TIME *ltime, date_mode_t fuzzydate, timestamp_type ts_type) { return check_date_with_warn(thd, ltime, date_conv_mode_t(fuzzydate), ts_type); } bool adjust_time_range_with_warn(THD *thd, MYSQL_TIME *ltime, uint dec); longlong pack_time(const MYSQL_TIME *my_time); void unpack_time(longlong packed, MYSQL_TIME *my_time, enum_mysql_timestamp_type ts_type); #endif /* SQL_TIME_INCLUDED */ server/private/handle_connections_win.h000064400000001564151031265040014412 0ustar00/* Copyright (c) 2018 MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /** Handles incoming socket and pipe connections, on Windows. Creates new (THD) connections.. */ extern void handle_connections_win(); extern void network_init_win(); server/private/mysqld_suffix.h000064400000002261151031265040012570 0ustar00#ifndef MYSQLD_SUFFIX_INCLUDED #define MYSQLD_SUFFIX_INCLUDED /* Copyright (c) 2000-2004, 2006, 2007 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Set MYSQL_SERVER_SUFFIX_STR. The following code is quite ugly as there is no portable way to easily set a string to the value of a macro */ #ifdef MYSQL_SERVER_SUFFIX #define MYSQL_SERVER_SUFFIX_STR STRINGIFY_ARG(MYSQL_SERVER_SUFFIX) #else #define MYSQL_SERVER_SUFFIX_STR MYSQL_SERVER_SUFFIX_DEF #endif #endif /* MYSQLD_SUFFIX_INCLUDED */ server/private/gcalc_slicescan.h000064400000041570151031265040012776 0ustar00/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. Copyright (C) 2011 Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef GCALC_SLICESCAN_INCLUDED #define GCALC_SLICESCAN_INCLUDED #ifndef DBUG_OFF // #define GCALC_CHECK_WITH_FLOAT #else #define GCALC_DBUG_OFF #endif /*DBUG_OFF*/ #ifndef GCALC_DBUG_OFF #define GCALC_DBUG_PRINT(b) DBUG_PRINT("Gcalc", b) #define GCALC_DBUG_ENTER(a) DBUG_ENTER("Gcalc " a) #define GCALC_DBUG_RETURN(r) DBUG_RETURN(r) #define GCALC_DBUG_VOID_RETURN DBUG_VOID_RETURN #define GCALC_DBUG_ASSERT(r) DBUG_ASSERT(r) #else #define GCALC_DBUG_PRINT(b) do {} while(0) #define GCALC_DBUG_ENTER(a) do {} while(0) #define GCALC_DBUG_RETURN(r) return (r) #define GCALC_DBUG_VOID_RETURN do {} while(0) #define GCALC_DBUG_ASSERT(r) do {} while(0) #endif /*GCALC_DBUG_OFF*/ #define GCALC_TERMINATED(state_var) (state_var && (*state_var)) #define GCALC_SET_TERMINATED(state_var, val) state_var= val #define GCALC_DECL_TERMINATED_STATE(varname) \ volatile int *varname; /* Gcalc_dyn_list class designed to manage long lists of same-size objects with the possible efficiency. It allocates fixed-size blocks of memory (blk_size specified at the time of creation). When new object is added to the list, it occupies part of this block until it's full. Then the new block is allocated. Freed objects are chained to the m_free list, and if it's not empty, the newly added object is taken from this list instead the block. */ class Gcalc_dyn_list { public: class Item { public: Item *next; }; Gcalc_dyn_list(size_t blk_size, size_t sizeof_item); Gcalc_dyn_list(const Gcalc_dyn_list &dl); ~Gcalc_dyn_list(); Item *new_item() { Item *result; if (m_free) { result= m_free; m_free= m_free->next; } else result= alloc_new_blk(); return result; } inline void free_item(Item *item) { item->next= m_free; m_free= item; } inline void free_list(Item **list, Item **hook) { *hook= m_free; m_free= *list; } void free_list(Item *list) { Item **hook= &list; while (*hook) hook= &(*hook)->next; free_list(&list, hook); } void reset(); void cleanup(); protected: size_t m_blk_size; size_t m_sizeof_item; unsigned int m_points_per_blk; void *m_first_blk; void **m_blk_hook; Item *m_free; Item *m_keep; Item *alloc_new_blk(); void format_blk(void* block); inline Item *ptr_add(Item *ptr, int n_items) { return (Item *)(((char*)ptr) + n_items * m_sizeof_item); } }; /* Internal Gcalc coordinates to provide the precise calculations */ #define GCALC_DIG_BASE 1000000000 typedef uint32 gcalc_digit_t; typedef unsigned long long gcalc_coord2; typedef gcalc_digit_t Gcalc_internal_coord; #define GCALC_COORD_BASE 2 #define GCALC_COORD_BASE2 4 #define GCALC_COORD_BASE3 6 #define GCALC_COORD_BASE4 8 #define GCALC_COORD_BASE5 10 typedef gcalc_digit_t Gcalc_coord1[GCALC_COORD_BASE]; typedef gcalc_digit_t Gcalc_coord2[GCALC_COORD_BASE*2]; typedef gcalc_digit_t Gcalc_coord3[GCALC_COORD_BASE*3]; void gcalc_mul_coord(Gcalc_internal_coord *result, int result_len, const Gcalc_internal_coord *a, int a_len, const Gcalc_internal_coord *b, int b_len); void gcalc_add_coord(Gcalc_internal_coord *result, int result_len, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b); void gcalc_sub_coord(Gcalc_internal_coord *result, int result_len, const Gcalc_internal_coord *a, const Gcalc_internal_coord *b); int gcalc_cmp_coord(const Gcalc_internal_coord *a, const Gcalc_internal_coord *b, int len); /* Internal coordinates declarations end. */ typedef uint gcalc_shape_info; /* Gcalc_heap represents the 'dynamic list' of Info objects, that contain information about vertexes of all the shapes that take part in some spatial calculation. Can become quite long. After filled, the list is usually sorted and then walked through in the slicescan algorithm. The Gcalc_heap and the algorithm can only operate with two kinds of shapes - polygon and polyline. So all the spatial objects should be represented as sets of these two. */ class Gcalc_heap : public Gcalc_dyn_list { public: enum node_type { nt_shape_node, nt_intersection, nt_eq_node }; class Info : public Gcalc_dyn_list::Item { public: node_type type; union { struct { /* nt_shape_node */ gcalc_shape_info shape; Info *left; Info *right; double x,y; Gcalc_coord1 ix, iy; int top_node; } shape; struct { /* nt_intersection */ /* Line p1-p2 supposed to intersect line p3-p4 */ const Info *p1; const Info *p2; const Info *p3; const Info *p4; void *data; int equal; } intersection; struct { /* nt_eq_node */ const Info *node; void *data; } eq; } node; bool is_bottom() const { GCALC_DBUG_ASSERT(type == nt_shape_node); return !node.shape.left; } bool is_top() const { GCALC_DBUG_ASSERT(type == nt_shape_node); return node.shape.top_node; } bool is_single_node() const { return is_bottom() && is_top(); } void calc_xy(double *x, double *y) const; int equal_pi(const Info *pi) const; #ifdef GCALC_CHECK_WITH_FLOAT void calc_xy_ld(long double *x, long double *y) const; #endif /*GCALC_CHECK_WITH_FLOAT*/ Info *get_next() { return (Info *)next; } const Info *get_next() const { return (const Info *)next; } }; Gcalc_heap(size_t blk_size=8192) : Gcalc_dyn_list(blk_size, sizeof(Info)), m_hook(&m_first), m_n_points(0) {} Gcalc_heap(const Gcalc_heap &gh) : Gcalc_dyn_list(gh), m_hook(&m_first), m_n_points(0) {} void set_extent(double xmin, double xmax, double ymin, double ymax); Info *new_point_info(double x, double y, gcalc_shape_info shape); void free_point_info(Info *i, Gcalc_dyn_list::Item **i_hook); Info *new_intersection(const Info *p1, const Info *p2, const Info *p3, const Info *p4); void prepare_operation(); inline bool ready() const { return m_hook == NULL; } Info *get_first() { return (Info *)m_first; } const Info *get_first() const { return (const Info *)m_first; } Gcalc_dyn_list::Item **get_last_hook() { return m_hook; } void reset(); #ifdef GCALC_CHECK_WITH_FLOAT long double get_double(const Gcalc_internal_coord *c) const; #endif /*GCALC_CHECK_WITH_FLOAT*/ double coord_extent; Gcalc_dyn_list::Item **get_cur_hook() { return m_hook; } private: Gcalc_dyn_list::Item *m_first; Gcalc_dyn_list::Item **m_hook; int m_n_points; }; /* the spatial object has to be represented as a set of simple polygones and polylines to be sent to the slicescan. Gcalc_shape_transporter class and his descendants are used to simplify storing the information about the shape into necessary structures. This base class only fills the Gcalc_heap with the information about shapes and vertices. Normally the Gcalc_shape_transporter family object is sent as a parameter to the 'get_shapes' method of an 'spatial' object so it can pass the spatial information about itself. The virtual methods are treating this data in a way the caller needs. */ class Gcalc_shape_transporter { private: Gcalc_heap::Info *m_first; Gcalc_heap::Info *m_prev; Gcalc_dyn_list::Item **m_prev_hook; int m_shape_started; void int_complete(); protected: Gcalc_heap *m_heap; int int_single_point(gcalc_shape_info Info, double x, double y); int int_add_point(gcalc_shape_info Info, double x, double y); void int_start_line() { DBUG_ASSERT(!m_shape_started); m_shape_started= 1; m_first= m_prev= NULL; } void int_complete_line() { DBUG_ASSERT(m_shape_started== 1); int_complete(); m_shape_started= 0; } void int_start_ring() { DBUG_ASSERT(m_shape_started== 2); m_shape_started= 3; m_first= m_prev= NULL; } void int_complete_ring() { DBUG_ASSERT(m_shape_started== 3); int_complete(); m_shape_started= 2; } void int_start_poly() { DBUG_ASSERT(!m_shape_started); m_shape_started= 2; } void int_complete_poly() { DBUG_ASSERT(m_shape_started== 2); m_shape_started= 0; } bool line_started() { return m_shape_started == 1; }; public: Gcalc_shape_transporter(Gcalc_heap *heap) : m_shape_started(0), m_heap(heap) {} virtual int single_point(double x, double y)=0; virtual int start_line()=0; virtual int complete_line()=0; virtual int start_poly()=0; virtual int complete_poly()=0; virtual int start_ring()=0; virtual int complete_ring()=0; virtual int add_point(double x, double y)=0; virtual int start_collection(int n_objects) { return 0; } virtual int empty_shape() { return 0; } int start_simple_poly() { return start_poly() || start_ring(); } int complete_simple_poly() { return complete_ring() || complete_poly(); } virtual ~Gcalc_shape_transporter() = default; }; enum Gcalc_scan_events { scev_none= 0, scev_point= 1, /* Just a new point in thread */ scev_thread= 2, /* Start of the new thread */ scev_two_threads= 4, /* A couple of new threads started */ scev_intersection= 8, /* Intersection happened */ scev_end= 16, /* Single thread finished */ scev_two_ends= 32, /* A couple of threads finished */ scev_single_point= 64 /* Got single point */ }; /* Gcalc_scan_iterator incapsulates the slicescan algorithm. It takes filled Gcalc_heap as a datasource. Then can be iterated through the vertexes and intersection points with the step() method. After the 'step()' one usually observes the current 'slice' to do the necessary calculations, like looking for intersections, calculating the area, whatever. */ class Gcalc_scan_iterator : public Gcalc_dyn_list { public: class point : public Gcalc_dyn_list::Item { public: Gcalc_coord1 dx; Gcalc_coord1 dy; Gcalc_heap::Info *pi; Gcalc_heap::Info *next_pi; Gcalc_heap::Info *ev_pi; const Gcalc_coord1 *l_border; const Gcalc_coord1 *r_border; point *ev_next; Gcalc_scan_events event; inline const point *c_get_next() const { return (const point *)next; } inline bool is_bottom() const { return !next_pi; } gcalc_shape_info get_shape() const { return pi->node.shape.shape; } inline point *get_next() { return (point *)next; } inline const point *get_next() const { return (const point *)next; } /* Compare the dx_dy parameters regarding the horiz_dir */ /* returns -1 if less, 0 if equal, 1 if bigger */ static int cmp_dx_dy(const Gcalc_coord1 dx_a, const Gcalc_coord1 dy_a, const Gcalc_coord1 dx_b, const Gcalc_coord1 dy_b); static int cmp_dx_dy(const Gcalc_heap::Info *p1, const Gcalc_heap::Info *p2, const Gcalc_heap::Info *p3, const Gcalc_heap::Info *p4); int cmp_dx_dy(const point *p) const; point **next_ptr() { return (point **) &next; } #ifndef GCALC_DBUG_OFF unsigned int thread; #endif /*GCALC_DBUG_OFF*/ #ifdef GCALC_CHECK_WITH_FLOAT void calc_x(long double *x, long double y, long double ix) const; #endif /*GCALC_CHECK_WITH_FLOAT*/ }; /* That class introduced mostly for the 'typecontrol' reason. */ /* only difference from the point classis the get_next() function. */ class event_point : public point { public: inline const event_point *get_next() const { return (const event_point*) ev_next; } int simple_event() const { return !ev_next ? (event & (scev_point | scev_end)) : (!ev_next->ev_next && event == scev_two_ends); } }; class intersection_info : public Gcalc_dyn_list::Item { public: point *edge_a; point *edge_b; Gcalc_coord2 t_a; Gcalc_coord2 t_b; int t_calculated; Gcalc_coord3 x_exp; int x_calculated; Gcalc_coord3 y_exp; int y_calculated; void calc_t() {if (!t_calculated) do_calc_t(); } void calc_y_exp() { if (!y_calculated) do_calc_y(); } void calc_x_exp() { if (!x_calculated) do_calc_x(); } void do_calc_t(); void do_calc_x(); void do_calc_y(); }; class slice_state { public: point *slice; point **event_position_hook; point *event_end; const Gcalc_heap::Info *pi; }; public: Gcalc_scan_iterator(size_t blk_size= 8192); GCALC_DECL_TERMINATED_STATE(killed) void init(Gcalc_heap *points); /* Iterator can be reused */ void reset(); int step(); Gcalc_heap::Info *more_points() { return m_cur_pi; } bool more_trapezoids() { return m_cur_pi && m_cur_pi->next; } const point *get_bottom_points() const { return m_bottom_points; } const point *get_event_position() const { return *state.event_position_hook; } const point *get_event_end() const { return state.event_end; } const event_point *get_events() const { return (const event_point *) (*state.event_position_hook == state.event_end ? m_bottom_points : *state.event_position_hook); } const point *get_b_slice() const { return state.slice; } double get_h() const; double get_y() const; double get_event_x() const; double get_sp_x(const point *sp) const; int intersection_step() const { return state.pi->type == Gcalc_heap::nt_intersection; } const Gcalc_heap::Info *get_cur_pi() const { return state.pi; } private: Gcalc_heap *m_heap; Gcalc_heap::Info *m_cur_pi; slice_state state; #ifndef GCALC_DBUG_OFF unsigned int m_cur_thread; #endif /*GCALC_DBUG_OFF*/ point *m_bottom_points; point **m_bottom_hook; int node_scan(); void eq_scan(); void intersection_scan(); void remove_bottom_node(); int insert_top_node(); int add_intersection(point *sp_a, point *sp_b, Gcalc_heap::Info *pi_from); int add_eq_node(Gcalc_heap::Info *node, point *sp); int add_events_for_node(point *sp_node); point *new_slice_point() { point *new_point= (point *)new_item(); return new_point; } intersection_info *new_intersection_info(point *a, point *b) { intersection_info *ii= (intersection_info *)new_item(); ii->edge_a= a; ii->edge_b= b; ii->t_calculated= ii->x_calculated= ii->y_calculated= 0; return ii; } int arrange_event(int do_sorting, int n_intersections); static double get_pure_double(const Gcalc_internal_coord *d, int d_len); }; /* Gcalc_trapezoid_iterator simplifies the calculations on the current slice of the Gcalc_scan_iterator. One can walk through the trapezoids formed between previous and current slices. */ #ifdef TMP_BLOCK class Gcalc_trapezoid_iterator { protected: const Gcalc_scan_iterator::point *sp0; const Gcalc_scan_iterator::point *sp1; public: Gcalc_trapezoid_iterator(const Gcalc_scan_iterator *scan_i) : sp0(scan_i->get_b_slice()), sp1(scan_i->get_t_slice()) {} inline bool more() const { return sp1 && sp1->next; } const Gcalc_scan_iterator::point *lt() const { return sp1; } const Gcalc_scan_iterator::point *lb() const { return sp0; } const Gcalc_scan_iterator::point *rb() const { const Gcalc_scan_iterator::point *result= sp0; while ((result= result->c_get_next())->is_bottom()) {} return result; } const Gcalc_scan_iterator::point *rt() const { return sp1->c_get_next(); } void operator++() { sp0= rb(); sp1= rt(); } }; #endif /*TMP_BLOCK*/ /* Gcalc_point_iterator simplifies the calculations on the current slice of the Gcalc_scan_iterator. One can walk through the points on the current slice. */ class Gcalc_point_iterator { protected: const Gcalc_scan_iterator::point *sp; public: Gcalc_point_iterator(const Gcalc_scan_iterator *scan_i): sp(scan_i->get_b_slice()) {} inline bool more() const { return sp != NULL; } inline void operator++() { sp= sp->c_get_next(); } inline const Gcalc_scan_iterator::point *point() const { return sp; } inline const Gcalc_heap::Info *get_pi() const { return sp->pi; } inline gcalc_shape_info get_shape() const { return sp->get_shape(); } inline void restart(const Gcalc_scan_iterator *scan_i) { sp= scan_i->get_b_slice(); } }; #endif /*GCALC_SLICESCAN_INCLUDED*/ server/private/records.h000064400000006113151031265040011334 0ustar00#ifndef SQL_RECORDS_H #define SQL_RECORDS_H /* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "table.h" struct st_join_table; class handler; class THD; class SQL_SELECT; class Copy_field; class SORT_INFO; struct READ_RECORD; void end_read_record(READ_RECORD *info); void free_cache(READ_RECORD *info); /** A context for reading through a single table using a chosen access method: index read, scan, etc, use of cache, etc. Use by: READ_RECORD read_record; init_read_record(&read_record, ...); while (read_record.read_record()) { ... } end_read_record(); */ struct READ_RECORD { typedef int (*Read_func)(READ_RECORD*); typedef void (*Unlock_row_func)(st_join_table *); typedef int (*Setup_func)(struct st_join_table*); TABLE *table; /* Head-form */ Unlock_row_func unlock_row; Read_func read_record_func; Read_func read_record_func_and_unpack_calls; THD *thd; SQL_SELECT *select; uint ref_length, reclength, rec_cache_size, error_offset; /** Counting records when reading result from filesort(). Used when filesort leaves the result in the filesort buffer. */ ha_rows unpack_counter; uchar *ref_pos; /* pointer to form->refpos */ uchar *rec_buf; /* to read field values after filesort */ uchar *cache,*cache_pos,*cache_end,*read_positions; /* Structure storing information about sorting */ SORT_INFO *sort_info; struct st_io_cache *io_cache; bool print_error; int read_record() { return read_record_func(this); } uchar *record() const { return table->record[0]; } /* SJ-Materialization runtime may need to read fields from the materialized table and unpack them into original table fields: */ Copy_field *copy_field; Copy_field *copy_field_end; public: READ_RECORD() : table(NULL), cache(NULL) {} ~READ_RECORD() { end_read_record(this); } }; bool init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, SQL_SELECT *select, SORT_INFO *sort, int use_record_cache, bool print_errors, bool disable_rr_cache); bool init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, bool print_error, uint idx, bool reverse); void rr_unlock_row(st_join_table *tab); #endif /* SQL_RECORDS_H */ server/private/uniques.h000064400000010171151031265040011363 0ustar00/* Copyright (c) 2016 MariaDB corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef UNIQUE_INCLUDED #define UNIQUE_INCLUDED #include "filesort.h" /* Unique -- class for unique (removing of duplicates). Puts all values to the TREE. If the tree becomes too big, it's dumped to the file. User can request sorted values, or just iterate through them. In the last case tree merging is performed in memory simultaneously with iteration, so it should be ~2-3x faster. */ class Unique :public Sql_alloc { DYNAMIC_ARRAY file_ptrs; ulong max_elements; /* Total number of elements that will be stored in-memory */ size_t max_in_memory_size; IO_CACHE file; TREE tree; /* Number of elements filtered out due to min_dupl_count when storing results to table. See Unique::get */ ulong filtered_out_elems; uint size; uint full_size; /* Size of element + space needed to store the number of duplicates found for the element. */ uint min_dupl_count; /* Minimum number of occurences of element required for it to be written to record_pointers. always 0 for unions, > 0 for intersections */ bool with_counters; bool merge(TABLE *table, uchar *buff, size_t size, bool without_last_merge); bool flush(); public: ulong elements; SORT_INFO sort; Unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg, uint size_arg, size_t max_in_memory_size_arg, uint min_dupl_count_arg= 0); ~Unique(); ulong elements_in_tree() { return tree.elements_in_tree; } inline bool unique_add(void *ptr) { DBUG_ENTER("unique_add"); DBUG_PRINT("info", ("tree %u - %lu", tree.elements_in_tree, max_elements)); if (!(tree.flag & TREE_ONLY_DUPS) && tree.elements_in_tree >= max_elements && flush()) DBUG_RETURN(1); DBUG_RETURN(!tree_insert(&tree, ptr, 0, tree.custom_arg)); } bool is_in_memory() { return (my_b_tell(&file) == 0); } void close_for_expansion() { tree.flag= TREE_ONLY_DUPS; } bool get(TABLE *table); /* Cost of searching for an element in the tree */ inline static double get_search_cost(ulonglong tree_elems, double compare_factor) { return log((double) tree_elems) / (compare_factor * M_LN2); } static double get_use_cost(uint *buffer, size_t nkeys, uint key_size, size_t max_in_memory_size, double compare_factor, bool intersect_fl, bool *in_memory); inline static int get_cost_calc_buff_size(size_t nkeys, uint key_size, size_t max_in_memory_size) { size_t max_elems_in_tree= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size); if (max_elems_in_tree == 0) max_elems_in_tree= 1; return (int) (sizeof(uint)*(1 + nkeys/max_elems_in_tree)); } void reset(); bool walk(TABLE *table, tree_walk_action action, void *walk_action_arg); uint get_size() const { return size; } size_t get_max_in_memory_size() const { return max_in_memory_size; } friend int unique_write_to_file(void* key, element_count count, void *unique); friend int unique_write_to_ptrs(void* key, element_count count, void *unique); friend int unique_write_to_file_with_count(void *key, element_count count, void *unique); friend int unique_intersect_write_to_ptrs(void *key, element_count count, void *unique); }; #endif /* UNIQUE_INCLUDED */ server/private/strfunc.h000064400000004343151031265040011362 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef STRFUNC_INCLUDED #define STRFUNC_INCLUDED typedef struct st_typelib TYPELIB; ulonglong find_set(const TYPELIB *lib, const char *x, size_t length, CHARSET_INFO *cs, char **err_pos, uint *err_len, bool *set_warning); ulonglong find_set_from_flags(TYPELIB *lib, uint default_name, ulonglong cur_set, ulonglong default_set, const char *str, uint length, CHARSET_INFO *cs, char **err_pos, uint *err_len, bool *set_warning); uint find_type(const TYPELIB *lib, const char *find, size_t length, bool part_match); uint find_type2(const TYPELIB *lib, const char *find, size_t length, CHARSET_INFO *cs); void unhex_type2(TYPELIB *lib); uint check_word(TYPELIB *lib, const char *val, const char *end, const char **end_of_word); int find_string_in_array(LEX_CSTRING * const haystack, LEX_CSTRING * const needle, CHARSET_INFO * const cs); const char *flagset_to_string(THD *thd, LEX_CSTRING *result, ulonglong set, const char *lib[]); const char *set_to_string(THD *thd, LEX_CSTRING *result, ulonglong set, const char *lib[]); /* These functions were protected by INNODB_COMPATIBILITY_HOOKS */ uint strconvert(CHARSET_INFO *from_cs, const char *from, size_t from_length, CHARSET_INFO *to_cs, char *to, size_t to_length, uint *errors); #endif /* STRFUNC_INCLUDED */ server/private/mysqld.h000064400000117011151031265040011204 0ustar00/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. Copyright (c) 2010, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MYSQLD_INCLUDED #define MYSQLD_INCLUDED #include "sql_basic_types.h" /* query_id_t */ #include "sql_mode.h" /* Sql_mode_dependency */ #include "sql_plugin.h" #include "sql_bitmap.h" /* Bitmap */ #include "my_decimal.h" /* my_decimal */ #include "mysql_com.h" /* SERVER_VERSION_LENGTH */ #include "my_counter.h" #include "mysql/psi/mysql_file.h" /* MYSQL_FILE */ #include "mysql/psi/mysql_socket.h" /* MYSQL_SOCKET */ #include "sql_list.h" /* I_List */ #include "sql_cmd.h" #include #include "my_pthread.h" #include "my_rdtsc.h" class THD; class CONNECT; struct handlerton; class Time_zone; struct scheduler_functions; typedef struct st_mysql_show_var SHOW_VAR; /* Bits from testflag */ #define TEST_PRINT_CACHED_TABLES 1U #define TEST_NO_KEY_GROUP 2U #define TEST_MIT_THREAD 4U #define TEST_BLOCKING 8U #define TEST_KEEP_TMP_TABLES 16U #define TEST_READCHECK 64U /**< Force use of readcheck */ #define TEST_NO_EXTRA 128U #define TEST_CORE_ON_SIGNAL 256U /**< Give core if signal */ #define TEST_SIGINT 1024U /**< Allow sigint on threads */ #define TEST_SYNCHRONIZATION 2048U /**< get server to do sleep in some places */ /* Keep things compatible */ #define OPT_DEFAULT SHOW_OPT_DEFAULT #define OPT_SESSION SHOW_OPT_SESSION #define OPT_GLOBAL SHOW_OPT_GLOBAL extern MYSQL_PLUGIN_IMPORT MY_TIMER_INFO sys_timer_info; /* Values for --slave-parallel-mode Must match order in slave_parallel_mode_typelib in sys_vars.cc. */ enum enum_slave_parallel_mode { SLAVE_PARALLEL_NONE, SLAVE_PARALLEL_MINIMAL, SLAVE_PARALLEL_CONSERVATIVE, SLAVE_PARALLEL_OPTIMISTIC, SLAVE_PARALLEL_AGGRESSIVE }; /* Function prototypes */ void kill_mysql(THD *thd); void close_connection(THD *thd, uint sql_errno= 0); void handle_connection_in_main_thread(CONNECT *thd); void create_thread_to_handle_connection(CONNECT *connect); void unlink_thd(THD *thd); void refresh_status(THD *thd); bool is_secure_file_path(char *path); extern void init_net_server_extension(THD *thd); extern void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock); extern void create_new_thread(CONNECT *connect); extern void ssl_acceptor_stats_update(int sslaccept_ret); extern int reinit_ssl(); extern "C" MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info; extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ; extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *national_charset_info; extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *table_alias_charset; /** Character set of the buildin error messages loaded from errmsg.sys. */ extern CHARSET_INFO *error_message_charset_info; extern CHARSET_INFO *character_set_filesystem; extern MY_BITMAP temp_pool; extern bool opt_large_files; extern bool opt_update_log, opt_bin_log, opt_error_log, opt_bin_log_compress; extern uint opt_bin_log_compress_min_len; extern my_bool opt_log, opt_bootstrap; extern my_bool opt_backup_history_log; extern my_bool opt_backup_progress_log; extern my_bool opt_support_flashback; extern ulonglong log_output_options; extern ulong log_backup_output_options; extern bool opt_disable_networking, opt_skip_show_db; extern bool opt_skip_name_resolve; extern bool opt_ignore_builtin_innodb; extern my_bool opt_character_set_client_handshake; extern my_bool debug_assert_on_not_freed_memory; extern MYSQL_PLUGIN_IMPORT bool volatile abort_loop; extern my_bool opt_safe_user_create; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; extern my_bool opt_slave_compressed_protocol, use_temp_pool; extern ulong slave_exec_mode_options, slave_ddl_exec_mode_options; extern ulong slave_retried_transactions; extern ulong transactions_multi_engine; extern ulong rpl_transactions_multi_engine; extern ulong transactions_gtid_foreign_engine; extern ulong slave_run_triggers_for_rbr; extern ulonglong slave_type_conversions_options; extern my_bool read_only, opt_readonly; extern MYSQL_PLUGIN_IMPORT my_bool lower_case_file_system; extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs; extern my_bool opt_secure_auth; extern my_bool opt_require_secure_transport; extern const char *current_dbug_option; extern char* opt_secure_file_priv; extern char* opt_secure_backup_file_priv; extern size_t opt_secure_backup_file_priv_len; extern my_bool sp_automatic_privileges, opt_noacl; extern ulong use_stat_tables; extern my_bool opt_old_style_user_limits, trust_function_creators; extern uint opt_crash_binlog_innodb; extern const char *shared_memory_base_name; extern MYSQL_PLUGIN_IMPORT char *mysqld_unix_port; extern my_bool opt_enable_shared_memory; extern ulong opt_replicate_events_marked_for_skip; extern char *default_tz_name; extern Time_zone *default_tz; extern char *my_bind_addr_str; extern char *default_storage_engine, *default_tmp_storage_engine; extern char *enforced_storage_engine; extern char *gtid_pos_auto_engines; extern plugin_ref *opt_gtid_pos_auto_plugins; extern bool opt_endinfo, using_udf_functions; extern my_bool locked_in_memory; extern bool opt_using_transactions; extern ulong current_pid; extern double expire_logs_days; extern ulong binlog_expire_logs_seconds; extern my_bool relay_log_recovery; extern uint sync_binlog_period, sync_relaylog_period, sync_relayloginfo_period, sync_masterinfo_period; extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size; extern ulong tc_log_page_waits; extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb; extern my_bool relay_log_recovery; extern uint select_errors,ha_open_options; extern ulonglong test_flags; extern uint protocol_version, dropping_tables; extern MYSQL_PLUGIN_IMPORT uint mysqld_port; extern ulong delay_key_write_options; extern char *opt_logname, *opt_slow_logname, *opt_bin_logname, *opt_relay_logname; extern char *opt_binlog_index_name; extern char *opt_backup_history_logname, *opt_backup_progress_logname, *opt_backup_settings_name; extern const char *log_output_str; extern const char *log_backup_output_str; /* System Versioning begin */ enum vers_system_time_t { SYSTEM_TIME_UNSPECIFIED = 0, SYSTEM_TIME_AS_OF, SYSTEM_TIME_FROM_TO, SYSTEM_TIME_BETWEEN, SYSTEM_TIME_BEFORE, // used for DELETE HISTORY ... BEFORE SYSTEM_TIME_HISTORY, // used for DELETE HISTORY SYSTEM_TIME_ALL }; struct vers_asof_timestamp_t { ulong type; my_time_t unix_time; ulong second_part; }; enum vers_alter_history_enum { VERS_ALTER_HISTORY_ERROR= 0, VERS_ALTER_HISTORY_KEEP }; /* System Versioning end */ extern char *mysql_home_ptr, *pidfile_name_ptr; extern MYSQL_PLUGIN_IMPORT char glob_hostname[FN_REFLEN]; extern char mysql_home[FN_REFLEN]; extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file; extern char default_logfile_name[FN_REFLEN]; extern char log_error_file[FN_REFLEN], *opt_tc_log_file, *opt_ddl_recovery_file; extern const double log_10[309]; extern ulonglong keybuff_size; extern ulonglong thd_startup_options; extern my_thread_id global_thread_id; extern ulong binlog_cache_use, binlog_cache_disk_use; extern ulong binlog_stmt_cache_use, binlog_stmt_cache_disk_use; extern ulong aborted_threads, aborted_connects, aborted_connects_preauth; extern ulong delayed_insert_timeout; extern ulong delayed_insert_limit, delayed_queue_size; extern ulong delayed_insert_threads, delayed_insert_writes; extern ulong delayed_rows_in_use,delayed_insert_errors; extern Atomic_counter slave_open_temp_tables; extern ulonglong query_cache_size; extern ulong query_cache_limit; extern ulong query_cache_min_res_unit; extern ulong slow_launch_threads, slow_launch_time; extern MYSQL_PLUGIN_IMPORT ulong max_connections; extern uint max_digest_length; extern ulong max_connect_errors, connect_timeout; extern uint max_password_errors; extern my_bool slave_allow_batching; extern my_bool allow_slave_start; extern LEX_CSTRING reason_slave_blocked; extern ulong slave_trans_retries; extern ulong slave_trans_retry_interval; extern uint slave_net_timeout; extern int max_user_connections; extern ulong what_to_log,flush_time; extern uint max_prepared_stmt_count, prepared_stmt_count; extern MYSQL_PLUGIN_IMPORT ulong open_files_limit; extern ulonglong binlog_cache_size, binlog_stmt_cache_size, binlog_file_cache_size; extern ulonglong max_binlog_cache_size, max_binlog_stmt_cache_size; extern ulong max_binlog_size; extern ulong slave_max_allowed_packet; extern ulong opt_binlog_rows_event_max_size; extern ulong binlog_row_metadata; extern ulong thread_cache_size; extern ulong stored_program_cache_size; extern ulong opt_slave_parallel_threads; extern ulong opt_slave_domain_parallel_threads; extern ulong opt_slave_parallel_max_queued; extern ulong opt_slave_parallel_mode; extern ulong opt_binlog_commit_wait_count; extern ulong opt_binlog_commit_wait_usec; extern my_bool opt_gtid_ignore_duplicates; extern uint opt_gtid_cleanup_batch_size; extern ulong back_log; extern ulong executed_events; extern char language[FN_REFLEN]; extern "C" MYSQL_PLUGIN_IMPORT ulong server_id; extern ulong concurrency; extern time_t server_start_time, flush_status_time; extern char *opt_mysql_tmpdir, mysql_charsets_dir[]; extern size_t mysql_unpacked_real_data_home_len; extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list; extern const char *first_keyword, *delayed_user, *slave_user; extern MYSQL_PLUGIN_IMPORT const char *my_localhost; extern MYSQL_PLUGIN_IMPORT const char **errmesg; /* Error messages */ extern const char *myisam_recover_options_str; extern const LEX_CSTRING in_left_expr_name, in_additional_cond, in_having_cond; extern const LEX_CSTRING NULL_clex_str; extern const LEX_CSTRING error_clex_str; extern SHOW_VAR status_vars[]; extern struct system_variables max_system_variables; extern struct system_status_var global_status_var; extern struct my_rnd_struct sql_rand; extern const char *opt_date_time_formats[]; extern handlerton *partition_hton; extern handlerton *myisam_hton; extern handlerton *heap_hton; extern const char *load_default_groups[]; extern struct my_option my_long_options[]; int handle_early_options(); extern int MYSQL_PLUGIN_IMPORT mysqld_server_started; extern int mysqld_server_initialized; extern "C" MYSQL_PLUGIN_IMPORT int orig_argc; extern "C" MYSQL_PLUGIN_IMPORT char **orig_argv; extern pthread_attr_t connection_attrib; extern my_bool old_mode; extern LEX_STRING opt_init_connect, opt_init_slave; extern char err_shared_dir[]; extern ulong connection_errors_select; extern ulong connection_errors_accept; extern ulong connection_errors_tcpwrap; extern ulong connection_errors_internal; extern ulong connection_errors_max_connection; extern ulong connection_errors_peer_addr; extern ulong log_warnings; extern my_bool encrypt_binlog; extern my_bool encrypt_tmp_disk_tables, encrypt_tmp_files; extern ulong encryption_algorithm; extern const char *encryption_algorithm_names[]; extern long opt_secure_timestamp; extern uint default_password_lifetime; extern my_bool disconnect_on_expired_password; enum secure_timestamp { SECTIME_NO, SECTIME_SUPER, SECTIME_REPL, SECTIME_YES }; #ifdef HAVE_MMAP extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool, key_LOCK_pending_checkpoint; #endif /* HAVE_MMAP */ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_BINLOG_LOCK_binlog_background_thread, key_LOCK_binlog_end_pos, key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi, key_LOCK_crypt, key_LOCK_delayed_create, key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log, key_LOCK_gdl, key_LOCK_global_system_variables, key_LOCK_logger, key_LOCK_manager, key_LOCK_prepared_stmt_count, key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status, key_LOCK_thd_data, key_LOCK_thd_kill, key_LOCK_user_conn, key_LOG_LOCK_log, key_master_info_data_lock, key_master_info_run_lock, key_master_info_sleep_lock, key_master_info_start_stop_lock, key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock, key_relay_log_info_log_space_lock, key_relay_log_info_run_lock, key_rpl_group_info_sleep_lock, key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data, key_TABLE_SHARE_LOCK_statistics, key_LOCK_start_thread, key_LOCK_error_messages, key_PARTITION_LOCK_auto_inc; extern PSI_mutex_key key_RELAYLOG_LOCK_index; extern PSI_mutex_key key_LOCK_relaylog_end_pos; extern PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state, key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry; extern PSI_mutex_key key_TABLE_SHARE_LOCK_share, key_LOCK_stats, key_LOCK_global_user_client_stats, key_LOCK_global_table_stats, key_LOCK_global_index_stats, key_LOCK_wakeup_ready, key_LOCK_wait_commit, key_TABLE_SHARE_LOCK_rotation; extern PSI_mutex_key key_LOCK_gtid_waiting; extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave, key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock, key_LOCK_SEQUENCE, key_rwlock_LOCK_vers_stats, key_rwlock_LOCK_stat_serial, key_rwlock_THD_list; #ifdef HAVE_MMAP extern PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool; #endif /* HAVE_MMAP */ extern PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond, key_BINLOG_COND_binlog_background_thread, key_BINLOG_COND_binlog_background_thread_end, key_COND_cache_status_changed, key_COND_manager, key_COND_rpl_status, key_COND_server_started, key_delayed_insert_cond, key_delayed_insert_cond_client, key_item_func_sleep_cond, key_master_info_data_cond, key_master_info_start_cond, key_master_info_stop_cond, key_master_info_sleep_cond, key_relay_log_info_data_cond, key_relay_log_info_log_space_cond, key_relay_log_info_start_cond, key_relay_log_info_stop_cond, key_rpl_group_info_sleep_cond, key_TABLE_SHARE_cond, key_user_level_lock_cond, key_COND_start_thread; extern PSI_cond_key key_RELAYLOG_COND_relay_log_updated, key_RELAYLOG_COND_bin_log_updated, key_COND_wakeup_ready, key_COND_wait_commit; extern PSI_cond_key key_RELAYLOG_COND_queue_busy; extern PSI_cond_key key_TC_LOG_MMAP_COND_queue_busy; extern PSI_cond_key key_COND_rpl_thread, key_COND_rpl_thread_queue, key_COND_rpl_thread_stop, key_COND_rpl_thread_pool, key_COND_parallel_entry, key_COND_group_commit_orderer; extern PSI_cond_key key_COND_wait_gtid, key_COND_gtid_ignore_duplicates; extern PSI_cond_key key_TABLE_SHARE_COND_rotation; extern PSI_thread_key key_thread_delayed_insert, key_thread_handle_manager, key_thread_kill_server, key_thread_main, key_thread_one_connection, key_thread_signal_hand, key_thread_slave_background, key_rpl_parallel_thread; extern PSI_file_key key_file_binlog, key_file_binlog_cache, key_file_binlog_index, key_file_binlog_index_cache, key_file_casetest, key_file_dbopt, key_file_ERRMSG, key_select_to_file, key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load, key_file_loadfile, key_file_log_event_data, key_file_log_event_info, key_file_master_info, key_file_misc, key_file_partition_ddl_log, key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog, key_file_trg, key_file_trn, key_file_init, key_file_log_ddl; extern PSI_file_key key_file_query_log, key_file_slow_log; extern PSI_file_key key_file_relaylog, key_file_relaylog_index, key_file_relaylog_cache, key_file_relaylog_index_cache; extern PSI_socket_key key_socket_tcpip, key_socket_unix, key_socket_client_connection; extern PSI_file_key key_file_binlog_state; #ifdef HAVE_des extern char* des_key_file; extern PSI_file_key key_file_des_key_file; extern PSI_mutex_key key_LOCK_des_key_file; extern mysql_mutex_t LOCK_des_key_file; #endif #ifdef HAVE_PSI_INTERFACE void init_server_psi_keys(); #endif /* HAVE_PSI_INTERFACE */ extern PSI_memory_key key_memory_locked_table_list; extern PSI_memory_key key_memory_locked_thread_list; extern PSI_memory_key key_memory_thd_transactions; extern PSI_memory_key key_memory_delegate; extern PSI_memory_key key_memory_acl_mem; extern PSI_memory_key key_memory_acl_memex; extern PSI_memory_key key_memory_acl_cache; extern PSI_memory_key key_memory_thd_main_mem_root; extern PSI_memory_key key_memory_help; extern PSI_memory_key key_memory_frm; extern PSI_memory_key key_memory_table_share; extern PSI_memory_key key_memory_gdl; extern PSI_memory_key key_memory_table_triggers_list; extern PSI_memory_key key_memory_prepared_statement_map; extern PSI_memory_key key_memory_prepared_statement_main_mem_root; extern PSI_memory_key key_memory_protocol_rset_root; extern PSI_memory_key key_memory_warning_info_warn_root; extern PSI_memory_key key_memory_sp_cache; extern PSI_memory_key key_memory_sp_head_main_root; extern PSI_memory_key key_memory_sp_head_execute_root; extern PSI_memory_key key_memory_sp_head_call_root; extern PSI_memory_key key_memory_table_mapping_root; extern PSI_memory_key key_memory_quick_range_select_root; extern PSI_memory_key key_memory_quick_index_merge_root; extern PSI_memory_key key_memory_quick_ror_intersect_select_root; extern PSI_memory_key key_memory_quick_ror_union_select_root; extern PSI_memory_key key_memory_quick_group_min_max_select_root; extern PSI_memory_key key_memory_test_quick_select_exec; extern PSI_memory_key key_memory_prune_partitions_exec; extern PSI_memory_key key_memory_binlog_recover_exec; extern PSI_memory_key key_memory_blob_mem_storage; extern PSI_memory_key key_memory_Sys_var_charptr_value; extern PSI_memory_key key_memory_THD_db; extern PSI_memory_key key_memory_user_var_entry; extern PSI_memory_key key_memory_user_var_entry_value; extern PSI_memory_key key_memory_Slave_job_group_group_relay_log_name; extern PSI_memory_key key_memory_Relay_log_info_group_relay_log_name; extern PSI_memory_key key_memory_binlog_cache_mngr; extern PSI_memory_key key_memory_Row_data_memory_memory; extern PSI_memory_key key_memory_errmsgs; extern PSI_memory_key key_memory_Event_queue_element_for_exec_names; extern PSI_memory_key key_memory_Event_scheduler_scheduler_param; extern PSI_memory_key key_memory_Gis_read_stream_err_msg; extern PSI_memory_key key_memory_Geometry_objects_data; extern PSI_memory_key key_memory_host_cache_hostname; extern PSI_memory_key key_memory_User_level_lock; extern PSI_memory_key key_memory_Filesort_info_record_pointers; extern PSI_memory_key key_memory_Sort_param_tmp_buffer; extern PSI_memory_key key_memory_Filesort_info_merge; extern PSI_memory_key key_memory_Filesort_buffer_sort_keys; extern PSI_memory_key key_memory_handler_errmsgs; extern PSI_memory_key key_memory_handlerton; extern PSI_memory_key key_memory_XID; extern PSI_memory_key key_memory_MYSQL_LOCK; extern PSI_memory_key key_memory_MYSQL_LOG_name; extern PSI_memory_key key_memory_TC_LOG_MMAP_pages; extern PSI_memory_key key_memory_my_str_malloc; extern PSI_memory_key key_memory_MYSQL_BIN_LOG_basename; extern PSI_memory_key key_memory_MYSQL_BIN_LOG_index; extern PSI_memory_key key_memory_MYSQL_RELAY_LOG_basename; extern PSI_memory_key key_memory_MYSQL_RELAY_LOG_index; extern PSI_memory_key key_memory_rpl_filter; extern PSI_memory_key key_memory_Security_context; extern PSI_memory_key key_memory_NET_buff; extern PSI_memory_key key_memory_NET_compress_packet; extern PSI_memory_key key_memory_my_bitmap_map; extern PSI_memory_key key_memory_QUICK_RANGE_SELECT_mrr_buf_desc; extern PSI_memory_key key_memory_TABLE_RULE_ENT; extern PSI_memory_key key_memory_Mutex_cond_array_Mutex_cond; extern PSI_memory_key key_memory_Owned_gtids_sidno_to_hash; extern PSI_memory_key key_memory_Sid_map_Node; extern PSI_memory_key key_memory_bison_stack; extern PSI_memory_key key_memory_TABLE_sort_io_cache; extern PSI_memory_key key_memory_DATE_TIME_FORMAT; extern PSI_memory_key key_memory_DDL_LOG_MEMORY_ENTRY; extern PSI_memory_key key_memory_ST_SCHEMA_TABLE; extern PSI_memory_key key_memory_ignored_db; extern PSI_memory_key key_memory_SLAVE_INFO; extern PSI_memory_key key_memory_log_event_old; extern PSI_memory_key key_memory_HASH_ROW_ENTRY; extern PSI_memory_key key_memory_table_def_memory; extern PSI_memory_key key_memory_MPVIO_EXT_auth_info; extern PSI_memory_key key_memory_LOG_POS_COORD; extern PSI_memory_key key_memory_XID_STATE; extern PSI_memory_key key_memory_Rpl_info_file_buffer; extern PSI_memory_key key_memory_Rpl_info_table; extern PSI_memory_key key_memory_binlog_pos; extern PSI_memory_key key_memory_db_worker_hash_entry; extern PSI_memory_key key_memory_rpl_slave_command_buffer; extern PSI_memory_key key_memory_binlog_ver_1_event; extern PSI_memory_key key_memory_rpl_slave_check_temp_dir; extern PSI_memory_key key_memory_TABLE; extern PSI_memory_key key_memory_binlog_statement_buffer; extern PSI_memory_key key_memory_user_conn; extern PSI_memory_key key_memory_dboptions_hash; extern PSI_memory_key key_memory_dbnames_cache; extern PSI_memory_key key_memory_hash_index_key_buffer; extern PSI_memory_key key_memory_THD_handler_tables_hash; extern PSI_memory_key key_memory_JOIN_CACHE; extern PSI_memory_key key_memory_READ_INFO; extern PSI_memory_key key_memory_partition_syntax_buffer; extern PSI_memory_key key_memory_global_system_variables; extern PSI_memory_key key_memory_THD_variables; extern PSI_memory_key key_memory_PROFILE; extern PSI_memory_key key_memory_LOG_name; extern PSI_memory_key key_memory_string_iterator; extern PSI_memory_key key_memory_frm_extra_segment_buff; extern PSI_memory_key key_memory_frm_form_pos; extern PSI_memory_key key_memory_frm_string; extern PSI_memory_key key_memory_Unique_sort_buffer; extern PSI_memory_key key_memory_Unique_merge_buffer; extern PSI_memory_key key_memory_shared_memory_name; extern PSI_memory_key key_memory_opt_bin_logname; extern PSI_memory_key key_memory_Query_cache; extern PSI_memory_key key_memory_READ_RECORD_cache; extern PSI_memory_key key_memory_Quick_ranges; extern PSI_memory_key key_memory_File_query_log_name; extern PSI_memory_key key_memory_Table_trigger_dispatcher; extern PSI_memory_key key_memory_show_slave_status_io_gtid_set; extern PSI_memory_key key_memory_write_set_extraction; extern PSI_memory_key key_memory_thd_timer; extern PSI_memory_key key_memory_THD_Session_tracker; extern PSI_memory_key key_memory_THD_Session_sysvar_resource_manager; extern PSI_memory_key key_memory_get_all_tables; extern PSI_memory_key key_memory_fill_schema_schemata; extern PSI_memory_key key_memory_native_functions; extern PSI_memory_key key_memory_JSON; extern PSI_memory_key key_memory_WSREP; /* MAINTAINER: Please keep this list in order, to limit merge collisions. Hint: grep PSI_stage_info | sort -u */ extern PSI_stage_info stage_apply_event; extern PSI_stage_info stage_after_create; extern PSI_stage_info stage_after_opening_tables; extern PSI_stage_info stage_after_table_lock; extern PSI_stage_info stage_allocating_local_table; extern PSI_stage_info stage_alter_inplace_prepare; extern PSI_stage_info stage_alter_inplace; extern PSI_stage_info stage_alter_inplace_commit; extern PSI_stage_info stage_after_apply_event; extern PSI_stage_info stage_changing_master; extern PSI_stage_info stage_checking_master_version; extern PSI_stage_info stage_checking_permissions; extern PSI_stage_info stage_checking_privileges_on_cached_query; extern PSI_stage_info stage_checking_query_cache_for_query; extern PSI_stage_info stage_cleaning_up; extern PSI_stage_info stage_closing_tables; extern PSI_stage_info stage_connecting_to_master; extern PSI_stage_info stage_converting_heap_to_myisam; extern PSI_stage_info stage_copying_to_group_table; extern PSI_stage_info stage_copying_to_tmp_table; extern PSI_stage_info stage_copy_to_tmp_table; extern PSI_stage_info stage_creating_delayed_handler; extern PSI_stage_info stage_creating_sort_index; extern PSI_stage_info stage_creating_table; extern PSI_stage_info stage_creating_tmp_table; extern PSI_stage_info stage_deleting_from_main_table; extern PSI_stage_info stage_deleting_from_reference_tables; extern PSI_stage_info stage_discard_or_import_tablespace; extern PSI_stage_info stage_end; extern PSI_stage_info stage_enabling_keys; extern PSI_stage_info stage_executing; extern PSI_stage_info stage_execution_of_init_command; extern PSI_stage_info stage_explaining; extern PSI_stage_info stage_finding_key_cache; extern PSI_stage_info stage_finished_reading_one_binlog_switching_to_next_binlog; extern PSI_stage_info stage_flushing_relay_log_and_master_info_repository; extern PSI_stage_info stage_flushing_relay_log_info_file; extern PSI_stage_info stage_freeing_items; extern PSI_stage_info stage_fulltext_initialization; extern PSI_stage_info stage_got_handler_lock; extern PSI_stage_info stage_got_old_table; extern PSI_stage_info stage_init; extern PSI_stage_info stage_init_update; extern PSI_stage_info stage_insert; extern PSI_stage_info stage_invalidating_query_cache_entries_table; extern PSI_stage_info stage_invalidating_query_cache_entries_table_list; extern PSI_stage_info stage_killing_slave; extern PSI_stage_info stage_logging_slow_query; extern PSI_stage_info stage_making_temp_file_append_before_load_data; extern PSI_stage_info stage_making_temp_file_create_before_load_data; extern PSI_stage_info stage_manage_keys; extern PSI_stage_info stage_master_has_sent_all_binlog_to_slave; extern PSI_stage_info stage_opening_tables; extern PSI_stage_info stage_optimizing; extern PSI_stage_info stage_preparing; extern PSI_stage_info stage_purging_old_relay_logs; extern PSI_stage_info stage_query_end; extern PSI_stage_info stage_starting_cleanup; extern PSI_stage_info stage_slave_sql_cleanup; extern PSI_stage_info stage_rollback; extern PSI_stage_info stage_rollback_implicit; extern PSI_stage_info stage_commit; extern PSI_stage_info stage_commit_implicit; extern PSI_stage_info stage_queueing_master_event_to_the_relay_log; extern PSI_stage_info stage_reading_event_from_the_relay_log; extern PSI_stage_info stage_recreating_table; extern PSI_stage_info stage_registering_slave_on_master; extern PSI_stage_info stage_removing_duplicates; extern PSI_stage_info stage_removing_tmp_table; extern PSI_stage_info stage_rename; extern PSI_stage_info stage_rename_result_table; extern PSI_stage_info stage_requesting_binlog_dump; extern PSI_stage_info stage_reschedule; extern PSI_stage_info stage_searching_rows_for_update; extern PSI_stage_info stage_sending_binlog_event_to_slave; extern PSI_stage_info stage_sending_cached_result_to_client; extern PSI_stage_info stage_sending_data; extern PSI_stage_info stage_setup; extern PSI_stage_info stage_slave_has_read_all_relay_log; extern PSI_stage_info stage_show_explain; extern PSI_stage_info stage_sorting; extern PSI_stage_info stage_sorting_for_group; extern PSI_stage_info stage_sorting_for_order; extern PSI_stage_info stage_sorting_result; extern PSI_stage_info stage_sql_thd_waiting_until_delay; extern PSI_stage_info stage_statistics; extern PSI_stage_info stage_storing_result_in_query_cache; extern PSI_stage_info stage_storing_row_into_queue; extern PSI_stage_info stage_system_lock; extern PSI_stage_info stage_unlocking_tables; extern PSI_stage_info stage_table_lock; extern PSI_stage_info stage_filling_schema_table; extern PSI_stage_info stage_update; extern PSI_stage_info stage_updating; extern PSI_stage_info stage_updating_main_table; extern PSI_stage_info stage_updating_reference_tables; extern PSI_stage_info stage_upgrading_lock; extern PSI_stage_info stage_user_lock; extern PSI_stage_info stage_user_sleep; extern PSI_stage_info stage_verifying_table; extern PSI_stage_info stage_waiting_for_ddl; extern PSI_stage_info stage_waiting_for_delay_list; extern PSI_stage_info stage_waiting_for_disk_space; extern PSI_stage_info stage_waiting_for_flush; extern PSI_stage_info stage_waiting_for_gtid_to_be_written_to_binary_log; extern PSI_stage_info stage_waiting_for_handler_insert; extern PSI_stage_info stage_waiting_for_handler_lock; extern PSI_stage_info stage_waiting_for_handler_open; extern PSI_stage_info stage_waiting_for_insert; extern PSI_stage_info stage_waiting_for_master_to_send_event; extern PSI_stage_info stage_waiting_for_master_update; extern PSI_stage_info stage_waiting_for_relay_log_space; extern PSI_stage_info stage_waiting_for_slave_mutex_on_exit; extern PSI_stage_info stage_waiting_for_slave_thread_to_start; extern PSI_stage_info stage_waiting_for_query_cache_lock; extern PSI_stage_info stage_waiting_for_table_flush; extern PSI_stage_info stage_waiting_for_the_next_event_in_relay_log; extern PSI_stage_info stage_waiting_for_the_slave_thread_to_advance_position; extern PSI_stage_info stage_waiting_to_finalize_termination; extern PSI_stage_info stage_binlog_waiting_background_tasks; extern PSI_stage_info stage_binlog_write; extern PSI_stage_info stage_binlog_processing_checkpoint_notify; extern PSI_stage_info stage_binlog_stopping_background_thread; extern PSI_stage_info stage_waiting_for_work_from_sql_thread; extern PSI_stage_info stage_waiting_for_prior_transaction_to_commit; extern PSI_stage_info stage_waiting_for_prior_transaction_to_start_commit; extern PSI_stage_info stage_waiting_for_room_in_worker_thread; extern PSI_stage_info stage_waiting_for_workers_idle; extern PSI_stage_info stage_waiting_for_ftwrl; extern PSI_stage_info stage_waiting_for_ftwrl_threads_to_pause; extern PSI_stage_info stage_waiting_for_rpl_thread_pool; extern PSI_stage_info stage_master_gtid_wait_primary; extern PSI_stage_info stage_master_gtid_wait; extern PSI_stage_info stage_gtid_wait_other_connection; extern PSI_stage_info stage_slave_background_process_request; extern PSI_stage_info stage_slave_background_wait_request; extern PSI_stage_info stage_waiting_for_deadlock_kill; extern PSI_stage_info stage_starting; #ifdef HAVE_PSI_STATEMENT_INTERFACE /** Statement instrumentation keys (sql). The last entry, at [SQLCOM_END], is for parsing errors. */ extern PSI_statement_info sql_statement_info[(uint) SQLCOM_END + 1]; /** Statement instrumentation keys (com). The last entry, at [COM_END], is for packet errors. */ extern PSI_statement_info com_statement_info[(uint) COM_END + 1]; /** Statement instrumentation key for replication. */ extern PSI_statement_info stmt_info_rpl; void init_sql_statement_info(); void init_com_statement_info(); #endif /* HAVE_PSI_STATEMENT_INTERFACE */ #ifndef _WIN32 extern pthread_t signal_thread; #endif #ifdef HAVE_OPENSSL extern struct st_VioSSLFd * ssl_acceptor_fd; #endif /* HAVE_OPENSSL */ /* The following variables were under INNODB_COMPABILITY_HOOKS */ extern my_bool opt_large_pages; extern uint opt_large_page_size; extern MYSQL_PLUGIN_IMPORT char lc_messages_dir[FN_REFLEN]; extern char *lc_messages_dir_ptr, *log_error_file_ptr; extern MYSQL_PLUGIN_IMPORT char reg_ext[FN_EXTLEN]; extern MYSQL_PLUGIN_IMPORT uint reg_ext_length; extern MYSQL_PLUGIN_IMPORT uint lower_case_table_names; extern MYSQL_PLUGIN_IMPORT bool mysqld_embedded; extern ulong specialflag; extern uint mysql_data_home_len; extern uint mysql_real_data_home_len; extern const char *mysql_real_data_home_ptr; extern ulong thread_handling; extern "C" MYSQL_PLUGIN_IMPORT char server_version[SERVER_VERSION_LENGTH]; extern char *server_version_ptr; extern bool using_custom_server_version; extern MYSQL_PLUGIN_IMPORT char mysql_real_data_home[]; extern char mysql_unpacked_real_data_home[]; extern MYSQL_PLUGIN_IMPORT struct system_variables global_system_variables; extern char default_logfile_name[FN_REFLEN]; extern char *my_proxy_protocol_networks; #define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) extern MYSQL_PLUGIN_IMPORT const key_map key_map_empty; extern MYSQL_PLUGIN_IMPORT key_map key_map_full; /* Should be threaded as const */ /* Server mutex locks and condition variables. */ extern mysql_mutex_t LOCK_item_func_sleep, LOCK_status, LOCK_error_log, LOCK_delayed_insert, LOCK_short_uuid_generator, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_active_mi, LOCK_manager, LOCK_user_conn, LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_backup_log; extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_global_system_variables; extern mysql_rwlock_t LOCK_all_status_vars; extern mysql_mutex_t LOCK_start_thread; extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_server_started; extern MYSQL_PLUGIN_IMPORT mysql_cond_t COND_server_started; extern mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern mysql_rwlock_t LOCK_ssl_refresh; extern mysql_prlock_t LOCK_system_variables_hash; extern mysql_cond_t COND_start_thread; extern mysql_cond_t COND_manager; extern my_bool opt_use_ssl; extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher, *opt_ssl_key, *opt_ssl_crl, *opt_ssl_crlpath; extern ulonglong tls_version; #ifdef MYSQL_SERVER /** only options that need special treatment in get_one_option() deserve to be listed below */ enum options_mysqld { OPT_to_set_the_start_number=256, OPT_BINLOG_DO_DB, OPT_BINLOG_FORMAT, OPT_BINLOG_IGNORE_DB, OPT_BIN_LOG, OPT_BOOTSTRAP, OPT_EXPIRE_LOGS_DAYS, OPT_BINLOG_EXPIRE_LOGS_SECONDS, OPT_CONSOLE, OPT_DEBUG_SYNC_TIMEOUT, OPT_REMOVED_OPTION, OPT_IGNORE_DB_DIRECTORY, OPT_ISAM_LOG, OPT_KEY_BUFFER_SIZE, OPT_KEY_CACHE_AGE_THRESHOLD, OPT_KEY_CACHE_BLOCK_SIZE, OPT_KEY_CACHE_DIVISION_LIMIT, OPT_KEY_CACHE_PARTITIONS, OPT_KEY_CACHE_CHANGED_BLOCKS_HASH_SIZE, OPT_LOG_BASENAME, OPT_LOG_ERROR, OPT_LOG_SLOW_FILTER, OPT_LOWER_CASE_TABLE_NAMES, OPT_PLUGIN_LOAD, OPT_PLUGIN_LOAD_ADD, OPT_PFS_INSTRUMENT, OPT_REPLICATE_DO_DB, OPT_REPLICATE_DO_TABLE, OPT_REPLICATE_IGNORE_DB, OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_REWRITE_DB, OPT_REPLICATE_WILD_DO_TABLE, OPT_REPLICATE_WILD_IGNORE_TABLE, OPT_SAFE, OPT_SERVER_ID, OPT_SILENT, OPT_SKIP_HOST_CACHE, OPT_SLAVE_PARALLEL_MODE, OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CERT, OPT_SSL_CIPHER, OPT_SSL_CRL, OPT_SSL_CRLPATH, OPT_SSL_KEY, OPT_THREAD_CONCURRENCY, OPT_WANT_CORE, #ifdef WITH_WSREP OPT_WSREP_CAUSAL_READS, OPT_WSREP_SYNC_WAIT, #endif /* WITH_WSREP */ OPT_MYSQL_COMPATIBILITY, OPT_TLS_VERSION, OPT_SECURE_AUTH, OPT_MYSQL_TO_BE_IMPLEMENTED, OPT_which_is_always_the_last }; #endif /** Query type constants (usable as bitmap flags). */ enum enum_query_type { /// Nothing specific, ordinary SQL query. QT_ORDINARY= 0, /// In utf8. QT_TO_SYSTEM_CHARSET= (1 << 0), /// Without character set introducers. QT_WITHOUT_INTRODUCERS= (1 << 1), /// view internal representation (like QT_ORDINARY except ORDER BY clause) QT_VIEW_INTERNAL= (1 << 2), /// If identifiers should not include database names, where unambiguous QT_ITEM_IDENT_SKIP_DB_NAMES= (1 << 3), /// If identifiers should not include table names, where unambiguous QT_ITEM_IDENT_SKIP_TABLE_NAMES= (1 << 4), /// If Item_cache_wrapper should not print QT_ITEM_CACHE_WRAPPER_SKIP_DETAILS= (1 << 5), /// If Item_subselect should print as just "(subquery#1)" /// rather than display the subquery body QT_ITEM_SUBSELECT_ID_ONLY= (1 << 6), /// If NULLIF(a,b) should print itself as /// CASE WHEN a_for_comparison=b THEN NULL ELSE a_for_return_value END /// when "a" was replaced to two different items /// (e.g. by equal fields propagation in optimize_cond()) /// or always as NULLIF(a, b). /// The default behaviour is to use CASE syntax when /// a_for_return_value is not the same as a_for_comparison. /// SHOW CREATE {VIEW|PROCEDURE|FUNCTION} and other cases where the /// original representation is required, should set this flag. QT_ITEM_ORIGINAL_FUNC_NULLIF= (1 << 7), /// good for parsing QT_PARSABLE= (1 << 8), // If an expression is constant, print the expression, not the value // it evaluates to. Should be used for error messages, so that they // don't reveal values. QT_NO_DATA_EXPANSION= (1 << 9), /// This value means focus on readability, not on ability to parse back, etc. QT_EXPLAIN= QT_TO_SYSTEM_CHARSET | QT_ITEM_IDENT_SKIP_DB_NAMES | QT_ITEM_CACHE_WRAPPER_SKIP_DETAILS | QT_ITEM_SUBSELECT_ID_ONLY, QT_SHOW_SELECT_NUMBER= (1<<10), /// Do not print database name or table name in the identifiers (even if /// this means the printout will be ambigous). It is assumed that the caller /// passing this flag knows what they are doing. QT_ITEM_IDENT_DISABLE_DB_TABLE_NAMES= (1 <<11), /// This is used for EXPLAIN EXTENDED extra warnings / Be more detailed /// Be more detailed than QT_EXPLAIN. /// Perhaps we should eventually include QT_ITEM_IDENT_SKIP_CURRENT_DATABASE /// here, as it would give better readable results QT_EXPLAIN_EXTENDED= QT_TO_SYSTEM_CHARSET| QT_SHOW_SELECT_NUMBER, // Remove wrappers added for TVC when creating or showing view QT_NO_WRAPPERS_FOR_TVC_IN_VIEW= (1 << 12), /// Print for FRM file. Focus on parse-back. /// e.g. VIEW expressions and virtual column expressions QT_FOR_FRM= (1 << 13) }; /* query_id */ extern Atomic_counter global_query_id; /* increment query_id and return it. */ inline __attribute__((warn_unused_result)) query_id_t next_query_id() { return global_query_id++; } inline query_id_t get_query_id() { return global_query_id; } /* increment global_thread_id and return it. */ extern __attribute__((warn_unused_result)) my_thread_id next_thread_id(void); /* TODO: Replace this with an inline function. */ #ifndef EMBEDDED_LIBRARY extern "C" void unireg_abort(int exit_code) __attribute__((noreturn)); #else extern "C" void unireg_clear(int exit_code); #define unireg_abort(exit_code) do { unireg_clear(exit_code); DBUG_RETURN(exit_code); } while(0) #endif inline void table_case_convert(char * name, uint length) { if (lower_case_table_names) files_charset_info->casedn(name, length, name, length); } extern char *set_server_version(char *buf, size_t size); #define current_thd _current_thd() void set_current_thd(THD *thd); /* @todo remove, make it static in ha_maria.cc currently it's needed for sql_select.cc */ extern handlerton *maria_hton; extern uint64 global_gtid_counter; extern my_bool opt_gtid_strict_mode; extern my_bool opt_userstat_running, debug_assert_if_crashed_table; extern uint mysqld_extra_port; extern ulong opt_progress_report_time; extern ulong extra_max_connections; extern ulonglong denied_connections; extern ulong thread_created; extern scheduler_functions *thread_scheduler, *extra_thread_scheduler; extern char *opt_log_basename; extern my_bool opt_master_verify_checksum; extern my_bool opt_stack_trace, disable_log_notes; extern my_bool opt_expect_abort; extern my_bool opt_slave_sql_verify_checksum; extern my_bool opt_mysql56_temporal_format, strict_password_validation; extern ulong binlog_checksum_options; extern bool max_user_connections_checking; extern ulong opt_binlog_dbug_fsync_sleep; static const int SERVER_UID_SIZE= 29; extern char server_uid[SERVER_UID_SIZE+1]; extern uint volatile global_disable_checkpoint; extern my_bool opt_help; extern int mysqld_main(int argc, char **argv); #ifdef _WIN32 extern HANDLE hEventShutdown; extern void mysqld_win_initiate_shutdown(); extern void mysqld_win_set_startup_complete(); extern void mysqld_win_extend_service_timeout(DWORD sec); extern void mysqld_set_service_status_callback(void (*)(DWORD, DWORD, DWORD)); extern void mysqld_win_set_service_name(const char *name); #endif #endif /* MYSQLD_INCLUDED */ server/private/log_slow.h000064400000004612151031265040011522 0ustar00/* Copyright (C) 2009, 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 or later of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Defining what to log to slow log */ #ifndef LOG_SLOW_INCLUDED #define LOG_SLOW_INCLUDED #define LOG_SLOW_VERBOSITY_INIT 0 #define LOG_SLOW_VERBOSITY_INNODB (1U << 0) /* Old option */ #define LOG_SLOW_VERBOSITY_QUERY_PLAN (1U << 1) #define LOG_SLOW_VERBOSITY_EXPLAIN (1U << 2) #define LOG_SLOW_VERBOSITY_STORAGE_ENGINE (1U << 3) /* Replaces InnoDB */ #define LOG_SLOW_VERBOSITY_WARNINGS (1U << 4) #define LOG_SLOW_VERBOSITY_FULL (1U << 5) #define LOG_SLOW_VERBOSITY_ENGINE (LOG_SLOW_VERBOSITY_FULL | \ LOG_SLOW_VERBOSITY_INNODB | \ LOG_SLOW_VERBOSITY_STORAGE_ENGINE) #define QPLAN_INIT QPLAN_QC_NO #define QPLAN_ADMIN (1U << 0) #define QPLAN_FILESORT (1U << 1) #define QPLAN_FILESORT_DISK (1U << 2) #define QPLAN_FILESORT_PRIORITY_QUEUE (1U << 3) #define QPLAN_FULL_JOIN (1U << 4) #define QPLAN_FULL_SCAN (1U << 5) #define QPLAN_NOT_USING_INDEX (1U << 6) #define QPLAN_QC (1U << 7) #define QPLAN_QC_NO (1U << 8) #define QPLAN_TMP_TABLE (1U << 9) #define QPLAN_TMP_DISK (1U << 10) /* ... */ #define QPLAN_STATUS (1UL << 31) /* not in the slow_log_filter */ #define QPLAN_MAX (1UL << 31) /* reserved as placeholder */ /* Bits for log_slow_disabled_statements */ #define LOG_SLOW_DISABLE_ADMIN (1 << 0) #define LOG_SLOW_DISABLE_CALL (1 << 1) #define LOG_SLOW_DISABLE_SLAVE (1 << 2) #define LOG_SLOW_DISABLE_SP (1 << 3) /* Bits for log_disabled_statements */ #define LOG_DISABLE_SLAVE (1 << 0) #define LOG_DISABLE_SP (1 << 1) #endif /* LOG_SLOW_INCLUDED */ server/private/keycaches.h000064400000003713151031265040011635 0ustar00#ifndef KEYCACHES_INCLUDED #define KEYCACHES_INCLUDED /* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "sql_list.h" #include #include extern "C" { typedef int (*process_key_cache_t) (const char *, KEY_CACHE *, void *); } class NAMED_ILINK; class NAMED_ILIST: public I_List { public: void delete_elements(void (*free_element)(const char*, void*)); bool delete_element(const char *name, size_t length, void (*free_element)(const char*, void*)); }; /* For key cache */ extern LEX_CSTRING default_key_cache_base; extern KEY_CACHE zero_key_cache; extern NAMED_ILIST key_caches; KEY_CACHE *create_key_cache(const char *name, size_t length); KEY_CACHE *get_key_cache(const LEX_CSTRING *cache_name); KEY_CACHE *get_or_create_key_cache(const char *name, size_t length); void free_key_cache(const char *name, void *key_cache); bool process_key_caches(process_key_cache_t func, void *param); /* For Rpl_filter */ extern LEX_CSTRING default_rpl_filter_base; extern NAMED_ILIST rpl_filters; Rpl_filter *create_rpl_filter(const char *name, size_t length); Rpl_filter *get_rpl_filter(LEX_CSTRING *filter_name); Rpl_filter *get_or_create_rpl_filter(const char *name, size_t length); void free_all_rpl_filters(void); #endif /* KEYCACHES_INCLUDED */ server/private/pfs_socket_provider.h000064400000004322151031265040013745 0ustar00/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef PFS_SOCKET_PROVIDER_H #define PFS_SOCKET_PROVIDER_H /** @file include/pfs_socket_provider.h Performance schema instrumentation (declarations). */ #ifdef HAVE_PSI_SOCKET_INTERFACE #ifdef MYSQL_SERVER #ifndef EMBEDDED_LIBRARY #ifndef MYSQL_DYNAMIC_PLUGIN #include "mysql/psi/psi.h" #define PSI_SOCKET_CALL(M) pfs_ ## M ## _v1 C_MODE_START void pfs_register_socket_v1(const char *category, PSI_socket_info_v1 *info, int count); PSI_socket* pfs_init_socket_v1(PSI_socket_key key, const my_socket *fd, const struct sockaddr *addr, socklen_t addr_len); void pfs_destroy_socket_v1(PSI_socket *socket); PSI_socket_locker* pfs_start_socket_wait_v1(PSI_socket_locker_state *state, PSI_socket *socket, PSI_socket_operation op, size_t count, const char *src_file, uint src_line); void pfs_end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count); void pfs_set_socket_state_v1(PSI_socket *socket, PSI_socket_state state); void pfs_set_socket_info_v1(PSI_socket *socket, const my_socket *fd, const struct sockaddr *addr, socklen_t addr_len); void pfs_set_socket_thread_owner_v1(PSI_socket *socket); C_MODE_END #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* MYSQL_SERVER */ #endif /* HAVE_PSI_SOCKET_INTERFACE */ #endif server/private/sql_derived.h000064400000002411151031265040012171 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_DERIVED_INCLUDED #define SQL_DERIVED_INCLUDED struct TABLE_LIST; class THD; struct LEX; bool mysql_handle_derived(LEX *lex, uint phases); bool mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases); Item *transform_condition_or_part(THD *thd, Item *cond, Item_transformer transformer, uchar *arg); bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived); #endif /* SQL_DERIVED_INCLUDED */ server/private/replication.h000064400000037352151031265040012215 0ustar00/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef REPLICATION_H #define REPLICATION_H /*************************************************************************** NOTE: plugin locking. The plugin is locked on Binlog_transmit_observer::transmit_start and is unlocked after Binlog_transmit_observer::transmit_stop. All other master observable events happen between these two and don't lock the plugin at all. Also a plugin is locked on Binlog_relay_IO_observer::thread_start and unlocked after Binlog_relay_IO_observer::thread_stop. ***************************************************************************/ #include typedef struct st_mysql MYSQL; #ifdef __cplusplus extern "C" { #endif /** Transaction observer flags. */ enum Trans_flags { /** Transaction is a real transaction */ TRANS_IS_REAL_TRANS = 1 }; /** Transaction observer parameter */ typedef struct Trans_param { uint32 server_id; uint32 flags; /* The latest binary log file name and position written by current transaction, if binary log is disabled or no log event has been written into binary log file by current transaction (events written into transaction log cache are not counted), these two member will be zero. */ const char *log_file; my_off_t log_pos; } Trans_param; /** Observes and extends transaction execution */ typedef struct Trans_observer { uint32 len; /** This callback is called after transaction commit This callback is called right after commit to storage engines for transactional tables. For non-transactional tables, this is called at the end of the statement, before sending statement status, if the statement succeeded. @note The return value is currently ignored by the server. @note This hook is called wo/ any global mutex held @param param The parameter for transaction observers @retval 0 Sucess @retval 1 Failure */ int (*after_commit)(Trans_param *param); /** This callback is called after transaction rollback This callback is called right after rollback to storage engines for transactional tables. For non-transactional tables, this is called at the end of the statement, before sending statement status, if the statement failed. @note The return value is currently ignored by the server. @param param The parameter for transaction observers @note This hook is called wo/ any global mutex held @retval 0 Sucess @retval 1 Failure */ int (*after_rollback)(Trans_param *param); } Trans_observer; /** Binlog storage flags */ enum Binlog_storage_flags { /** Binary log was sync:ed */ BINLOG_STORAGE_IS_SYNCED = 1, /** First(or alone) in a group commit */ BINLOG_GROUP_COMMIT_LEADER = 2, /** Last(or alone) in a group commit */ BINLOG_GROUP_COMMIT_TRAILER = 4 }; /** Binlog storage observer parameters */ typedef struct Binlog_storage_param { uint32 server_id; } Binlog_storage_param; /** Observe binlog logging storage */ typedef struct Binlog_storage_observer { uint32 len; /** This callback is called after binlog has been flushed This callback is called after cached events have been flushed to binary log file. Whether the binary log file is synchronized to disk is indicated by the bit BINLOG_STORAGE_IS_SYNCED in @a flags. @note: this hook is called with LOCK_log mutex held @param param Observer common parameter @param log_file Binlog file name been updated @param log_pos Binlog position after update @param flags flags for binlog storage @retval 0 Sucess @retval 1 Failure */ int (*after_flush)(Binlog_storage_param *param, const char *log_file, my_off_t log_pos, uint32 flags); /** This callback is called after binlog has been synced This callback is called after events flushed to disk has been sync:ed ("group committed"). @note: this hook is called with LOCK_after_binlog_sync mutex held @param param Observer common parameter @param log_file Binlog file name been updated @param log_pos Binlog position after update @param flags flags for binlog storage @retval 0 Sucess @retval 1 Failure */ int (*after_sync)(Binlog_storage_param *param, const char *log_file, my_off_t log_pos, uint32 flags); } Binlog_storage_observer; /** Replication binlog transmitter (binlog dump) observer parameter. */ typedef struct Binlog_transmit_param { uint32 server_id; uint32 flags; } Binlog_transmit_param; /** Observe and extends the binlog dumping thread. */ typedef struct Binlog_transmit_observer { uint32 len; /** This callback is called when binlog dumping starts @param param Observer common parameter @param log_file Binlog file name to transmit from @param log_pos Binlog position to transmit from @retval 0 Sucess @retval 1 Failure */ int (*transmit_start)(Binlog_transmit_param *param, const char *log_file, my_off_t log_pos); /** This callback is called when binlog dumping stops @param param Observer common parameter @retval 0 Sucess @retval 1 Failure */ int (*transmit_stop)(Binlog_transmit_param *param); /** This callback is called to reserve bytes in packet header for event transmission This callback is called when resetting transmit packet header to reserve bytes for this observer in packet header. The @a header buffer is allocated by the server code, and @a size is the size of the header buffer. Each observer can only reserve a maximum size of @a size in the header. @param param Observer common parameter @param header Pointer of the header buffer @param size Size of the header buffer @param len Header length reserved by this observer @retval 0 Sucess @retval 1 Failure */ int (*reserve_header)(Binlog_transmit_param *param, unsigned char *header, unsigned long size, unsigned long *len); /** This callback is called before sending an event packet to slave @param param Observer common parameter @param packet Binlog event packet to send @param len Length of the event packet @param log_file Binlog file name of the event packet to send @param log_pos Binlog position of the event packet to send @retval 0 Sucess @retval 1 Failure */ int (*before_send_event)(Binlog_transmit_param *param, unsigned char *packet, unsigned long len, const char *log_file, my_off_t log_pos ); /** This callback is called after sending an event packet to slave @param param Observer common parameter @param event_buf Binlog event packet buffer sent @param len length of the event packet buffer @retval 0 Sucess @retval 1 Failure */ int (*after_send_event)(Binlog_transmit_param *param, const char *event_buf, unsigned long len); /** This callback is called after resetting master status This is called when executing the command RESET MASTER, and is used to reset status variables added by observers. @param param Observer common parameter @retval 0 Sucess @retval 1 Failure */ int (*after_reset_master)(Binlog_transmit_param *param); } Binlog_transmit_observer; /** Binlog relay IO flags */ enum Binlog_relay_IO_flags { /** Binary relay log was sync:ed */ BINLOG_RELAY_IS_SYNCED = 1 }; /** Replication binlog relay IO observer parameter */ typedef struct Binlog_relay_IO_param { uint32 server_id; /* Master host, user and port */ char *host; char *user; unsigned int port; char *master_log_name; my_off_t master_log_pos; MYSQL *mysql; /* the connection to master */ } Binlog_relay_IO_param; /** Observes and extends the service of slave IO thread. */ typedef struct Binlog_relay_IO_observer { uint32 len; /** This callback is called when slave IO thread starts @param param Observer common parameter @retval 0 Sucess @retval 1 Failure */ int (*thread_start)(Binlog_relay_IO_param *param); /** This callback is called when slave IO thread stops @param param Observer common parameter @retval 0 Sucess @retval 1 Failure */ int (*thread_stop)(Binlog_relay_IO_param *param); /** This callback is called before slave requesting binlog transmission from master This is called before slave issuing BINLOG_DUMP command to master to request binlog. @param param Observer common parameter @param flags binlog dump flags @retval 0 Sucess @retval 1 Failure */ int (*before_request_transmit)(Binlog_relay_IO_param *param, uint32 flags); /** This callback is called after read an event packet from master @param param Observer common parameter @param packet The event packet read from master @param len Length of the event packet read from master @param event_buf The event packet return after process @param event_len The length of event packet return after process @retval 0 Sucess @retval 1 Failure */ int (*after_read_event)(Binlog_relay_IO_param *param, const char *packet, unsigned long len, const char **event_buf, unsigned long *event_len); /** This callback is called after written an event packet to relay log @param param Observer common parameter @param event_buf Event packet written to relay log @param event_len Length of the event packet written to relay log @param flags flags for relay log @retval 0 Sucess @retval 1 Failure */ int (*after_queue_event)(Binlog_relay_IO_param *param, const char *event_buf, unsigned long event_len, uint32 flags); /** This callback is called after reset slave relay log IO status @param param Observer common parameter @retval 0 Sucess @retval 1 Failure */ int (*after_reset_slave)(Binlog_relay_IO_param *param); } Binlog_relay_IO_observer; /** Register a transaction observer @param observer The transaction observer to register @param p pointer to the internal plugin structure @retval 0 Sucess @retval 1 Observer already exists */ int register_trans_observer(Trans_observer *observer, void *p); /** Unregister a transaction observer @param observer The transaction observer to unregister @param p pointer to the internal plugin structure @retval 0 Sucess @retval 1 Observer not exists */ int unregister_trans_observer(Trans_observer *observer, void *p); /** Register a binlog storage observer @param observer The binlog storage observer to register @param p pointer to the internal plugin structure @retval 0 Sucess @retval 1 Observer already exists */ int register_binlog_storage_observer(Binlog_storage_observer *observer, void *p); /** Unregister a binlog storage observer @param observer The binlog storage observer to unregister @param p pointer to the internal plugin structure @retval 0 Sucess @retval 1 Observer not exists */ int unregister_binlog_storage_observer(Binlog_storage_observer *observer, void *p); /** Register a binlog transmit observer @param observer The binlog transmit observer to register @param p pointer to the internal plugin structure @retval 0 Sucess @retval 1 Observer already exists */ int register_binlog_transmit_observer(Binlog_transmit_observer *observer, void *p); /** Unregister a binlog transmit observer @param observer The binlog transmit observer to unregister @param p pointer to the internal plugin structure @retval 0 Sucess @retval 1 Observer not exists */ int unregister_binlog_transmit_observer(Binlog_transmit_observer *observer, void *p); /** Register a binlog relay IO (slave IO thread) observer @param observer The binlog relay IO observer to register @param p pointer to the internal plugin structure @retval 0 Sucess @retval 1 Observer already exists */ int register_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void *p); /** Unregister a binlog relay IO (slave IO thread) observer @param observer The binlog relay IO observer to unregister @param p pointer to the internal plugin structure @retval 0 Sucess @retval 1 Observer not exists */ int unregister_binlog_relay_io_observer(Binlog_relay_IO_observer *observer, void *p); /** Connect to master This function can only used in the slave I/O thread context, and will use the same master information to do the connection. @code MYSQL *mysql = mysql_init(NULL); if (rpl_connect_master(mysql)) { // do stuff with the connection } mysql_close(mysql); // close the connection @endcode @param mysql address of MYSQL structure to use, pass NULL will create a new one @return address of MYSQL structure on success, NULL on failure */ MYSQL *rpl_connect_master(MYSQL *mysql); /** Get the value of user variable as an integer. This function will return the value of variable @a name as an integer. If the original value of the variable is not an integer, the value will be converted into an integer. @param name user variable name @param value pointer to return the value @param null_value if not NULL, the function will set it to true if the value of variable is null, set to false if not @retval 0 Success @retval 1 Variable not found */ int get_user_var_int(const char *name, long long int *value, int *null_value); /** Get the value of user variable as a double precision float number. This function will return the value of variable @a name as real number. If the original value of the variable is not a real number, the value will be converted into a real number. @param name user variable name @param value pointer to return the value @param null_value if not NULL, the function will set it to true if the value of variable is null, set to false if not @retval 0 Success @retval 1 Variable not found */ int get_user_var_real(const char *name, double *value, int *null_value); /** Get the value of user variable as a string. This function will return the value of variable @a name as string. If the original value of the variable is not a string, the value will be converted into a string. @param name user variable name @param value pointer to the value buffer @param len length of the value buffer @param precision precision of the value if it is a float number @param null_value if not NULL, the function will set it to true if the value of variable is null, set to false if not @retval 0 Success @retval 1 Variable not found */ int get_user_var_str(const char *name, char *value, unsigned long len, unsigned int precision, int *null_value); #ifdef __cplusplus } #endif #endif /* REPLICATION_H */ server/private/my_json_writer.h000064400000043716151031265040012757 0ustar00/* Copyright (C) 2014 SkySQL Ab, MariaDB Corporation Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef JSON_WRITER_INCLUDED #define JSON_WRITER_INCLUDED #include "my_base.h" #if !defined(NDEBUG) || defined(JSON_WRITER_UNIT_TEST) || defined ENABLED_JSON_WRITER_CONSISTENCY_CHECKS #include #include #include #include #endif #ifdef JSON_WRITER_UNIT_TEST #include "sql_string.h" constexpr uint FAKE_SELECT_LEX_ID= UINT_MAX; // Also, mock objects are defined in my_json_writer-t.cc #define VALIDITY_ASSERT(x) if (!(x)) this->invalid_json= true; #else #include "sql_select.h" #define VALIDITY_ASSERT(x) DBUG_ASSERT(x) #endif #include class Opt_trace_stmt; class Opt_trace_context; class Json_writer; struct TABLE_LIST; /* Single_line_formatting_helper is used by Json_writer to do better formatting of JSON documents. The idea is to catch arrays that can be printed on one line: arrayName : [ "boo", 123, 456 ] and actually print them on one line. Arrrays that occupy too much space on the line, or have nested members cannot be printed on one line. We hook into JSON printing functions and try to detect the pattern. While detecting the pattern, we will accumulate "boo", 123, 456 as strings. Then, - either the pattern is broken, and we print the elements out, - or the pattern lasts till the end of the array, and we print the array on one line. */ class Single_line_formatting_helper { enum enum_state { INACTIVE, ADD_MEMBER, IN_ARRAY, DISABLED }; /* This works like a finite automaton. state=DISABLED means the helper is disabled - all on_XXX functions will return false (which means "not handled") and do nothing. +->-+ | v INACTIVE ---> ADD_MEMBER ---> IN_ARRAY--->-+ ^ | +------------------<--------------------+ For other states: INACTIVE - initial state, we have nothing. ADD_MEMBER - add_member() was called, the buffer has "member_name\0". IN_ARRAY - start_array() was called. */ enum enum_state state; enum { MAX_LINE_LEN= 80 }; char buffer[80]; /* The data in the buffer is located between buffer[0] and buf_ptr */ char *buf_ptr; uint line_len; Json_writer *owner; public: Single_line_formatting_helper() : state(INACTIVE), buf_ptr(buffer) {} void init(Json_writer *owner_arg) { owner= owner_arg; } bool on_add_member(const char *name, size_t len); bool on_start_array(); bool on_end_array(); void on_start_object(); // on_end_object() is not needed. bool on_add_str(const char *str, size_t num_bytes); /* Returns true if the helper is flushing its buffer and is probably making calls back to its Json_writer. (The Json_writer uses this function to avoid re-doing the processing that it has already done before making a call to fmt_helper) */ bool is_making_writer_calls() const { return state == DISABLED; } private: void flush_on_one_line(); void disable_and_flush(); }; /* Something that looks like class String, but has an internal limit of how many bytes one can append to it. Bytes that were truncated due to the size limitation are counted. */ class String_with_limit { public: String_with_limit() : size_limit(SIZE_T_MAX), truncated_len(0) { str.length(0); } size_t get_truncated_bytes() const { return truncated_len; } size_t get_size_limit() { return size_limit; } void set_size_limit(size_t limit_arg) { // Setting size limit to be shorter than length will not have the desired // effect DBUG_ASSERT(str.length() < size_limit); size_limit= limit_arg; } void append(const char *s, size_t size) { if (str.length() + size <= size_limit) { // Whole string can be added, just do it str.append(s, size); } else { // We cannot add the whole string if (str.length() < size_limit) { // But we can still add something size_t bytes_to_add = size_limit - str.length(); str.append(s, bytes_to_add); truncated_len += size - bytes_to_add; } else truncated_len += size; } } void append(const char *s) { append(s, strlen(s)); } void append(char c) { if (str.length() + 1 > size_limit) truncated_len++; else str.append(c); } const String *get_string() { return &str; } size_t length() { return str.length(); } private: String str; // str must not get longer than this many bytes. size_t size_limit; // How many bytes were truncated from the string size_t truncated_len; }; /* A class to write well-formed JSON documents. The documents are also formatted for human readability. */ class Json_writer { #if !defined(NDEBUG) || defined(JSON_WRITER_UNIT_TEST) /* In debug mode, Json_writer will fail and assertion if one attempts to produce an invalid JSON document (e.g. JSON array having named elements). */ std::vector named_items_expectation; bool named_item_expected() const; bool got_name; #ifdef JSON_WRITER_UNIT_TEST public: // When compiled for unit test, creating invalid JSON will set this to true // instead of an assertion. bool invalid_json= false; #endif #endif public: /* Add a member. We must be in an object. */ Json_writer& add_member(const char *name); Json_writer& add_member(const char *name, size_t len); /* Add atomic values */ void add_str(const char* val); void add_str(const char* val, size_t num_bytes); void add_str(const String &str); void add_str(Item *item); void add_table_name(const JOIN_TAB *tab); void add_table_name(const TABLE* table); void add_ll(longlong val); void add_ull(ulonglong val); void add_size(longlong val); void add_double(double val); void add_bool(bool val); void add_null(); private: void add_unquoted_str(const char* val); void add_unquoted_str(const char* val, size_t len); bool on_add_str(const char *str, size_t num_bytes); void on_start_object(); public: /* Start a child object */ void start_object(); void start_array(); void end_object(); void end_array(); /* One can set a limit of how large a JSON document should be. Writes beyond that size will be counted, but will not be collected. */ void set_size_limit(size_t mem_size) { output.set_size_limit(mem_size); } size_t get_truncated_bytes() { return output.get_truncated_bytes(); } Json_writer() : #if !defined(NDEBUG) || defined(JSON_WRITER_UNIT_TEST) got_name(false), #endif indent_level(0), document_start(true), element_started(false), first_child(true) { fmt_helper.init(this); } private: // TODO: a stack of (name, bool is_object_or_array) elements. int indent_level; enum { INDENT_SIZE = 2 }; friend class Single_line_formatting_helper; friend class Json_writer_nesting_guard; bool document_start; bool element_started; bool first_child; Single_line_formatting_helper fmt_helper; void append_indent(); void start_element(); void start_sub_element(); public: String_with_limit output; }; /* A class to add values to Json_writer_object and Json_writer_array */ class Json_value_helper { Json_writer* writer; public: void init(Json_writer *my_writer) { writer= my_writer; } void add_str(const char* val) { writer->add_str(val); } void add_str(const char* val, size_t length) { writer->add_str(val, length); } void add_str(const String &str) { writer->add_str(str.ptr(), str.length()); } void add_str(const LEX_CSTRING &str) { writer->add_str(str.str, str.length); } void add_str(Item *item) { writer->add_str(item); } void add_ll(longlong val) { writer->add_ll(val); } void add_size(longlong val) { writer->add_size(val); } void add_double(double val) { writer->add_double(val); } void add_bool(bool val) { writer->add_bool(val); } void add_null() { writer->add_null(); } void add_table_name(const JOIN_TAB *tab) { writer->add_table_name(tab); } void add_table_name(const TABLE* table) { writer->add_table_name(table); } }; /* A common base for Json_writer_object and Json_writer_array */ class Json_writer_struct { Json_writer_struct(const Json_writer_struct&)= delete; Json_writer_struct& operator=(const Json_writer_struct&)= delete; #ifdef ENABLED_JSON_WRITER_CONSISTENCY_CHECKS static thread_local std::vector named_items_expectation; #endif protected: Json_writer* my_writer; Json_value_helper context; /* Tells when a json_writer_struct has been closed or not */ bool closed; explicit Json_writer_struct(Json_writer *writer) : my_writer(writer) { context.init(my_writer); closed= false; #ifdef ENABLED_JSON_WRITER_CONSISTENCY_CHECKS named_items_expectation.push_back(expect_named_children); #endif } explicit Json_writer_struct(THD *thd) : Json_writer_struct(thd->opt_trace.get_current_json()) { } public: #ifdef ENABLED_JSON_WRITER_CONSISTENCY_CHECKS virtual ~Json_writer_struct() { named_items_expectation.pop_back(); } #else virtual ~Json_writer_struct() = default; #endif bool trace_started() const { return my_writer != 0; } #ifdef ENABLED_JSON_WRITER_CONSISTENCY_CHECKS bool named_item_expected() const { return named_items_expectation.size() > 1 && *(named_items_expectation.rbegin() + 1); } #endif }; /* RAII-based class to start/end writing a JSON object into the JSON document There is "ignore mode": one can initialize Json_writer_object with a NULL Json_writer argument, and then all its calls will do nothing. This is used by optimizer trace which can be enabled or disabled. */ class Json_writer_object : public Json_writer_struct { private: void add_member(const char *name) { my_writer->add_member(name); } public: explicit Json_writer_object(Json_writer* writer, const char *str= nullptr) : Json_writer_struct(writer) { #ifdef ENABLED_JSON_WRITER_CONSISTENCY_CHECKS DBUG_ASSERT(named_item_expected()); #endif if (unlikely(my_writer)) { if (str) my_writer->add_member(str); my_writer->start_object(); } } explicit Json_writer_object(THD* thd, const char *str= nullptr) : Json_writer_object(thd->opt_trace.get_current_json(), str) { } ~Json_writer_object() { if (my_writer && !closed) my_writer->end_object(); closed= TRUE; } Json_writer_object& add(const char *name, bool value) { DBUG_ASSERT(!closed); if (my_writer) { add_member(name); context.add_bool(value); } return *this; } Json_writer_object& add(const char *name, ulonglong value) { DBUG_ASSERT(!closed); if (my_writer) { add_member(name); my_writer->add_ull(value); } return *this; } template::value>::type > Json_writer_object& add(const char *name, IntT value) { DBUG_ASSERT(!closed); if (my_writer) { add_member(name); context.add_ll(value); } return *this; } Json_writer_object& add(const char *name, double value) { DBUG_ASSERT(!closed); if (my_writer) { add_member(name); context.add_double(value); } return *this; } Json_writer_object& add(const char *name, const char *value) { DBUG_ASSERT(!closed); if (my_writer) { add_member(name); context.add_str(value); } return *this; } Json_writer_object& add(const char *name, const char *value, size_t num_bytes) { add_member(name); context.add_str(value, num_bytes); return *this; } Json_writer_object& add(const char *name, const LEX_CSTRING &value) { DBUG_ASSERT(!closed); if (my_writer) { add_member(name); context.add_str(value.str, value.length); } return *this; } Json_writer_object& add(const char *name, Item *value) { DBUG_ASSERT(!closed); if (my_writer) { add_member(name); context.add_str(value); } return *this; } Json_writer_object& add_null(const char*name) { DBUG_ASSERT(!closed); if (my_writer) { add_member(name); context.add_null(); } return *this; } Json_writer_object& add_table_name(const JOIN_TAB *tab) { DBUG_ASSERT(!closed); if (my_writer) { add_member("table"); context.add_table_name(tab); } return *this; } Json_writer_object& add_table_name(const TABLE *table) { DBUG_ASSERT(!closed); if (my_writer) { add_member("table"); context.add_table_name(table); } return *this; } Json_writer_object& add_select_number(uint select_number) { DBUG_ASSERT(!closed); if (my_writer) { add_member("select_id"); if (unlikely(select_number == FAKE_SELECT_LEX_ID)) context.add_str("fake"); else context.add_ll(static_cast(select_number)); } return *this; } void end() { DBUG_ASSERT(!closed); if (unlikely(my_writer)) my_writer->end_object(); closed= TRUE; } }; /* RAII-based class to start/end writing a JSON array into the JSON document There is "ignore mode": one can initialize Json_writer_array with a NULL Json_writer argument, and then all its calls will do nothing. This is used by optimizer trace which can be enabled or disabled. */ class Json_writer_array : public Json_writer_struct { public: explicit Json_writer_array(Json_writer *writer, const char *str= nullptr) : Json_writer_struct(writer) { #ifdef ENABLED_JSON_WRITER_CONSISTENCY_CHECKS DBUG_ASSERT(!named_item_expected()); #endif if (unlikely(my_writer)) { if (str) my_writer->add_member(str); my_writer->start_array(); } } explicit Json_writer_array(THD *thd, const char *str= nullptr) : Json_writer_array(thd->opt_trace.get_current_json(), str) { } ~Json_writer_array() { if (unlikely(my_writer && !closed)) { my_writer->end_array(); closed= TRUE; } } void end() { DBUG_ASSERT(!closed); if (unlikely(my_writer)) my_writer->end_array(); closed= TRUE; } Json_writer_array& add(bool value) { DBUG_ASSERT(!closed); if (my_writer) context.add_bool(value); return *this; } Json_writer_array& add(ulonglong value) { DBUG_ASSERT(!closed); if (my_writer) context.add_ll(static_cast(value)); return *this; } Json_writer_array& add(longlong value) { DBUG_ASSERT(!closed); if (my_writer) context.add_ll(value); return *this; } Json_writer_array& add(double value) { DBUG_ASSERT(!closed); if (my_writer) context.add_double(value); return *this; } #ifndef _WIN64 Json_writer_array& add(size_t value) { DBUG_ASSERT(!closed); if (my_writer) context.add_ll(static_cast(value)); return *this; } #endif Json_writer_array& add(const char *value) { DBUG_ASSERT(!closed); if (my_writer) context.add_str(value); return *this; } Json_writer_array& add(const char *value, size_t num_bytes) { DBUG_ASSERT(!closed); if (my_writer) context.add_str(value, num_bytes); return *this; } Json_writer_array& add(const LEX_CSTRING &value) { DBUG_ASSERT(!closed); if (my_writer) context.add_str(value.str, value.length); return *this; } Json_writer_array& add(Item *value) { DBUG_ASSERT(!closed); if (my_writer) context.add_str(value); return *this; } Json_writer_array& add_null() { DBUG_ASSERT(!closed); if (my_writer) context.add_null(); return *this; } Json_writer_array& add_table_name(const JOIN_TAB *tab) { DBUG_ASSERT(!closed); if (my_writer) context.add_table_name(tab); return *this; } Json_writer_array& add_table_name(const TABLE *table) { DBUG_ASSERT(!closed); if (my_writer) context.add_table_name(table); return *this; } }; /* RAII-based class to disable writing into the JSON document The tracing is disabled as soon as the object is created. The destuctor is called as soon as we exit the scope of the object and the tracing is enabled back. */ class Json_writer_temp_disable { public: Json_writer_temp_disable(THD *thd_arg); ~Json_writer_temp_disable(); THD *thd; }; /* RAII-based helper class to detect incorrect use of Json_writer. The idea is that a function typically must leave Json_writer at the same identation level as it was when it was invoked. Leaving it at a different level typically means we forgot to close an object or an array So, here is a way to guard void foo(Json_writer *writer) { Json_writer_nesting_guard(writer); .. do something with writer // at the end of the function, ~Json_writer_nesting_guard() is called // and it makes sure that the nesting is the same as when the function was // entered. } */ class Json_writer_nesting_guard { #ifdef DBUG_OFF public: Json_writer_nesting_guard(Json_writer *) {} #else Json_writer* writer; int indent_level; public: Json_writer_nesting_guard(Json_writer *writer_arg) : writer(writer_arg), indent_level(writer->indent_level) {} ~Json_writer_nesting_guard() { DBUG_ASSERT(indent_level == writer->indent_level); } #endif }; #endif server/private/structs.h000064400000063413151031265040011410 0ustar00#ifndef STRUCTS_INCLUDED #define STRUCTS_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. Copyright (c) 2009, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* The old structures from unireg */ #include "sql_plugin.h" /* plugin_ref */ #include "sql_const.h" /* MAX_REFLENGTH */ #include "my_time.h" /* enum_mysql_timestamp_type */ #include "thr_lock.h" /* thr_lock_type */ #include "my_base.h" /* ha_rows, ha_key_alg */ #include /* USERNAME_LENGTH */ #include "sql_bitmap.h" struct TABLE; class Type_handler; class Field; class Index_statistics; struct Lex_ident_cli_st; class THD; /* Array index type for table.field[] */ typedef uint16 field_index_t; typedef struct st_date_time_format { uchar positions[8]; char time_separator; /* Separator between hour and minute */ uint flag; /* For future */ LEX_CSTRING format; } DATE_TIME_FORMAT; typedef struct st_keyfile_info { /* used with ha_info() */ uchar ref[MAX_REFLENGTH]; /* Pointer to current row */ uchar dupp_ref[MAX_REFLENGTH]; /* Pointer to dupp row */ uint ref_length; /* Length of ref (1-8) */ uint block_size; /* index block size */ File filenr; /* (uniq) filenr for table */ ha_rows records; /* Records i datafilen */ ha_rows deleted; /* Deleted records */ ulonglong data_file_length; /* Length off data file */ ulonglong max_data_file_length; /* Length off data file */ ulonglong index_file_length; ulonglong max_index_file_length; ulonglong delete_length; /* Free bytes */ ulonglong auto_increment_value; int errkey,sortkey; /* Last errorkey and sorted by */ time_t create_time; /* When table was created */ time_t check_time; time_t update_time; ulong mean_rec_length; /* physical reclength */ } KEYFILE_INFO; typedef struct st_key_part_info { /* Info about a key part */ Field *field; /* the Field object for the indexed prefix of the original table Field. NOT necessarily the original Field */ uint offset; /* Offset in record (from 0) */ uint null_offset; /* Offset to null_bit in record */ /* Length of key part in bytes, excluding NULL flag and length bytes */ uint length; /* Number of bytes required to store the keypart value. This may be different from the "length" field as it also counts - possible NULL-flag byte (see HA_KEY_NULL_LENGTH) - possible HA_KEY_BLOB_LENGTH bytes needed to store actual value length. */ uint store_length; uint16 key_type; field_index_t fieldnr; /* Fieldnr begins counting from 1 */ uint16 key_part_flag; /* 0 or HA_REVERSE_SORT */ uint8 type; uint8 null_bit; /* Position to null_bit */ } KEY_PART_INFO ; class engine_option_value; struct ha_index_option_struct; typedef struct st_key { uint key_length; /* total length of user defined key parts */ ulong flags; /* dupp key and pack flags */ uint user_defined_key_parts; /* How many key_parts */ uint usable_key_parts; /* Should normally be = user_defined_key_parts */ uint ext_key_parts; /* Number of key parts in extended key */ ulong ext_key_flags; /* Flags for extended key */ /* Parts of primary key that are in the extension of this index. Example: if this structure describes idx1, which is defined as INDEX idx1 (pk2, col2) and pk is defined as: PRIMARY KEY (pk1, pk2) then pk1 is in the extension idx1, ext_key_part_map.is_set(0) == true pk2 is explicitly present in idx1, it is not in the extension, so ext_key_part_map.is_set(1) == false */ key_part_map ext_key_part_map; /* Bitmap of indexes having common parts with this index (only key parts from key definitions are taken into account) */ key_map overlapped; /* Set of keys constraint correlated with this key */ key_map constraint_correlated; LEX_CSTRING name; uint block_size; enum ha_key_alg algorithm; /* The flag is on if statistical data for the index prefixes has to be taken from the system statistical tables. */ bool is_statistics_from_stat_tables; /* Note that parser is used when the table is opened for use, and parser_name is used when the table is being created. */ union { plugin_ref parser; /* Fulltext [pre]parser */ LEX_CSTRING *parser_name; /* Fulltext [pre]parser name */ }; KEY_PART_INFO *key_part; /* Unique name for cache; db + \0 + table_name + \0 + key_name + \0 */ uchar *cache_name; /* Array of AVG(#records with the same field value) for 1st ... Nth key part. 0 means 'not known'. For temporary heap tables this member is NULL. */ ulong *rec_per_key; /* This structure is used for statistical data on the index that has been read from the statistical table index_stat */ Index_statistics *read_stats; /* This structure is used for statistical data on the index that is collected by the function collect_statistics_for_table */ Index_statistics *collected_stats; TABLE *table; LEX_CSTRING comment; /** reference to the list of options or NULL */ engine_option_value *option_list; ha_index_option_struct *option_struct; /* structure with parsed options */ double actual_rec_per_key(uint i) const; bool without_overlaps; /* TRUE if index needs to be ignored */ bool is_ignored; } KEY; struct st_join_table; typedef struct st_reginfo { /* Extra info about reg */ struct st_join_table *join_tab; /* Used by SELECT() */ enum thr_lock_type lock_type; /* How database is used */ bool skip_locked; bool not_exists_optimize; /* TRUE <=> range optimizer found that there is no rows satisfying table conditions. */ bool impossible_range; } REGINFO; /* Originally MySQL used MYSQL_TIME structure inside server only, but since 4.1 it's exported to user in the new client API. Define aliases for new names to keep existing code simple. */ typedef enum enum_mysql_timestamp_type timestamp_type; typedef struct { ulong year,month,day,hour; ulonglong minute,second,second_part; bool neg; } INTERVAL; typedef struct st_known_date_time_format { const char *format_name; const char *date_format; const char *datetime_format; const char *time_format; } KNOWN_DATE_TIME_FORMAT; extern const char *show_comp_option_name[]; typedef int *(*update_var)(THD *, struct st_mysql_show_var *); struct USER_AUTH : public Sql_alloc { LEX_CSTRING plugin, auth_str, pwtext; USER_AUTH *next; USER_AUTH() : next(NULL) { plugin.str= auth_str.str= ""; pwtext.str= NULL; plugin.length= auth_str.length= pwtext.length= 0; } }; struct AUTHID { LEX_CSTRING user, host; void init() { memset(this, 0, sizeof(*this)); } void copy(MEM_ROOT *root, const LEX_CSTRING *usr, const LEX_CSTRING *host); bool is_role() const { return user.str[0] && (!host.str || !host.str[0]); } void set_lex_string(LEX_CSTRING *l, char *buf) { if (is_role()) *l= user; else { l->str= buf; l->length= strxmov(buf, user.str, "@", host.str, NullS) - buf; } } void parse(const char *str, size_t length); bool read_from_mysql_proc_row(THD *thd, TABLE *table); }; struct LEX_USER: public AUTHID { USER_AUTH *auth; bool has_auth() { return auth && (auth->plugin.length || auth->auth_str.length || auth->pwtext.length); } }; /* This structure specifies the maximum amount of resources which can be consumed by each account. Zero value of a member means there is no limit. */ typedef struct user_resources { /* Maximum number of queries/statements per hour. */ uint questions; /* Maximum number of updating statements per hour (which statements are updating is defined by sql_command_flags array). */ uint updates; /* Maximum number of connections established per hour. */ uint conn_per_hour; /* Maximum number of concurrent connections. If -1 then no new connections allowed */ int user_conn; /* Max query timeout */ double max_statement_time; /* Values of this enum and specified_limits member are used by the parser to store which user limits were specified in GRANT statement. */ enum {QUERIES_PER_HOUR= 1, UPDATES_PER_HOUR= 2, CONNECTIONS_PER_HOUR= 4, USER_CONNECTIONS= 8, MAX_STATEMENT_TIME= 16}; uint specified_limits; } USER_RESOURCES; /* This structure is used for counting resources consumed and for checking them against specified user limits. */ typedef struct user_conn { /* Pointer to user+host key (pair separated by '\0') defining the entity for which resources are counted (By default it is user account thus priv_user/priv_host pair is used. If --old-style-user-limits option is enabled, resources are counted for each user+host separately). */ char *user; /* Pointer to host part of the key. */ char *host; /** The moment of time when per hour counters were reset last time (i.e. start of "hour" for conn_per_hour, updates, questions counters). */ ulonglong reset_utime; /* Total length of the key. */ uint len; /* Current amount of concurrent connections for this account. */ int connections; /* Current number of connections per hour, number of updating statements per hour and total number of statements per hour for this account. */ uint conn_per_hour, updates, questions; /* Maximum amount of resources which account is allowed to consume. */ USER_RESOURCES user_resources; } USER_CONN; typedef struct st_user_stats { char user[MY_MAX(USERNAME_LENGTH, LIST_PROCESS_HOST_LEN) + 1]; // Account name the user is mapped to when this is a user from mapped_user. // Otherwise, the same value as user. char priv_user[MY_MAX(USERNAME_LENGTH, LIST_PROCESS_HOST_LEN) + 1]; uint user_name_length; uint total_connections; uint total_ssl_connections; uint concurrent_connections; time_t connected_time; // in seconds ha_rows rows_read, rows_sent; ha_rows rows_updated, rows_deleted, rows_inserted; ulonglong bytes_received; ulonglong bytes_sent; ulonglong binlog_bytes_written; ulonglong select_commands, update_commands, other_commands; ulonglong commit_trans, rollback_trans; ulonglong denied_connections, lost_connections, max_statement_time_exceeded; ulonglong access_denied_errors; ulonglong empty_queries; double busy_time; // in seconds double cpu_time; // in seconds } USER_STATS; typedef struct st_table_stats { char table[NAME_LEN * 2 + 2]; // [db] + '\0' + [table] + '\0' size_t table_name_length; ulonglong rows_read, rows_changed; ulonglong rows_changed_x_indexes; /* Stores enum db_type, but forward declarations cannot be done */ int engine_type; } TABLE_STATS; typedef struct st_index_stats { // [db] + '\0' + [table] + '\0' + [index] + '\0' char index[NAME_LEN * 3 + 3]; size_t index_name_length; /* Length of 'index' */ ulonglong rows_read; } INDEX_STATS; /* Bits in form->update */ #define REG_MAKE_DUPP 1U /* Make a copy of record when read */ #define REG_NEW_RECORD 2U /* Write a new record if not found */ #define REG_UPDATE 4U /* Uppdate record */ #define REG_DELETE 8U /* Delete found record */ #define REG_PROG 16U /* User is updating database */ #define REG_CLEAR_AFTER_WRITE 32U #define REG_MAY_BE_UPDATED 64U #define REG_AUTO_UPDATE 64U /* Used in D-forms for scroll-tables */ #define REG_OVERWRITE 128U #define REG_SKIP_DUP 256U /* Bits in form->status */ #define STATUS_NO_RECORD (1U+2U) /* Record isn't usable */ #define STATUS_GARBAGE 1U #define STATUS_NOT_FOUND 2U /* No record in database when needed */ #define STATUS_NO_PARENT 4U /* Parent record wasn't found */ #define STATUS_NOT_READ 8U /* Record isn't read */ #define STATUS_UPDATED 16U /* Record is updated by formula */ #define STATUS_NULL_ROW 32U /* table->null_row is set */ #define STATUS_DELETED 64U /* Such interval is "discrete": it is the set of { auto_inc_interval_min + k * increment, 0 <= k <= (auto_inc_interval_values-1) } Where "increment" is maintained separately by the user of this class (and is currently only thd->variables.auto_increment_increment). It mustn't derive from Sql_alloc, because SET INSERT_ID needs to allocate memory which must stay allocated for use by the next statement. */ class Discrete_interval { private: ulonglong interval_min; ulonglong interval_values; ulonglong interval_max; // excluded bound. Redundant. public: Discrete_interval *next; // used when linked into Discrete_intervals_list void replace(ulonglong start, ulonglong val, ulonglong incr) { interval_min= start; interval_values= val; interval_max= (val == ULONGLONG_MAX) ? val : start + val * incr; } Discrete_interval(ulonglong start, ulonglong val, ulonglong incr) : next(NULL) { replace(start, val, incr); }; Discrete_interval() : next(NULL) { replace(0, 0, 0); }; ulonglong minimum() const { return interval_min; }; ulonglong values() const { return interval_values; }; ulonglong maximum() const { return interval_max; }; /* If appending [3,5] to [1,2], we merge both in [1,5] (they should have the same increment for that, user of the class has to ensure that). That is just a space optimization. Returns 0 if merge succeeded. */ bool merge_if_contiguous(ulonglong start, ulonglong val, ulonglong incr) { if (interval_max == start) { if (val == ULONGLONG_MAX) { interval_values= interval_max= val; } else { interval_values+= val; interval_max= start + val * incr; } return 0; } return 1; }; }; /* List of Discrete_interval objects */ class Discrete_intervals_list { private: Discrete_interval *head; Discrete_interval *tail; /* When many intervals are provided at the beginning of the execution of a statement (in a replication slave or SET INSERT_ID), "current" points to the interval being consumed by the thread now (so "current" goes from "head" to "tail" then to NULL). */ Discrete_interval *current; uint elements; // number of elements void set_members(Discrete_interval *h, Discrete_interval *t, Discrete_interval *c, uint el) { head= h; tail= t; current= c; elements= el; } void operator=(Discrete_intervals_list &); /* prevent use of these */ Discrete_intervals_list(const Discrete_intervals_list &); public: Discrete_intervals_list() : head(NULL), current(NULL), elements(0) {}; void empty_no_free() { set_members(NULL, NULL, NULL, 0); } void empty() { for (Discrete_interval *i= head; i;) { Discrete_interval *next= i->next; delete i; i= next; } empty_no_free(); } void copy_shallow(const Discrete_intervals_list * dli) { head= dli->get_head(); tail= dli->get_tail(); current= dli->get_current(); elements= dli->nb_elements(); } void swap (Discrete_intervals_list * dli) { Discrete_interval *h, *t, *c; uint el; h= dli->get_head(); t= dli->get_tail(); c= dli->get_current(); el= dli->nb_elements(); dli->copy_shallow(this); set_members(h, t, c, el); } const Discrete_interval* get_next() { Discrete_interval *tmp= current; if (current != NULL) current= current->next; return tmp; } ~Discrete_intervals_list() { empty(); }; bool append(ulonglong start, ulonglong val, ulonglong incr); bool append(Discrete_interval *interval); ulonglong minimum() const { return (head ? head->minimum() : 0); }; ulonglong maximum() const { return (head ? tail->maximum() : 0); }; uint nb_elements() const { return elements; } Discrete_interval* get_head() const { return head; }; Discrete_interval* get_tail() const { return tail; }; Discrete_interval* get_current() const { return current; }; }; /* DDL options: - CREATE IF NOT EXISTS - DROP IF EXISTS - CREATE LIKE - REPLACE */ struct DDL_options_st { public: enum Options { OPT_NONE= 0, OPT_IF_NOT_EXISTS= 2, // CREATE TABLE IF NOT EXISTS OPT_LIKE= 4, // CREATE TABLE LIKE OPT_OR_REPLACE= 16, // CREATE OR REPLACE TABLE OPT_OR_REPLACE_SLAVE_GENERATED= 32,// REPLACE was added on slave, it was // not in the original query on master. OPT_IF_EXISTS= 64, OPT_CREATE_SELECT= 128 // CREATE ... SELECT }; private: Options m_options; public: Options create_like_options() const { return (DDL_options_st::Options) (((uint) m_options) & (OPT_IF_NOT_EXISTS | OPT_OR_REPLACE)); } void init() { m_options= OPT_NONE; } void init(Options options) { m_options= options; } void set(Options other) { m_options= other; } void set(const DDL_options_st other) { m_options= other.m_options; } bool if_not_exists() const { return m_options & OPT_IF_NOT_EXISTS; } bool or_replace() const { return m_options & OPT_OR_REPLACE; } bool or_replace_slave_generated() const { return m_options & OPT_OR_REPLACE_SLAVE_GENERATED; } bool like() const { return m_options & OPT_LIKE; } bool if_exists() const { return m_options & OPT_IF_EXISTS; } bool is_create_select() const { return m_options & OPT_CREATE_SELECT; } void add(const DDL_options_st::Options other) { m_options= (Options) ((uint) m_options | (uint) other); } void add(const DDL_options_st &other) { add(other.m_options); } DDL_options_st operator|(const DDL_options_st &other) { add(other.m_options); return *this; } DDL_options_st operator|=(DDL_options_st::Options other) { add(other); return *this; } }; class DDL_options: public DDL_options_st { public: DDL_options() { init(); } DDL_options(Options options) { init(options); } DDL_options(const DDL_options_st &options) { DDL_options_st::operator=(options); } }; struct Lex_length_and_dec_st { private: const char *m_length; const char *m_dec; public: void set(const char *length, const char *dec) { m_length= length; m_dec= dec; } const char *length() const { return m_length; } const char *dec() const { return m_dec; } }; struct Lex_field_type_st: public Lex_length_and_dec_st { private: const Type_handler *m_handler; void set(const Type_handler *handler, const char *length, const char *dec) { m_handler= handler; Lex_length_and_dec_st::set(length, dec); } public: void set(const Type_handler *handler, Lex_length_and_dec_st length_and_dec) { m_handler= handler; Lex_length_and_dec_st::operator=(length_and_dec); } void set_handler_length_flags(const Type_handler *handler, const char *length, uint32 flags); void set(const Type_handler *handler, const char *length) { set(handler, length, 0); } void set(const Type_handler *handler) { set(handler, 0, 0); } void set_handler(const Type_handler *handler) { m_handler= handler; } const Type_handler *type_handler() const { return m_handler; } }; struct Lex_dyncol_type_st: public Lex_length_and_dec_st { private: int m_type; // enum_dynamic_column_type is not visible here, so use int public: void set(int type, const char *length, const char *dec) { m_type= type; Lex_length_and_dec_st::set(length, dec); } void set(int type, Lex_length_and_dec_st length_and_dec) { m_type= type; Lex_length_and_dec_st::operator=(length_and_dec); } void set(int type, const char *length) { set(type, length, 0); } void set(int type) { set(type, 0, 0); } int dyncol_type() const { return m_type; } }; struct Lex_spblock_handlers_st { public: int hndlrs; void init(int count) { hndlrs= count; } }; struct Lex_spblock_st: public Lex_spblock_handlers_st { public: int vars; int conds; int curs; void init() { vars= conds= hndlrs= curs= 0; } void init_using_vars(uint nvars) { vars= nvars; conds= hndlrs= curs= 0; } void join(const Lex_spblock_st &b1, const Lex_spblock_st &b2) { vars= b1.vars + b2.vars; conds= b1.conds + b2.conds; hndlrs= b1.hndlrs + b2.hndlrs; curs= b1.curs + b2.curs; } }; class Lex_spblock: public Lex_spblock_st { public: Lex_spblock() { init(); } Lex_spblock(const Lex_spblock_handlers_st &other) { vars= conds= curs= 0; hndlrs= other.hndlrs; } }; struct Lex_for_loop_bounds_st { public: class sp_assignment_lex *m_index; // The first iteration value (or cursor) class sp_assignment_lex *m_target_bound; // The last iteration value int8 m_direction; bool m_implicit_cursor; bool is_for_loop_cursor() const { return m_target_bound == NULL; } }; class Lex_for_loop_bounds_intrange: public Lex_for_loop_bounds_st { public: Lex_for_loop_bounds_intrange(int8 direction, class sp_assignment_lex *left_expr, class sp_assignment_lex *right_expr) { m_direction= direction; m_index= direction > 0 ? left_expr : right_expr; m_target_bound= direction > 0 ? right_expr : left_expr; m_implicit_cursor= false; } }; struct Lex_for_loop_st { public: class sp_variable *m_index; // The first iteration value (or cursor) class sp_variable *m_target_bound; // The last iteration value int m_cursor_offset; int8 m_direction; bool m_implicit_cursor; void init() { m_index= 0; m_target_bound= 0; m_cursor_offset= 0; m_direction= 0; m_implicit_cursor= false; } bool is_for_loop_cursor() const { return m_target_bound == NULL; } bool is_for_loop_explicit_cursor() const { return is_for_loop_cursor() && !m_implicit_cursor; } }; enum trim_spec { TRIM_LEADING, TRIM_TRAILING, TRIM_BOTH }; struct Lex_trim_st { Item *m_remove; Item *m_source; trim_spec m_spec; public: void set(trim_spec spec, Item *remove, Item *source) { m_spec= spec; m_remove= remove; m_source= source; } void set(trim_spec spec, Item *source) { set(spec, NULL, source); } Item *make_item_func_trim_std(THD *thd) const; Item *make_item_func_trim_oracle(THD *thd) const; }; class Lex_trim: public Lex_trim_st { public: Lex_trim(trim_spec spec, Item *source) { set(spec, source); } }; class Lex_substring_spec_st { public: Item *m_subject; Item *m_from; Item *m_for; static Lex_substring_spec_st init(Item *subject, Item *from, Item *xfor= NULL) { Lex_substring_spec_st res; res.m_subject= subject; res.m_from= from; res.m_for= xfor; return res; } }; class st_select_lex; class Lex_select_lock { public: struct { uint defined_lock:1; uint update_lock:1; uint defined_timeout:1; uint skip_locked:1; }; ulong timeout; void empty() { defined_lock= update_lock= defined_timeout= skip_locked= FALSE; timeout= 0; } void set_to(st_select_lex *sel); }; class Lex_select_limit { public: /* explicit LIMIT clause was used */ bool explicit_limit; bool with_ties; Item *select_limit, *offset_limit; void clear() { explicit_limit= FALSE; // No explicit limit given by user with_ties= FALSE; // No use of WITH TIES operator select_limit= NULL; // denotes the default limit = HA_POS_ERROR offset_limit= NULL; // denotes the default offset = 0 } }; struct st_order; class Load_data_param { protected: CHARSET_INFO *m_charset; // Character set of the file ulonglong m_fixed_length; // Sum of target field lengths for fixed format bool m_is_fixed_length; bool m_use_blobs; public: Load_data_param(CHARSET_INFO *cs, bool is_fixed_length): m_charset(cs), m_fixed_length(0), m_is_fixed_length(is_fixed_length), m_use_blobs(false) { } bool add_outvar_field(THD *thd, const Field *field); bool add_outvar_user_var(THD *thd); CHARSET_INFO *charset() const { return m_charset; } bool is_fixed_length() const { return m_is_fixed_length; } bool use_blobs() const { return m_use_blobs; } }; class Load_data_outvar { public: virtual ~Load_data_outvar() = default; virtual bool load_data_set_null(THD *thd, const Load_data_param *param)= 0; virtual bool load_data_set_value(THD *thd, const char *pos, uint length, const Load_data_param *param)= 0; virtual bool load_data_set_no_data(THD *thd, const Load_data_param *param)= 0; virtual void load_data_print_for_log_event(THD *thd, class String *to) const= 0; virtual bool load_data_add_outvar(THD *thd, Load_data_param *param) const= 0; virtual uint load_data_fixed_length() const= 0; }; class Timeval: public timeval { protected: Timeval() = default; public: Timeval(my_time_t sec, ulong usec) { tv_sec= sec; /* Since tv_usec is not always of type ulong, cast usec parameter explicitly to uint to avoid compiler warnings about losing integer precision. */ DBUG_ASSERT(usec < 1000000); tv_usec= (uint)usec; } explicit Timeval(const timeval &tv) :timeval(tv) { } }; #endif /* STRUCTS_INCLUDED */ server/private/sql_type_fixedbin_storage.h000064400000012533151031265040015132 0ustar00#ifndef SQL_TYPE_FIXEDBIN_STORAGE #define SQL_TYPE_FIXEDBIN_STORAGE /* Copyright (c) 2019,2021 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This is a common code for plugin (?) types that are generally handled like strings, but have their own fixed size on-disk binary storage format and their own (variable size) canonical string representation. Examples are INET6 and UUID types. The MariaDB server uses three binary representations of a data type: 1. In-memory binary representation (user visible) This representation: - can be used in INSERT..VALUES (X'AABBCC') - can be used in WHERE conditions: WHERE c1=X'AABBCC' - is returned by CAST(x AS BINARY(N)) - is returned by Field::val_native() and Item::val_native() 2. In-record binary representation (user invisible) This representation: - is used in records (is pointed by Field::ptr) - must be comparable by memcmp() 3. Binlog binary (row) representation Usually, for string data types the binlog representation is based on the in-record representation with trailing byte compression: - trailing space compression for text string data types - trailing zero compression for binary string data types We have to have separate in-memory and in-record representations because we use HA_KEYTYPE_BINARY for indexing. The engine API does not have a way to pass a comparison function as a parameter. The default implementation below assumes that: - the in-memory and in-record representations are equal - the binlog representation is compatible with BINARY(N) This is OK for simple data types, like INET6. Data type implementations that need different representations can override the default implementation (like e.g. UUID does). */ /***********************************************************************/ template class FixedBinTypeStorage { protected: // The buffer that stores the in-memory binary representation char m_buffer[NATIVE_LEN]; FixedBinTypeStorage() = default; FixedBinTypeStorage & set_zero() { bzero(&m_buffer, sizeof(m_buffer)); return *this; } public: // Initialize from the in-memory binary representation FixedBinTypeStorage(const char *str, size_t length) { if (length != binary_length()) set_zero(); else memcpy(&m_buffer, str, sizeof(m_buffer)); } // Return the buffer with the in-memory representation Lex_cstring to_lex_cstring() const { return Lex_cstring(m_buffer, sizeof(m_buffer)); } static constexpr uint binary_length() { return NATIVE_LEN; } static constexpr uint max_char_length() { return MAX_CHAR_LEN; } // Compare the in-memory binary representations of two values static int cmp(const LEX_CSTRING &a, const LEX_CSTRING &b) { DBUG_ASSERT(a.length == binary_length()); DBUG_ASSERT(b.length == binary_length()); return memcmp(a.str, b.str, b.length); } /* Convert from the in-memory to the in-record representation. Used in Field::store_native(). */ static void memory_to_record(char *to, const char *from) { memcpy(to, from, NATIVE_LEN); } /* Convert from the in-record to the in-memory representation Used in Field::val_native(). */ static void record_to_memory(char *to, const char *from) { memcpy(to, from, NATIVE_LEN); } /* Hash the in-record representation Used in Field::hash(). */ static void hash_record(uchar *ptr, Hasher *hasher) { hasher->add(&my_charset_bin, ptr, binary_length()); } static bool only_zero_bytes(const char *ptr, size_t length) { for (uint i= 0 ; i < length; i++) { if (ptr[i] != 0) return false; } return true; } static ulong KEY_pack_flags(uint column_nr) { /* Return zero by default. A particular data type can override this method return some flags, e.g. HA_PACK_KEY to enable key prefix compression. */ return 0; } /* Convert from the in-record to the binlog representation. Used in Field::pack(), and in filesort to store the addon fields. By default, do what BINARY(N) does. */ static uchar *pack(uchar *to, const uchar *from, uint max_length) { return StringPack(&my_charset_bin, binary_length()).pack(to, from, max_length); } /* Convert from the in-binary-log to the in-record representation. Used in Field::unpack(). By default, do what BINARY(N) does. */ static const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end, uint param_data) { return StringPack(&my_charset_bin, binary_length()).unpack(to, from, from_end, param_data); } }; #endif /* SQL_TYPE_FIXEDBIN_STORAGE */ server/private/tztime.h000064400000006505151031265040011214 0ustar00#ifndef TZTIME_INCLUDED #define TZTIME_INCLUDED /* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class interface */ #endif #include "my_time.h" /* my_time_t */ #include "mysql_time.h" /* MYSQL_TIME */ #include "sql_list.h" /* Sql_alloc */ #include "sql_string.h" /* String */ class THD; #if !defined(TESTTIME) && !defined(TZINFO2SQL) class THD; /** This class represents abstract time zone and provides basic interface for MYSQL_TIME <-> my_time_t conversion. Actual time zones which are specified by DB, or via offset or use system functions are its descendants. */ class Time_zone: public Sql_alloc { public: Time_zone() = default; /* Remove gcc warning */ /** Converts local time in broken down MYSQL_TIME representation to my_time_t (UTC seconds since Epoch) represenation. Returns 0 in case of error. May set error_code to ER_WARN_DATA_OUT_OF_RANGE or ER_WARN_INVALID_TIMESTAMP, see TIME_to_timestamp()) */ virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t, uint *error_code) const = 0; /** Converts time in my_time_t representation to local time in broken down MYSQL_TIME representation. */ virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const = 0; /** Because of constness of String returned by get_name() time zone name have to be already zeroended to be able to use String::ptr() instead of c_ptr(). */ virtual const String * get_name() const = 0; /** We need this only for surpressing warnings, objects of this type are allocated on MEM_ROOT and should not require destruction. */ virtual ~Time_zone() = default; protected: static inline void adjust_leap_second(MYSQL_TIME *t); }; extern Time_zone * my_tz_UTC; extern MYSQL_PLUGIN_IMPORT Time_zone * my_tz_SYSTEM; extern Time_zone * my_tz_OFFSET0; extern Time_zone * my_tz_find(THD *thd, const String *name); extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap); extern void my_tz_free(); extern my_time_t sec_since_epoch_TIME(MYSQL_TIME *t); /** Number of elements in table list produced by my_tz_get_table_list() (this table list contains tables which are needed for dynamical loading of time zone descriptions). Actually it is imlementation detail that should not be used anywhere outside of tztime.h and tztime.cc. */ static const int MY_TZ_TABLES_COUNT= 4; #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */ #endif /* TZTIME_INCLUDED */ server/private/rowid_filter.h000064400000036165151031265040012376 0ustar00/* Copyright (c) 2018, 2019 MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ROWID_FILTER_INCLUDED #define ROWID_FILTER_INCLUDED #include "mariadb.h" #include "sql_array.h" /* What rowid / primary filters are -------------------------------- Consider a join query Q of the form SELECT * FROM T1, ... , Tk WHERE P. For any of the table reference Ti(Q) from the from clause of Q different rowid / primary key filters (pk-filters for short) can be built. A pk-filter F built for Ti(Q) is a set of rowids / primary keys of Ti F= {pk1,...,pkN} such that for any row r=r1||...||rk from the result set of Q ri's rowid / primary key pk(ri) is contained in F. When pk-filters are useful -------------------------- If building a pk-filter F for Ti(Q )is not too costly and its cardinality #F is much less than the cardinality of T - #T then using the pk-filter when executing Q might be quite beneficial. Let r be a random row from Ti. Let s(F) be the probability that pk(r) belongs to F. Let BC(F) be the cost of building F. Suppose that the optimizer has chosen for Q a plan with this join order T1 => ... Tk and that the table Ti is accessed by a ref access using index I. Let K = {k1,...,kM} be the set of all rowid/primary keys values used to access rows of Ti when looking for matches in this table.to join Ti by index I. Let's assume that two set sets K and F are uncorrelated. With this assumption if before accessing data from Ti by the rowid / primary key k we first check whether k is in F then we can expect saving on M*(1-s(S)) accesses of data rows from Ti. If we can guarantee that test whether k is in F is relatively cheap then we can gain a lot assuming that BC(F) is much less then the cost of fetching M*(1-s(S)) records from Ti and following evaluation of conditions pushed into Ti. Making pk-filter test cheap --------------------------- If the search structure to test whether an element is in F can be fully placed in RAM then this test is expected to be be much cheaper than a random access of a record from Ti. We'll consider two search structures for pk-filters: ordered array and bloom filter. Ordered array is easy to implement, but it's space consuming. If a filter contains primary keys then at least space for each primary key from the filter must be allocated in the search structure. On a the opposite a bloom filter requires a fixed number of bits and this number does not depend on the cardinality of the pk-filter (10 bits per element will serve pk-filter of any size). */ /* How and when the optimizer builds and uses range rowid filters -------------------------------------------------------------- 1. In make_join_statistics() for each join table s after the call of get_quick_record_count() the TABLE::method init_cost_info_for_usable_range_rowid_filters() is called The method build an array of Range_rowid_filter_cost_info elements containing the cost info on possible range filters for s->table. The array is optimized for further usage. 2. For each partial join order when the optimizer considers joining table s to this partial join In the function best_access_path() a. When evaluating a ref access r by index idx to join s the optimizer estimates the effect of usage of each possible range filter f and chooses one with the best gain. The gain is taken into account when the cost of thr ref access r is calculated. If it turns out that this is the best ref access to join s then the info about the chosen filter together with the info on r is remembered in the corresponding element of the array of POSITION structures. [We evaluate every pair (ref access, range_filter) rather then every pair (best ref access, range filter) because if the index ref_idx used for ref access r correlates with the index rf_idx used by the filter f then the pair (r,f) is not evaluated at all as we don't know how to estimate the effect of correlation between ref_idx and rf_idx.] b. When evaluating the best range access to join table s the optimizer estimates the effect of usage of each possible range filter f and chooses one with the best gain. [Here we should have evaluated every pair (range access, range filter) as well, but it's not done yet.] 3. When the cheapest execution plan has been chosen and after the call of JOIN::get_best_combination() The method JOIN::make_range_rowid_filters() is called For each range rowid filter used in the chosen execution plan the method creates a quick select object to be able to perform index range scan to fill the filter at the execution stage. The method also creates Range_rowid_filter objects that are used at the execution stage. 4. Just before the execution stage The method JOIN::init_range_rowid_filters() is called. For each join table s that is to be accessed with usage of a range filter the method allocates containers for the range filter and it lets the engine know that the filter will be used when accessing s. 5. At the execution stage In the function sub_select() just before the first access of a join table s employing a range filter The method JOIN_TAB::build_range_rowid_filter_if_needed() is called The method fills the filter using the quick select created by JOIN::make_range_rowid_filters(). 6. The accessed key tuples are checked against the filter within the engine using the info pushed into it. */ struct TABLE; class SQL_SELECT; class Rowid_filter_container; class Range_rowid_filter_cost_info; /* Cost to write rowid into array */ #define ARRAY_WRITE_COST 0.005 /* Factor used to calculate cost of sorting rowids in array */ #define ARRAY_SORT_C 0.01 /* Cost to evaluate condition */ #define COST_COND_EVAL 0.2 typedef enum { SORTED_ARRAY_CONTAINER, BLOOM_FILTER_CONTAINER // Not used yet } Rowid_filter_container_type; /** @class Rowid_filter_container The interface for different types of containers to store info on the set of rowids / primary keys that defines a pk-filter. There will be two implementations of this abstract class. - sorted array - bloom filter */ class Rowid_filter_container : public Sql_alloc { public: virtual Rowid_filter_container_type get_type() = 0; /* Allocate memory for the container */ virtual bool alloc() = 0; /* @brief Add info on a rowid / primary to the container @param ctxt The context info (opaque) @param elem The rowid / primary key to be added to the container @retval true if elem is successfully added */ virtual bool add(void *ctxt, char *elem) = 0; /* @brief Check whether a rowid / primary key is in container @param ctxt The context info (opaque) @param elem The rowid / primary key to be checked against the container @retval False if elem is definitely not in the container */ virtual bool check(void *ctxt, char *elem) = 0; /* True if the container does not contain any element */ virtual bool is_empty() = 0; virtual ~Rowid_filter_container() = default; }; /** @class Rowid_filter The interface for different types of pk-filters Currently we support only range pk filters. */ class Rowid_filter : public Sql_alloc { protected: /* The container to store info the set of elements in the filter */ Rowid_filter_container *container; Rowid_filter_tracker *tracker; public: enum build_return_code { SUCCESS, NON_FATAL_ERROR, FATAL_ERROR, }; Rowid_filter(Rowid_filter_container *container_arg) : container(container_arg) {} /* Build the filter : fill it with info on the set of elements placed there */ virtual build_return_code build() = 0; /* Check whether an element is in the filter. Returns false is the elements is definitely not in the filter. */ virtual bool check(char *elem) = 0; virtual ~Rowid_filter() = default; bool is_empty() { return container->is_empty(); } Rowid_filter_container *get_container() { return container; } void set_tracker(Rowid_filter_tracker *track_arg) { tracker= track_arg; } Rowid_filter_tracker *get_tracker() { return tracker; } }; /** @class Rowid_filter_container The implementation of the Rowid_interface used for pk-filters that are filled when performing range index scans. */ class Range_rowid_filter: public Rowid_filter { /* The table for which the rowid filter is built */ TABLE *table; /* The select to perform the range scan to fill the filter */ SQL_SELECT *select; /* The cost info on the filter (used for EXPLAIN/ANALYZE) */ Range_rowid_filter_cost_info *cost_info; public: Range_rowid_filter(TABLE *tab, Range_rowid_filter_cost_info *cost_arg, Rowid_filter_container *container_arg, SQL_SELECT *sel) : Rowid_filter(container_arg), table(tab), select(sel), cost_info(cost_arg) {} ~Range_rowid_filter(); build_return_code build() override; bool check(char *elem) override { if (container->is_empty()) return false; bool was_checked= container->check(table, elem); tracker->increment_checked_elements_count(was_checked); return was_checked; } SQL_SELECT *get_select() { return select; } }; /** @class Refpos_container_sorted_array The wrapper class over Dynamic_array to facilitate operations over array of elements of the type char[N] where N is the same for all elements */ class Refpos_container_sorted_array : public Sql_alloc { /* Maximum number of elements in the array (Now is used only at the initialization of the dynamic array) */ uint max_elements; /* Number of bytes allocated for an element */ uint elem_size; /* The dynamic array over which the wrapper is built */ Dynamic_array *array; public: Refpos_container_sorted_array(uint max_elems, uint elem_sz) : max_elements(max_elems), elem_size(elem_sz), array(0) {} ~Refpos_container_sorted_array() { delete array; array= 0; } bool alloc() { array= new Dynamic_array (PSI_INSTRUMENT_MEM, elem_size * max_elements, elem_size * max_elements/sizeof(char) + 1); return array == NULL; } bool add(char *elem) { for (uint i= 0; i < elem_size; i++) { if (array->append(elem[i])) return true; } return false; } char *get_pos(uint n) { return array->get_pos(n * elem_size); } uint elements() { return (uint) (array->elements() / elem_size); } void sort(qsort_cmp2 cmp, void *cmp_arg) { my_qsort2(array->front(), array->elements() / elem_size, elem_size, cmp, cmp_arg); } bool is_empty() { return elements() == 0; } }; /** @class Rowid_filter_sorted_array The implementation of the Rowid_filter_container interface as a sorted array container of rowids / primary keys */ class Rowid_filter_sorted_array: public Rowid_filter_container { /* The dynamic array to store rowids / primary keys */ Refpos_container_sorted_array refpos_container; /* Initially false, becomes true after the first call of (check() */ bool is_checked; public: Rowid_filter_sorted_array(uint elems, uint elem_size) : refpos_container(elems, elem_size), is_checked(false) {} Rowid_filter_container_type get_type() override { return SORTED_ARRAY_CONTAINER; } bool alloc() override { return refpos_container.alloc(); } bool add(void *ctxt, char *elem) override { return refpos_container.add(elem); } bool check(void *ctxt, char *elem) override; bool is_empty() override { return refpos_container.is_empty(); } }; /** @class Range_rowid_filter_cost_info An objects of this class is created for each potentially usable range filter. It contains the info that allows to figure out whether usage of the range filter promises some gain. */ class Range_rowid_filter_cost_info : public Sql_alloc { /* The table for which the range filter is to be built (if needed) */ TABLE *table; /* Estimated number of elements in the filter */ ulonglong est_elements; /* The cost of building the range filter */ double b; /* a*N-b yields the gain of the filter for N key tuples of the index key_no */ double a; /* The value of N where the gain is 0 */ double cross_x; /* Used for pruning of the potential range filters */ key_map abs_independent; /* These two parameters are used to choose the best range filter in the function TABLE::best_range_rowid_filter_for_partial_join */ double a_adj; double cross_x_adj; public: /* The type of the container of the range filter */ Rowid_filter_container_type container_type; /* The index whose range scan would be used to build the range filter */ uint key_no; /* The selectivity of the range filter */ double selectivity; Range_rowid_filter_cost_info() : table(0), key_no(0) {} void init(Rowid_filter_container_type cont_type, TABLE *tab, uint key_no); double build_cost(Rowid_filter_container_type container_type); inline double lookup_cost(Rowid_filter_container_type cont_type); inline double avg_access_and_eval_gain_per_row(Rowid_filter_container_type cont_type); inline double avg_adjusted_gain_per_row(double access_cost_factor); inline void set_adjusted_gain_param(double access_cost_factor); /* Get the gain that usage of filter promises for r key tuples */ inline double get_gain(double r) { return r * a - b; } /* Get the adjusted gain that usage of filter promises for r key tuples */ inline double get_adjusted_gain(double r) { return r * a_adj - b; } /* The gain promised by usage of the filter for r key tuples due to less condition evaluations */ inline double get_cmp_gain(double r) { return r * (1 - selectivity) / TIME_FOR_COMPARE; } Rowid_filter_container *create_container(); double get_a() const { return a; } void trace_info(THD *thd); friend void TABLE::prune_range_rowid_filters(); friend void TABLE::init_cost_info_for_usable_range_rowid_filters(THD *thd); friend Range_rowid_filter_cost_info * TABLE::best_range_rowid_filter_for_partial_join(uint access_key_no, double records, double access_cost_factor); }; #endif /* ROWID_FILTER_INCLUDED */ server/private/my_rdtsc.h000064400000020351151031265040011517 0ustar00/* Copyright (c) 2008 MySQL AB, 2009 Sun Microsystems, Inc. Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* rdtsc3 -- multi-platform timer code pgulutzan@mysql.com, 2005-08-29 modified 2008-11-02 */ #ifndef MY_RDTSC_H #define MY_RDTSC_H # ifndef __has_builtin # define __has_builtin(x) 0 /* Compatibility with non-clang compilers */ # endif # if __has_builtin(__builtin_readcyclecounter) # elif defined _WIN32 # include # elif defined __i386__ || defined __x86_64__ # include # elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H) # include # elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) # include # endif /** Characteristics of a timer. */ struct my_timer_unit_info { /** Routine used for the timer. */ ulonglong routine; /** Overhead of the timer. */ ulonglong overhead; /** Frequency of the timer. */ ulonglong frequency; /** Resolution of the timer. */ ulonglong resolution; }; /** Characteristics of all the supported timers. @sa my_timer_init(). */ struct my_timer_info { /** Characteristics of the cycle timer. */ struct my_timer_unit_info cycles; /** Characteristics of the nanosecond timer. */ struct my_timer_unit_info nanoseconds; /** Characteristics of the microsecond timer. */ struct my_timer_unit_info microseconds; /** Characteristics of the millisecond timer. */ struct my_timer_unit_info milliseconds; /** Characteristics of the tick timer. */ struct my_timer_unit_info ticks; }; typedef struct my_timer_info MY_TIMER_INFO; C_MODE_START /** A cycle timer. On clang we use __builtin_readcyclecounter(), except for AARCH64. On other compilers: On IA-32 and AMD64, we use the RDTSC instruction. On IA-64, we read the ar.itc register. On SPARC, we read the tick register. On POWER, we read the Time Base Register (which is not really a cycle count but a separate counter with less than nanosecond resolution). On IBM S/390 System z we use the STCK instruction. On ARM, we probably should use the Generic Timer, but should figure out how to ensure that it can be accessed. On AARCH64, we use the generic timer base register. We override clang implementation for aarch64 as it access a PMU register which is not guaranteed to be active. Sadly, we have nothing for the Digital Alpha, MIPS, Motorola m68k, HP PA-RISC or other non-mainstream (or obsolete) processors. TODO: consider C++11 std::chrono::high_resolution_clock. We fall back to gethrtime() where available. On the platforms that do not have a CYCLE timer, "wait" events are initialized to use NANOSECOND instead of CYCLE during performance_schema initialization (at the server startup). Linux performance monitor (see "man perf_event_open") can provide cycle counter on the platforms that do not have other kinds of cycle counters. But we don't use it so far. ARM notes --------- During tests on ARMv7 Debian, perf_even_open() based cycle counter provided too low frequency with too high overhead: MariaDB [performance_schema]> SELECT * FROM performance_timers; +-------------+-----------------+------------------+----------------+ | TIMER_NAME | TIMER_FREQUENCY | TIMER_RESOLUTION | TIMER_OVERHEAD | +-------------+-----------------+------------------+----------------+ | CYCLE | 689368159 | 1 | 970 | | NANOSECOND | 1000000000 | 1 | 308 | | MICROSECOND | 1000000 | 1 | 417 | | MILLISECOND | 1000 | 1000 | 407 | | TICK | 127 | 1 | 612 | +-------------+-----------------+------------------+----------------+ Therefore, it was decided not to use perf_even_open() on ARM (i.e. go without CYCLE and have "wait" events use NANOSECOND by default). @return the current timer value, in cycles. */ static inline ulonglong my_timer_cycles(void) { # if __has_builtin(__builtin_readcyclecounter) && !defined (__aarch64__) return __builtin_readcyclecounter(); # elif defined _M_IX86 || defined _M_X64 || defined __i386__ || defined __x86_64__ return __rdtsc(); #elif defined _M_ARM64 return _ReadStatusReg(ARM64_CNTVCT); # elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H) return (ulonglong) __getReg(_IA64_REG_AR_ITC); /* (3116) */ #elif defined(__GNUC__) && defined(__ia64__) { ulonglong result; __asm __volatile__ ("mov %0=ar.itc" : "=r" (result)); return result; } #elif defined __GNUC__ && defined __powerpc__ return __builtin_ppc_get_timebase(); #elif defined(__GNUC__) && defined(__sparcv9) && defined(_LP64) { ulonglong result; __asm __volatile__ ("rd %%tick,%0" : "=r" (result)); return result; } #elif defined(__GNUC__) && defined(__sparc__) && !defined(_LP64) { union { ulonglong wholeresult; struct { ulong high; ulong low; } splitresult; } result; __asm __volatile__ ("rd %%tick,%1; srlx %1,32,%0" : "=r" (result.splitresult.high), "=r" (result.splitresult.low)); return result.wholeresult; } #elif defined(__GNUC__) && defined(__s390__) /* covers both s390 and s390x */ { ulonglong result; __asm__ __volatile__ ("stck %0" : "=Q" (result) : : "cc"); return result; } #elif defined(__GNUC__) && defined (__aarch64__) { ulonglong result; __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result)); return result; } #elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) /* gethrtime may appear as either cycle or nanosecond counter */ return (ulonglong) gethrtime(); #else # define MY_TIMER_CYCLES_IS_ZERO return 0; #endif } #ifdef MY_TIMER_CYCLES_IS_ZERO static inline size_t my_pseudo_random(void) { /* In some platforms, pthread_self() might return a structure that cannot be converted to a number like this. Possible alternatives could include gettid() or sched_getcpu(). */ return ((size_t) pthread_self()) / 16; } #else # define my_pseudo_random my_timer_cycles #endif /** A nanosecond timer. @return the current timer value, in nanoseconds. */ ulonglong my_timer_nanoseconds(void); /** A microseconds timer. @return the current timer value, in microseconds. */ ulonglong my_timer_microseconds(void); /** A millisecond timer. @return the current timer value, in milliseconds. */ ulonglong my_timer_milliseconds(void); /** A ticks timer. @return the current timer value, in ticks. */ ulonglong my_timer_ticks(void); /** Timer initialization function. @param [out] mti the timer characteristics. */ void my_timer_init(MY_TIMER_INFO *mti); C_MODE_END #define MY_TIMER_ROUTINE_RDTSC 5 #define MY_TIMER_ROUTINE_ASM_IA64 6 #define MY_TIMER_ROUTINE_PPC_GET_TIMEBASE 7 #define MY_TIMER_ROUTINE_GETHRTIME 9 #define MY_TIMER_ROUTINE_READ_REAL_TIME 10 #define MY_TIMER_ROUTINE_CLOCK_GETTIME 11 #define MY_TIMER_ROUTINE_GETTIMEOFDAY 13 #define MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER 14 #define MY_TIMER_ROUTINE_GETTICKCOUNT 15 #define MY_TIMER_ROUTINE_TIME 16 #define MY_TIMER_ROUTINE_TIMES 17 #define MY_TIMER_ROUTINE_FTIME 18 #define MY_TIMER_ROUTINE_ASM_GCC_SPARC64 23 #define MY_TIMER_ROUTINE_ASM_GCC_SPARC32 24 #define MY_TIMER_ROUTINE_MACH_ABSOLUTE_TIME 25 #define MY_TIMER_ROUTINE_GETSYSTEMTIMEASFILETIME 26 #define MY_TIMER_ROUTINE_ASM_S390 28 #define MY_TIMER_ROUTINE_AARCH64 29 #endif server/private/dur_prop.h000064400000002072151031265040011525 0ustar00/* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _my_dur_prop_h #define _my_dur_prop_h enum durability_properties { /* Preserves the durability properties defined by the engine */ HA_REGULAR_DURABILITY= 0, /* Ignore the durability properties defined by the engine and write only in-memory entries. */ HA_IGNORE_DURABILITY= 1 }; #endif /* _my_dur_prop_h */ server/private/ha_handler_stats.h000064400000004437151031265040013205 0ustar00#ifndef HA_HANDLER_STATS_INCLUDED #define HA_HANDLER_STATS_INCLUDED /* Copyright (c) 2023, MariaDB Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Definitions for parameters to do with handler-routines */ class ha_handler_stats { public: ulonglong pages_accessed; /* Pages accessed from page cache */ ulonglong pages_updated; /* Pages changed in page cache */ ulonglong pages_read_count; /* Pages read from disk */ /* Time spent reading pages, in timer_tracker_frequency() units */ ulonglong pages_read_time; /* Number of pages that we've requested to prefetch while running the query. Note that we don't know: - how much time was spent reading these pages (and how to count the time if reading was done in parallel) - whether the pages were read by "us" or somebody else... */ ulonglong pages_prefetched; ulonglong undo_records_read; /* Time spent in engine, in timer_tracker_frequency() units */ ulonglong engine_time; uint active; /* <> 0 if status has to be updated */ ha_handler_stats() { active= 0; } #define first_stat pages_accessed #define last_stat engine_time inline void reset() { bzero((void*) this, sizeof(*this)); } inline void add(ha_handler_stats *stats) { ulonglong *to= &first_stat; ulonglong *from= &stats->first_stat; do { (*to)+= *from++; } while (to++ != &last_stat); } inline bool has_stats() { if (!active) return 0; ulonglong *to= &first_stat; do { if (*to) return 1; } while (to++ != &last_stat); return 0; } }; #endif /* HA_HANDLER_STATS_INCLUDED */ server/private/wsrep_condition_variable.h000064400000002714151031265040014751 0ustar00/* Copyright 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WSREP_CONDITION_VARIABLE_H #define WSREP_CONDITION_VARIABLE_H /* wsrep-lib */ #include "wsrep/condition_variable.hpp" /* implementation */ #include "my_pthread.h" class Wsrep_condition_variable : public wsrep::condition_variable { public: Wsrep_condition_variable(mysql_cond_t* cond) : m_cond(cond) { } ~Wsrep_condition_variable() = default; void notify_one() override { mysql_cond_signal(m_cond); } void notify_all() override { mysql_cond_broadcast(m_cond); } void wait(wsrep::unique_lock& lock) override { mysql_mutex_t* mutex= static_cast(lock.mutex()->native()); mysql_cond_wait(m_cond, mutex); } private: mysql_cond_t* m_cond; }; #endif /* WSREP_CONDITION_VARIABLE_H */ server/private/contributors.h000064400000011416151031265040012432 0ustar00#ifndef CONTRIBUTORS_INCLUDED #define CONTRIBUTORS_INCLUDED /* Copyright (c) 2006 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Structure of the name list */ struct show_table_contributors_st { const char *name; const char *location; const char *comment; }; /* Output from "SHOW CONTRIBUTORS" Get permission before editing. Names should be encoded using UTF-8. See also https://mariadb.com/kb/en/log-of-mariadb-contributions/ */ struct show_table_contributors_st show_table_contributors[]= { /* MariaDB Foundation sponsors, alphabetical by tier */ {"Amazon", "https://www.amazon.com/", "Diamond Sponsor of the MariaDB Foundation"}, {"Acronis", "https://www.acronis.com/", "Platinum Sponsor of the MariaDB Foundation"}, {"Alibaba Cloud", "https://www.alibabacloud.com/", "Platinum Sponsor of the MariaDB Foundation"}, {"Cstrnncoll(name.str, name.length, str->str, str->length) == 0; } }; /////////////////////////////////////////////////////////////////////////// /** class sp_pcursor. Stores information about a cursor: - Cursor's name in LEX_STRING. - Cursor's formal parameter descriptions. Formal parameter descriptions reside in a separate context block, pointed by the "m_param_context" member. m_param_context can be NULL. This means a cursor with no parameters. Otherwise, the number of variables in m_param_context means the number of cursor's formal parameters. Note, m_param_context can be not NULL, but have no variables. This is also means a cursor with no parameters (similar to NULL). */ class sp_pcursor: public LEX_CSTRING { class sp_pcontext *m_param_context; // Formal parameters class sp_lex_cursor *m_lex; // The cursor statement LEX public: sp_pcursor(const LEX_CSTRING *name, class sp_pcontext *param_ctx, class sp_lex_cursor *lex) :LEX_CSTRING(*name), m_param_context(param_ctx), m_lex(lex) { } class sp_pcontext *param_context() const { return m_param_context; } class sp_lex_cursor *lex() const { return m_lex; } bool check_param_count_with_error(uint param_count) const; }; /////////////////////////////////////////////////////////////////////////// /// This class represents 'DECLARE HANDLER' statement. class sp_handler : public Sql_alloc { public: /// Enumeration of possible handler types. /// Note: UNDO handlers are not (and have never been) supported. enum enum_type { EXIT, CONTINUE }; /// Handler type. enum_type type; /// Conditions caught by this handler. List condition_values; public: /// The constructor. /// /// @param _type SQL-handler type. sp_handler(enum_type _type) :Sql_alloc(), type(_type) { } }; /////////////////////////////////////////////////////////////////////////// /// The class represents parse-time context, which keeps track of declared /// variables/parameters, conditions, handlers, cursors and labels. /// /// sp_pcontext objects are organized in a tree according to the following /// rules: /// - one sp_pcontext object corresponds for for each BEGIN..END block; /// - one sp_pcontext object corresponds for each exception handler; /// - one additional sp_pcontext object is created to contain /// Stored Program parameters. /// /// sp_pcontext objects are used both at parse-time and at runtime. /// /// During the parsing stage sp_pcontext objects are used: /// - to look up defined names (e.g. declared variables and visible /// labels); /// - to check for duplicates; /// - for error checking; /// - to calculate offsets to be used at runtime. /// /// During the runtime phase, a tree of sp_pcontext objects is used: /// - for error checking (e.g. to check correct number of parameters); /// - to resolve SQL-handlers. class sp_pcontext : public Sql_alloc { public: enum enum_scope { /// REGULAR_SCOPE designates regular BEGIN ... END blocks. REGULAR_SCOPE, /// HANDLER_SCOPE designates SQL-handler blocks. HANDLER_SCOPE }; class Lex_for_loop: public Lex_for_loop_st { public: /* The label poiting to the body start, either explicit or automatically generated. Used during generation of "ITERATE loop_label" to check if "loop_label" is a FOR loop label. - In case of a FOR loop, some additional code (cursor fetch or iteger increment) is generated before the backward jump to the beginning of the loop body. - In case of other loop types (WHILE, REPEAT) only the jump is generated. */ const sp_label *m_start_label; Lex_for_loop() :m_start_label(NULL) { Lex_for_loop_st::init(); } Lex_for_loop(const Lex_for_loop_st &for_loop, const sp_label *start) :m_start_label(start) { Lex_for_loop_st::operator=(for_loop); } }; public: sp_pcontext(); ~sp_pcontext(); /// Create and push a new context in the tree. /// @param thd thread context. /// @param scope scope of the new parsing context. /// @return the node created. sp_pcontext *push_context(THD *thd, enum_scope scope); /// Pop a node from the parsing context tree. /// @return the parent node. sp_pcontext *pop_context(); sp_pcontext *parent_context() const { return m_parent; } sp_pcontext *child_context(uint i) const { return i < m_children.elements() ? m_children.at(i) : NULL; } /// Calculate and return the number of handlers to pop between the given /// context and this one. /// /// @param ctx the other parsing context. /// @param exclusive specifies if the last scope should be excluded. /// /// @return the number of handlers to pop between the given context and /// this one. If 'exclusive' is true, don't count the last scope we are /// leaving; this is used for LEAVE where we will jump to the hpop /// instructions. uint diff_handlers(const sp_pcontext *ctx, bool exclusive) const; /// Calculate and return the number of cursors to pop between the given /// context and this one. /// /// @param ctx the other parsing context. /// @param exclusive specifies if the last scope should be excluded. /// /// @return the number of cursors to pop between the given context and /// this one. If 'exclusive' is true, don't count the last scope we are /// leaving; this is used for LEAVE where we will jump to the cpop /// instructions. uint diff_cursors(const sp_pcontext *ctx, bool exclusive) const; ///////////////////////////////////////////////////////////////////////// // SP-variables (parameters and variables). ///////////////////////////////////////////////////////////////////////// /// @return the maximum number of variables used in this and all child /// contexts. For the root parsing context, this gives us the number of /// slots needed for variables during the runtime phase. uint max_var_index() const { return m_max_var_index; } /// @return the current number of variables used in the parent contexts /// (from the root), including this context. uint current_var_count() const { return m_var_offset + (uint)m_vars.elements(); } /// @return the number of variables in this context alone. uint context_var_count() const { return (uint)m_vars.elements(); } /// return the i-th variable on the current context sp_variable *get_context_variable(uint i) const { DBUG_ASSERT(i < m_vars.elements()); return m_vars.at(i); } /* Return the i-th last context variable. If i is 0, then return the very last variable in m_vars. */ sp_variable *get_last_context_variable(uint i= 0) const { DBUG_ASSERT(i < m_vars.elements()); return m_vars.at(m_vars.elements() - i - 1); } /// Add SP-variable to the parsing context. /// /// @param thd Thread context. /// @param name Name of the SP-variable. /// /// @return instance of newly added SP-variable. sp_variable *add_variable(THD *thd, const LEX_CSTRING *name); /// Retrieve full type information about SP-variables in this parsing /// context and its children. /// /// @param field_def_lst[out] Container to store type information. void retrieve_field_definitions(List *field_def_lst) const; /// Find SP-variable by name. /// /// The function does a linear search (from newer to older variables, /// in case we have shadowed names). /// /// The function is called only at parsing time. /// /// @param name Variable name. /// @param current_scope_only A flag if we search only in current scope. /// /// @return instance of found SP-variable, or NULL if not found. sp_variable *find_variable(const LEX_CSTRING *name, bool current_scope_only) const; /// Find SP-variable by the offset in the root parsing context. /// /// The function is used for two things: /// - When evaluating parameters at the beginning, and setting out parameters /// at the end, of invocation. (Top frame only, so no recursion then.) /// - For printing of sp_instr_set. (Debug mode only.) /// /// @param offset Variable offset in the root parsing context. /// /// @return instance of found SP-variable, or NULL if not found. sp_variable *find_variable(uint offset) const; /// Set the current scope boundary (for default values). /// /// @param n The number of variables to skip. void declare_var_boundary(uint n) { m_pboundary= n; } ///////////////////////////////////////////////////////////////////////// // CASE expressions. ///////////////////////////////////////////////////////////////////////// int register_case_expr() { return m_num_case_exprs++; } int get_num_case_exprs() const { return m_num_case_exprs; } bool push_case_expr_id(int case_expr_id) { return m_case_expr_ids.append(case_expr_id); } void pop_case_expr_id() { m_case_expr_ids.pop(); } int get_current_case_expr_id() const { return *m_case_expr_ids.back(); } ///////////////////////////////////////////////////////////////////////// // Labels. ///////////////////////////////////////////////////////////////////////// sp_label *push_label(THD *thd, const LEX_CSTRING *name, uint ip, sp_label::enum_type type, List * list); sp_label *push_label(THD *thd, const LEX_CSTRING *name, uint ip, sp_label::enum_type type) { return push_label(thd, name, ip, type, &m_labels); } sp_label *push_goto_label(THD *thd, const LEX_CSTRING *name, uint ip, sp_label::enum_type type) { return push_label(thd, name, ip, type, &m_goto_labels); } sp_label *push_label(THD *thd, const LEX_CSTRING *name, uint ip) { return push_label(thd, name, ip, sp_label::IMPLICIT); } sp_label *push_goto_label(THD *thd, const LEX_CSTRING *name, uint ip) { return push_goto_label(thd, name, ip, sp_label::GOTO); } sp_label *find_label(const LEX_CSTRING *name); sp_label *find_goto_label(const LEX_CSTRING *name, bool recusive); sp_label *find_goto_label(const LEX_CSTRING *name) { return find_goto_label(name, true); } sp_label *find_label_current_loop_start(); sp_label *last_label() { sp_label *label= m_labels.head(); if (!label && m_parent) label= m_parent->last_label(); return label; } sp_label *last_goto_label() { return m_goto_labels.head(); } sp_label *pop_label() { return m_labels.pop(); } bool block_label_declare(LEX_CSTRING *label) { sp_label *lab= find_label(label); if (lab) { my_error(ER_SP_LABEL_REDEFINE, MYF(0), label->str); return true; } return false; } ///////////////////////////////////////////////////////////////////////// // Conditions. ///////////////////////////////////////////////////////////////////////// bool add_condition(THD *thd, const LEX_CSTRING *name, sp_condition_value *value); /// See comment for find_variable() above. sp_condition_value *find_condition(const LEX_CSTRING *name, bool current_scope_only) const; sp_condition_value * find_declared_or_predefined_condition(THD *thd, const LEX_CSTRING *name) const; bool declare_condition(THD *thd, const LEX_CSTRING *name, sp_condition_value *val) { if (find_condition(name, true)) { my_error(ER_SP_DUP_COND, MYF(0), name->str); return true; } return add_condition(thd, name, val); } ///////////////////////////////////////////////////////////////////////// // Handlers. ///////////////////////////////////////////////////////////////////////// sp_handler *add_handler(THD* thd, sp_handler::enum_type type); /// This is an auxilary parsing-time function to check if an SQL-handler /// exists in the current parsing context (current scope) for the given /// SQL-condition. This function is used to check for duplicates during /// the parsing phase. /// /// This function can not be used during the runtime phase to check /// SQL-handler existence because it searches for the SQL-handler in the /// current scope only (during runtime, current and parent scopes /// should be checked according to the SQL-handler resolution rules). /// /// @param condition_value the handler condition value /// (not SQL-condition!). /// /// @retval true if such SQL-handler exists. /// @retval false otherwise. bool check_duplicate_handler(const sp_condition_value *cond_value) const; /// Find an SQL handler for the given SQL condition according to the /// SQL-handler resolution rules. This function is used at runtime. /// /// @param value The error code and the SQL state /// @param level The SQL condition level /// /// @return a pointer to the found SQL-handler or NULL. sp_handler *find_handler(const Sql_condition_identity &identity) const; ///////////////////////////////////////////////////////////////////////// // Cursors. ///////////////////////////////////////////////////////////////////////// bool add_cursor(const LEX_CSTRING *name, sp_pcontext *param_ctx, class sp_lex_cursor *lex); /// See comment for find_variable() above. const sp_pcursor *find_cursor(const LEX_CSTRING *name, uint *poff, bool current_scope_only) const; const sp_pcursor *find_cursor_with_error(const LEX_CSTRING *name, uint *poff, bool current_scope_only) const { const sp_pcursor *pcursor= find_cursor(name, poff, current_scope_only); if (!pcursor) { my_error(ER_SP_CURSOR_MISMATCH, MYF(0), name->str); return NULL; } return pcursor; } /// Find cursor by offset (for SHOW {PROCEDURE|FUNCTION} CODE only). const sp_pcursor *find_cursor(uint offset) const; const sp_pcursor *get_cursor_by_local_frame_offset(uint offset) const { return &m_cursors.at(offset); } uint cursor_offset() const { return m_cursor_offset; } uint frame_cursor_count() const { return (uint)m_cursors.elements(); } uint max_cursor_index() const { return m_max_cursor_index + (uint)m_cursors.elements(); } uint current_cursor_count() const { return m_cursor_offset + (uint)m_cursors.elements(); } void set_for_loop(const Lex_for_loop_st &for_loop) { m_for_loop= Lex_for_loop(for_loop, last_label()); } const Lex_for_loop &for_loop() { return m_for_loop; } private: /// Constructor for a tree node. /// @param prev the parent parsing context /// @param scope scope of this parsing context sp_pcontext(sp_pcontext *prev, enum_scope scope); void init(uint var_offset, uint cursor_offset, int num_case_expressions); /* Prevent use of these */ sp_pcontext(const sp_pcontext &); void operator=(sp_pcontext &); sp_condition_value *find_predefined_condition(const LEX_CSTRING *name) const; private: /// m_max_var_index -- number of variables (including all types of arguments) /// in this context including all children contexts. /// /// m_max_var_index >= m_vars.elements(). /// /// m_max_var_index of the root parsing context contains number of all /// variables (including arguments) in all enclosed contexts. uint m_max_var_index; /// The maximum sub context's framesizes. uint m_max_cursor_index; /// Parent context. sp_pcontext *m_parent; /// An index of the first SP-variable in this parsing context. The index /// belongs to a runtime table of SP-variables. /// /// Note: /// - m_var_offset is 0 for root parsing context; /// - m_var_offset is different for all nested parsing contexts. uint m_var_offset; /// Cursor offset for this context. uint m_cursor_offset; /// Boundary for finding variables in this context. This is the number of /// variables currently "invisible" to default clauses. This is normally 0, /// but will be larger during parsing of DECLARE ... DEFAULT, to get the /// scope right for DEFAULT values. uint m_pboundary; int m_num_case_exprs; /// SP parameters/variables. Dynamic_array m_vars; /// Stack of CASE expression ids. Dynamic_array m_case_expr_ids; /// Stack of SQL-conditions. Dynamic_array m_conditions; /// Stack of cursors. Dynamic_array m_cursors; /// Stack of SQL-handlers. Dynamic_array m_handlers; /* In the below example the label <> has two meanings: - GOTO lab : must go before the beginning of the loop - CONTINUE lab : must go to the beginning of the loop We solve this by storing block labels and goto labels into separate lists. BEGIN <> FOR i IN a..10 LOOP ... GOTO lab; ... CONTINUE lab; ... END LOOP; END; */ /// List of block labels List m_labels; /// List of goto labels List m_goto_labels; /// Children contexts, used for destruction. Dynamic_array m_children; /// Scope of this parsing context. enum_scope m_scope; /// FOR LOOP characteristics Lex_for_loop m_for_loop; }; // class sp_pcontext : public Sql_alloc #endif /* _SP_PCONTEXT_H_ */ server/private/unireg.h000064400000017044151031265040011171 0ustar00#ifndef UNIREG_INCLUDED #define UNIREG_INCLUDED /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include /* FRM_VER */ /* Extra functions used by unireg library */ #ifndef NO_ALARM_LOOP #define NO_ALARM_LOOP /* lib5 and popen can't use alarm */ #endif /* These paths are converted to other systems (WIN95) before use */ #define LANGUAGE "english/" #define ERRMSG_FILE "errmsg.sys" #define TEMP_PREFIX "MY" #define LOG_PREFIX "ML" #define PROGDIR "bin/" #ifndef MYSQL_DATADIR #define MYSQL_DATADIR "data/" #endif #ifndef SHAREDIR #define SHAREDIR "share/" #endif #ifndef PLUGINDIR #define PLUGINDIR "lib/plugin" #endif #define MAX_ERROR_RANGES 4 /* 1000-2000, 2000-3000, 3000-4000, 4000-5000 */ #define ERRORS_PER_RANGE 1000 #define DEFAULT_ERRMSGS my_default_lc_messages->errmsgs->errmsgs #define CURRENT_THD_ERRMSGS (current_thd)->variables.errmsgs #ifndef mysqld_error_find_printf_error_used #define ER_DEFAULT(X) DEFAULT_ERRMSGS[((X)-ER_ERROR_FIRST) / ERRORS_PER_RANGE][(X)% ERRORS_PER_RANGE] #define ER_THD(thd,X) ((thd)->variables.errmsgs[((X)-ER_ERROR_FIRST) / ERRORS_PER_RANGE][(X) % ERRORS_PER_RANGE]) #define ER(X) ER_THD(current_thd, (X)) #endif #define ER_THD_OR_DEFAULT(thd,X) ((thd) ? ER_THD(thd, (X)) : ER_DEFAULT(X)) #define SPECIAL_USE_LOCKS 1 /* Lock used databases */ #define SPECIAL_NO_NEW_FUNC 2 /* Skip new functions */ #define SPECIAL_SKIP_SHOW_DB 4 /* Don't allow 'show db' */ #define SPECIAL_WAIT_IF_LOCKED 8 /* Wait if locked database */ #define SPECIAL_SAME_DB_NAME 16 /* form name = file name */ #define SPECIAL_ENGLISH 32 /* English error messages */ #define SPECIAL_NO_RESOLVE 64 /* Obsolete */ #define SPECIAL_NO_PRIOR 128 /* Obsolete */ #define SPECIAL_BIG_SELECTS 256 /* Don't use heap tables */ #define SPECIAL_NO_HOST_CACHE 512 /* Don't cache hosts */ #define SPECIAL_SHORT_LOG_FORMAT 1024 #define SPECIAL_SAFE_MODE 2048 #define SPECIAL_LOG_QUERIES_NOT_USING_INDEXES 4096 /* Obsolete */ /* Extern defines */ #define store_record(A,B) memcpy((A)->B,(A)->record[0],(size_t) (A)->s->reclength) #define restore_record(A,B) memcpy((A)->record[0],(A)->B,(size_t) (A)->s->reclength) #define cmp_record(A,B) memcmp((A)->record[0],(A)->B,(size_t) (A)->s->reclength) #define empty_record(A) { \ restore_record((A),s->default_values); \ if ((A)->s->null_bytes) \ bfill((A)->null_flags,(A)->s->null_bytes,255); \ } /* Defines for use with openfrm, openprt and openfrd */ #define READ_ALL (1 << 0) /* openfrm: Read all parameters */ #define EXTRA_RECORD (1 << 3) /* Reserve space for an extra record */ #define DELAYED_OPEN (1 << 12) /* Open table later */ #define OPEN_VIEW_NO_PARSE (1 << 14) /* Open frm only if it's a view, but do not parse view itself */ /** This flag is used in function get_all_tables() which fills I_S tables with data which are retrieved from frm files and storage engine The flag means that we need to open FRM file only to get necessary data. */ #define OPEN_FRM_FILE_ONLY (1 << 15) /** This flag is used in function get_all_tables() which fills I_S tables with data which are retrieved from frm files and storage engine The flag means that we need to process tables only to get necessary data. Views are not processed. */ #define OPEN_TABLE_ONLY (1 << 16) /** This flag is used in function get_all_tables() which fills I_S tables with data which are retrieved from frm files and storage engine The flag means that we need to process views only to get necessary data. Tables are not processed. */ #define OPEN_VIEW_ONLY (1 << 17) /** This flag is used in function get_all_tables() which fills I_S tables with data which are retrieved from frm files and storage engine. The flag means that we need to open a view using open_normal_and_derived_tables() function. */ #define OPEN_VIEW_FULL (1 << 18) /** This flag is used in function get_all_tables() which fills I_S tables with data which are retrieved from frm files and storage engine. The flag means that I_S table uses optimization algorithm. */ #define OPTIMIZE_I_S_TABLE (1 << 19) /** This flag is used to instruct tdc_open_view() to check metadata version. */ #define CHECK_METADATA_VERSION (1 << 20) /* The flag means that we need to process trigger files only. */ #define OPEN_TRIGGER_ONLY (1 << 21) /* Minimum length pattern before Turbo Boyer-Moore is used for SELECT "text" LIKE "%pattern%", excluding the two wildcards in class Item_func_like. */ #define MIN_TURBOBM_PATTERN_LEN 3 /* Defines for binary logging. Do not decrease the value of BIN_LOG_HEADER_SIZE. Do not even increase it before checking code. */ #define BIN_LOG_HEADER_SIZE 4 #define DEFAULT_KEY_CACHE_NAME "default" /* Include prototypes for unireg */ #include "mysqld_error.h" #include "structs.h" /* All structs we need */ #include "sql_list.h" /* List<> */ #include "field.h" /* Create_field */ /* Types of values in the MariaDB extra2 frm segment. Each value is written as type: 1 byte length: 1 byte (1..255) or \0 and 2 bytes. binary value of the 'length' bytes. Older MariaDB servers can ignore values of unknown types if the type code is less than 128 (EXTRA2_ENGINE_IMPORTANT). Otherwise older (but newer than 10.0.1) servers are required to report an error. */ enum extra2_frm_value_type { EXTRA2_TABLEDEF_VERSION=0, EXTRA2_DEFAULT_PART_ENGINE=1, EXTRA2_GIS=2, EXTRA2_APPLICATION_TIME_PERIOD=3, EXTRA2_PERIOD_FOR_SYSTEM_TIME=4, EXTRA2_INDEX_FLAGS=5, #define EXTRA2_ENGINE_IMPORTANT 128 EXTRA2_ENGINE_TABLEOPTS=128, EXTRA2_FIELD_FLAGS=129, EXTRA2_FIELD_DATA_TYPE_INFO=130, EXTRA2_PERIOD_WITHOUT_OVERLAPS=131, }; enum extra2_field_flags { VERS_OPTIMIZED_UPDATE= 1 << INVISIBLE_MAX_BITS, }; enum extra2_index_flags { EXTRA2_DEFAULT_INDEX_FLAGS, EXTRA2_IGNORED_KEY }; static inline size_t extra2_read_len(const uchar **extra2, const uchar *end) { size_t length= *(*extra2)++; if (length) return length; if ((*extra2) + 2 >= end) return 0; length= uint2korr(*extra2); (*extra2)+= 2; if (length < 256 || *extra2 + length > end) return 0; return length; } LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table, HA_CREATE_INFO *create_info, List &create_fields, uint keys, KEY *key_info, handler *db_file); #define FRM_HEADER_SIZE 64 #define FRM_FORMINFO_SIZE 288 #define FRM_MAX_SIZE (1024*1024) static inline bool is_binary_frm_header(uchar *head) { return head[0] == 254 && head[1] == 1 && head[2] >= FRM_VER && head[2] <= FRM_VER_CURRENT; } #endif server/private/sql_sequence.h000064400000012074151031265040012365 0ustar00/* Copyright (c) 2017, MariaDB corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_SEQUENCE_INCLUDED #define SQL_SEQUENCE_INCLUDED #define seq_field_used_min_value 1 #define seq_field_used_max_value 2 #define seq_field_used_start 4 #define seq_field_used_increment 8 #define seq_field_used_cache 16 #define seq_field_used_cycle 32 #define seq_field_used_restart 64 #define seq_field_used_restart_value 128 /* Field position in sequence table for some fields we refer to directly */ #define NEXT_FIELD_NO 0 #define MIN_VALUE_FIELD_NO 1 #define ROUND_FIELD_NO 7 /** sequence_definition is used when defining a sequence as part of create */ class sequence_definition :public Sql_alloc { public: sequence_definition(): min_value(1), max_value(LONGLONG_MAX-1), start(1), increment(1), cache(1000), round(0), restart(0), cycle(0), used_fields(0) {} longlong reserved_until; longlong min_value; longlong max_value; longlong start; longlong increment; longlong cache; ulonglong round; longlong restart; // alter sequence restart value bool cycle; uint used_fields; // Which fields where used in CREATE bool check_and_adjust(bool set_reserved_until); void store_fields(TABLE *table); void read_fields(TABLE *table); int write_initial_sequence(TABLE *table); int write(TABLE *table, bool all_fields); /* This must be called after sequence data has been updated */ void adjust_values(longlong next_value); inline void print_dbug() { DBUG_PRINT("sequence", ("reserved: %lld start: %lld increment: %lld min_value: %lld max_value: %lld cache: %lld round: %lld", reserved_until, start, increment, min_value, max_value, cache, round)); } protected: /* The following values are the values from sequence_definition merged with global auto_increment_offset and auto_increment_increment */ longlong real_increment; longlong next_free_value; }; /** SEQUENCE is in charge of managing the sequence values. It's also responsible to generate new values and updating the sequence table (engine=SQL_SEQUENCE) trough it's specialized handler interface. If increment is 0 then the sequence will be be using auto_increment_increment and auto_increment_offset variables, just like AUTO_INCREMENT is using. */ class SEQUENCE :public sequence_definition { public: enum seq_init { SEQ_UNINTIALIZED, SEQ_IN_PREPARE, SEQ_IN_ALTER, SEQ_READY_TO_USE }; SEQUENCE(); ~SEQUENCE(); int read_initial_values(TABLE *table); int read_stored_values(TABLE *table); void write_lock(TABLE *table); void write_unlock(TABLE *table); void read_lock(TABLE *table); void read_unlock(TABLE *table); void copy(sequence_definition *seq) { sequence_definition::operator= (*seq); adjust_values(reserved_until); all_values_used= 0; } longlong next_value(TABLE *table, bool second_round, int *error); int set_value(TABLE *table, longlong next_value, ulonglong round_arg, bool is_used); longlong increment_value(longlong value) { if (real_increment > 0) { if (value > max_value - real_increment || value + real_increment > max_value) value= max_value + 1; else value+= real_increment; } else { if (value + real_increment < min_value || value < min_value - real_increment) value= min_value - 1; else value+= real_increment; } return value; } bool all_values_used; seq_init initialized; private: mysql_rwlock_t mutex; }; /** Class to cache last value of NEXT VALUE from the sequence */ class SEQUENCE_LAST_VALUE { public: SEQUENCE_LAST_VALUE(uchar *key_arg, uint length_arg) :key(key_arg), length(length_arg) {} ~SEQUENCE_LAST_VALUE() { my_free((void*) key); } /* Returns 1 if table hasn't been dropped or re-created */ bool check_version(TABLE *table); void set_version(TABLE *table); const uchar *key; uint length; bool null_value; longlong value; uchar table_version[MY_UUID_SIZE]; }; class Create_field; extern bool prepare_sequence_fields(THD *thd, List *fields); extern bool check_sequence_fields(LEX *lex, List *fields, const LEX_CSTRING db, const LEX_CSTRING table_name); extern bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list); #endif /* SQL_SEQUENCE_INCLUDED */ server/private/wsrep_mutex.h000064400000002300151031265040012247 0ustar00/* Copyright 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WSREP_MUTEX_H #define WSREP_MUTEX_H /* wsrep-lib */ #include "wsrep/mutex.hpp" /* implementation */ #include "my_pthread.h" class Wsrep_mutex : public wsrep::mutex { public: Wsrep_mutex(mysql_mutex_t* mutex) : m_mutex(mutex) { } void lock() override { mysql_mutex_lock(m_mutex); } void unlock() override { mysql_mutex_unlock(m_mutex); } void* native() override { return m_mutex; } private: mysql_mutex_t* m_mutex; }; #endif /* WSREP_MUTEX_H */ server/private/rpl_constants.h000064400000006435151031265040012573 0ustar00/* Copyright (c) 2007 MySQL AB, 2008 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef RPL_CONSTANTS_H #define RPL_CONSTANTS_H #include #include /** Enumeration of the incidents that can occur for the server. */ enum Incident { /** No incident */ INCIDENT_NONE = 0, /** There are possibly lost events in the replication stream */ INCIDENT_LOST_EVENTS = 1, /** Shall be last event of the enumeration */ INCIDENT_COUNT }; /** Enumeration of the reserved formats of Binlog extra row information */ enum ExtraRowInfoFormat { /** Reserved formats 0 -> 63 inclusive */ ERIF_LASTRESERVED = 63, /** Available / uncontrolled formats 64 -> 254 inclusive */ ERIF_OPEN1 = 64, ERIF_OPEN2 = 65, ERIF_LASTOPEN = 254, /** Multi-payload format 255 Length is total length, payload is sequence of sub-payloads with their own headers containing length + format. */ ERIF_MULTI = 255 }; /* 1 byte length, 1 byte format Length is total length in bytes, including 2 byte header Length values 0 and 1 are currently invalid and reserved. */ #define EXTRA_ROW_INFO_LEN_OFFSET 0 #define EXTRA_ROW_INFO_FORMAT_OFFSET 1 #define EXTRA_ROW_INFO_HDR_BYTES 2 #define EXTRA_ROW_INFO_MAX_PAYLOAD (255 - EXTRA_ROW_INFO_HDR_BYTES) enum enum_binlog_checksum_alg { BINLOG_CHECKSUM_ALG_OFF= 0, // Events are without checksum though its generator // is checksum-capable New Master (NM). BINLOG_CHECKSUM_ALG_CRC32= 1, // CRC32 of zlib algorithm. BINLOG_CHECKSUM_ALG_ENUM_END, // the cut line: valid alg range is [1, 0x7f]. BINLOG_CHECKSUM_ALG_UNDEF= 255 // special value to tag undetermined yet checksum // or events from checksum-unaware servers }; #define BINLOG_CRYPTO_SCHEME_LENGTH 1 #define BINLOG_KEY_VERSION_LENGTH 4 #define BINLOG_IV_LENGTH MY_AES_BLOCK_SIZE #define BINLOG_IV_OFFS_LENGTH 4 #define BINLOG_NONCE_LENGTH (BINLOG_IV_LENGTH - BINLOG_IV_OFFS_LENGTH) struct Binlog_crypt_data { uint scheme; uint key_version, key_length, ctx_size; uchar key[MY_AES_MAX_KEY_LENGTH]; uchar nonce[BINLOG_NONCE_LENGTH]; int init(uint sch, uint kv) { scheme= sch; ctx_size= encryption_ctx_size(ENCRYPTION_KEY_SYSTEM_DATA, kv); key_version= kv; key_length= sizeof(key); return encryption_key_get(ENCRYPTION_KEY_SYSTEM_DATA, kv, key, &key_length); } void set_iv(uchar* iv, uint32 offs) const { memcpy(iv, nonce, BINLOG_NONCE_LENGTH); int4store(iv + BINLOG_NONCE_LENGTH, offs); } }; #endif /* RPL_CONSTANTS_H */ server/private/sql_const.h000064400000025734151031265040011712 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file File containing constants that can be used throughout the server. @note This file shall not contain or include any declarations of any kinds. */ #ifndef SQL_CONST_INCLUDED #define SQL_CONST_INCLUDED #include #define LIBLEN FN_REFLEN-FN_LEN /* Max l{ngd p} dev */ /* extra 4+4 bytes for slave tmp tables */ #define MAX_DBKEY_LENGTH (NAME_LEN*2+1+1+4+4) #define MAX_ALIAS_NAME 256 #define MAX_FIELD_NAME (NAME_LEN+1) /* Max colum name length +1 */ #define MAX_SYS_VAR_LENGTH 32 #define MAX_KEY MAX_INDEXES /* Max used keys */ #define MAX_REF_PARTS 32 /* Max parts used as ref */ /* Maximum length of the data part of an index lookup key. The "data part" is defined as the value itself, not including the NULL-indicator bytes or varchar length bytes ("the Extras"). We need this value because there was a bug where length of the Extras were not counted. You probably need MAX_KEY_LENGTH, not this constant. */ #define MAX_DATA_LENGTH_FOR_KEY 3072 #if SIZEOF_OFF_T > 4 #define MAX_REFLENGTH 8 /* Max length for record ref */ #else #define MAX_REFLENGTH 4 /* Max length for record ref */ #endif #define MAX_HOSTNAME (HOSTNAME_LENGTH + 1) /* len+1 in mysql.user */ #define MAX_CONNECTION_NAME NAME_LEN #define MAX_MBWIDTH 3 /* Max multibyte sequence */ #define MAX_FILENAME_MBWIDTH 5 #define MAX_FIELD_CHARLENGTH 255 /* In MAX_FIELD_VARCHARLENGTH we reserve extra bytes for the overhead: - 2 bytes for the length - 1 byte for NULL bits to avoid the "Row size too large" error for these three corner definitions: CREATE TABLE t1 (c VARBINARY(65533)); CREATE TABLE t1 (c VARBINARY(65534)); CREATE TABLE t1 (c VARBINARY(65535)); Like VARCHAR(65536), they will be converted to BLOB automatically in non-strict mode. */ #define MAX_FIELD_VARCHARLENGTH (65535-2-1) #define MAX_FIELD_BLOBLENGTH UINT_MAX32 /* cf field_blob::get_length() */ #define CONVERT_IF_BIGGER_TO_BLOB 512 /* Threshold *in characters* */ /* Max column width +1 */ #define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1) #define MAX_BIT_FIELD_LENGTH 64 /* Max length in bits for bit fields */ #define MAX_DATE_WIDTH 10 /* YYYY-MM-DD */ #define MIN_TIME_WIDTH 10 /* -HHH:MM:SS */ #define MAX_TIME_WIDTH 16 /* -DDDDDD HH:MM:SS */ #define MAX_TIME_FULL_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */ #define MAX_DATETIME_FULL_WIDTH 26 /* YYYY-MM-DD HH:MM:SS.###### */ #define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */ #define MAX_DATETIME_COMPRESSED_WIDTH 14 /* YYYYMMDDHHMMSS */ #define MAX_DATETIME_PRECISION 6 #define MAX_TABLES (sizeof(table_map)*8-3) /* Max tables in join */ #define PARAM_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-3)) #define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2)) #define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1)) #define PSEUDO_TABLE_BITS (PARAM_TABLE_BIT | OUTER_REF_TABLE_BIT | \ RAND_TABLE_BIT) #define CONNECT_STRING_MAXLEN 65535 /* stored in 2 bytes in .frm */ #define MAX_FIELDS 4096 /* Limit in the .frm file */ #define MAX_PARTITIONS 8192 #define MAX_SELECT_NESTING (SELECT_NESTING_MAP_SIZE - 1) #define MAX_SORT_MEMORY 2048*1024 #define MIN_SORT_MEMORY 1024 /* Some portable defines */ #define STRING_BUFFER_USUAL_SIZE 80 /* Memory allocated when parsing a statement / saving a statement */ #define MEM_ROOT_BLOCK_SIZE 8192 #define MEM_ROOT_PREALLOC 8192 #define TRANS_MEM_ROOT_BLOCK_SIZE 4096 #define TRANS_MEM_ROOT_PREALLOC 4096 #define DEFAULT_ERROR_COUNT 64 #define EXTRA_RECORDS 10 /* Extra records in sort */ #define SCROLL_EXTRA 5 /* Extra scroll-rows. */ #define FIELD_NAME_USED ((uint) 32768) /* Bit set if fieldname used */ #define FORM_NAME_USED ((uint) 16384) /* Bit set if formname used */ #define FIELD_NR_MASK 16383 /* To get fieldnumber */ #define FERR -1 /* Error from my_functions */ #define CREATE_MODE 0 /* Default mode on new files */ #define NAMES_SEP_CHAR 255 /* Char to sep. names */ #define READ_RECORD_BUFFER (uint) (IO_SIZE*8) /* Pointer_buffer_size */ #define DISK_BUFFER_SIZE (uint) (IO_SIZE*16) /* Size of diskbuffer */ #define FRM_VER_TRUE_VARCHAR (FRM_VER+4) /* 10 */ #define FRM_VER_EXPRESSSIONS (FRM_VER+5) /* 11 */ #define FRM_VER_CURRENT FRM_VER_EXPRESSSIONS /*************************************************************************** Configuration parameters ****************************************************************************/ #define ACL_CACHE_SIZE 256 #define MAX_PASSWORD_LENGTH 32 #define HOST_CACHE_SIZE 128 #define MAX_ACCEPT_RETRY 10 // Test accept this many times #define MAX_FIELDS_BEFORE_HASH 32 #define USER_VARS_HASH_SIZE 16 #define SEQUENCES_HASH_SIZE 16 #define TABLE_OPEN_CACHE_MIN 200 #define TABLE_OPEN_CACHE_DEFAULT 2000 #define TABLE_DEF_CACHE_DEFAULT 400 /** We must have room for at least 400 table definitions in the table cache, since otherwise there is no chance prepared statements that use these many tables can work. Prepared statements use table definition cache ids (table_map_id) as table version identifiers. If the table definition cache size is less than the number of tables used in a statement, the contents of the table definition cache is guaranteed to rotate between a prepare and execute. This leads to stable validation errors. In future we shall use more stable version identifiers, for now the only solution is to ensure that the table definition cache can contain at least all tables of a given statement. */ #define TABLE_DEF_CACHE_MIN 400 /** Maximum number of connections default value. 151 is larger than Apache's default max children, to avoid "too many connections" error in a common setup. */ #define MAX_CONNECTIONS_DEFAULT 151 /* Stack reservation. Feel free to raise this by the smallest amount you can to get the "execution_constants" test to pass. */ #define STACK_MIN_SIZE 16000 // Abort if less stack during eval. #define STACK_MIN_SIZE_FOR_OPEN (1024*80) #define STACK_BUFF_ALLOC 352 ///< For stack overrun checks #ifndef MYSQLD_NET_RETRY_COUNT #define MYSQLD_NET_RETRY_COUNT 10 ///< Abort read after this many int. #endif /* Allocations with MEM_ROOT. We should try to keep these as powers of 2 and not higher than 32768 to get full benefit of allocators like tcmalloc that will for these use a local heap without locks. */ #define QUERY_ALLOC_BLOCK_SIZE 32768 #define QUERY_ALLOC_PREALLOC_SIZE 32768 /* 65536 could be better */ #define TRANS_ALLOC_BLOCK_SIZE 8192 #define TRANS_ALLOC_PREALLOC_SIZE 4096 #define RANGE_ALLOC_BLOCK_SIZE 4096 #define ACL_ALLOC_BLOCK_SIZE 1024 #define UDF_ALLOC_BLOCK_SIZE 1024 #define TABLE_PREALLOC_BLOCK_SIZE 8192 #define TABLE_ALLOC_BLOCK_SIZE 4096 #define WARN_ALLOC_BLOCK_SIZE 2048 #define WARN_ALLOC_PREALLOC_SIZE 1024 #define TMP_TABLE_BLOCK_SIZE 16384 #define TMP_TABLE_PREALLOC_SIZE 32768 #define SHOW_ALLOC_BLOCK_SIZE 32768 /* The following parameters is to decide when to use an extra cache to optimise seeks when reading a big table in sorted order */ #define MIN_FILE_LENGTH_TO_USE_ROW_CACHE (10L*1024*1024) #define MIN_ROWS_TO_USE_TABLE_CACHE 100 #define MIN_ROWS_TO_USE_BULK_INSERT 100 /** The following is used to decide if MySQL should use table scanning instead of reading with keys. The number says how many evaluation of the WHERE clause is comparable to reading one extra row from a table. */ #define TIME_FOR_COMPARE 5.0 // 5 WHERE compares == one read #define TIME_FOR_COMPARE_IDX 20.0 #define IDX_BLOCK_COPY_COST ((double) 1 / TIME_FOR_COMPARE) #define IDX_LOOKUP_COST ((double) 1 / 8) #define MULTI_RANGE_READ_SETUP_COST (IDX_BLOCK_COPY_COST/10) /** Number of comparisons of table rowids equivalent to reading one row from a table. */ #define TIME_FOR_COMPARE_ROWID (TIME_FOR_COMPARE*100) /* cost1 is better that cost2 only if cost1 + COST_EPS < cost2 */ #define COST_EPS 0.001 /* For sequential disk seeks the cost formula is: DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST * #blocks_to_skip The cost of average seek DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST*BLOCKS_IN_AVG_SEEK =1.0. */ #define DISK_SEEK_BASE_COST ((double)0.9) #define BLOCKS_IN_AVG_SEEK 128 #define DISK_SEEK_PROP_COST ((double)0.1/BLOCKS_IN_AVG_SEEK) /** Number of rows in a reference table when refereed through a not unique key. This value is only used when we don't know anything about the key distribution. */ #define MATCHING_ROWS_IN_OTHER_TABLE 10 /* Subquery materialization-related constants */ #define HEAP_TEMPTABLE_LOOKUP_COST 0.05 #define DISK_TEMPTABLE_LOOKUP_COST 1.0 #define SORT_INDEX_CMP_COST 0.02 #define COST_MAX (DBL_MAX * (1.0 - DBL_EPSILON)) #define COST_ADD(c,d) (COST_MAX - (d) > (c) ? (c) + (d) : COST_MAX) #define COST_MULT(c,f) (COST_MAX / (f) > (c) ? (c) * (f) : COST_MAX) #define MY_CHARSET_BIN_MB_MAXLEN 1 /** Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used). */ #define KEY_DEFAULT_PACK_LENGTH 8 /** Characters shown for the command in 'show processlist'. */ #define PROCESS_LIST_WIDTH 100 /* Characters shown for the command in 'information_schema.processlist' */ #define PROCESS_LIST_INFO_WIDTH 65535 #define PRECISION_FOR_DOUBLE 53 #define PRECISION_FOR_FLOAT 24 /* -[digits].E+## */ #define MAX_FLOAT_STR_LENGTH (FLT_DIG + 6) /* -[digits].E+### */ #define MAX_DOUBLE_STR_LENGTH (DBL_DIG + 7) /* Default time to wait before aborting a new client connection that does not respond to "initial server greeting" timely */ #define CONNECT_TIMEOUT 10 /* Wait 5 minutes before removing thread from thread cache */ #define THREAD_CACHE_TIMEOUT 5*60 /* The following can also be changed from the command line */ #define DEFAULT_CONCURRENCY 10 #define DELAYED_LIMIT 100 /**< pause after xxx inserts */ #define DELAYED_QUEUE_SIZE 1000 #define DELAYED_WAIT_TIMEOUT (5*60) /**< Wait for delayed insert */ #define MAX_CONNECT_ERRORS 100 ///< errors before disabling host #define LONG_TIMEOUT ((ulong) 3600L*24L*365L) /** Maximum length of time zone name that we support (Time zone name is char(64) in db). mysqlbinlog needs it. */ #define MAX_TIME_ZONE_NAME_LENGTH (NAME_LEN + 1) #define SP_PSI_STATEMENT_INFO_COUNT 19 #endif /* SQL_CONST_INCLUDED */ server/private/repl_failsafe.h000064400000003061151031265040012466 0ustar00#ifndef REPL_FAILSAFE_INCLUDED #define REPL_FAILSAFE_INCLUDED /* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef HAVE_REPLICATION #include "mysql.h" #include #include "slave.h" extern Atomic_counter binlog_dump_thread_count; typedef enum {RPL_AUTH_MASTER=0,RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE, RPL_LOST_SOLDIER,RPL_TROOP_SOLDIER, RPL_RECOVERY_CAPTAIN,RPL_NULL /* inactive */, RPL_ANY /* wild card used by change_rpl_status */ } RPL_STATUS; extern ulong rpl_status; extern mysql_mutex_t LOCK_rpl_status; extern mysql_cond_t COND_rpl_status; extern TYPELIB rpl_role_typelib; extern const char* rpl_role_type[], *rpl_status_type[]; void change_rpl_status(ulong from_status, ulong to_status); int find_recovery_captain(THD* thd, MYSQL* mysql); bool show_slave_hosts(THD* thd); #endif /* HAVE_REPLICATION */ #endif /* REPL_FAILSAFE_INCLUDED */ server/private/sql_servers.h000064400000003361151031265040012245 0ustar00#ifndef SQL_SERVERS_INCLUDED #define SQL_SERVERS_INCLUDED /* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "slave.h" // for tables_ok(), rpl_filter class THD; typedef struct st_lex_server_options LEX_SERVER_OPTIONS; typedef struct st_mem_root MEM_ROOT; /* structs */ typedef struct st_federated_server { const char *server_name; long port; size_t server_name_length; const char *db, *scheme, *username, *password, *socket, *owner, *host, *sport; } FOREIGN_SERVER; /* cache handlers */ bool servers_init(bool dont_read_server_table); bool servers_reload(THD *thd); void servers_free(bool end=0); /* insert functions */ int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options); /* drop functions */ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options); /* update functions */ int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options); /* lookup functions */ FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name, FOREIGN_SERVER *server_buffer); #endif /* SQL_SERVERS_INCLUDED */ server/private/sql_list.h000064400000053672151031265040011541 0ustar00#ifndef INCLUDES_MYSQL_SQL_LIST_H #define INCLUDES_MYSQL_SQL_LIST_H /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_alloc.h" #include /** Simple intrusive linked list. @remark Similar in nature to base_list, but intrusive. It keeps a a pointer to the first element in the list and a indirect reference to the last element. */ template class SQL_I_List :public Sql_alloc { public: uint elements; /** The first element in the list. */ T *first; /** A reference to the next element in the list. */ T **next; SQL_I_List() { empty(); } SQL_I_List(const SQL_I_List &tmp) : Sql_alloc() { elements= tmp.elements; first= tmp.first; next= elements ? tmp.next : &first; } SQL_I_List& operator=(const SQL_I_List &tmp) { elements= tmp.elements; first= tmp.first; next= elements ? tmp.next : &first;; return *this; } inline void empty() { elements= 0; first= NULL; next= &first; } inline void link_in_list(T *element, T **next_ptr) { elements++; (*next)= element; next= next_ptr; *next= NULL; } inline void save_and_clear(SQL_I_List *save) { *save= *this; empty(); } inline void push_front(SQL_I_List *save) { /* link current list last */ *save->next= first; first= save->first; elements+= save->elements; } inline void push_back(SQL_I_List *save) { if (save->first) { *next= save->first; next= save->next; elements+= save->elements; } } }; /* Basic single linked list Used for item and item_buffs. All list ends with a pointer to the 'end_of_list' element, which data pointer is a null pointer and the next pointer points to itself. This makes it very fast to traverse lists as we don't have to test for a specialend condition for list that can't contain a null pointer. */ /** list_node - a node of a single-linked list. @note We never call a destructor for instances of this class. */ struct list_node :public Sql_alloc { list_node *next; void *info; list_node(const void *info_par, list_node *next_par) :next(next_par), info(const_cast(info_par)) {} list_node() /* For end_of_list */ { info= 0; next= this; } }; extern MYSQL_PLUGIN_IMPORT list_node end_of_list; class base_list :public Sql_alloc { protected: list_node *first,**last; public: uint elements; bool operator==(const base_list &rhs) const { return elements == rhs.elements && first == rhs.first && last == rhs.last; } base_list& operator=(const base_list &rhs) { elements= rhs.elements; first= rhs.first; last= elements ? rhs.last : &first; return *this; } inline void empty() { elements=0; first= &end_of_list; last=&first;} inline base_list() { empty(); } /** This is a shallow copy constructor that implicitly passes the ownership from the source list to the new instance. The old instance is not updated, so both objects end up sharing the same nodes. If one of the instances then adds or removes a node, the other becomes out of sync ('last' pointer), while still operational. Some old code uses and relies on this behaviour. This logic is quite tricky: please do not use it in any new code. */ inline base_list(const base_list &tmp) :Sql_alloc() { *this= tmp; } /** Construct a deep copy of the argument in memory root mem_root. The elements themselves are copied by pointer. If you also need to copy elements by value, you should employ list_copy_and_replace_each_value after creating a copy. */ bool copy(const base_list *rhs, MEM_ROOT *mem_root); base_list(const base_list &rhs, MEM_ROOT *mem_root) { copy(&rhs, mem_root); } inline base_list(bool) {} inline bool push_back(void *info) { if (((*last)=new list_node(info, &end_of_list))) { last= &(*last)->next; elements++; return 0; } return 1; } inline bool push_back(void *info, MEM_ROOT *mem_root) { if (((*last)=new (mem_root) list_node(info, &end_of_list))) { last= &(*last)->next; elements++; return 0; } return 1; } bool push_front_impl(list_node *node) { if (node) { if (last == &first) last= &node->next; first=node; elements++; return 0; } return 1; } inline bool push_front(void *info) { return push_front_impl(new list_node(info, first)); } inline bool push_front(void *info, MEM_ROOT *mem_root) { return push_front_impl(new (mem_root) list_node(info,first)); } void remove(list_node **prev) { list_node *node=(*prev)->next; if (!--elements) last= &first; else if (last == &(*prev)->next) last= prev; delete *prev; *prev=node; } inline void append(base_list *list) { if (!list->is_empty()) { if (is_empty()) { *this= *list; return; } *last= list->first; last= list->last; elements+= list->elements; } } inline void *pop(void) { if (first == &end_of_list) return 0; list_node *tmp=first; first=first->next; if (!--elements) last= &first; return tmp->info; } /* Remove from this list elements that are contained in the passed list. We assume that the passed list is a tail of this list (that is, the whole list_node* elements are shared). */ inline void disjoin(const base_list *list) { list_node **prev= &first; list_node *node= first; list_node *list_first= list->first; elements=0; while (node != &end_of_list && node != list_first) { prev= &node->next; node= node->next; elements++; if (node == &end_of_list) return; } *prev= &end_of_list; last= prev; } inline void prepend(base_list *list) { if (!list->is_empty()) { if (is_empty()) last= list->last; *list->last= first; first= list->first; elements+= list->elements; } } /** Swap two lists. */ inline void swap(base_list &rhs) { list_node **rhs_last=rhs.last; swap_variables(list_node *, first, rhs.first); swap_variables(uint, elements, rhs.elements); rhs.last= last == &first ? &rhs.first : last; last = rhs_last == &rhs.first ? &first : rhs_last; } inline list_node* last_node() { return *last; } inline list_node* first_node() { return first;} inline void *head() { return first->info; } inline void **head_ref() { return first != &end_of_list ? &first->info : 0; } inline bool is_empty() { return first == &end_of_list ; } inline list_node *last_ref() { return &end_of_list; } template inline bool add_unique(T *info, bool (*eq)(T *a, T *b)) { list_node *node= first; for (; node != &end_of_list && (!(*eq)(static_cast(node->info), info)); node= node->next) ; if (node == &end_of_list) return push_back(info); return 1; } friend class base_list_iterator; friend class error_list; friend class error_list_iterator; /* Return N-th element in the list, or NULL if the list has less than N elements. */ void *elem(uint n) { list_node *node= first; void *data= NULL; for (uint i= 0; i <= n; i++) { if (node == &end_of_list) { data= NULL; break; } data= node->info; node= node->next; } return data; } #ifdef LIST_EXTRA_DEBUG /* Check list invariants and print results into trace. Invariants are: - (*last) points to end_of_list - There are no NULLs in the list. - base_list::elements is the number of elements in the list. SYNOPSIS check_list() name Name to print to trace file RETURN 1 The list is Ok. 0 List invariants are not met. */ bool check_list(const char *name) { base_list *list= this; list_node *node= first; uint cnt= 0; while (node->next != &end_of_list) { if (!node->info) { DBUG_PRINT("list_invariants",("%s: error: NULL element in the list", name)); return FALSE; } node= node->next; cnt++; } if (last != &(node->next)) { DBUG_PRINT("list_invariants", ("%s: error: wrong last pointer", name)); return FALSE; } if (cnt+1 != elements) { DBUG_PRINT("list_invariants", ("%s: error: wrong element count", name)); return FALSE; } DBUG_PRINT("list_invariants", ("%s: list is ok", name)); return TRUE; } #endif // LIST_EXTRA_DEBUG protected: void after(const void *info, list_node *node) { list_node *new_node=new list_node(info,node->next); node->next=new_node; elements++; if (last == &(node->next)) last= &new_node->next; } }; class base_list_iterator { protected: base_list *list; list_node **el,**prev,*current; void sublist(base_list &ls, uint elm) { ls.first= *el; ls.last= list->last; ls.elements= elm; } public: base_list_iterator() :list(0), el(0), prev(0), current(0) {} base_list_iterator(base_list &list_par) { init(list_par); } inline void init(base_list &list_par) { list= &list_par; el= &list_par.first; prev= 0; current= 0; } inline void *next(void) { prev=el; current= *el; el= ¤t->next; return current->info; } /* Get what calling next() would return, without moving the iterator */ inline void *peek() { return (*el)->info; } inline void *next_fast(void) { list_node *tmp; tmp= *el; el= &tmp->next; return tmp->info; } inline void rewind(void) { el= &list->first; } inline void *replace(const void *element) { // Return old element void *tmp=current->info; DBUG_ASSERT(current->info != 0); current->info= const_cast(element); return tmp; } void *replace(base_list &new_list) { void *ret_value=current->info; if (!new_list.is_empty()) { *new_list.last=current->next; current->info=new_list.first->info; current->next=new_list.first->next; if ((list->last == ¤t->next) && (new_list.elements > 1)) list->last= new_list.last; list->elements+=new_list.elements-1; } return ret_value; // return old element } inline void remove(void) // Remove current { list->remove(prev); el=prev; current=0; // Safeguard } void after(const void *element) // Insert element after current { list->after(element,current); current=current->next; el= ¤t->next; } inline void **ref(void) // Get reference pointer { return ¤t->info; } inline bool is_last(void) { return el == &list->last_ref()->next; } inline bool at_end() { return current == &end_of_list; } friend class error_list_iterator; }; template class List :public base_list { public: inline List() :base_list() {} inline List(const List &tmp, MEM_ROOT *mem_root) : base_list(tmp, mem_root) {} inline bool push_back(T *a) { return base_list::push_back(a); } inline bool push_back(T *a, MEM_ROOT *mem_root) { return base_list::push_back((void*) a, mem_root); } inline bool push_front(T *a) { return base_list::push_front(a); } inline bool push_front(T *a, MEM_ROOT *mem_root) { return base_list::push_front((void*) a, mem_root); } inline T* head() {return (T*) base_list::head(); } inline T** head_ref() {return (T**) base_list::head_ref(); } inline T* pop() {return (T*) base_list::pop(); } inline void append(List *list) { base_list::append(list); } inline void prepend(List *list) { base_list::prepend(list); } inline void disjoin(List *list) { base_list::disjoin(list); } inline bool add_unique(T *a, bool (*eq)(T *a, T *b)) { return base_list::add_unique(a, eq); } inline bool copy(const List *list, MEM_ROOT *root) { return base_list::copy(list, root); } void delete_elements(void) { list_node *element,*next; for (element=first; element != &end_of_list; element=next) { next=element->next; delete (T*) element->info; } empty(); } T *elem(uint n) { return (T*) base_list::elem(n); } // Create a new list with one element static List *make(MEM_ROOT *mem_root, T *first) { List *res= new (mem_root) List; return res == NULL || res->push_back(first, mem_root) ? NULL : res; } class Iterator; using value_type= T; using iterator= Iterator; iterator begin() const { return iterator(first); } iterator end() const { return iterator(); } class Iterator { public: using iterator_category= std::forward_iterator_tag; using value_type= T; using difference_type= std::ptrdiff_t; using pointer= T *; using reference= T &; Iterator(list_node *p= &end_of_list) : node{p} {} Iterator &operator++() { DBUG_ASSERT(node != &end_of_list); node= node->next; return *this; } Iterator operator++(int) { Iterator tmp(*this); operator++(); return tmp; } T &operator*() { return *static_cast(node->info); } T *operator->() { return static_cast(node->info); } bool operator==(const typename List::iterator &rhs) { return node == rhs.node; } bool operator!=(const typename List::iterator &rhs) { return node != rhs.node; } private: list_node *node{&end_of_list}; }; }; template class List_iterator :public base_list_iterator { public: List_iterator(List &a) : base_list_iterator(a) {} List_iterator() : base_list_iterator() {} inline void init(List &a) { base_list_iterator::init(a); } inline T* operator++(int) { return (T*) base_list_iterator::next(); } inline T* peek() { return (T*) base_list_iterator::peek(); } inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); } inline T *replace(List &a) { return (T*) base_list_iterator::replace(a); } inline void rewind(void) { base_list_iterator::rewind(); } inline void remove() { base_list_iterator::remove(); } inline void after(T *a) { base_list_iterator::after(a); } inline T** ref(void) { return (T**) base_list_iterator::ref(); } }; template class List_iterator_fast :public base_list_iterator { protected: inline T *replace(T *) { return (T*) 0; } inline T *replace(List &) { return (T*) 0; } inline void remove(void) {} inline void after(T *) {} inline T** ref(void) { return (T**) 0; } public: inline List_iterator_fast(List &a) : base_list_iterator(a) {} inline List_iterator_fast() : base_list_iterator() {} inline void init(List &a) { base_list_iterator::init(a); } inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); } inline void rewind(void) { base_list_iterator::rewind(); } void sublist(List &list_arg, uint el_arg) { base_list_iterator::sublist(list_arg, el_arg); } }; /* Bubble sort algorithm for List. This sort function is supposed to be used only for very short list. Currently it is used for the lists of Item_equal objects and for some lists in the table elimination algorithms. In both cases the sorted lists are very short. */ template inline void bubble_sort(List *list_to_sort, int (*sort_func)(T *a, T *b, void *arg), void *arg) { bool swap; T **ref1= 0; T **ref2= 0; List_iterator it(*list_to_sort); do { T **last_ref= ref1; T *item1= it++; ref1= it.ref(); T *item2; swap= FALSE; while ((item2= it++) && (ref2= it.ref()) != last_ref) { if (sort_func(item1, item2, arg) > 0) { *ref1= item2; *ref2= item1; swap= TRUE; } else item1= item2; ref1= ref2; } it.rewind(); } while (swap); } /* A simple intrusive list which automaticly removes element from list on delete (for THD element) */ struct ilink { struct ilink **prev,*next; static void *operator new(size_t size) throw () { return (void*)my_malloc(PSI_INSTRUMENT_ME, (uint)size, MYF(MY_WME | MY_FAE | ME_FATAL)); } static void operator delete(void* ptr_arg, size_t) { my_free(ptr_arg); } inline ilink() { prev=0; next=0; } inline void unlink() { /* Extra tests because element doesn't have to be linked */ if (prev) *prev= next; if (next) next->prev=prev; prev=0 ; next=0; } inline void assert_linked() { DBUG_ASSERT(prev != 0 && next != 0); } inline void assert_not_linked() { DBUG_ASSERT(prev == 0 && next == 0); } virtual ~ilink() { unlink(); } /*lint -e1740 */ }; /* Needed to be able to have an I_List of char* strings in mysqld.cc. */ class i_string: public ilink { public: const char* ptr; i_string():ptr(0) { } i_string(const char* s) : ptr(s) {} }; /* needed for linked list of two strings for replicate-rewrite-db */ class i_string_pair: public ilink { public: const char* key; const char* val; i_string_pair():key(0),val(0) { } i_string_pair(const char* key_arg, const char* val_arg) : key(key_arg),val(val_arg) {} }; template class I_List_iterator; class base_ilist { struct ilink *first; struct ilink last; public: inline void empty() { first= &last; last.prev= &first; } base_ilist() { empty(); } inline bool is_empty() { return first == &last; } // Returns true if p is the last "real" object in the list, // i.e. p->next points to the sentinel. inline bool is_last(ilink *p) { return p->next == NULL || p->next == &last; } inline void append(ilink *a) { first->prev= &a->next; a->next=first; a->prev= &first; first=a; } inline void push_back(ilink *a) { *last.prev= a; a->next= &last; a->prev= last.prev; last.prev= &a->next; } inline struct ilink *get() { struct ilink *first_link=first; if (first_link == &last) return 0; first_link->unlink(); // Unlink from list return first_link; } inline struct ilink *head() { return (first != &last) ? first : 0; } /** Moves list elements to new owner, and empties current owner (i.e. this). @param[in,out] new_owner The new owner of the list elements. Should be empty in input. */ void move_elements_to(base_ilist *new_owner) { DBUG_ASSERT(new_owner->is_empty()); new_owner->first= first; new_owner->last= last; empty(); } friend class base_ilist_iterator; private: /* We don't want to allow copying of this class, as that would give us two list heads containing the same elements. So we declare, but don't define copy CTOR and assignment operator. */ base_ilist(const base_ilist&); void operator=(const base_ilist&); }; class base_ilist_iterator { base_ilist *list; struct ilink **el; protected: struct ilink *current; public: base_ilist_iterator(base_ilist &list_par) :list(&list_par), el(&list_par.first),current(0) {} void *next(void) { /* This is coded to allow push_back() while iterating */ current= *el; if (current == &list->last) return 0; el= ¤t->next; return current; } /* Unlink element returned by last next() call */ inline void unlink(void) { struct ilink **tmp= current->prev; current->unlink(); el= tmp; } }; template class I_List :private base_ilist { public: I_List() :base_ilist() {} inline bool is_last(T *p) { return base_ilist::is_last(p); } inline void empty() { base_ilist::empty(); } inline bool is_empty() { return base_ilist::is_empty(); } inline void append(T* a) { base_ilist::append(a); } inline void push_back(T* a) { base_ilist::push_back(a); } inline T* get() { return (T*) base_ilist::get(); } inline T* head() { return (T*) base_ilist::head(); } inline void move_elements_to(I_List* new_owner) { base_ilist::move_elements_to(new_owner); } #ifndef _lint friend class I_List_iterator; #endif }; template class I_List_iterator :public base_ilist_iterator { public: I_List_iterator(I_List &a) : base_ilist_iterator(a) {} inline T* operator++(int) { return (T*) base_ilist_iterator::next(); } /* Remove element returned by last next() call */ inline void remove(void) { unlink(); delete (T*) current; current= 0; // Safety } }; /** Make a deep copy of each list element. @note A template function and not a template method of class List is employed because of explicit template instantiation: in server code there are explicit instantiations of List and an explicit instantiation of a template requires that any method of the instantiated class used in the template can be resolved. Evidently not all template arguments have clone() method with the right signature. @return You must query the error state in THD for out-of-memory situation after calling this function. */ template inline void list_copy_and_replace_each_value(List &list, MEM_ROOT *mem_root) { /* Make a deep copy of each element */ List_iterator it(list); T *el; while ((el= it++)) it.replace(el->clone(mem_root)); } void free_list(I_List *list); void free_list(I_List *list); #endif // INCLUDES_MYSQL_SQL_LIST_H server/private/sql_audit.h000064400000033167151031265040011671 0ustar00#ifndef SQL_AUDIT_INCLUDED #define SQL_AUDIT_INCLUDED /* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include #include "sql_class.h" extern unsigned long mysql_global_audit_mask[]; extern void mysql_audit_initialize(); extern void mysql_audit_finalize(); extern void mysql_audit_init_thd(THD *thd); extern void mysql_audit_free_thd(THD *thd); extern void mysql_audit_acquire_plugins(THD *thd, ulong *event_class_mask); #ifndef EMBEDDED_LIBRARY extern void mysql_audit_notify(THD *thd, uint event_class, const void *event); static inline bool mysql_audit_general_enabled() { return mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK; } static inline bool mysql_audit_connection_enabled() { return mysql_global_audit_mask[0] & MYSQL_AUDIT_CONNECTION_CLASSMASK; } static inline bool mysql_audit_table_enabled() { return mysql_global_audit_mask[0] & MYSQL_AUDIT_TABLE_CLASSMASK; } #else static inline void mysql_audit_notify(THD *thd, uint event_class, const void *event) {} #define mysql_audit_general_enabled() 0 #define mysql_audit_connection_enabled() 0 #define mysql_audit_table_enabled() 0 #endif extern my_bool mysql_audit_release_required(THD *thd); extern void mysql_audit_release(THD *thd); static inline unsigned int strlen_uint(const char *s) { return (uint)strlen(s); } static inline unsigned int safe_strlen_uint(const char *s) { return (uint)safe_strlen(s); } #define MAX_USER_HOST_SIZE 512 static inline uint make_user_name(THD *thd, char *buf) { const Security_context *sctx= thd->security_ctx; char *end= strxnmov(buf, MAX_USER_HOST_SIZE, sctx->priv_user[0] ? sctx->priv_user : "", "[", sctx->user ? sctx->user : "", "] @ ", sctx->host ? sctx->host : "", " [", sctx->ip ? sctx->ip : "", "]", NullS); return (uint)(end-buf); } /** Call audit plugins of GENERAL audit class, MYSQL_AUDIT_GENERAL_LOG subtype. @param[in] thd @param[in] time time that event occurred @param[in] user User name @param[in] userlen User name length @param[in] cmd Command name @param[in] cmdlen Command name length @param[in] query Query string @param[in] querylen Query string length */ static inline void mysql_audit_general_log(THD *thd, time_t time, const char *user, uint userlen, const char *cmd, uint cmdlen, const char *query, uint querylen) { if (mysql_audit_general_enabled()) { mysql_event_general event; event.event_subclass= MYSQL_AUDIT_GENERAL_LOG; event.general_error_code= 0; event.general_time= time; event.general_user= user; event.general_user_length= userlen; event.general_command= cmd; event.general_command_length= cmdlen; event.general_query= query; event.general_query_length= querylen; event.general_rows= 0; if (thd) { event.general_thread_id= (unsigned long)thd->thread_id; event.general_charset= thd->variables.character_set_client; event.database= thd->db; event.query_id= thd->query_id; } else { event.general_thread_id= 0; event.general_charset= global_system_variables.character_set_client; event.database= null_clex_str; event.query_id= 0; } mysql_audit_notify(thd, MYSQL_AUDIT_GENERAL_CLASS, &event); } } /** Call audit plugins of GENERAL audit class. event_subtype should be set to one of: MYSQL_AUDIT_GENERAL_ERROR MYSQL_AUDIT_GENERAL_RESULT MYSQL_AUDIT_GENERAL_STATUS @param[in] thd @param[in] event_subtype Type of general audit event. @param[in] error_code Error code @param[in] msg Message */ static inline void mysql_audit_general(THD *thd, uint event_subtype, int error_code, const char *msg) { DBUG_ENTER("mysql_audit_general"); if (mysql_audit_general_enabled()) { char user_buff[MAX_USER_HOST_SIZE+1]; mysql_event_general event; event.event_subclass= event_subtype; event.general_error_code= error_code; event.general_time= my_time(0); event.general_command= msg; event.general_command_length= safe_strlen_uint(msg); if (thd) { event.general_user= user_buff; event.general_user_length= make_user_name(thd, user_buff); event.general_thread_id= (unsigned long)thd->thread_id; event.general_query= thd->query_string.str(); event.general_query_length= (unsigned) thd->query_string.length(); event.general_charset= thd->query_string.charset(); event.general_rows= thd->get_stmt_da()->current_row_for_warning(); event.database= thd->db; event.query_id= thd->query_id; } else { event.general_user= NULL; event.general_user_length= 0; event.general_thread_id= 0; event.general_query= NULL; event.general_query_length= 0; event.general_charset= &my_charset_bin; event.general_rows= 0; event.database= null_clex_str; event.query_id= 0; } mysql_audit_notify(thd, MYSQL_AUDIT_GENERAL_CLASS, &event); } DBUG_VOID_RETURN; } static inline void mysql_audit_notify_connection_connect(THD *thd) { if (mysql_audit_connection_enabled()) { const Security_context *sctx= thd->security_ctx; mysql_event_connection event; event.event_subclass= MYSQL_AUDIT_CONNECTION_CONNECT; event.status= thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0; event.thread_id= (unsigned long)thd->thread_id; event.user= sctx->user; event.user_length= safe_strlen_uint(sctx->user); event.priv_user= sctx->priv_user; event.priv_user_length= strlen_uint(sctx->priv_user); event.external_user= sctx->external_user; event.external_user_length= safe_strlen_uint(sctx->external_user); event.proxy_user= sctx->proxy_user; event.proxy_user_length= strlen_uint(sctx->proxy_user); event.host= sctx->host; event.host_length= safe_strlen_uint(sctx->host); event.ip= sctx->ip; event.ip_length= safe_strlen_uint(sctx->ip); event.database= thd->db; mysql_audit_notify(thd, MYSQL_AUDIT_CONNECTION_CLASS, &event); } } static inline void mysql_audit_notify_connection_disconnect(THD *thd, int errcode) { if (mysql_audit_connection_enabled()) { const Security_context *sctx= thd->security_ctx; mysql_event_connection event; event.event_subclass= MYSQL_AUDIT_CONNECTION_DISCONNECT; event.status= errcode; event.thread_id= (unsigned long)thd->thread_id; event.user= sctx->user; event.user_length= safe_strlen_uint(sctx->user); event.priv_user= sctx->priv_user; event.priv_user_length= strlen_uint(sctx->priv_user); event.external_user= sctx->external_user; event.external_user_length= safe_strlen_uint(sctx->external_user); event.proxy_user= sctx->proxy_user; event.proxy_user_length= strlen_uint(sctx->proxy_user); event.host= sctx->host; event.host_length= safe_strlen_uint(sctx->host); event.ip= sctx->ip; event.ip_length= safe_strlen_uint(sctx->ip) ; event.database= thd->db; mysql_audit_notify(thd, MYSQL_AUDIT_CONNECTION_CLASS, &event); } } static inline void mysql_audit_notify_connection_change_user(THD *thd, const Security_context *old_ctx) { if (mysql_audit_connection_enabled()) { mysql_event_connection event; event.event_subclass= MYSQL_AUDIT_CONNECTION_CHANGE_USER; event.status= thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0; event.thread_id= (unsigned long)thd->thread_id; event.user= old_ctx->user; event.user_length= safe_strlen_uint(old_ctx->user); event.priv_user= old_ctx->priv_user; event.priv_user_length= strlen_uint(old_ctx->priv_user); event.external_user= old_ctx->external_user; event.external_user_length= safe_strlen_uint(old_ctx->external_user); event.proxy_user= old_ctx->proxy_user; event.proxy_user_length= strlen_uint(old_ctx->proxy_user); event.host= old_ctx->host; event.host_length= safe_strlen_uint(old_ctx->host); event.ip= old_ctx->ip; event.ip_length= safe_strlen_uint(old_ctx->ip); event.database= thd->db; mysql_audit_notify(thd, MYSQL_AUDIT_CONNECTION_CLASS, &event); } } static inline void mysql_audit_external_lock_ex(THD *thd, my_thread_id thread_id, const char *user, const char *host, const char *ip, query_id_t query_id, TABLE_SHARE *share, int lock) { if (lock != F_UNLCK && mysql_audit_table_enabled()) { const Security_context *sctx= thd->security_ctx; mysql_event_table event; event.event_subclass= MYSQL_AUDIT_TABLE_LOCK; event.read_only= lock == F_RDLCK; event.thread_id= (unsigned long)thread_id; event.user= user; event.priv_user= sctx->priv_user; event.priv_host= sctx->priv_host; event.external_user= sctx->external_user; event.proxy_user= sctx->proxy_user; event.host= host; event.ip= ip; event.database= share->db; event.table= share->table_name; event.new_database= null_clex_str; event.new_table= null_clex_str; event.query_id= query_id; mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, &event); } } static inline void mysql_audit_external_lock(THD *thd, TABLE_SHARE *share, int lock) { mysql_audit_external_lock_ex(thd, thd->thread_id, thd->security_ctx->user, thd->security_ctx->host, thd->security_ctx->ip, thd->query_id, share, lock); } static inline void mysql_audit_create_table(TABLE *table) { if (mysql_audit_table_enabled()) { THD *thd= table->in_use; const TABLE_SHARE *share= table->s; const Security_context *sctx= thd->security_ctx; mysql_event_table event; event.event_subclass= MYSQL_AUDIT_TABLE_CREATE; event.read_only= 0; event.thread_id= (unsigned long)thd->thread_id; event.user= sctx->user; event.priv_user= sctx->priv_user; event.priv_host= sctx->priv_host; event.external_user= sctx->external_user; event.proxy_user= sctx->proxy_user; event.host= sctx->host; event.ip= sctx->ip; event.database= share->db; event.table= share->table_name; event.new_database= null_clex_str; event.new_table= null_clex_str; event.query_id= thd->query_id; mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, &event); } } static inline void mysql_audit_drop_table(THD *thd, TABLE_LIST *table) { if (mysql_audit_table_enabled()) { const Security_context *sctx= thd->security_ctx; mysql_event_table event; event.event_subclass= MYSQL_AUDIT_TABLE_DROP; event.read_only= 0; event.thread_id= (unsigned long)thd->thread_id; event.user= sctx->user; event.priv_user= sctx->priv_user; event.priv_host= sctx->priv_host; event.external_user= sctx->external_user; event.proxy_user= sctx->proxy_user; event.host= sctx->host; event.ip= sctx->ip; event.database= table->db; event.table= table->table_name; event.new_database= null_clex_str; event.new_table= null_clex_str; event.query_id= thd->query_id; mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, &event); } } static inline void mysql_audit_rename_table(THD *thd, const LEX_CSTRING *old_db, const LEX_CSTRING *old_tb, const LEX_CSTRING *new_db, const LEX_CSTRING *new_tb) { if (mysql_audit_table_enabled()) { const Security_context *sctx= thd->security_ctx; mysql_event_table event; event.event_subclass= MYSQL_AUDIT_TABLE_RENAME; event.read_only= 0; event.thread_id= (unsigned long)thd->thread_id; event.user= sctx->user; event.priv_user= sctx->priv_user; event.priv_host= sctx->priv_host; event.external_user= sctx->external_user; event.proxy_user= sctx->proxy_user; event.host= sctx->host; event.ip= sctx->ip; event.database= *old_db; event.table= *old_tb; event.new_database= *new_db; event.new_table= *new_tb; event.query_id= thd->query_id; mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, &event); } } static inline void mysql_audit_alter_table(THD *thd, TABLE_LIST *table) { if (mysql_audit_table_enabled()) { const Security_context *sctx= thd->security_ctx; mysql_event_table event; event.event_subclass= MYSQL_AUDIT_TABLE_ALTER; event.read_only= 0; event.thread_id= (unsigned long)thd->thread_id; event.user= sctx->user; event.priv_user= sctx->priv_user; event.priv_host= sctx->priv_host; event.external_user= sctx->external_user; event.proxy_user= sctx->proxy_user; event.host= sctx->host; event.ip= sctx->ip; event.database= table->db; event.table= table->table_name; event.new_database= null_clex_str; event.new_table= null_clex_str; event.query_id= thd->query_id; mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, &event); } } #endif /* SQL_AUDIT_INCLUDED */ server/private/filesort.h000064400000016163151031265040011530 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef FILESORT_INCLUDED #define FILESORT_INCLUDED #include "my_base.h" /* ha_rows */ #include "sql_alloc.h" #include "filesort_utils.h" class SQL_SELECT; class THD; struct TABLE; class Filesort_tracker; struct SORT_FIELD; struct SORT_FIELD_ATTR; typedef struct st_order ORDER; class JOIN; class Addon_fields; class Sort_keys; /** Sorting related info. To be extended by another WL to include complete filesort implementation. */ class Filesort: public Sql_alloc { public: /** List of expressions to order the table by */ ORDER *order; /** Number of records to return */ ha_rows limit; /** ORDER BY list with some precalculated info for filesort */ SORT_FIELD *sortorder; /* Used with ROWNUM. Contains the number of rows filesort has found so far */ ha_rows *accepted_rows; /** select to use for getting records */ SQL_SELECT *select; /** TRUE <=> free select on destruction */ bool own_select; /** TRUE means we are using Priority Queue for order by with limit. */ bool using_pq; /* TRUE means sort operation must produce table rowids. FALSE means that it also has an option of producing {sort_key, addon_fields} pairs. Usually initialized with value of join_tab->keep_current_rowid to allow for a call to table->file->position() using these table rowids. */ bool sort_positions; /* TRUE means all the fields of table of whose bitmap read_set is set need to be read while reading records in the sort buffer. FALSE otherwise */ bool set_all_read_bits; Filesort_tracker *tracker; Sort_keys *sort_keys; /* Unpack temp table columns to base table columns*/ void (*unpack)(TABLE *); Filesort(ORDER *order_arg, ha_rows limit_arg, bool sort_positions_arg, SQL_SELECT *select_arg): order(order_arg), limit(limit_arg), sortorder(NULL), accepted_rows(0), select(select_arg), own_select(false), using_pq(false), sort_positions(sort_positions_arg), set_all_read_bits(false), sort_keys(NULL), unpack(NULL) { DBUG_ASSERT(order); }; ~Filesort() { cleanup(); } /* Prepare ORDER BY list for sorting. */ Sort_keys* make_sortorder(THD *thd, JOIN *join, table_map first_table_bit); private: void cleanup(); }; class SORT_INFO { /// Buffer for sorting keys. Filesort_buffer filesort_buffer; public: SORT_INFO() :addon_fields(NULL), record_pointers(0), sort_keys(NULL), sorted_result_in_fsbuf(FALSE) { buffpek.str= 0; my_b_clear(&io_cache); } ~SORT_INFO(); void free_data() { close_cached_file(&io_cache); free_addon_buff(); my_free(record_pointers); my_free(buffpek.str); my_free(addon_fields); free_sort_buffer(); } void reset() { free_data(); record_pointers= 0; buffpek.str= 0; addon_fields= 0; sorted_result_in_fsbuf= false; } void free_addon_buff(); IO_CACHE io_cache; /* If sorted through filesort */ LEX_STRING buffpek; /* Buffer for buffpek structures */ Addon_fields *addon_fields; /* Addon field descriptors */ uchar *record_pointers; /* If sorted in memory */ Sort_keys *sort_keys; /* Sort key descriptors*/ /** If the entire result of filesort fits in memory, we skip the merge phase. We may leave the result in filesort_buffer (indicated by sorted_result_in_fsbuf), or we may strip away the sort keys, and copy the sorted result into a new buffer. @see save_index() */ bool sorted_result_in_fsbuf; /* How many rows in final result. Also how many rows in record_pointers, if used */ ha_rows return_rows; ha_rows examined_rows; /* How many rows read */ ha_rows found_rows; /* How many rows was accepted */ /** Sort filesort_buffer */ void sort_buffer(Sort_param *param, uint count) { filesort_buffer.sort_buffer(param, count); } uchar **get_sort_keys() { return filesort_buffer.get_sort_keys(); } uchar *get_sorted_record(uint ix) { return filesort_buffer.get_sorted_record(ix); } uchar *alloc_sort_buffer(uint num_records, uint record_length) { return filesort_buffer.alloc_sort_buffer(num_records, record_length); } void free_sort_buffer() { filesort_buffer.free_sort_buffer(); } bool isfull() const { return filesort_buffer.isfull(); } void init_record_pointers() { filesort_buffer.init_record_pointers(); } void init_next_record_pointer() { filesort_buffer.init_next_record_pointer(); } uchar *get_next_record_pointer() { return filesort_buffer.get_next_record_pointer(); } void adjust_next_record_pointer(uint val) { filesort_buffer.adjust_next_record_pointer(val); } Bounds_checked_array get_raw_buf() { return filesort_buffer.get_raw_buf(); } size_t sort_buffer_size() const { return filesort_buffer.sort_buffer_size(); } bool is_allocated() const { return filesort_buffer.is_allocated(); } void set_sort_length(uint val) { filesort_buffer.set_sort_length(val); } uint get_sort_length() const { return filesort_buffer.get_sort_length(); } bool has_filesort_result_in_memory() const { return record_pointers || sorted_result_in_fsbuf; } /// Are we using "addon fields"? bool using_addon_fields() const { return addon_fields != NULL; } /// Are we using "packed addon fields"? bool using_packed_addons(); /** Copies (unpacks) values appended to sorted fields from a buffer back to their regular positions specified by the Field::ptr pointers. @param buff Buffer which to unpack the value from */ template inline void unpack_addon_fields(uchar *buff); bool using_packed_sortkeys(); friend SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, Filesort_tracker* tracker, JOIN *join, table_map first_table_bit); }; SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, Filesort_tracker* tracker, JOIN *join=NULL, table_map first_table_bit=0); bool filesort_use_addons(TABLE *table, uint sortlength, uint *length, uint *fields, uint *null_fields, uint *m_packable_length); void change_double_for_sort(double nr,uchar *to); void store_length(uchar *to, uint length, uint pack_length); void reverse_key(uchar *to, const SORT_FIELD_ATTR *sort_field); #endif /* FILESORT_INCLUDED */ server/private/wsrep_high_priority_service.h000064400000011460151031265040015514 0ustar00/* Copyright 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WSREP_HIGH_PRIORITY_SERVICE_H #define WSREP_HIGH_PRIORITY_SERVICE_H #include "wsrep/high_priority_service.hpp" #include "my_global.h" #include "sql_error.h" /* Diagnostics area */ #include "sql_class.h" /* rpl_group_info */ class THD; class Relay_log_info; class Wsrep_server_service; class Wsrep_high_priority_service : public wsrep::high_priority_service, public wsrep::high_priority_context { public: Wsrep_high_priority_service(THD*); ~Wsrep_high_priority_service(); int start_transaction(const wsrep::ws_handle&, const wsrep::ws_meta&) override; int next_fragment(const wsrep::ws_meta&) override; const wsrep::transaction& transaction() const override; int adopt_transaction(const wsrep::transaction&) override; int apply_write_set(const wsrep::ws_meta&, const wsrep::const_buffer&, wsrep::mutable_buffer&) override = 0; int append_fragment_and_commit(const wsrep::ws_handle&, const wsrep::ws_meta&, const wsrep::const_buffer&, const wsrep::xid&) override; int remove_fragments(const wsrep::ws_meta&) override; int commit(const wsrep::ws_handle&, const wsrep::ws_meta&) override; int rollback(const wsrep::ws_handle&, const wsrep::ws_meta&) override; int apply_toi(const wsrep::ws_meta&, const wsrep::const_buffer&, wsrep::mutable_buffer&) override; void store_globals() override; void reset_globals() override; void switch_execution_context(wsrep::high_priority_service&) override; int log_dummy_write_set(const wsrep::ws_handle&, const wsrep::ws_meta&, wsrep::mutable_buffer&) override; void adopt_apply_error(wsrep::mutable_buffer&) override; virtual bool check_exit_status() const = 0; void debug_crash(const char*) override; protected: friend Wsrep_server_service; THD* m_thd; Relay_log_info* m_rli; rpl_group_info* m_rgi; struct shadow { ulonglong option_bits; uint server_status; struct st_vio* vio; ulong tx_isolation; char* db; size_t db_length; //struct timeval user_time; my_hrtime_t user_time; longlong row_count_func; bool wsrep_applier; } m_shadow; }; class Wsrep_applier_service : public Wsrep_high_priority_service { public: Wsrep_applier_service(THD*); ~Wsrep_applier_service(); int apply_write_set(const wsrep::ws_meta&, const wsrep::const_buffer&, wsrep::mutable_buffer&) override; int apply_nbo_begin(const wsrep::ws_meta&, const wsrep::const_buffer& data, wsrep::mutable_buffer& err) override; void after_apply() override; bool is_replaying() const override { return false; } bool check_exit_status() const override; }; class Wsrep_replayer_service : public Wsrep_high_priority_service { public: Wsrep_replayer_service(THD* replayer_thd, THD* orig_thd); ~Wsrep_replayer_service(); int apply_write_set(const wsrep::ws_meta&, const wsrep::const_buffer&, wsrep::mutable_buffer&) override; int apply_nbo_begin(const wsrep::ws_meta&, const wsrep::const_buffer& data, wsrep::mutable_buffer& err) override { DBUG_ASSERT(0); /* DDL should never cause replaying */ return 0; } void after_apply() override { } bool is_replaying() const override { return true; } void replay_status(enum wsrep::provider::status status) { m_replay_status = status; } enum wsrep::provider::status replay_status() const { return m_replay_status; } /* Replayer should never be forced to exit */ bool check_exit_status() const override { return false; } private: THD* m_orig_thd; struct da_shadow { enum Diagnostics_area::enum_diagnostics_status status; ulonglong affected_rows; ulonglong last_insert_id; char message[MYSQL_ERRMSG_SIZE]; da_shadow() : status() , affected_rows() , last_insert_id() , message() { } } m_da_shadow; enum wsrep::provider::status m_replay_status; }; #endif /* WSREP_HIGH_PRIORITY_SERVICE_H */ server/private/lf.h000064400000014476151031265040010307 0ustar00/* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef INCLUDE_LF_INCLUDED #define INCLUDE_LF_INCLUDED #include C_MODE_START /* wait-free dynamic array, see lf_dynarray.c 4 levels of 256 elements each mean 4311810304 elements in an array - it should be enough for a while */ #define LF_DYNARRAY_LEVEL_LENGTH 256 #define LF_DYNARRAY_LEVELS 4 typedef struct { void * volatile level[LF_DYNARRAY_LEVELS]; uint size_of_element; } LF_DYNARRAY; typedef int (*lf_dynarray_func)(void *, void *); void lf_dynarray_init(LF_DYNARRAY *array, uint element_size); void lf_dynarray_destroy(LF_DYNARRAY *array); void *lf_dynarray_value(LF_DYNARRAY *array, uint idx); void *lf_dynarray_lvalue(LF_DYNARRAY *array, uint idx); int lf_dynarray_iterate(LF_DYNARRAY *array, lf_dynarray_func func, void *arg); /* pin manager for memory allocator, lf_alloc-pin.c */ #define LF_PINBOX_PINS 4 #define LF_PURGATORY_SIZE 100 typedef void lf_pinbox_free_func(void *, void *, void*); typedef struct { LF_DYNARRAY pinarray; lf_pinbox_free_func *free_func; void *free_func_arg; uint free_ptr_offset; uint32 volatile pinstack_top_ver; /* this is a versioned pointer */ uint32 volatile pins_in_array; /* number of elements in array */ } LF_PINBOX; typedef struct { void * volatile pin[LF_PINBOX_PINS]; LF_PINBOX *pinbox; void *purgatory; uint32 purgatory_count; uint32 volatile link; /* avoid false sharing */ char pad[CPU_LEVEL1_DCACHE_LINESIZE]; } LF_PINS; /* compile-time assert to make sure we have enough pins. */ #define lf_pin(PINS, PIN, ADDR) \ do { \ compile_time_assert(PIN < LF_PINBOX_PINS); \ my_atomic_storeptr(&(PINS)->pin[PIN], (ADDR)); \ } while(0) #define lf_unpin(PINS, PIN) lf_pin(PINS, PIN, NULL) #define lf_assert_pin(PINS, PIN) assert((PINS)->pin[PIN] != 0) #define lf_assert_unpin(PINS, PIN) assert((PINS)->pin[PIN] == 0) void lf_pinbox_init(LF_PINBOX *pinbox, uint free_ptr_offset, lf_pinbox_free_func *free_func, void * free_func_arg); void lf_pinbox_destroy(LF_PINBOX *pinbox); LF_PINS *lf_pinbox_get_pins(LF_PINBOX *pinbox); void lf_pinbox_put_pins(LF_PINS *pins); void lf_pinbox_free(LF_PINS *pins, void *addr); /* memory allocator, lf_alloc-pin.c */ typedef struct st_lf_allocator { LF_PINBOX pinbox; uchar * volatile top; uint element_size; uint32 volatile mallocs; void (*constructor)(uchar *); /* called, when an object is malloc()'ed */ void (*destructor)(uchar *); /* called, when an object is free()'d */ } LF_ALLOCATOR; void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset); void lf_alloc_destroy(LF_ALLOCATOR *allocator); uint lf_alloc_pool_count(LF_ALLOCATOR *allocator); /* shortcut macros to access underlying pinbox functions from an LF_ALLOCATOR see lf_pinbox_get_pins() and lf_pinbox_put_pins() */ #define lf_alloc_free(PINS, PTR) lf_pinbox_free((PINS), (PTR)) #define lf_alloc_get_pins(A) lf_pinbox_get_pins(&(A)->pinbox) #define lf_alloc_put_pins(PINS) lf_pinbox_put_pins(PINS) #define lf_alloc_direct_free(ALLOC, ADDR) \ do { \ if ((ALLOC)->destructor) \ (ALLOC)->destructor((uchar*) ADDR); \ my_free(ADDR); \ } while(0) void *lf_alloc_new(LF_PINS *pins); C_MODE_END /* extendible hash, lf_hash.cc */ #include C_MODE_START typedef struct st_lf_hash LF_HASH; typedef void (*lf_hash_initializer)(LF_HASH *hash, void *dst, const void *src); #define LF_HASH_UNIQUE 1 /* lf_hash overhead per element (that is, sizeof(LF_SLIST) */ extern const int LF_HASH_OVERHEAD; struct st_lf_hash { LF_DYNARRAY array; /* hash itself */ LF_ALLOCATOR alloc; /* allocator for elements */ my_hash_get_key get_key; /* see HASH */ lf_hash_initializer initializer; /* called when an element is inserted */ my_hash_function hash_function; /* see HASH */ CHARSET_INFO *charset; /* see HASH */ uint key_offset, key_length; /* see HASH */ uint element_size; /* size of memcpy'ed area on insert */ uint flags; /* LF_HASH_UNIQUE, etc */ int32 volatile size; /* size of array */ int32 volatile count; /* number of elements in the hash */ }; void lf_hash_init(LF_HASH *hash, uint element_size, uint flags, uint key_offset, uint key_length, my_hash_get_key get_key, CHARSET_INFO *charset); void lf_hash_destroy(LF_HASH *hash); int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data); void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen); void *lf_hash_search_using_hash_value(LF_HASH *hash, LF_PINS *pins, my_hash_value_type hash_value, const void *key, uint keylen); int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen); int lf_hash_iterate(LF_HASH *hash, LF_PINS *pins, my_hash_walk_action action, void *argument); #define lf_hash_size(hash) \ my_atomic_load32_explicit(&(hash)->count, MY_MEMORY_ORDER_RELAXED) /* shortcut macros to access underlying pinbox functions from an LF_HASH see lf_pinbox_get_pins() and lf_pinbox_put_pins() */ #define lf_hash_get_pins(HASH) lf_alloc_get_pins(&(HASH)->alloc) #define lf_hash_put_pins(PINS) lf_pinbox_put_pins(PINS) #define lf_hash_search_unpin(PINS) lf_unpin((PINS), 2) /* cleanup */ C_MODE_END #endif server/private/derror.h000064400000001724151031265040011173 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef DERROR_INCLUDED #define DERROR_INCLUDED bool init_errmessage(void); void free_error_messages(); bool read_texts(const char *file_name, const char *language, const char ****data); #endif /* DERROR_INCLUDED */ server/private/sql_partition_admin.h000064400000013464151031265040013742 0ustar00/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_PARTITION_ADMIN_H #define SQL_PARTITION_ADMIN_H #ifndef WITH_PARTITION_STORAGE_ENGINE /** Stub class that returns a error if the partition storage engine is not supported. */ class Sql_cmd_partition_unsupported : public Sql_cmd { public: Sql_cmd_partition_unsupported() {} ~Sql_cmd_partition_unsupported() {} /* Override SQLCOM_*, since it is an ALTER command */ virtual enum_sql_command sql_command_code() const override { return SQLCOM_ALTER_TABLE; } bool execute(THD *thd) override; }; class Sql_cmd_alter_table_exchange_partition : public Sql_cmd_partition_unsupported { public: Sql_cmd_alter_table_exchange_partition() {} ~Sql_cmd_alter_table_exchange_partition() {} }; class Sql_cmd_alter_table_analyze_partition : public Sql_cmd_partition_unsupported { public: Sql_cmd_alter_table_analyze_partition() {} ~Sql_cmd_alter_table_analyze_partition() {} }; class Sql_cmd_alter_table_check_partition : public Sql_cmd_partition_unsupported { public: Sql_cmd_alter_table_check_partition() {} ~Sql_cmd_alter_table_check_partition() {} }; class Sql_cmd_alter_table_optimize_partition : public Sql_cmd_partition_unsupported { public: Sql_cmd_alter_table_optimize_partition() {} ~Sql_cmd_alter_table_optimize_partition() {} }; class Sql_cmd_alter_table_repair_partition : public Sql_cmd_partition_unsupported { public: Sql_cmd_alter_table_repair_partition() {} ~Sql_cmd_alter_table_repair_partition() {} }; class Sql_cmd_alter_table_truncate_partition : public Sql_cmd_partition_unsupported { public: Sql_cmd_alter_table_truncate_partition() {} ~Sql_cmd_alter_table_truncate_partition() {} }; #else /** Class that represents the ALTER TABLE t1 ANALYZE PARTITION p statement. */ class Sql_cmd_alter_table_exchange_partition : public Sql_cmd_common_alter_table { public: /** Constructor, used to represent a ALTER TABLE EXCHANGE PARTITION statement. */ Sql_cmd_alter_table_exchange_partition() : Sql_cmd_common_alter_table() {} ~Sql_cmd_alter_table_exchange_partition() = default; bool execute(THD *thd) override; private: bool exchange_partition(THD *thd, TABLE_LIST *, Alter_info *); }; /** Class that represents the ALTER TABLE t1 ANALYZE PARTITION p statement. */ class Sql_cmd_alter_table_analyze_partition : public Sql_cmd_analyze_table { public: /** Constructor, used to represent a ALTER TABLE ANALYZE PARTITION statement. */ Sql_cmd_alter_table_analyze_partition() : Sql_cmd_analyze_table() {} ~Sql_cmd_alter_table_analyze_partition() = default; bool execute(THD *thd) override; /* Override SQLCOM_ANALYZE, since it is an ALTER command */ enum_sql_command sql_command_code() const override { return SQLCOM_ALTER_TABLE; } }; /** Class that represents the ALTER TABLE t1 CHECK PARTITION p statement. */ class Sql_cmd_alter_table_check_partition : public Sql_cmd_check_table { public: /** Constructor, used to represent a ALTER TABLE CHECK PARTITION statement. */ Sql_cmd_alter_table_check_partition() : Sql_cmd_check_table() {} ~Sql_cmd_alter_table_check_partition() = default; bool execute(THD *thd) override; /* Override SQLCOM_CHECK, since it is an ALTER command */ enum_sql_command sql_command_code() const override { return SQLCOM_ALTER_TABLE; } }; /** Class that represents the ALTER TABLE t1 OPTIMIZE PARTITION p statement. */ class Sql_cmd_alter_table_optimize_partition : public Sql_cmd_optimize_table { public: /** Constructor, used to represent a ALTER TABLE OPTIMIZE PARTITION statement. */ Sql_cmd_alter_table_optimize_partition() : Sql_cmd_optimize_table() {} ~Sql_cmd_alter_table_optimize_partition() = default; bool execute(THD *thd) override; /* Override SQLCOM_OPTIMIZE, since it is an ALTER command */ enum_sql_command sql_command_code() const override { return SQLCOM_ALTER_TABLE; } }; /** Class that represents the ALTER TABLE t1 REPAIR PARTITION p statement. */ class Sql_cmd_alter_table_repair_partition : public Sql_cmd_repair_table { public: /** Constructor, used to represent a ALTER TABLE REPAIR PARTITION statement. */ Sql_cmd_alter_table_repair_partition() : Sql_cmd_repair_table() {} ~Sql_cmd_alter_table_repair_partition() = default; bool execute(THD *thd) override; /* Override SQLCOM_REPAIR, since it is an ALTER command */ enum_sql_command sql_command_code() const override { return SQLCOM_ALTER_TABLE; } }; /** Class that represents the ALTER TABLE t1 TRUNCATE PARTITION p statement. */ class Sql_cmd_alter_table_truncate_partition : public Sql_cmd_truncate_table { public: /** Constructor, used to represent a ALTER TABLE TRUNCATE PARTITION statement. */ Sql_cmd_alter_table_truncate_partition() = default; virtual ~Sql_cmd_alter_table_truncate_partition() = default; bool execute(THD *thd) override; /* Override SQLCOM_TRUNCATE, since it is an ALTER command */ enum_sql_command sql_command_code() const override { return SQLCOM_ALTER_TABLE; } }; #endif /* WITH_PARTITION_STORAGE_ENGINE */ #endif /* SQL_PARTITION_ADMIN_H */ server/private/lex.h000064400000071601151031265040010467 0ustar00#ifndef LEX_INCLUDED #define LEX_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. Copyright (c) 2009, 2015, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file includes all reserved words and functions */ #include "lex_symbol.h" SYM_GROUP sym_group_common= {"", ""}; SYM_GROUP sym_group_geom= {"Spatial extensions", "HAVE_SPATIAL"}; SYM_GROUP sym_group_rtree= {"RTree keys", "HAVE_RTREE_KEYS"}; /* We don't want to include sql_yacc.h into gen_lex_hash */ #ifdef NO_YACC_SYMBOLS #define SYM_OR_NULL(A) 0 #else #define SYM_OR_NULL(A) A #endif #define SYM(A) SYM_OR_NULL(A),0,&sym_group_common /* Symbols are broken into separated arrays to allow field names with same name as functions. These are kept sorted for human lookup (the symbols are hashed). NOTE! The symbol tables should be the same regardless of what features are compiled into the server. Don't add ifdef'ed symbols to the lists NOTE!! If you add or delete symbols from this file, you must also update results for the perfschema.start_server_low_digest_sql_length test! */ SYMBOL symbols[] = { { "&&", SYM(AND_AND_SYM)}, { "<=", SYM(LE)}, { "<>", SYM(NE)}, { "!=", SYM(NE)}, { ">=", SYM(GE)}, { "<<", SYM(SHIFT_LEFT)}, { ">>", SYM(SHIFT_RIGHT)}, { "<=>", SYM(EQUAL_SYM)}, { "ACCESSIBLE", SYM(ACCESSIBLE_SYM)}, { "ACCOUNT", SYM(ACCOUNT_SYM)}, { "ACTION", SYM(ACTION)}, { "ADD", SYM(ADD)}, { "ADMIN", SYM(ADMIN_SYM)}, { "AFTER", SYM(AFTER_SYM)}, { "AGAINST", SYM(AGAINST)}, { "AGGREGATE", SYM(AGGREGATE_SYM)}, { "ALL", SYM(ALL)}, { "ALGORITHM", SYM(ALGORITHM_SYM)}, { "ALTER", SYM(ALTER)}, { "ALWAYS", SYM(ALWAYS_SYM)}, { "ANALYZE", SYM(ANALYZE_SYM)}, { "AND", SYM(AND_SYM)}, { "ANY", SYM(ANY_SYM)}, { "AS", SYM(AS)}, { "ASC", SYM(ASC)}, { "ASCII", SYM(ASCII_SYM)}, { "ASENSITIVE", SYM(ASENSITIVE_SYM)}, { "AT", SYM(AT_SYM)}, { "ATOMIC", SYM(ATOMIC_SYM)}, { "AUTHORS", SYM(AUTHORS_SYM)}, { "AUTO_INCREMENT", SYM(AUTO_INC)}, { "AUTOEXTEND_SIZE", SYM(AUTOEXTEND_SIZE_SYM)}, { "AVG", SYM(AVG_SYM)}, { "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH)}, { "BACKUP", SYM(BACKUP_SYM)}, { "BEFORE", SYM(BEFORE_SYM)}, { "BEGIN", SYM(BEGIN_MARIADB_SYM)}, { "BETWEEN", SYM(BETWEEN_SYM)}, { "BIGINT", SYM(BIGINT)}, { "BINARY", SYM(BINARY)}, { "BINLOG", SYM(BINLOG_SYM)}, { "BIT", SYM(BIT_SYM)}, { "BLOB", SYM(BLOB_MARIADB_SYM)}, { "BLOCK", SYM(BLOCK_SYM)}, { "BODY", SYM(BODY_MARIADB_SYM)}, { "BOOL", SYM(BOOL_SYM)}, { "BOOLEAN", SYM(BOOLEAN_SYM)}, { "BOTH", SYM(BOTH)}, { "BTREE", SYM(BTREE_SYM)}, { "BY", SYM(BY)}, { "BYTE", SYM(BYTE_SYM)}, { "CACHE", SYM(CACHE_SYM)}, { "CALL", SYM(CALL_SYM)}, { "CASCADE", SYM(CASCADE)}, { "CASCADED", SYM(CASCADED)}, { "CASE", SYM(CASE_SYM)}, { "CATALOG_NAME", SYM(CATALOG_NAME_SYM)}, { "CHAIN", SYM(CHAIN_SYM)}, { "CHANGE", SYM(CHANGE)}, { "CHANGED", SYM(CHANGED)}, { "CHAR", SYM(CHAR_SYM)}, { "CHARACTER", SYM(CHAR_SYM)}, { "CHARSET", SYM(CHARSET)}, { "CHECK", SYM(CHECK_SYM)}, { "CHECKPOINT", SYM(CHECKPOINT_SYM)}, { "CHECKSUM", SYM(CHECKSUM_SYM)}, { "CIPHER", SYM(CIPHER_SYM)}, { "CLASS_ORIGIN", SYM(CLASS_ORIGIN_SYM)}, { "CLIENT", SYM(CLIENT_SYM)}, { "CLOB", SYM(CLOB_MARIADB_SYM)}, { "CLOSE", SYM(CLOSE_SYM)}, { "COALESCE", SYM(COALESCE)}, { "CODE", SYM(CODE_SYM)}, { "COLLATE", SYM(COLLATE_SYM)}, { "COLLATION", SYM(COLLATION_SYM)}, { "COLUMN", SYM(COLUMN_SYM)}, { "COLUMN_NAME", SYM(COLUMN_NAME_SYM)}, { "COLUMNS", SYM(COLUMNS)}, { "COLUMN_ADD", SYM(COLUMN_ADD_SYM)}, { "COLUMN_CHECK", SYM(COLUMN_CHECK_SYM)}, { "COLUMN_CREATE", SYM(COLUMN_CREATE_SYM)}, { "COLUMN_DELETE", SYM(COLUMN_DELETE_SYM)}, { "COLUMN_GET", SYM(COLUMN_GET_SYM)}, { "COMMENT", SYM(COMMENT_SYM)}, { "COMMIT", SYM(COMMIT_SYM)}, { "COMMITTED", SYM(COMMITTED_SYM)}, { "COMPACT", SYM(COMPACT_SYM)}, { "COMPLETION", SYM(COMPLETION_SYM)}, { "COMPRESSED", SYM(COMPRESSED_SYM)}, { "CONCURRENT", SYM(CONCURRENT)}, { "CONDITION", SYM(CONDITION_SYM)}, { "CONNECTION", SYM(CONNECTION_SYM)}, { "CONSISTENT", SYM(CONSISTENT_SYM)}, { "CONSTRAINT", SYM(CONSTRAINT)}, { "CONSTRAINT_CATALOG", SYM(CONSTRAINT_CATALOG_SYM)}, { "CONSTRAINT_NAME", SYM(CONSTRAINT_NAME_SYM)}, { "CONSTRAINT_SCHEMA", SYM(CONSTRAINT_SCHEMA_SYM)}, { "CONTAINS", SYM(CONTAINS_SYM)}, { "CONTEXT", SYM(CONTEXT_SYM)}, { "CONTINUE", SYM(CONTINUE_MARIADB_SYM)}, { "CONTRIBUTORS", SYM(CONTRIBUTORS_SYM)}, { "CONVERT", SYM(CONVERT_SYM)}, { "CPU", SYM(CPU_SYM)}, { "CREATE", SYM(CREATE)}, { "CROSS", SYM(CROSS)}, { "CUBE", SYM(CUBE_SYM)}, { "CURRENT", SYM(CURRENT_SYM)}, { "CURRENT_DATE", SYM(CURDATE)}, { "CURRENT_POS", SYM(CURRENT_POS_SYM)}, { "CURRENT_ROLE", SYM(CURRENT_ROLE)}, { "CURRENT_TIME", SYM(CURTIME)}, { "CURRENT_TIMESTAMP", SYM(NOW_SYM)}, { "CURRENT_USER", SYM(CURRENT_USER)}, { "CURSOR", SYM(CURSOR_SYM)}, { "CURSOR_NAME", SYM(CURSOR_NAME_SYM)}, { "CYCLE", SYM(CYCLE_SYM)}, { "DATA", SYM(DATA_SYM)}, { "DATABASE", SYM(DATABASE)}, { "DATABASES", SYM(DATABASES)}, { "DATAFILE", SYM(DATAFILE_SYM)}, { "DATE", SYM(DATE_SYM)}, { "DATETIME", SYM(DATETIME)}, { "DAY", SYM(DAY_SYM)}, { "DAY_HOUR", SYM(DAY_HOUR_SYM)}, { "DAY_MICROSECOND", SYM(DAY_MICROSECOND_SYM)}, { "DAY_MINUTE", SYM(DAY_MINUTE_SYM)}, { "DAY_SECOND", SYM(DAY_SECOND_SYM)}, { "DEALLOCATE", SYM(DEALLOCATE_SYM)}, { "DEC", SYM(DECIMAL_SYM)}, { "DECIMAL", SYM(DECIMAL_SYM)}, { "DECLARE", SYM(DECLARE_MARIADB_SYM)}, { "DEFAULT", SYM(DEFAULT)}, { "DEFINER", SYM(DEFINER_SYM)}, { "DELAYED", SYM(DELAYED_SYM)}, { "DELAY_KEY_WRITE", SYM(DELAY_KEY_WRITE_SYM)}, { "DELETE", SYM(DELETE_SYM)}, { "DELETE_DOMAIN_ID", SYM(DELETE_DOMAIN_ID_SYM)}, { "DESC", SYM(DESC)}, { "DESCRIBE", SYM(DESCRIBE)}, { "DES_KEY_FILE", SYM(DES_KEY_FILE)}, { "DETERMINISTIC", SYM(DETERMINISTIC_SYM)}, { "DIAGNOSTICS", SYM(DIAGNOSTICS_SYM)}, { "DIRECTORY", SYM(DIRECTORY_SYM)}, { "DISABLE", SYM(DISABLE_SYM)}, { "DISCARD", SYM(DISCARD)}, { "DISK", SYM(DISK_SYM)}, { "DISTINCT", SYM(DISTINCT)}, { "DISTINCTROW", SYM(DISTINCT)}, /* Access likes this */ { "DIV", SYM(DIV_SYM)}, { "DO", SYM(DO_SYM)}, { "DOUBLE", SYM(DOUBLE_SYM)}, { "DO_DOMAIN_IDS", SYM(DO_DOMAIN_IDS_SYM)}, { "DROP", SYM(DROP)}, { "DUAL", SYM(DUAL_SYM)}, { "DUMPFILE", SYM(DUMPFILE)}, { "DUPLICATE", SYM(DUPLICATE_SYM)}, { "DYNAMIC", SYM(DYNAMIC_SYM)}, { "EACH", SYM(EACH_SYM)}, { "ELSE", SYM(ELSE)}, { "ELSEIF", SYM(ELSEIF_MARIADB_SYM)}, { "ELSIF", SYM(ELSIF_MARIADB_SYM)}, { "EMPTY", SYM(EMPTY_SYM)}, { "ENABLE", SYM(ENABLE_SYM)}, { "ENCLOSED", SYM(ENCLOSED)}, { "END", SYM(END)}, { "ENDS", SYM(ENDS_SYM)}, { "ENGINE", SYM(ENGINE_SYM)}, { "ENGINES", SYM(ENGINES_SYM)}, { "ENUM", SYM(ENUM)}, { "ERROR", SYM(ERROR_SYM)}, { "ERRORS", SYM(ERRORS)}, { "ESCAPE", SYM(ESCAPE_SYM)}, { "ESCAPED", SYM(ESCAPED)}, { "EVENT", SYM(EVENT_SYM)}, { "EVENTS", SYM(EVENTS_SYM)}, { "EVERY", SYM(EVERY_SYM)}, { "EXAMINED", SYM(EXAMINED_SYM)}, { "EXCEPT", SYM(EXCEPT_SYM)}, { "EXCHANGE", SYM(EXCHANGE_SYM)}, { "EXCLUDE", SYM(EXCLUDE_SYM)}, { "EXECUTE", SYM(EXECUTE_SYM)}, { "EXCEPTION", SYM(EXCEPTION_MARIADB_SYM)}, { "EXISTS", SYM(EXISTS)}, { "EXIT", SYM(EXIT_MARIADB_SYM)}, { "EXPANSION", SYM(EXPANSION_SYM)}, { "EXPIRE", SYM(EXPIRE_SYM)}, { "EXPORT", SYM(EXPORT_SYM)}, { "EXPLAIN", SYM(DESCRIBE)}, { "EXTENDED", SYM(EXTENDED_SYM)}, { "EXTENT_SIZE", SYM(EXTENT_SIZE_SYM)}, { "FALSE", SYM(FALSE_SYM)}, { "FAST", SYM(FAST_SYM)}, { "FAULTS", SYM(FAULTS_SYM)}, { "FEDERATED", SYM(FEDERATED_SYM)}, { "FETCH", SYM(FETCH_SYM)}, { "FIELDS", SYM(COLUMNS)}, { "FILE", SYM(FILE_SYM)}, { "FIRST", SYM(FIRST_SYM)}, { "FIXED", SYM(FIXED_SYM)}, { "FLOAT", SYM(FLOAT_SYM)}, { "FLOAT4", SYM(FLOAT_SYM)}, { "FLOAT8", SYM(DOUBLE_SYM)}, { "FLUSH", SYM(FLUSH_SYM)}, { "FOLLOWING", SYM(FOLLOWING_SYM)}, { "FOLLOWS", SYM(FOLLOWS_SYM)}, { "FOR", SYM(FOR_SYM)}, { "FORCE", SYM(FORCE_SYM)}, { "FOREIGN", SYM(FOREIGN)}, { "FORMAT", SYM(FORMAT_SYM)}, { "FOUND", SYM(FOUND_SYM)}, { "FROM", SYM(FROM)}, { "FULL", SYM(FULL)}, { "FULLTEXT", SYM(FULLTEXT_SYM)}, { "FUNCTION", SYM(FUNCTION_SYM)}, { "GENERAL", SYM(GENERAL)}, { "GENERATED", SYM(GENERATED_SYM)}, { "GET_FORMAT", SYM(GET_FORMAT)}, { "GET", SYM(GET_SYM)}, { "GLOBAL", SYM(GLOBAL_SYM)}, { "GOTO", SYM(GOTO_MARIADB_SYM)}, { "GRANT", SYM(GRANT)}, { "GRANTS", SYM(GRANTS)}, { "GROUP", SYM(GROUP_SYM)}, { "HANDLER", SYM(HANDLER_SYM)}, { "HARD", SYM(HARD_SYM)}, { "HASH", SYM(HASH_SYM)}, { "HAVING", SYM(HAVING)}, { "HELP", SYM(HELP_SYM)}, { "HIGH_PRIORITY", SYM(HIGH_PRIORITY)}, { "HISTORY", SYM(HISTORY_SYM)}, { "HOST", SYM(HOST_SYM)}, { "HOSTS", SYM(HOSTS_SYM)}, { "HOUR", SYM(HOUR_SYM)}, { "HOUR_MICROSECOND", SYM(HOUR_MICROSECOND_SYM)}, { "HOUR_MINUTE", SYM(HOUR_MINUTE_SYM)}, { "HOUR_SECOND", SYM(HOUR_SECOND_SYM)}, { "ID", SYM(ID_SYM)}, { "IDENTIFIED", SYM(IDENTIFIED_SYM)}, { "IF", SYM(IF_SYM)}, { "IGNORE", SYM(IGNORE_SYM)}, { "IGNORED", SYM(IGNORED_SYM)}, { "IGNORE_DOMAIN_IDS", SYM(IGNORE_DOMAIN_IDS_SYM)}, { "IGNORE_SERVER_IDS", SYM(IGNORE_SERVER_IDS_SYM)}, { "IMMEDIATE", SYM(IMMEDIATE_SYM)}, { "IMPORT", SYM(IMPORT)}, { "INTERSECT", SYM(INTERSECT_SYM)}, { "IN", SYM(IN_SYM)}, { "INCREMENT", SYM(INCREMENT_SYM)}, { "INDEX", SYM(INDEX_SYM)}, { "INDEXES", SYM(INDEXES)}, { "INFILE", SYM(INFILE)}, { "INITIAL_SIZE", SYM(INITIAL_SIZE_SYM)}, { "INNER", SYM(INNER_SYM)}, { "INOUT", SYM(INOUT_SYM)}, { "INSENSITIVE", SYM(INSENSITIVE_SYM)}, { "INSERT", SYM(INSERT)}, { "INSERT_METHOD", SYM(INSERT_METHOD)}, { "INSTALL", SYM(INSTALL_SYM)}, { "INT", SYM(INT_SYM)}, { "INT1", SYM(TINYINT)}, { "INT2", SYM(SMALLINT)}, { "INT3", SYM(MEDIUMINT)}, { "INT4", SYM(INT_SYM)}, { "INT8", SYM(BIGINT)}, { "INTEGER", SYM(INT_SYM)}, { "INTERVAL", SYM(INTERVAL_SYM)}, { "INVISIBLE", SYM(INVISIBLE_SYM)}, { "INTO", SYM(INTO)}, { "IO", SYM(IO_SYM)}, { "IO_THREAD", SYM(RELAY_THREAD)}, { "IPC", SYM(IPC_SYM)}, { "IS", SYM(IS)}, { "ISOLATION", SYM(ISOLATION)}, { "ISOPEN", SYM(ISOPEN_SYM)}, { "ISSUER", SYM(ISSUER_SYM)}, { "ITERATE", SYM(ITERATE_SYM)}, { "INVOKER", SYM(INVOKER_SYM)}, { "JOIN", SYM(JOIN_SYM)}, { "JSON", SYM(JSON_SYM)}, { "JSON_TABLE", SYM(JSON_TABLE_SYM)}, { "KEY", SYM(KEY_SYM)}, { "KEYS", SYM(KEYS)}, { "KEY_BLOCK_SIZE", SYM(KEY_BLOCK_SIZE)}, { "KILL", SYM(KILL_SYM)}, { "LANGUAGE", SYM(LANGUAGE_SYM)}, { "LAST", SYM(LAST_SYM)}, { "LAST_VALUE", SYM(LAST_VALUE)}, { "LASTVAL", SYM(LASTVAL_SYM)}, { "LEADING", SYM(LEADING)}, { "LEAVE", SYM(LEAVE_SYM)}, { "LEAVES", SYM(LEAVES)}, { "LEFT", SYM(LEFT)}, { "LESS", SYM(LESS_SYM)}, { "LEVEL", SYM(LEVEL_SYM)}, { "LIKE", SYM(LIKE)}, { "LIMIT", SYM(LIMIT)}, { "LINEAR", SYM(LINEAR_SYM)}, { "LINES", SYM(LINES)}, { "LIST", SYM(LIST_SYM)}, { "LOAD", SYM(LOAD)}, { "LOCAL", SYM(LOCAL_SYM)}, { "LOCALTIME", SYM(NOW_SYM)}, { "LOCALTIMESTAMP", SYM(NOW_SYM)}, { "LOCK", SYM(LOCK_SYM)}, { "LOCKED", SYM(LOCKED_SYM)}, { "LOCKS", SYM(LOCKS_SYM)}, { "LOGFILE", SYM(LOGFILE_SYM)}, { "LOGS", SYM(LOGS_SYM)}, { "LONG", SYM(LONG_SYM)}, { "LONGBLOB", SYM(LONGBLOB)}, { "LONGTEXT", SYM(LONGTEXT)}, { "LOOP", SYM(LOOP_SYM)}, { "LOW_PRIORITY", SYM(LOW_PRIORITY)}, { "MASTER", SYM(MASTER_SYM)}, { "MASTER_CONNECT_RETRY", SYM(MASTER_CONNECT_RETRY_SYM)}, { "MASTER_DELAY", SYM(MASTER_DELAY_SYM)}, { "MASTER_GTID_POS", SYM(MASTER_GTID_POS_SYM)}, { "MASTER_HOST", SYM(MASTER_HOST_SYM)}, { "MASTER_LOG_FILE", SYM(MASTER_LOG_FILE_SYM)}, { "MASTER_LOG_POS", SYM(MASTER_LOG_POS_SYM)}, { "MASTER_PASSWORD", SYM(MASTER_PASSWORD_SYM)}, { "MASTER_PORT", SYM(MASTER_PORT_SYM)}, { "MASTER_SERVER_ID", SYM(MASTER_SERVER_ID_SYM)}, { "MASTER_SSL", SYM(MASTER_SSL_SYM)}, { "MASTER_SSL_CA", SYM(MASTER_SSL_CA_SYM)}, { "MASTER_SSL_CAPATH",SYM(MASTER_SSL_CAPATH_SYM)}, { "MASTER_SSL_CERT", SYM(MASTER_SSL_CERT_SYM)}, { "MASTER_SSL_CIPHER",SYM(MASTER_SSL_CIPHER_SYM)}, { "MASTER_SSL_CRL", SYM(MASTER_SSL_CRL_SYM)}, { "MASTER_SSL_CRLPATH",SYM(MASTER_SSL_CRLPATH_SYM)}, { "MASTER_SSL_KEY", SYM(MASTER_SSL_KEY_SYM)}, { "MASTER_SSL_VERIFY_SERVER_CERT", SYM(MASTER_SSL_VERIFY_SERVER_CERT_SYM)}, { "MASTER_USER", SYM(MASTER_USER_SYM)}, { "MASTER_USE_GTID", SYM(MASTER_USE_GTID_SYM)}, { "MASTER_HEARTBEAT_PERIOD", SYM(MASTER_HEARTBEAT_PERIOD_SYM)}, { "MATCH", SYM(MATCH)}, { "MAX_CONNECTIONS_PER_HOUR", SYM(MAX_CONNECTIONS_PER_HOUR)}, { "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR)}, { "MAX_ROWS", SYM(MAX_ROWS)}, { "MAX_SIZE", SYM(MAX_SIZE_SYM)}, { "MAX_STATEMENT_TIME", SYM(MAX_STATEMENT_TIME_SYM)}, { "MAX_UPDATES_PER_HOUR", SYM(MAX_UPDATES_PER_HOUR)}, { "MAX_USER_CONNECTIONS", SYM(MAX_USER_CONNECTIONS_SYM)}, { "MAXVALUE", SYM(MAXVALUE_SYM)}, { "MEDIUM", SYM(MEDIUM_SYM)}, { "MEDIUMBLOB", SYM(MEDIUMBLOB)}, { "MEDIUMINT", SYM(MEDIUMINT)}, { "MEDIUMTEXT", SYM(MEDIUMTEXT)}, { "MEMORY", SYM(MEMORY_SYM)}, { "MERGE", SYM(MERGE_SYM)}, { "MESSAGE_TEXT", SYM(MESSAGE_TEXT_SYM)}, { "MICROSECOND", SYM(MICROSECOND_SYM)}, { "MIDDLEINT", SYM(MEDIUMINT)}, /* For powerbuilder */ { "MIGRATE", SYM(MIGRATE_SYM)}, { "MINUS", SYM(MINUS_ORACLE_SYM)}, { "MINUTE", SYM(MINUTE_SYM)}, { "MINUTE_MICROSECOND", SYM(MINUTE_MICROSECOND_SYM)}, { "MINUTE_SECOND", SYM(MINUTE_SECOND_SYM)}, { "MINVALUE", SYM(MINVALUE_SYM)}, { "MIN_ROWS", SYM(MIN_ROWS)}, { "MOD", SYM(MOD_SYM)}, { "MODE", SYM(MODE_SYM)}, { "MODIFIES", SYM(MODIFIES_SYM)}, { "MODIFY", SYM(MODIFY_SYM)}, { "MONITOR", SYM(MONITOR_SYM)}, { "MONTH", SYM(MONTH_SYM)}, { "MUTEX", SYM(MUTEX_SYM)}, { "MYSQL", SYM(MYSQL_SYM)}, { "MYSQL_ERRNO", SYM(MYSQL_ERRNO_SYM)}, { "NAME", SYM(NAME_SYM)}, { "NAMES", SYM(NAMES_SYM)}, { "NATIONAL", SYM(NATIONAL_SYM)}, { "NATURAL", SYM(NATURAL)}, { "NCHAR", SYM(NCHAR_SYM)}, { "NESTED", SYM(NESTED_SYM)}, { "NEVER", SYM(NEVER_SYM)}, { "NEXT", SYM(NEXT_SYM)}, { "NEXTVAL", SYM(NEXTVAL_SYM)}, { "NO", SYM(NO_SYM)}, { "NOMAXVALUE", SYM(NOMAXVALUE_SYM)}, { "NOMINVALUE", SYM(NOMINVALUE_SYM)}, { "NOCACHE", SYM(NOCACHE_SYM)}, { "NOCYCLE", SYM(NOCYCLE_SYM)}, { "NO_WAIT", SYM(NO_WAIT_SYM)}, { "NOWAIT", SYM(NOWAIT_SYM)}, { "NODEGROUP", SYM(NODEGROUP_SYM)}, { "NONE", SYM(NONE_SYM)}, { "NOT", SYM(NOT_SYM)}, { "NOTFOUND", SYM(NOTFOUND_SYM)}, { "NO_WRITE_TO_BINLOG", SYM(NO_WRITE_TO_BINLOG)}, { "NULL", SYM(NULL_SYM)}, { "NUMBER", SYM(NUMBER_MARIADB_SYM)}, { "NUMERIC", SYM(NUMERIC_SYM)}, { "NVARCHAR", SYM(NVARCHAR_SYM)}, { "OF", SYM(OF_SYM)}, { "OFFSET", SYM(OFFSET_SYM)}, { "OLD_PASSWORD", SYM(OLD_PASSWORD_SYM)}, { "ON", SYM(ON)}, { "ONE", SYM(ONE_SYM)}, { "ONLINE", SYM(ONLINE_SYM)}, { "ONLY", SYM(ONLY_SYM)}, { "OPEN", SYM(OPEN_SYM)}, { "OPTIMIZE", SYM(OPTIMIZE)}, { "OPTIONS", SYM(OPTIONS_SYM)}, { "OPTION", SYM(OPTION)}, { "OPTIONALLY", SYM(OPTIONALLY)}, { "OR", SYM(OR_SYM)}, { "ORDER", SYM(ORDER_SYM)}, { "ORDINALITY", SYM(ORDINALITY_SYM)}, { "OTHERS", SYM(OTHERS_MARIADB_SYM)}, { "OUT", SYM(OUT_SYM)}, { "OUTER", SYM(OUTER)}, { "OUTFILE", SYM(OUTFILE)}, { "OVER", SYM(OVER_SYM)}, { "OVERLAPS", SYM(OVERLAPS_SYM)}, { "OWNER", SYM(OWNER_SYM)}, { "PACKAGE", SYM(PACKAGE_MARIADB_SYM)}, { "PACK_KEYS", SYM(PACK_KEYS_SYM)}, { "PAGE", SYM(PAGE_SYM)}, { "PAGE_CHECKSUM", SYM(PAGE_CHECKSUM_SYM)}, { "PARSER", SYM(PARSER_SYM)}, { "PARSE_VCOL_EXPR", SYM(PARSE_VCOL_EXPR_SYM)}, { "PATH", SYM(PATH_SYM)}, { "PERIOD", SYM(PERIOD_SYM)}, { "PARTIAL", SYM(PARTIAL)}, { "PARTITION", SYM(PARTITION_SYM)}, { "PARTITIONING", SYM(PARTITIONING_SYM)}, { "PARTITIONS", SYM(PARTITIONS_SYM)}, { "PASSWORD", SYM(PASSWORD_SYM)}, { "PERSISTENT", SYM(PERSISTENT_SYM)}, { "PHASE", SYM(PHASE_SYM)}, { "PLUGIN", SYM(PLUGIN_SYM)}, { "PLUGINS", SYM(PLUGINS_SYM)}, { "PORT", SYM(PORT_SYM)}, { "PORTION", SYM(PORTION_SYM)}, { "PRECEDES", SYM(PRECEDES_SYM)}, { "PRECEDING", SYM(PRECEDING_SYM)}, { "PRECISION", SYM(PRECISION)}, { "PREPARE", SYM(PREPARE_SYM)}, { "PRESERVE", SYM(PRESERVE_SYM)}, { "PREV", SYM(PREV_SYM)}, { "PREVIOUS", SYM(PREVIOUS_SYM)}, { "PRIMARY", SYM(PRIMARY_SYM)}, { "PRIVILEGES", SYM(PRIVILEGES)}, { "PROCEDURE", SYM(PROCEDURE_SYM)}, { "PROCESS" , SYM(PROCESS)}, { "PROCESSLIST", SYM(PROCESSLIST_SYM)}, { "PROFILE", SYM(PROFILE_SYM)}, { "PROFILES", SYM(PROFILES_SYM)}, { "PROXY", SYM(PROXY_SYM)}, { "PURGE", SYM(PURGE)}, { "QUARTER", SYM(QUARTER_SYM)}, { "QUERY", SYM(QUERY_SYM)}, { "QUICK", SYM(QUICK)}, { "RAISE", SYM(RAISE_MARIADB_SYM)}, { "RANGE", SYM(RANGE_SYM)}, { "RAW", SYM(RAW_MARIADB_SYM)}, { "READ", SYM(READ_SYM)}, { "READ_ONLY", SYM(READ_ONLY_SYM)}, { "READ_WRITE", SYM(READ_WRITE_SYM)}, { "READS", SYM(READS_SYM)}, { "REAL", SYM(REAL)}, { "REBUILD", SYM(REBUILD_SYM)}, { "RECOVER", SYM(RECOVER_SYM)}, { "RECURSIVE", SYM(RECURSIVE_SYM)}, { "REDO_BUFFER_SIZE", SYM(REDO_BUFFER_SIZE_SYM)}, { "REDOFILE", SYM(REDOFILE_SYM)}, { "REDUNDANT", SYM(REDUNDANT_SYM)}, { "REFERENCES", SYM(REFERENCES)}, { "REGEXP", SYM(REGEXP)}, { "RELAY", SYM(RELAY)}, { "RELAYLOG", SYM(RELAYLOG_SYM)}, { "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM)}, { "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM)}, { "RELAY_THREAD", SYM(RELAY_THREAD)}, { "RELEASE", SYM(RELEASE_SYM)}, { "RELOAD", SYM(RELOAD)}, { "REMOVE", SYM(REMOVE_SYM)}, { "RENAME", SYM(RENAME)}, { "REORGANIZE", SYM(REORGANIZE_SYM)}, { "REPAIR", SYM(REPAIR)}, { "REPEATABLE", SYM(REPEATABLE_SYM)}, { "REPLACE", SYM(REPLACE)}, { "REPLAY", SYM(REPLAY_SYM)}, { "REPLICA", SYM(SLAVE)}, { "REPLICAS", SYM(SLAVES)}, { "REPLICA_POS", SYM(SLAVE_POS_SYM)}, { "REPLICATION", SYM(REPLICATION)}, { "REPEAT", SYM(REPEAT_SYM)}, { "REQUIRE", SYM(REQUIRE_SYM)}, { "RESET", SYM(RESET_SYM)}, { "RESIGNAL", SYM(RESIGNAL_SYM)}, { "RESTART", SYM(RESTART_SYM)}, { "RESTORE", SYM(RESTORE_SYM)}, { "RESTRICT", SYM(RESTRICT)}, { "RESUME", SYM(RESUME_SYM)}, { "RETURNED_SQLSTATE",SYM(RETURNED_SQLSTATE_SYM)}, { "RETURN", SYM(RETURN_MARIADB_SYM)}, { "RETURNING", SYM(RETURNING_SYM)}, { "RETURNS", SYM(RETURNS_SYM)}, { "REUSE", SYM(REUSE_SYM)}, { "REVERSE", SYM(REVERSE_SYM)}, { "REVOKE", SYM(REVOKE)}, { "RIGHT", SYM(RIGHT)}, { "RLIKE", SYM(REGEXP)}, /* Like in mSQL2 */ { "ROLE", SYM(ROLE_SYM)}, { "ROLLBACK", SYM(ROLLBACK_SYM)}, { "ROLLUP", SYM(ROLLUP_SYM)}, { "ROUTINE", SYM(ROUTINE_SYM)}, { "ROW", SYM(ROW_SYM)}, { "ROWCOUNT", SYM(ROWCOUNT_SYM)}, /* Oracle-N */ { "ROWNUM", SYM(ROWNUM_SYM)}, /* Oracle-R */ { "ROWS", SYM(ROWS_SYM)}, { "ROWTYPE", SYM(ROWTYPE_MARIADB_SYM)}, { "ROW_COUNT", SYM(ROW_COUNT_SYM)}, { "ROW_FORMAT", SYM(ROW_FORMAT_SYM)}, { "RTREE", SYM(RTREE_SYM)}, { "SAVEPOINT", SYM(SAVEPOINT_SYM)}, { "SCHEDULE", SYM(SCHEDULE_SYM)}, { "SCHEMA", SYM(DATABASE)}, { "SCHEMA_NAME", SYM(SCHEMA_NAME_SYM)}, { "SCHEMAS", SYM(DATABASES)}, { "SECOND", SYM(SECOND_SYM)}, { "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM)}, { "SECURITY", SYM(SECURITY_SYM)}, { "SELECT", SYM(SELECT_SYM)}, { "SENSITIVE", SYM(SENSITIVE_SYM)}, { "SEPARATOR", SYM(SEPARATOR_SYM)}, { "SEQUENCE", SYM(SEQUENCE_SYM)}, { "SERIAL", SYM(SERIAL_SYM)}, { "SERIALIZABLE", SYM(SERIALIZABLE_SYM)}, { "SESSION", SYM(SESSION_SYM)}, { "SERVER", SYM(SERVER_SYM)}, { "SET", SYM(SET)}, { "SETVAL", SYM(SETVAL_SYM)}, { "SHARE", SYM(SHARE_SYM)}, { "SHOW", SYM(SHOW)}, { "SHUTDOWN", SYM(SHUTDOWN)}, { "SIGNAL", SYM(SIGNAL_SYM)}, { "SIGNED", SYM(SIGNED_SYM)}, { "SIMPLE", SYM(SIMPLE_SYM)}, { "SKIP", SYM(SKIP_SYM)}, { "SLAVE", SYM(SLAVE)}, { "SLAVES", SYM(SLAVES)}, { "SLAVE_POS", SYM(SLAVE_POS_SYM)}, { "SLOW", SYM(SLOW)}, { "SNAPSHOT", SYM(SNAPSHOT_SYM)}, { "SMALLINT", SYM(SMALLINT)}, { "SOCKET", SYM(SOCKET_SYM)}, { "SOFT", SYM(SOFT_SYM)}, { "SOME", SYM(ANY_SYM)}, { "SONAME", SYM(SONAME_SYM)}, { "SOUNDS", SYM(SOUNDS_SYM)}, { "SOURCE", SYM(SOURCE_SYM)}, { "STAGE", SYM(STAGE_SYM)}, { "STORED", SYM(STORED_SYM)}, { "SPATIAL", SYM(SPATIAL_SYM)}, { "SPECIFIC", SYM(SPECIFIC_SYM)}, { "REF_SYSTEM_ID", SYM(REF_SYSTEM_ID_SYM)}, { "SQL", SYM(SQL_SYM)}, { "SQLEXCEPTION", SYM(SQLEXCEPTION_SYM)}, { "SQLSTATE", SYM(SQLSTATE_SYM)}, { "SQLWARNING", SYM(SQLWARNING_SYM)}, { "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT)}, { "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT)}, { "SQL_CACHE", SYM(SQL_CACHE_SYM)}, { "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS)}, { "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM)}, { "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT)}, { "SQL_THREAD", SYM(SQL_THREAD)}, { "SQL_TSI_SECOND", SYM(SECOND_SYM)}, { "SQL_TSI_MINUTE", SYM(MINUTE_SYM)}, { "SQL_TSI_HOUR", SYM(HOUR_SYM)}, { "SQL_TSI_DAY", SYM(DAY_SYM)}, { "SQL_TSI_WEEK", SYM(WEEK_SYM)}, { "SQL_TSI_MONTH", SYM(MONTH_SYM)}, { "SQL_TSI_QUARTER", SYM(QUARTER_SYM)}, { "SQL_TSI_YEAR", SYM(YEAR_SYM)}, { "SSL", SYM(SSL_SYM)}, { "START", SYM(START_SYM)}, { "STARTING", SYM(STARTING)}, { "STARTS", SYM(STARTS_SYM)}, { "STATEMENT", SYM(STATEMENT_SYM)}, { "STATS_AUTO_RECALC",SYM(STATS_AUTO_RECALC_SYM)}, { "STATS_PERSISTENT", SYM(STATS_PERSISTENT_SYM)}, { "STATS_SAMPLE_PAGES",SYM(STATS_SAMPLE_PAGES_SYM)}, { "STATUS", SYM(STATUS_SYM)}, { "STOP", SYM(STOP_SYM)}, { "STORAGE", SYM(STORAGE_SYM)}, { "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN)}, { "STRING", SYM(STRING_SYM)}, { "SUBCLASS_ORIGIN", SYM(SUBCLASS_ORIGIN_SYM)}, { "SUBJECT", SYM(SUBJECT_SYM)}, { "SUBPARTITION", SYM(SUBPARTITION_SYM)}, { "SUBPARTITIONS", SYM(SUBPARTITIONS_SYM)}, { "SUPER", SYM(SUPER_SYM)}, { "SUSPEND", SYM(SUSPEND_SYM)}, { "SWAPS", SYM(SWAPS_SYM)}, { "SWITCHES", SYM(SWITCHES_SYM)}, { "SYSDATE", SYM(SYSDATE)}, { "SYSTEM", SYM(SYSTEM)}, { "SYSTEM_TIME", SYM(SYSTEM_TIME_SYM)}, { "TABLE", SYM(TABLE_SYM)}, { "TABLE_NAME", SYM(TABLE_NAME_SYM)}, { "TABLES", SYM(TABLES)}, { "TABLESPACE", SYM(TABLESPACE)}, { "TABLE_CHECKSUM", SYM(TABLE_CHECKSUM_SYM)}, { "TEMPORARY", SYM(TEMPORARY)}, { "TEMPTABLE", SYM(TEMPTABLE_SYM)}, { "TERMINATED", SYM(TERMINATED)}, { "TEXT", SYM(TEXT_SYM)}, { "THAN", SYM(THAN_SYM)}, { "THEN", SYM(THEN_SYM)}, { "TIES", SYM(TIES_SYM)}, { "TIME", SYM(TIME_SYM)}, { "TIMESTAMP", SYM(TIMESTAMP)}, { "TIMESTAMPADD", SYM(TIMESTAMP_ADD)}, { "TIMESTAMPDIFF", SYM(TIMESTAMP_DIFF)}, { "TINYBLOB", SYM(TINYBLOB)}, { "TINYINT", SYM(TINYINT)}, { "TINYTEXT", SYM(TINYTEXT)}, { "TO", SYM(TO_SYM)}, { "TRAILING", SYM(TRAILING)}, { "TRANSACTION", SYM(TRANSACTION_SYM)}, { "TRANSACTIONAL", SYM(TRANSACTIONAL_SYM)}, { "THREADS", SYM(THREADS_SYM)}, { "TRIGGER", SYM(TRIGGER_SYM)}, { "TRIGGERS", SYM(TRIGGERS_SYM)}, { "TRUE", SYM(TRUE_SYM)}, { "TRUNCATE", SYM(TRUNCATE_SYM)}, { "TYPE", SYM(TYPE_SYM)}, { "UNBOUNDED", SYM(UNBOUNDED_SYM)}, { "UNCOMMITTED", SYM(UNCOMMITTED_SYM)}, { "UNDEFINED", SYM(UNDEFINED_SYM)}, { "UNDO_BUFFER_SIZE", SYM(UNDO_BUFFER_SIZE_SYM)}, { "UNDOFILE", SYM(UNDOFILE_SYM)}, { "UNDO", SYM(UNDO_SYM)}, { "UNICODE", SYM(UNICODE_SYM)}, { "UNION", SYM(UNION_SYM)}, { "UNIQUE", SYM(UNIQUE_SYM)}, { "UNKNOWN", SYM(UNKNOWN_SYM)}, { "UNLOCK", SYM(UNLOCK_SYM)}, { "UNINSTALL", SYM(UNINSTALL_SYM)}, { "UNSIGNED", SYM(UNSIGNED)}, { "UNTIL", SYM(UNTIL_SYM)}, { "UPDATE", SYM(UPDATE_SYM)}, { "UPGRADE", SYM(UPGRADE_SYM)}, { "USAGE", SYM(USAGE)}, { "USE", SYM(USE_SYM)}, { "USER", SYM(USER_SYM)}, { "USER_RESOURCES", SYM(RESOURCES)}, { "USE_FRM", SYM(USE_FRM)}, { "USING", SYM(USING)}, { "UTC_DATE", SYM(UTC_DATE_SYM)}, { "UTC_TIME", SYM(UTC_TIME_SYM)}, { "UTC_TIMESTAMP", SYM(UTC_TIMESTAMP_SYM)}, { "VALUE", SYM(VALUE_SYM)}, { "VALUES", SYM(VALUES)}, { "VARBINARY", SYM(VARBINARY)}, { "VARCHAR", SYM(VARCHAR)}, { "VARCHARACTER", SYM(VARCHAR)}, { "VARCHAR2", SYM(VARCHAR2_MARIADB_SYM)}, { "VARIABLES", SYM(VARIABLES)}, { "VARYING", SYM(VARYING)}, { "VIA", SYM(VIA_SYM)}, { "VIEW", SYM(VIEW_SYM)}, { "VIRTUAL", SYM(VIRTUAL_SYM)}, { "VISIBLE", SYM(VISIBLE_SYM)}, { "VERSIONING", SYM(VERSIONING_SYM)}, { "WAIT", SYM(WAIT_SYM)}, { "WARNINGS", SYM(WARNINGS)}, { "WEEK", SYM(WEEK_SYM)}, { "WEIGHT_STRING", SYM(WEIGHT_STRING_SYM)}, { "WHEN", SYM(WHEN_SYM)}, { "WHERE", SYM(WHERE)}, { "WHILE", SYM(WHILE_SYM)}, { "WINDOW", SYM(WINDOW_SYM)}, { "WITH", SYM(WITH)}, { "WITHIN", SYM(WITHIN)}, { "WITHOUT", SYM(WITHOUT)}, { "WORK", SYM(WORK_SYM)}, { "WRAPPER", SYM(WRAPPER_SYM)}, { "WRITE", SYM(WRITE_SYM)}, { "X509", SYM(X509_SYM)}, { "XOR", SYM(XOR)}, { "XA", SYM(XA_SYM)}, { "XML", SYM(XML_SYM)}, /* LOAD XML Arnold/Erik */ { "YEAR", SYM(YEAR_SYM)}, { "YEAR_MONTH", SYM(YEAR_MONTH_SYM)}, { "ZEROFILL", SYM(ZEROFILL)}, { "||", SYM(OR2_SYM)} }; SYMBOL sql_functions[] = { { "ADDDATE", SYM(ADDDATE_SYM)}, { "BIT_AND", SYM(BIT_AND)}, { "BIT_OR", SYM(BIT_OR)}, { "BIT_XOR", SYM(BIT_XOR)}, { "CAST", SYM(CAST_SYM)}, { "COUNT", SYM(COUNT_SYM)}, { "CUME_DIST", SYM(CUME_DIST_SYM)}, { "CURDATE", SYM(CURDATE)}, { "CURTIME", SYM(CURTIME)}, { "DATE_ADD", SYM(DATE_ADD_INTERVAL)}, { "DATE_SUB", SYM(DATE_SUB_INTERVAL)}, { "DENSE_RANK", SYM(DENSE_RANK_SYM)}, { "EXTRACT", SYM(EXTRACT_SYM)}, { "FIRST_VALUE", SYM(FIRST_VALUE_SYM)}, { "GROUP_CONCAT", SYM(GROUP_CONCAT_SYM)}, { "JSON_ARRAYAGG", SYM(JSON_ARRAYAGG_SYM)}, { "JSON_OBJECTAGG", SYM(JSON_OBJECTAGG_SYM)}, { "LAG", SYM(LAG_SYM)}, { "LEAD", SYM(LEAD_SYM)}, { "MAX", SYM(MAX_SYM)}, { "MEDIAN", SYM(MEDIAN_SYM)}, { "MID", SYM(SUBSTRING)}, /* unireg function */ { "MIN", SYM(MIN_SYM)}, { "NOW", SYM(NOW_SYM)}, { "NTH_VALUE", SYM(NTH_VALUE_SYM)}, { "NTILE", SYM(NTILE_SYM)}, { "POSITION", SYM(POSITION_SYM)}, { "PERCENT_RANK", SYM(PERCENT_RANK_SYM)}, { "PERCENTILE_CONT", SYM(PERCENTILE_CONT_SYM)}, { "PERCENTILE_DISC", SYM(PERCENTILE_DISC_SYM)}, { "RANK", SYM(RANK_SYM)}, { "ROW_NUMBER", SYM(ROW_NUMBER_SYM)}, { "SESSION_USER", SYM(USER_SYM)}, { "STD", SYM(STD_SYM)}, { "STDDEV", SYM(STD_SYM)}, { "STDDEV_POP", SYM(STD_SYM)}, { "STDDEV_SAMP", SYM(STDDEV_SAMP_SYM)}, { "SUBDATE", SYM(SUBDATE_SYM)}, { "SUBSTR", SYM(SUBSTRING)}, { "SUBSTRING", SYM(SUBSTRING)}, { "SUM", SYM(SUM_SYM)}, { "SYSTEM_USER", SYM(USER_SYM)}, { "TRIM", SYM(TRIM)}, { "TRIM_ORACLE", SYM(TRIM_ORACLE)}, { "VARIANCE", SYM(VARIANCE_SYM)}, { "VAR_POP", SYM(VARIANCE_SYM)}, { "VAR_SAMP", SYM(VAR_SAMP_SYM)}, }; size_t symbols_length= sizeof(symbols) / sizeof(SYMBOL); size_t sql_functions_length= sizeof(sql_functions) / sizeof(SYMBOL); #endif /* LEX_INCLUDED */ server/private/sql_base.h000064400000062430151031265040011470 0ustar00/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2011, 2018, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_BASE_INCLUDED #define SQL_BASE_INCLUDED #include "sql_class.h" /* enum_column_usage */ #include "sql_trigger.h" /* trg_event_type */ #include "mysqld.h" /* key_map */ #include "table_cache.h" class Item_ident; struct Name_resolution_context; class Open_table_context; class Open_tables_state; class Prelocking_strategy; struct TABLE_LIST; class THD; struct handlerton; struct TABLE; typedef class st_select_lex SELECT_LEX; typedef struct st_lock_param_type ALTER_PARTITION_PARAM_TYPE; /* This enumeration type is used only by the function find_item_in_list to return the info on how an item has been resolved against a list of possibly aliased items. The item can be resolved: - against an alias name of the list's element (RESOLVED_AGAINST_ALIAS) - against non-aliased field name of the list (RESOLVED_WITH_NO_ALIAS) - against an aliased field name of the list (RESOLVED_BEHIND_ALIAS) - ignoring the alias name in cases when SQL requires to ignore aliases (e.g. when the resolved field reference contains a table name or when the resolved item is an expression) (RESOLVED_IGNORING_ALIAS) */ enum enum_resolution_type { NOT_RESOLVED=0, RESOLVED_IGNORING_ALIAS, RESOLVED_BEHIND_ALIAS, RESOLVED_WITH_NO_ALIAS, RESOLVED_AGAINST_ALIAS }; /* Argument to flush_tables() of what to flush */ enum flush_tables_type { FLUSH_ALL, FLUSH_NON_TRANS_TABLES, FLUSH_SYS_TABLES }; enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE, IGNORE_EXCEPT_NON_UNIQUE}; /* Flag bits for unique_table() */ #define CHECK_DUP_ALLOW_DIFFERENT_ALIAS 1 #define CHECK_DUP_FOR_CREATE 2 #define CHECK_DUP_SKIP_TEMP_TABLE 4 uint get_table_def_key(const TABLE_LIST *table_list, const char **key); TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update, uint lock_flags); /* mysql_lock_tables() and open_table() flags bits */ #define MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK 0x0001 #define MYSQL_OPEN_IGNORE_FLUSH 0x0002 /* MYSQL_OPEN_TEMPORARY_ONLY (0x0004) is not used anymore. */ #define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008 #define MYSQL_LOCK_LOG_TABLE 0x0010 /** Do not try to acquire a metadata lock on the table: we already have one. */ #define MYSQL_OPEN_HAS_MDL_LOCK 0x0020 /** If in locked tables mode, ignore the locked tables and get a new instance of the table. */ #define MYSQL_OPEN_GET_NEW_TABLE 0x0040 /* 0x0080 used to be MYSQL_OPEN_SKIP_TEMPORARY */ /** Fail instead of waiting when conficting metadata lock is discovered. */ #define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0100 /** Open tables using MDL_SHARED lock instead of one specified in parser. */ #define MYSQL_OPEN_FORCE_SHARED_MDL 0x0200 /** Open tables using MDL_SHARED_HIGH_PRIO lock instead of one specified in parser. */ #define MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL 0x0400 /** When opening or locking the table, use the maximum timeout (LONG_TIMEOUT = 1 year) rather than the user-supplied timeout value. */ #define MYSQL_LOCK_IGNORE_TIMEOUT 0x0800 /** When acquiring "strong" (SNW, SNRW, X) metadata locks on tables to be open do not acquire global and schema-scope IX locks. */ #define MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK 0x1000 #define MYSQL_LOCK_NOT_TEMPORARY 0x2000 #define MYSQL_LOCK_USE_MALLOC 0x4000 /** Only check THD::killed if waits happen (e.g. wait on MDL, wait on table flush, wait on thr_lock.c locks) while opening and locking table. */ #define MYSQL_OPEN_IGNORE_KILLED 0x8000 /** Don't try to auto-repair table */ #define MYSQL_OPEN_IGNORE_REPAIR 0x10000 /** Don't call decide_logging_format. Used for statistic tables etc */ #define MYSQL_OPEN_IGNORE_LOGGING_FORMAT 0x20000 /* Don't use statistics tables */ #define MYSQL_OPEN_IGNORE_ENGINE_STATS 0x40000 /** Please refer to the internals manual. */ #define MYSQL_OPEN_REOPEN (MYSQL_OPEN_IGNORE_FLUSH |\ MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |\ MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\ MYSQL_LOCK_IGNORE_TIMEOUT |\ MYSQL_OPEN_GET_NEW_TABLE |\ MYSQL_OPEN_HAS_MDL_LOCK) bool is_locked_view(THD *thd, TABLE_LIST *t); bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx); bool get_key_map_from_key_list(key_map *map, TABLE *table, List *index_list); TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name); TABLE *find_write_locked_table(TABLE *list, const char *db, const char *table_name); thr_lock_type read_lock_type_for_table(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool routine_modifies_data); my_bool mysql_rm_tmp_tables(void); void close_tables_for_reopen(THD *thd, TABLE_LIST **tables, const MDL_savepoint &start_of_statement_svp); bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db, LEX_CSTRING *table, thr_lock_type lock_type); TABLE_LIST *find_table_in_list(TABLE_LIST *table, TABLE_LIST *TABLE_LIST::*link, const LEX_CSTRING *db_name, const LEX_CSTRING *table_name); int close_thread_tables(THD *thd); void switch_to_nullable_trigger_fields(List &items, TABLE *); void switch_defaults_to_nullable_trigger_fields(TABLE *table); bool fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, List &fields, List &values, bool ignore_errors, enum trg_event_type event); bool fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, Field **field, List &values, bool ignore_errors, enum trg_event_type event); bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator *it, bool any_privileges, uint *hidden_bit_fields, bool returning_field); void make_leaves_list(THD *thd, List &list, TABLE_LIST *tables, bool full_table_list, TABLE_LIST *boundary); int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, List *sum_func_list, SELECT_LEX *sl, bool returning_field); int setup_returning_fields(THD* thd, TABLE_LIST* table_list); bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, List &item, enum_column_usage column_usage, List *sum_func_list, List *pre_fix, bool allow_sum_func, THD_WHERE where= THD_WHERE::DEFAULT_WHERE); void unfix_fields(List &items); bool fill_record(THD * thd, TABLE *table_arg, List &fields, List &values, bool ignore_errors, bool update); bool fill_record(THD *thd, TABLE *table, Field **field, List &values, bool ignore_errors, bool use_value, bool check_for_evaluability); Field * find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *first_table, TABLE_LIST *last_table, ignored_tables_list_t ignored_tables, Item **ref, find_item_error_report_type report_error, bool check_privileges, bool register_tree_change); Field * find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, const char *name, size_t length, const char *item_name, const char *db_name, const char *table_name, ignored_tables_list_t ignored_tables, Item **ref, bool check_privileges, bool allow_rowid, field_index_t *cached_field_index_ptr, bool register_tree_change, TABLE_LIST **actual_table); Field * find_field_in_table(THD *thd, TABLE *table, const char *name, size_t length, bool allow_rowid, field_index_t *cached_field_index_ptr); Field * find_field_in_table_sef(TABLE *table, const char *name); Item ** find_item_in_list(Item *item, List &items, uint *counter, find_item_error_report_type report_error, enum_resolution_type *resolution, uint limit= 0); bool setup_tables(THD *thd, Name_resolution_context *context, List *from_clause, TABLE_LIST *tables, List &leaves, bool select_insert, bool full_table_list); bool setup_tables_and_check_access(THD *thd, Name_resolution_context *context, List *from_clause, TABLE_LIST *tables, List &leaves, bool select_insert, privilege_t want_access_first, privilege_t want_access, bool full_table_list); bool wait_while_table_is_used(THD *thd, TABLE *table, enum ha_extra_function function); void drop_open_table(THD *thd, TABLE *table, const LEX_CSTRING *db_name, const LEX_CSTRING *table_name); void update_non_unique_table_error(TABLE_LIST *update, const char *operation, TABLE_LIST *duplicate); int setup_conds(THD *thd, TABLE_LIST *tables, List &leaves, COND **conds); void wrap_ident(THD *thd, Item **conds); int setup_ftfuncs(SELECT_LEX* select); void cleanup_ftfuncs(SELECT_LEX *select_lex); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); bool lock_table_names(THD *thd, const DDL_options_st &options, TABLE_LIST *table_list, TABLE_LIST *table_list_end, ulong lock_wait_timeout, uint flags); static inline bool lock_table_names(THD *thd, TABLE_LIST *table_list, TABLE_LIST *table_list_end, ulong lock_wait_timeout, uint flags) { return lock_table_names(thd, thd->lex->create_info, table_list, table_list_end, lock_wait_timeout, flags); } bool open_tables(THD *thd, const DDL_options_st &options, TABLE_LIST **tables, uint *counter, uint flags, Prelocking_strategy *prelocking_strategy); static inline bool open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags, Prelocking_strategy *prelocking_strategy) { return open_tables(thd, thd->lex->create_info, tables, counter, flags, prelocking_strategy); } /* open_and_lock_tables with optional derived handling */ bool open_and_lock_tables(THD *thd, const DDL_options_st &options, TABLE_LIST *tables, bool derived, uint flags, Prelocking_strategy *prelocking_strategy); static inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, bool derived, uint flags, Prelocking_strategy *prelocking_strategy) { return open_and_lock_tables(thd, thd->lex->create_info, tables, derived, flags, prelocking_strategy); } /* simple open_and_lock_tables without derived handling for single table */ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, thr_lock_type lock_type, uint flags, Prelocking_strategy *prelocking_strategy); bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags, uint dt_phases); bool open_tables_only_view_structure(THD *thd, TABLE_LIST *tables, bool can_deadlock); bool open_and_lock_internal_tables(TABLE *table, bool lock); bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags); int decide_logging_format(THD *thd, TABLE_LIST *tables); void close_thread_table(THD *thd, TABLE **table_ptr); TABLE_LIST* unique_table_in_insert_returning_subselect(THD *thd, TABLE_LIST *table, SELECT_LEX *sel); TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, uint check_flag); bool is_equal(const LEX_CSTRING *a, const LEX_CSTRING *b); class Open_tables_backup; /* Functions to work with system tables. */ bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list); void close_system_tables(THD *thd); void close_mysql_tables(THD *thd); TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table); TABLE *open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup); void close_log_table(THD *thd, Open_tables_backup *backup); bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool wait_for_refresh, ulong timeout); void purge_tables(); bool flush_tables(THD *thd, flush_tables_type flag); void close_all_tables_for_name(THD *thd, TABLE_SHARE *share, ha_extra_function extra, TABLE *skip_table); OPEN_TABLE_LIST *list_open_tables(THD *thd, const LEX_CSTRING &db, const char *wild); bool tdc_open_view(THD *thd, TABLE_LIST *table_list, uint flags); TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, const char *table_name, int *p_error); void mark_tmp_table_for_reuse(TABLE *table); int dynamic_column_error_message(enum_dyncol_func_result rc); /* open_and_lock_tables with optional derived handling */ int open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived); extern "C" qsort_cmp2 simple_raw_key_cmp; extern "C" int count_distinct_walk(void *elem, element_count count, void *arg); int simple_str_key_cmp(void *arg, const void *key1, const void *key2); extern Item **not_found_item; extern Field *not_found_field; extern Field *view_ref_found; /** clean/setup table fields and map. @param table TABLE structure pointer (which should be setup) @param table_list TABLE_LIST structure pointer (owner of TABLE) @param tablenr table number */ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) { table->used_fields= 0; table_list->reset_const_table(); table->null_row= 0; table->status= STATUS_NO_RECORD; table->maybe_null= table_list->outer_join; TABLE_LIST *embedding= table_list->embedding; while (!table->maybe_null && embedding) { table->maybe_null= embedding->outer_join; embedding= embedding->embedding; } DBUG_ASSERT(tablenr <= MAX_TABLES); table->tablenr= tablenr; table->map= (table_map) 1 << tablenr; table->force_index= table_list->force_index; table->force_index_order= table->force_index_group= 0; table->covering_keys= table->s->keys_for_keyread; } inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table, LEX_CSTRING *db_name, LEX_CSTRING *table_name) { return find_table_in_list(table, &TABLE_LIST::next_global, db_name, table_name); } inline bool setup_fields_with_no_wrap(THD *thd, Ref_ptr_array ref_pointer_array, List &item, enum_column_usage column_usage, List *sum_func_list, bool allow_sum_func, THD_WHERE where= THD_WHERE::DEFAULT_WHERE) { bool res; SELECT_LEX *first= thd->lex->first_select_lex(); DBUG_ASSERT(thd->lex->current_select == first); first->no_wrap_view_item= TRUE; res= setup_fields(thd, ref_pointer_array, item, column_usage, sum_func_list, NULL, allow_sum_func, where); first->no_wrap_view_item= FALSE; return res; } /** An abstract class for a strategy specifying how the prelocking algorithm should extend the prelocking set while processing already existing elements in the set. */ class Prelocking_strategy { public: virtual ~Prelocking_strategy() = default; virtual void reset(THD *thd) { }; virtual bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx, Sroutine_hash_entry *rt, sp_head *sp, bool *need_prelocking) = 0; virtual bool handle_table(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool *need_prelocking) = 0; virtual bool handle_view(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool *need_prelocking)= 0; virtual bool handle_end(THD *thd) { return 0; }; }; /** A Strategy for prelocking algorithm suitable for DML statements. Ensures that all tables used by all statement's SF/SP/triggers and required for foreign key checks are prelocked and SF/SPs used are cached. */ class DML_prelocking_strategy : public Prelocking_strategy { public: bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx, Sroutine_hash_entry *rt, sp_head *sp, bool *need_prelocking) override; bool handle_table(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool *need_prelocking) override; bool handle_view(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool *need_prelocking) override; }; /** A strategy for prelocking algorithm to be used for LOCK TABLES statement. */ class Lock_tables_prelocking_strategy : public DML_prelocking_strategy { bool handle_table(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool *need_prelocking) override; }; /** Strategy for prelocking algorithm to be used for ALTER TABLE statements. Unlike DML or LOCK TABLES strategy, it doesn't prelock triggers, views or stored routines, since they are not used during ALTER. */ class Alter_table_prelocking_strategy : public Prelocking_strategy { public: bool handle_routine(THD *thd, Query_tables_list *prelocking_ctx, Sroutine_hash_entry *rt, sp_head *sp, bool *need_prelocking) override; bool handle_table(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool *need_prelocking) override; bool handle_view(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool *need_prelocking) override; }; inline bool open_tables(THD *thd, const DDL_options_st &options, TABLE_LIST **tables, uint *counter, uint flags) { DML_prelocking_strategy prelocking_strategy; return open_tables(thd, options, tables, counter, flags, &prelocking_strategy); } inline bool open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags) { DML_prelocking_strategy prelocking_strategy; return open_tables(thd, thd->lex->create_info, tables, counter, flags, &prelocking_strategy); } inline TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, thr_lock_type lock_type, uint flags) { DML_prelocking_strategy prelocking_strategy; return open_n_lock_single_table(thd, table_l, lock_type, flags, &prelocking_strategy); } /* open_and_lock_tables with derived handling */ inline bool open_and_lock_tables(THD *thd, const DDL_options_st &options, TABLE_LIST *tables, bool derived, uint flags) { DML_prelocking_strategy prelocking_strategy; return open_and_lock_tables(thd, options, tables, derived, flags, &prelocking_strategy); } inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, bool derived, uint flags) { DML_prelocking_strategy prelocking_strategy; return open_and_lock_tables(thd, thd->lex->create_info, tables, derived, flags, &prelocking_strategy); } bool restart_trans_for_tables(THD *thd, TABLE_LIST *table); bool extend_table_list(THD *thd, TABLE_LIST *tables, Prelocking_strategy *prelocking_strategy, bool has_prelocking_list); /** A context of open_tables() function, used to recover from a failed open_table() or open_routine() attempt. */ class Open_table_context { public: enum enum_open_table_action { OT_NO_ACTION= 0, OT_BACKOFF_AND_RETRY, OT_REOPEN_TABLES, OT_DISCOVER, OT_REPAIR }; Open_table_context(THD *thd, uint flags); bool recover_from_failed_open(); bool request_backoff_action(enum_open_table_action action_arg, TABLE_LIST *table); bool can_recover_from_failed_open() const { return m_action != OT_NO_ACTION; } /** When doing a back-off, we close all tables acquired by this statement. Return an MDL savepoint taken at the beginning of the statement, so that we can rollback to it before waiting on locks. */ const MDL_savepoint &start_of_statement_svp() const { return m_start_of_statement_svp; } inline ulong get_timeout() const { return m_timeout; } uint get_flags() const { return m_flags; } /** Set flag indicating that we have already acquired metadata lock protecting this statement against GRL while opening tables. */ void set_has_protection_against_grl(enum_mdl_type mdl_type) { m_has_protection_against_grl|= MDL_BIT(mdl_type); } bool has_protection_against_grl(enum_mdl_type mdl_type) const { return (bool) (m_has_protection_against_grl & MDL_BIT(mdl_type)); } private: /* THD for which tables are opened. */ THD *m_thd; /** For OT_DISCOVER and OT_REPAIR actions, the table list element for the table which definition should be re-discovered or which should be repaired. */ TABLE_LIST *m_failed_table; MDL_savepoint m_start_of_statement_svp; /** Lock timeout in seconds. Initialized to LONG_TIMEOUT when opening system tables or to the "lock_wait_timeout" system variable for regular tables. */ ulong m_timeout; /* open_table() flags. */ uint m_flags; /** Back off action. */ enum enum_open_table_action m_action; /** Whether we had any locks when this context was created. If we did, they are from the previous statement of a transaction, and we can't safely do back-off (and release them). */ bool m_has_locks; /** Indicates that in the process of opening tables we have acquired protection against global read lock. */ mdl_bitmap_t m_has_protection_against_grl; }; /** Check if a TABLE_LIST instance represents a pre-opened temporary table. */ inline bool is_temporary_table(TABLE_LIST *tl) { if (tl->view || tl->schema_table) return FALSE; if (!tl->table) return FALSE; /* NOTE: 'table->s' might be NULL for specially constructed TABLE instances. See SHOW TRIGGERS for example. */ if (!tl->table->s) return FALSE; return tl->table->s->tmp_table != NO_TMP_TABLE; } /** This internal handler is used to trap ER_NO_SUCH_TABLE. */ class No_such_table_error_handler : public Internal_error_handler { public: No_such_table_error_handler() : m_handled_errors(0), m_unhandled_errors(0), first_error(0) {} bool handle_condition(THD *thd, uint sql_errno, const char* sqlstate, Sql_condition::enum_warning_level *level, const char* msg, Sql_condition ** cond_hdl) override; /** Returns TRUE if one or more ER_NO_SUCH_TABLE errors have been trapped and no other errors have been seen. FALSE otherwise. */ bool safely_trapped_errors(); uint got_error() { return first_error; } private: int m_handled_errors; int m_unhandled_errors; uint first_error; }; #endif /* SQL_BASE_INCLUDED */ server/private/procedure.h000064400000015200151031265040011660 0ustar00#ifndef PROCEDURE_INCLUDED #define PROCEDURE_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2009, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* When using sql procedures */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif /* It is necessary to include set_var.h instead of item.h because there are dependencies on include order for set_var.h and item.h. This will be resolved later. */ #include "sql_class.h" /* select_result, set_var.h: THD */ #include "set_var.h" /* Item */ #define PROC_NO_SORT 1 /**< Bits in flags */ #define PROC_GROUP 2 /**< proc must have group */ /* Procedure items used by procedures to store values for send_result_set_metadata */ class Item_proc :public Item { public: Item_proc(THD *thd, const char *name_par): Item(thd) { this->name.str= name_par; this->name.length= strlen(name_par); } enum Type type() const override { return Item::PROC_ITEM; } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { /* We can get to here when using a CURSOR for a query with PROCEDURE: DECLARE c CURSOR FOR SELECT * FROM t1 PROCEDURE analyse(); OPEN c; */ return create_tmp_field_ex_simple(root, table, src, param); } virtual void set(double nr)=0; virtual void set(const char *str,uint length,CHARSET_INFO *cs)=0; virtual void set(longlong nr)=0; const Type_handler *type_handler() const override=0; void set(const char *str) { set(str,(uint) strlen(str), default_charset()); } unsigned int size_of() { return sizeof(*this);} bool check_vcol_func_processor(void *arg) override { DBUG_ASSERT(0); // impossible return mark_unsupported_function("proc", arg, VCOL_IMPOSSIBLE); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } Item* do_get_copy(THD *thd) const override { return 0; } }; class Item_proc_real :public Item_proc { double value; public: Item_proc_real(THD *thd, const char *name_par, uint dec): Item_proc(thd, name_par) { decimals=dec; max_length=float_length(dec); } const Type_handler *type_handler() const override { return &type_handler_double; } void set(double nr) override { value=nr; } void set(longlong nr) override { value=(double) nr; } void set(const char *str,uint length,CHARSET_INFO *cs) override { int err_not_used; char *end_not_used; value= cs->strntod((char*) str,length, &end_not_used, &err_not_used); } double val_real() override { return value; } longlong val_int() override { return (longlong) value; } String *val_str(String *s) override { s->set_real(value,decimals,default_charset()); return s; } my_decimal *val_decimal(my_decimal *) override; unsigned int size_of() { return sizeof(*this);} }; class Item_proc_int :public Item_proc { longlong value; public: Item_proc_int(THD *thd, const char *name_par): Item_proc(thd, name_par) { max_length=11; } const Type_handler *type_handler() const override { if (unsigned_flag) return &type_handler_ulonglong; return &type_handler_slonglong; } void set(double nr) override { value=(longlong) nr; } void set(longlong nr) override { value=nr; } void set(const char *str,uint length, CHARSET_INFO *cs) override { int err; value= cs->strntoll(str,length,10,NULL,&err); } double val_real() override { return (double) value; } longlong val_int() override { return value; } String *val_str(String *s) override { s->set(value, default_charset()); return s; } my_decimal *val_decimal(my_decimal *) override; unsigned int size_of() { return sizeof(*this);} Item *do_get_copy(THD *thd) const override { return nullptr; } Item *do_build_clone(THD *thd) const override { return nullptr; } }; class Item_proc_string :public Item_proc { String value; public: Item_proc_string(THD *thd, const char *name_par, uint length): Item_proc(thd, name_par) { this->max_length=length; value.set_thread_specific(); } const Type_handler *type_handler() const override { return &type_handler_varchar; } void set(double nr) override { value.set_real(nr, 2, default_charset()); } void set(longlong nr) override { value.set(nr, default_charset()); } void set(const char *str, uint length, CHARSET_INFO *cs) override { value.copy(str,length,cs); } double val_real() override { int err_not_used; char *end_not_used; CHARSET_INFO *cs= value.charset(); return cs->strntod((char*) value.ptr(), value.length(), &end_not_used, &err_not_used); } longlong val_int() override { int err; CHARSET_INFO *cs=value.charset(); return cs->strntoll(value.ptr(), value.length(), 10, NULL, &err); } String *val_str(String*) override { return null_value ? (String*) 0 : &value; } my_decimal *val_decimal(my_decimal *) override; void cleanup() override { value.free(); } unsigned int size_of() { return sizeof(*this);} Item *do_get_copy(THD *thd) const override { return nullptr; } Item *do_build_clone(THD *thd) const override { return nullptr; } }; /* The procedure class definitions */ class Procedure { protected: List *fields; select_result *result; public: const uint flags; ORDER *group,*param_fields; Procedure(select_result *res,uint flags_par) :result(res),flags(flags_par), group(0),param_fields(0) {} virtual ~Procedure() {group=param_fields=0; fields=0; } virtual void add(void)=0; virtual void end_group(void)=0; virtual int send_row(List &fields)=0; virtual bool change_columns(THD *thd, List &fields)= 0; virtual void update_refs(void) {} virtual int end_of_records() { return 0; } }; Procedure *setup_procedure(THD *thd,ORDER *proc_param,select_result *result, List &field_list,int *error); #endif /* PROCEDURE_INCLUDED */ server/private/sql_partition.h000064400000027450151031265040012572 0ustar00#ifndef SQL_PARTITION_INCLUDED #define SQL_PARTITION_INCLUDED /* Copyright (c) 2006, 2017, Oracle and/or its affiliates. Copyright (c) 2011, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_list.h" /* List */ #include "table.h" /* TABLE_LIST */ class Alter_info; class Alter_table_ctx; class Field; class String; class handler; class partition_info; struct TABLE; struct TABLE_LIST; typedef struct st_bitmap MY_BITMAP; typedef struct st_key KEY; typedef struct st_key_range key_range; /* Flags for partition handlers */ #define HA_CAN_PARTITION (1 << 0) /* Partition support */ #define HA_CAN_UPDATE_PARTITION_KEY (1 << 1) #define HA_CAN_PARTITION_UNIQUE (1 << 2) #define HA_USE_AUTO_PARTITION (1 << 3) #define HA_ONLY_VERS_PARTITION (1 << 4) #define NORMAL_PART_NAME 0 #define TEMP_PART_NAME 1 #define RENAMED_PART_NAME 2 typedef struct st_lock_param_type { TABLE_LIST *table_list; ulonglong copied; ulonglong deleted; THD *thd; HA_CREATE_INFO *create_info; Alter_info *alter_info; TABLE *table; KEY *key_info_buffer; LEX_CUSTRING org_tabledef_version; uchar *pack_frm_data; uint key_count; uint db_options; size_t pack_frm_len; partition_info *part_info; } ALTER_PARTITION_PARAM_TYPE; typedef struct { longlong list_value; uint32 partition_id; } LIST_PART_ENTRY; typedef struct { uint32 start_part; uint32 end_part; } part_id_range; class String_list; struct st_partition_iter; #define NOT_A_PARTITION_ID UINT_MAX32 bool is_partition_in_list(char *part_name, List list_part_names); char *are_partitions_in_table(partition_info *new_part_info, partition_info *old_part_info); bool check_reorganise_list(partition_info *new_part_info, partition_info *old_part_info, List list_part_names); handler *get_ha_partition(partition_info *part_info); int get_part_for_buf(const uchar *buf, const uchar *rec0, partition_info *part_info, uint32 *part_id); void prune_partition_set(const TABLE *table, part_id_range *part_spec); bool check_partition_info(partition_info *part_info,handlerton **eng_type, TABLE *table, handler *file, HA_CREATE_INFO *info); void set_linear_hash_mask(partition_info *part_info, uint num_parts); bool fix_partition_func(THD *thd, TABLE *table, bool create_table_ind); void get_partition_set(const TABLE *table, uchar *buf, const uint index, const key_range *key_spec, part_id_range *part_spec); uint get_partition_field_store_length(Field *field); void get_full_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info, const key_range *key_spec, part_id_range *part_spec); bool mysql_unpack_partition(THD *thd, char *part_buf, uint part_info_len, TABLE *table, bool is_create_table_ind, handlerton *default_db_type, bool *work_part_info_used); void make_used_partitions_str(MEM_ROOT *mem_root, partition_info *part_info, String *parts_str, String_list &used_partitions_list); uint32 get_list_array_idx_for_endpoint(partition_info *part_info, bool left_endpoint, bool include_endpoint); uint32 get_partition_id_range_for_endpoint(partition_info *part_info, bool left_endpoint, bool include_endpoint); bool check_part_func_fields(Field **ptr, bool ok_with_charsets); bool field_is_partition_charset(Field *field); Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs); /** Append all fields in read_set to string @param[in,out] str String to append to. @param[in] row Row to append. @param[in] table Table containing read_set and fields for the row. */ void append_row_to_str(String &str, const uchar *row, TABLE *table); void truncate_partition_filename(char *path); /* A "Get next" function for partition iterator. SYNOPSIS partition_iter_func() part_iter Partition iterator, you call only "iter.get_next(&iter)" DESCRIPTION Depending on whether partitions or sub-partitions are iterated, the function returns next subpartition id/partition number. The sequence of returned numbers is not ordered and may contain duplicates. When the end of sequence is reached, NOT_A_PARTITION_ID is returned, and the iterator resets itself (so next get_next() call will start to enumerate the set all over again). RETURN NOT_A_PARTITION_ID if there are no more partitions. [sub]partition_id of the next partition */ typedef uint32 (*partition_iter_func)(st_partition_iter* part_iter); /* Partition set iterator. Used to enumerate a set of [sub]partitions obtained in partition interval analysis (see get_partitions_in_range_iter). For the user, the only meaningful field is get_next, which may be used as follows: part_iterator.get_next(&part_iterator); Initialization is done by any of the following calls: - get_partitions_in_range_iter-type function call - init_single_partition_iterator() - init_all_partitions_iterator() Cleanup is not needed. */ typedef struct st_partition_iter { partition_iter_func get_next; /* Valid for "Interval mapping" in LIST partitioning: if true, let the iterator also produce id of the partition that contains NULL value. */ bool ret_null_part, ret_null_part_orig; /* We should return DEFAULT partition. */ bool ret_default_part, ret_default_part_orig; struct st_part_num_range { uint32 start; uint32 cur; uint32 end; }; struct st_field_value_range { longlong start; longlong cur; longlong end; }; union { struct st_part_num_range part_nums; struct st_field_value_range field_vals; }; partition_info *part_info; } PARTITION_ITERATOR; /* Get an iterator for set of partitions that match given field-space interval SYNOPSIS get_partitions_in_range_iter() part_info Partitioning info is_subpart store_length_array Length of fields packed in opt_range_key format min_val Left edge, field value in opt_range_key format max_val Right edge, field value in opt_range_key format min_len Length of minimum value max_len Length of maximum value flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE, NO_MAX_RANGE part_iter Iterator structure to be initialized DESCRIPTION Functions with this signature are used to perform "Partitioning Interval Analysis". This analysis is applicable for any type of [sub]partitioning by some function of a single fieldX. The idea is as follows: Given an interval "const1 <=? fieldX <=? const2", find a set of partitions that may contain records with value of fieldX within the given interval. The min_val, max_val and flags parameters specify the interval. The set of partitions is returned by initializing an iterator in *part_iter NOTES There are currently three functions of this type: - get_part_iter_for_interval_via_walking - get_part_iter_for_interval_cols_via_map - get_part_iter_for_interval_via_mapping RETURN 0 - No matching partitions, iterator not initialized 1 - Some partitions would match, iterator intialized for traversing them -1 - All partitions would match, iterator not initialized */ typedef int (*get_partitions_in_range_iter)(partition_info *part_info, bool is_subpart, uint32 *store_length_array, uchar *min_val, uchar *max_val, uint min_len, uint max_len, uint flags, PARTITION_ITERATOR *part_iter); #include "partition_info.h" #ifdef WITH_PARTITION_STORAGE_ENGINE uint fast_alter_partition_table(THD *thd, TABLE *table, Alter_info *alter_info, HA_CREATE_INFO *create_info, TABLE_LIST *table_list); bool set_part_state(Alter_info *alter_info, partition_info *tab_part_info, enum partition_state part_state); uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, HA_CREATE_INFO *create_info, bool *partition_changed, bool *fast_alter_table); char *generate_partition_syntax(THD *thd, partition_info *part_info, uint *buf_length, bool show_partition_options, HA_CREATE_INFO *create_info, Alter_info *alter_info); char *generate_partition_syntax_for_frm(THD *thd, partition_info *part_info, uint *buf_length, HA_CREATE_INFO *create_info, Alter_info *alter_info); bool verify_data_with_partition(TABLE *table, TABLE *part_table, uint32 part_id); bool compare_partition_options(HA_CREATE_INFO *table_create_info, partition_element *part_elem); bool partition_key_modified(TABLE *table, const MY_BITMAP *fields); #else #define partition_key_modified(X,Y) 0 #endif int __attribute__((warn_unused_result)) create_partition_name(char *out, size_t outlen, const char *in1, const char *in2, uint name_variant, bool translate); int __attribute__((warn_unused_result)) create_subpartition_name(char *out, size_t outlen, const char *in1, const char *in2, const char *in3, uint name_variant); void set_key_field_ptr(KEY *key_info, const uchar *new_buf, const uchar *old_buf); /** Set up table for creating a partition. Copy info from partition to the table share so the created partition has the correct info. @param thd THD object @param share Table share to be updated. @param info Create info to be updated. @param part_elem partition_element containing the info. @return status @retval TRUE Error @retval FALSE Success @details Set up 1) Comment on partition 2) MAX_ROWS, MIN_ROWS on partition 3) Index file name on partition 4) Data file name on partition */ bool set_up_table_before_create(THD *thd, TABLE_SHARE *share, const char *partition_name_with_path, HA_CREATE_INFO *info, partition_element *part_elem); #endif /* SQL_PARTITION_INCLUDED */ server/private/sql_error.h000064400000115244151031265040011711 0ustar00/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_ERROR_H #define SQL_ERROR_H #include "sql_list.h" /* Sql_alloc, MEM_ROOT, list */ #include "sql_type_int.h" // Longlong_hybrid #include "sql_string.h" /* String */ #include "sql_plist.h" /* I_P_List */ #include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */ #include "my_time.h" /* MYSQL_TIME */ #include "decimal.h" class THD; class my_decimal; class sp_condition_value; /* Types of LOG warnings, used by note_verbosity */ #define NOTE_VERBOSITY_NORMAL (1U << 0) /* Show warnings about keys parts that cannot be used */ #define NOTE_VERBOSITY_UNUSABLE_KEYS (1U << 1) /* Show warnings in explain for key parts that cannot be used */ #define NOTE_VERBOSITY_EXPLAIN (1U << 2) /////////////////////////////////////////////////////////////////////////// class Sql_state { protected: /** This member is always NUL terminated. */ char m_sqlstate[SQLSTATE_LENGTH + 1]; public: Sql_state() { memset(m_sqlstate, 0, sizeof(m_sqlstate)); } Sql_state(const char *sqlstate) { set_sqlstate(sqlstate); } const char* get_sqlstate() const { return m_sqlstate; } void set_sqlstate(const Sql_state *other) { *this= *other; } void set_sqlstate(const char *sqlstate) { memcpy(m_sqlstate, sqlstate, SQLSTATE_LENGTH); m_sqlstate[SQLSTATE_LENGTH]= '\0'; } bool eq(const Sql_state *other) const { return strcmp(m_sqlstate, other->m_sqlstate) == 0; } bool has_sql_state() const { return m_sqlstate[0] != '\0'; } /** Checks if this SQL state defines a WARNING condition. Note: m_sqlstate must contain a valid SQL-state. @retval true if this SQL state defines a WARNING condition. @retval false otherwise. */ inline bool is_warning() const { return m_sqlstate[0] == '0' && m_sqlstate[1] == '1'; } /** Checks if this SQL state defines a NOT FOUND condition. Note: m_sqlstate must contain a valid SQL-state. @retval true if this SQL state defines a NOT FOUND condition. @retval false otherwise. */ inline bool is_not_found() const { return m_sqlstate[0] == '0' && m_sqlstate[1] == '2'; } /** Checks if this SQL state defines an EXCEPTION condition. Note: m_sqlstate must contain a valid SQL-state. @retval true if this SQL state defines an EXCEPTION condition. @retval false otherwise. */ inline bool is_exception() const { return m_sqlstate[0] != '0' || m_sqlstate[1] > '2'; } }; class Sql_state_errno: public Sql_state { protected: /** MySQL extension, MYSQL_ERRNO condition item. SQL error number. One of ER_ codes from share/errmsg.txt. Set by set_error_status. */ uint m_sql_errno; public: Sql_state_errno() :m_sql_errno(0) { } Sql_state_errno(uint sql_errno) :m_sql_errno(sql_errno) { } Sql_state_errno(uint sql_errno, const char *sql_state) :Sql_state(sql_state), m_sql_errno(sql_errno) { } /** Get the SQL_ERRNO of this condition. @return the sql error number condition item. */ uint get_sql_errno() const { return m_sql_errno; } void set(uint sql_errno, const char *sqlstate) { m_sql_errno= sql_errno; set_sqlstate(sqlstate); } void clear() { m_sql_errno= 0; } }; class Sql_state_errno_level: public Sql_state_errno { public: /* Enumeration value describing the severity of the error. Note that these enumeration values must correspond to the indices of the sql_print_message_handlers array. */ enum enum_warning_level { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; protected: /** Severity (error, warning, note) of this condition. */ enum_warning_level m_level; void assign_defaults(const Sql_state_errno *value); public: /** Get the error level of this condition. @return the error level condition item. */ enum_warning_level get_level() const { return m_level; } Sql_state_errno_level() :m_level(WARN_LEVEL_ERROR) { } Sql_state_errno_level(uint sqlerrno, const char* sqlstate, enum_warning_level level) :Sql_state_errno(sqlerrno, sqlstate), m_level(level) { } Sql_state_errno_level(const Sql_state_errno &state_errno, enum_warning_level level) :Sql_state_errno(state_errno), m_level(level) { } void clear() { m_level= WARN_LEVEL_ERROR; Sql_state_errno::clear(); } }; /* class Sql_user_condition_identity. Instances of this class uniquely idetify user defined conditions (EXCEPTION). SET sql_mode=ORACLE; CREATE PROCEDURE p1 AS a EXCEPTION; BEGIN RAISE a; EXCEPTION WHEN a THEN NULL; END; Currently a user defined condition is identified by a pointer to its parse time sp_condition_value instance. This can change when we add packages. See MDEV-10591. */ class Sql_user_condition_identity { protected: const sp_condition_value *m_user_condition_value; public: Sql_user_condition_identity() :m_user_condition_value(NULL) { } Sql_user_condition_identity(const sp_condition_value *value) :m_user_condition_value(value) { } const sp_condition_value *get_user_condition_value() const { return m_user_condition_value; } void set(const Sql_user_condition_identity &identity) { *this= identity; } void clear() { m_user_condition_value= NULL; } }; /** class Sql_condition_identity. Instances of this class uniquely identify conditions (including user-defined exceptions for sql_mode=ORACLE) and store everything that is needed for handler search purposes in sp_pcontext::find_handler(). */ class Sql_condition_identity: public Sql_state_errno_level, public Sql_user_condition_identity { public: Sql_condition_identity() = default; Sql_condition_identity(const Sql_state_errno_level &st, const Sql_user_condition_identity &ucid) :Sql_state_errno_level(st), Sql_user_condition_identity(ucid) { } Sql_condition_identity(const Sql_state_errno &st, enum_warning_level level, const Sql_user_condition_identity &ucid) :Sql_state_errno_level(st, level), Sql_user_condition_identity(ucid) { } Sql_condition_identity(uint sqlerrno, const char* sqlstate, enum_warning_level level, const Sql_user_condition_identity &ucid) :Sql_state_errno_level(sqlerrno, sqlstate, level), Sql_user_condition_identity(ucid) { } void clear() { Sql_state_errno_level::clear(); Sql_user_condition_identity::clear(); } }; class Sql_condition_items { protected: /** SQL CLASS_ORIGIN condition item. */ String m_class_origin; /** SQL SUBCLASS_ORIGIN condition item. */ String m_subclass_origin; /** SQL CONSTRAINT_CATALOG condition item. */ String m_constraint_catalog; /** SQL CONSTRAINT_SCHEMA condition item. */ String m_constraint_schema; /** SQL CONSTRAINT_NAME condition item. */ String m_constraint_name; /** SQL CATALOG_NAME condition item. */ String m_catalog_name; /** SQL SCHEMA_NAME condition item. */ String m_schema_name; /** SQL TABLE_NAME condition item. */ String m_table_name; /** SQL COLUMN_NAME condition item. */ String m_column_name; /** SQL CURSOR_NAME condition item. */ String m_cursor_name; Sql_condition_items() :m_class_origin((const char*) NULL, 0, & my_charset_utf8mb3_bin), m_subclass_origin((const char*) NULL, 0, & my_charset_utf8mb3_bin), m_constraint_catalog((const char*) NULL, 0, & my_charset_utf8mb3_bin), m_constraint_schema((const char*) NULL, 0, & my_charset_utf8mb3_bin), m_constraint_name((const char*) NULL, 0, & my_charset_utf8mb3_bin), m_catalog_name((const char*) NULL, 0, & my_charset_utf8mb3_bin), m_schema_name((const char*) NULL, 0, & my_charset_utf8mb3_bin), m_table_name((const char*) NULL, 0, & my_charset_utf8mb3_bin), m_column_name((const char*) NULL, 0, & my_charset_utf8mb3_bin), m_cursor_name((const char*) NULL, 0, & my_charset_utf8mb3_bin) { } void clear() { m_class_origin.length(0); m_subclass_origin.length(0); m_constraint_catalog.length(0); m_constraint_schema.length(0); m_constraint_name.length(0); m_catalog_name.length(0); m_schema_name.length(0); m_table_name.length(0); m_column_name.length(0); m_cursor_name.length(0); } }; /** Representation of a SQL condition. A SQL condition can be a completion condition (note, warning), or an exception condition (error, not found). */ class Sql_condition : public Sql_alloc, public Sql_condition_identity, public Sql_condition_items { public: /** Convert a bitmask consisting of MYSQL_TIME_{NOTE|WARN}_XXX bits to WARN_LEVEL_XXX */ static enum_warning_level time_warn_level(uint warnings) { return MYSQL_TIME_WARN_HAVE_WARNINGS(warnings) ? WARN_LEVEL_WARN : WARN_LEVEL_NOTE; } /** Get the MESSAGE_TEXT of this condition. @return the message text. */ const char* get_message_text() const; /** Get the MESSAGE_OCTET_LENGTH of this condition. @return the length in bytes of the message text. */ int get_message_octet_length() const; private: /* The interface of Sql_condition is mostly private, by design, so that only the following code: - various raise_error() or raise_warning() methods in class THD, - the implementation of SIGNAL / RESIGNAL / GET DIAGNOSTICS - catch / re-throw of SQL conditions in stored procedures (sp_rcontext) is allowed to create / modify a SQL condition. Enforcing this policy prevents confusion, since the only public interface available to the rest of the server implementation is the interface offered by the THD methods (THD::raise_error()), which should be used. */ friend class THD; friend class Warning_info; friend class Sql_cmd_common_signal; friend class Sql_cmd_signal; friend class Sql_cmd_resignal; friend class sp_rcontext; friend class Condition_information_item; /** Default constructor. This constructor is usefull when allocating arrays. Note that the init() method should be called to complete the Sql_condition. */ Sql_condition() :m_mem_root(NULL) { } /** Complete the Sql_condition initialisation. @param mem_root The memory root to use for the condition items of this condition */ void init(MEM_ROOT *mem_root) { DBUG_ASSERT(mem_root != NULL); DBUG_ASSERT(m_mem_root == NULL); m_mem_root= mem_root; } /** Constructor. @param mem_root The memory root to use for the condition items of this condition */ Sql_condition(MEM_ROOT *mem_root) :m_mem_root(mem_root) { DBUG_ASSERT(mem_root != NULL); } Sql_condition(MEM_ROOT *mem_root, const Sql_user_condition_identity &ucid) :Sql_condition_identity(Sql_state_errno_level(), ucid), m_mem_root(mem_root) { DBUG_ASSERT(mem_root != NULL); } /** Constructor for a fixed message text. @param mem_root - memory root @param value - the error number and the sql state for this condition @param level - the error level for this condition @param msg - the message text for this condition */ Sql_condition(MEM_ROOT *mem_root, const Sql_condition_identity &value, const char *msg) :Sql_condition_identity(value), m_mem_root(mem_root) { DBUG_ASSERT(mem_root != NULL); DBUG_ASSERT(value.get_sql_errno() != 0); DBUG_ASSERT(msg != NULL); set_builtin_message_text(msg); } /** Destructor. */ ~Sql_condition() = default; /** Copy optional condition items attributes. @param cond the condition to copy. */ void copy_opt_attributes(const Sql_condition *cond); /** Set the condition message test. @param str Message text, expressed in the character set derived from the server --language option */ void set_builtin_message_text(const char* str); /** Set the CLASS_ORIGIN of this condition. */ void set_class_origin(); /** Set the SUBCLASS_ORIGIN of this condition. */ void set_subclass_origin(); /** Assign the condition items 'MYSQL_ERRNO', 'level' and 'MESSAGE_TEXT' default values of a condition. @param thd - current thread, to access to localized error messages @param from - copy condition items from here (can be NULL) */ void assign_defaults(THD *thd, const Sql_state_errno *from); /** Clear this SQL condition. */ void clear() { Sql_condition_identity::clear(); Sql_condition_items::clear(); m_message_text.length(0); } private: /** Message text, expressed in the character set implied by --language. */ String m_message_text; /** Pointers for participating in the list of conditions. */ Sql_condition *next_in_wi; Sql_condition **prev_in_wi; /** Memory root to use to hold condition item values. */ MEM_ROOT *m_mem_root; }; /////////////////////////////////////////////////////////////////////////// /** Information about warnings of the current connection. */ class Warning_info { /** The type of the counted and doubly linked list of conditions. */ typedef I_P_List, I_P_List_counter, I_P_List_fast_push_back > Sql_condition_list; /** A memory root to allocate warnings and errors */ MEM_ROOT m_warn_root; /** List of warnings of all severities (levels). */ Sql_condition_list m_warn_list; /** A break down of the number of warnings per severity (level). */ uint m_warn_count[(uint) Sql_condition::WARN_LEVEL_END]; /** The number of warnings of the current statement. Warning_info life cycle differs from statement life cycle -- it may span multiple statements. In that case we get m_current_statement_warn_count 0, whereas m_warn_list is not empty. */ uint m_current_statement_warn_count; /* Row counter, to print in errors and warnings. Not increased in create_sort_index(); may differ from examined_row_count. */ ulong m_current_row_for_warning; /** Used to optionally clear warnings only once per statement. */ ulonglong m_warn_id; /** A pointer to an element of m_warn_list. It determines SQL-condition instance which corresponds to the error state in Diagnostics_area. This is needed for properly processing SQL-conditions in SQL-handlers. When an SQL-handler is found for the current error state in Diagnostics_area, this pointer is needed to remove the corresponding SQL-condition from the Warning_info list. @note m_error_condition might be NULL in the following cases: - Diagnostics_area set to fatal error state (like OOM); - Max number of Warning_info elements has been reached (thus, there is no corresponding SQL-condition object in Warning_info). */ const Sql_condition *m_error_condition; /** Indicates if push_warning() allows unlimited number of warnings. */ bool m_allow_unlimited_warnings; bool initialized; /* Set to 1 if init() has been called */ /** Read only status. */ bool m_read_only; /** Pointers for participating in the stack of Warning_info objects. */ Warning_info *m_next_in_da; Warning_info **m_prev_in_da; List m_marked_sql_conditions; public: Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings, bool initialized); ~Warning_info(); /* Allocate memory for structures */ void init(); void free_memory(); private: Warning_info(const Warning_info &rhs); /* Not implemented */ Warning_info& operator=(const Warning_info &rhs); /* Not implemented */ /** Checks if Warning_info contains SQL-condition with the given message. @param message_str Message string. @param message_length Length of message string. @return true if the Warning_info contains an SQL-condition with the given message. */ bool has_sql_condition(const char *message_str, size_t message_length) const; /** Checks if Warning_info contains SQL-condition with the given error id @param sql_errno SQL-condition error number @return true if the Warning_info contains an SQL-condition with the given error id. */ bool has_sql_condition(uint sql_errno) const; /** Reset the warning information. Clear all warnings, the number of warnings, reset current row counter to point to the first row. @param new_id new Warning_info id. */ void clear(ulonglong new_id); /** Only clear warning info if haven't yet done that already for the current query. Allows to be issued at any time during the query, without risk of clearing some warnings that have been generated by the current statement. @todo: This is a sign of sloppy coding. Instead we need to designate one place in a statement life cycle where we call Warning_info::clear(). @param query_id Current query id. */ void opt_clear(ulonglong query_id) { if (query_id != m_warn_id) clear(query_id); } /** Concatenate the list of warnings. It's considered tolerable to lose an SQL-condition in case of OOM-error, or if the number of SQL-conditions in the Warning_info reached top limit. @param thd Thread context. @param source Warning_info object to copy SQL-conditions from. */ void append_warning_info(THD *thd, const Warning_info *source); /** Reset between two COM_ commands. Warnings are preserved between commands, but statement_warn_count indicates the number of warnings of this particular statement only. */ void reset_for_next_command() { m_current_statement_warn_count= 0; } /** Mark active SQL-conditions for later removal. This is done to simulate stacked DAs for HANDLER statements. */ void mark_sql_conditions_for_removal(); /** Unmark SQL-conditions, which were marked for later removal. This is done to simulate stacked DAs for HANDLER statements. */ void unmark_sql_conditions_from_removal() { m_marked_sql_conditions.empty(); } /** Remove SQL-conditions that are marked for deletion. This is done to simulate stacked DAs for HANDLER statements. */ void remove_marked_sql_conditions(); /** Check if the given SQL-condition is marked for removal in this Warning_info instance. @param cond the SQL-condition. @retval true if the given SQL-condition is marked for removal in this Warning_info instance. @retval false otherwise. */ bool is_marked_for_removal(const Sql_condition *cond) const; /** Mark a single SQL-condition for removal (add the given SQL-condition to the removal list of this Warning_info instance). */ void mark_condition_for_removal(Sql_condition *cond) { m_marked_sql_conditions.push_back(cond, &m_warn_root); } /** Used for @@warning_count system variable, which prints the number of rows returned by SHOW WARNINGS. */ ulong warn_count() const { /* This may be higher than warn_list.elements() if we have had more warnings than thd->variables.max_error_count. */ return (m_warn_count[(uint) Sql_condition::WARN_LEVEL_NOTE] + m_warn_count[(uint) Sql_condition::WARN_LEVEL_ERROR] + m_warn_count[(uint) Sql_condition::WARN_LEVEL_WARN]); } /** The number of errors, or number of rows returned by SHOW ERRORS, also the value of session variable @@error_count. */ ulong error_count() const { return m_warn_count[(uint) Sql_condition::WARN_LEVEL_ERROR]; } /** The number of conditions (errors, warnings and notes) in the list. */ uint cond_count() const { return m_warn_list.elements(); } /** Id of the warning information area. */ ulonglong id() const { return m_warn_id; } /** Set id of the warning information area. */ void id(ulonglong id_arg) { m_warn_id= id_arg; } /** Do we have any errors and warnings that we can *show*? */ bool is_empty() const { return m_warn_list.is_empty(); } /** Increment the current row counter to point at the next row. */ void inc_current_row_for_warning() { m_current_row_for_warning++; } /** Reset the current row counter. Start counting from the first row. */ void reset_current_row_for_warning() { m_current_row_for_warning= 1; } ulong set_current_row_for_warning(ulong row) { ulong old_row= m_current_row_for_warning; m_current_row_for_warning= row; return old_row; } /** Return the current counter value. */ ulong current_row_for_warning() const { return m_current_row_for_warning; } /** Return the number of warnings thrown by the current statement. */ ulong current_statement_warn_count() const { return m_current_statement_warn_count; } /** Make sure there is room for the given number of conditions. */ void reserve_space(THD *thd, uint count); /** Add a new SQL-condition to the current list and increment the respective counters. @param thd Thread context. @param identity SQL-condition identity @param msg SQL-condition message. @return a pointer to the added SQL-condition. */ Sql_condition *push_warning(THD *thd, const Sql_condition_identity *identity, const char* msg); /** Add a new SQL-condition to the current list and increment the respective counters. @param thd Thread context. @param sql_condition SQL-condition to copy values from. @return a pointer to the added SQL-condition. */ Sql_condition *push_warning(THD *thd, const Sql_condition *sql_condition); /** Set the read only status for this statement area. This is a privileged operation, reserved for the implementation of diagnostics related statements, to enforce that the statement area is left untouched during execution. The diagnostics statements are: - SHOW WARNINGS - SHOW ERRORS - GET DIAGNOSTICS @param read_only the read only property to set. */ void set_read_only(bool read_only_arg) { m_read_only= read_only_arg; } /** Read only status. @return the read only property. */ bool is_read_only() const { return m_read_only; } /** @return SQL-condition, which corresponds to the error state in Diagnostics_area. @see m_error_condition. */ const Sql_condition *get_error_condition() const { return m_error_condition; } /** Set SQL-condition, which corresponds to the error state in Diagnostics_area. @see m_error_condition. */ void set_error_condition(const Sql_condition *error_condition) { m_error_condition= error_condition; } /** Reset SQL-condition, which corresponds to the error state in Diagnostics_area. @see m_error_condition. */ void clear_error_condition() { m_error_condition= NULL; } // for: // - m_next_in_da / m_prev_in_da // - is_marked_for_removal() friend class Diagnostics_area; }; extern size_t err_conv(char *buff, uint to_length, const char *from, uint from_length, CHARSET_INFO *from_cs); class ErrBuff { protected: mutable char err_buffer[MYSQL_ERRMSG_SIZE]; public: ErrBuff() { err_buffer[0]= '\0'; } const char *ptr() const { return err_buffer; } LEX_CSTRING set_longlong(const Longlong_hybrid &nr) const { int radix= nr.is_unsigned() ? 10 : -10; const char *end= longlong10_to_str(nr.value(), err_buffer, radix); DBUG_ASSERT(end >= err_buffer); return {err_buffer, (size_t) (end - err_buffer)}; } LEX_CSTRING set_double(double nr) const { size_t length= my_gcvt(nr, MY_GCVT_ARG_DOUBLE, sizeof(err_buffer), err_buffer, 0); return {err_buffer, length}; } LEX_CSTRING set_decimal(const decimal_t *d) const { int length= sizeof(err_buffer); decimal2string(d, err_buffer, &length, 0, 0, ' '); DBUG_ASSERT(length >= 0); return {err_buffer, (size_t) length}; } LEX_CSTRING set_str(const char *str, size_t len, CHARSET_INFO *cs) const { DBUG_ASSERT(len < UINT_MAX32); len= err_conv(err_buffer, (uint) sizeof(err_buffer), str, (uint) len, cs); return {err_buffer, len}; } LEX_CSTRING set_mysql_time(const MYSQL_TIME *ltime) const { int length= my_TIME_to_str(ltime, err_buffer, AUTO_SEC_PART_DIGITS); DBUG_ASSERT(length >= 0); return {err_buffer, (size_t) length}; } }; class ErrConv: public ErrBuff { public: ErrConv() = default; virtual ~ErrConv() = default; virtual LEX_CSTRING lex_cstring() const= 0; inline const char *ptr() const { return lex_cstring().str; } }; class ErrConvString : public ErrConv { const char *str; size_t len; CHARSET_INFO *cs; public: ErrConvString(const char *str_arg, size_t len_arg, CHARSET_INFO *cs_arg) : ErrConv(), str(str_arg), len(len_arg), cs(cs_arg) {} ErrConvString(const char *str_arg, CHARSET_INFO *cs_arg) : ErrConv(), str(str_arg), len(strlen(str_arg)), cs(cs_arg) {} ErrConvString(const String *s) : ErrConv(), str(s->ptr()), len(s->length()), cs(s->charset()) {} LEX_CSTRING lex_cstring() const override { return set_str(str, len, cs); } }; class ErrConvInteger : public ErrConv, public Longlong_hybrid { public: ErrConvInteger(const Longlong_hybrid &nr) : ErrConv(), Longlong_hybrid(nr) { } LEX_CSTRING lex_cstring() const override { return set_longlong(static_cast(*this)); } }; class ErrConvDouble: public ErrConv { double num; public: ErrConvDouble(double num_arg) : ErrConv(), num(num_arg) {} LEX_CSTRING lex_cstring() const override { return set_double(num); } }; class ErrConvTime : public ErrConv { const MYSQL_TIME *ltime; public: ErrConvTime(const MYSQL_TIME *ltime_arg) : ErrConv(), ltime(ltime_arg) {} LEX_CSTRING lex_cstring() const override { return set_mysql_time(ltime); } }; class ErrConvDecimal : public ErrConv { const decimal_t *d; public: ErrConvDecimal(const decimal_t *d_arg) : ErrConv(), d(d_arg) {} LEX_CSTRING lex_cstring() const override { return set_decimal(d); } }; /////////////////////////////////////////////////////////////////////////// /** Stores status of the currently executed statement. Cleared at the beginning of the statement, and then can hold either OK, ERROR, or EOF status. Can not be assigned twice per statement. */ class Diagnostics_area: public Sql_state_errno, public Sql_user_condition_identity { private: /** The type of the counted and doubly linked list of conditions. */ typedef I_P_List, I_P_List_counter, I_P_List_fast_push_back > Warning_info_list; public: /** Const iterator used to iterate through the warning list. */ typedef Warning_info::Sql_condition_list::Const_Iterator Sql_condition_iterator; enum enum_diagnostics_status { /** The area is cleared at start of a statement. */ DA_EMPTY= 0, /** Set whenever one calls my_ok(). */ DA_OK, /** Set whenever one calls my_eof(). */ DA_EOF, /** Set whenever one calls my_ok() in PS bulk mode. */ DA_OK_BULK, /** Set whenever one calls my_eof() in PS bulk mode. */ DA_EOF_BULK, /** Set whenever one calls my_error() or my_message(). */ DA_ERROR, /** Set in case of a custom response, such as one from COM_STMT_PREPARE. */ DA_DISABLED }; void set_overwrite_status(bool can_overwrite_status) { m_can_overwrite_status= can_overwrite_status; } /** True if status information is sent to the client. */ bool is_sent() const { return m_is_sent; } void set_is_sent(bool is_sent_arg) { m_is_sent= is_sent_arg; } void set_ok_status(ulonglong affected_rows, ulonglong last_insert_id, const char *message); void set_eof_status(THD *thd); void set_error_status(uint sql_errno); void set_error_status(uint sql_errno, const char *message, const char *sqlstate, const Sql_user_condition_identity &ucid, const Sql_condition *error_condition); void set_error_status(uint sql_errno, const char *message, const char *sqlstate, const Sql_condition *error_condition) { set_error_status(sql_errno, message, sqlstate, Sql_user_condition_identity(), error_condition); } void disable_status(); void reset_diagnostics_area(); bool is_set() const { return m_status != DA_EMPTY; } bool is_error() const { return m_status == DA_ERROR; } bool is_eof() const { return m_status == DA_EOF; } bool is_ok() const { return m_status == DA_OK; } bool is_disabled() const { return m_status == DA_DISABLED; } void set_bulk_execution(bool bulk) { is_bulk_execution= bulk; } bool is_bulk_op() const { return is_bulk_execution; } enum_diagnostics_status status() const { return m_status; } const char *message() const { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK || m_status == DA_OK_BULK || m_status == DA_EOF_BULK); return m_message; } uint sql_errno() const { DBUG_ASSERT(m_status == DA_ERROR); return Sql_state_errno::get_sql_errno(); } const char* get_sqlstate() const { DBUG_ASSERT(m_status == DA_ERROR); return Sql_state::get_sqlstate(); } ulonglong affected_rows() const { DBUG_ASSERT(m_status == DA_OK || m_status == DA_OK_BULK); return m_affected_rows; } void set_message(const char *msg) { strmake_buf(m_message, msg); } ulonglong last_insert_id() const { DBUG_ASSERT(m_status == DA_OK || m_status == DA_OK_BULK); return m_last_insert_id; } uint statement_warn_count() const { DBUG_ASSERT(m_status == DA_OK || m_status == DA_OK_BULK || m_status == DA_EOF ||m_status == DA_EOF_BULK ); return m_statement_warn_count; } uint unsafe_statement_warn_count() const { return m_statement_warn_count; } /** Get the current errno, state and id of the user defined condition and return them as Sql_condition_identity. */ Sql_condition_identity get_error_condition_identity() const { DBUG_ASSERT(m_status == DA_ERROR); return Sql_condition_identity(*this /*Sql_state_errno*/, Sql_condition::WARN_LEVEL_ERROR, *this /*Sql_user_condition_identity*/); } /* Used to count any warnings pushed after calling set_ok_status(). */ void increment_warning() { if (m_status != DA_EMPTY) m_statement_warn_count++; } Diagnostics_area(bool initialize); Diagnostics_area(ulonglong warning_info_id, bool allow_unlimited_warnings, bool initialize); void init() { m_main_wi.init() ; } void free_memory() { m_main_wi.free_memory() ; } void push_warning_info(Warning_info *wi) { m_wi_stack.push_front(wi); } void pop_warning_info() { DBUG_ASSERT(m_wi_stack.elements() > 0); m_wi_stack.remove(m_wi_stack.front()); } void set_warning_info_id(ulonglong id) { get_warning_info()->id(id); } ulonglong warning_info_id() const { return get_warning_info()->id(); } /** Compare given current warning info and current warning info and see if they are different. They will be different if warnings have been generated or statements that use tables have been executed. This is checked by comparing m_warn_id. @param wi Warning info to compare with current Warning info. @return false if they are equal, true if they are not. */ bool warning_info_changed(const Warning_info *wi) const { return get_warning_info()->id() != wi->id(); } bool is_warning_info_empty() const { return get_warning_info()->is_empty(); } ulong current_statement_warn_count() const { return get_warning_info()->current_statement_warn_count(); } bool has_sql_condition(const char *message_str, size_t message_length) const { return get_warning_info()->has_sql_condition(message_str, message_length); } bool has_sql_condition(uint sql_errno) const { return get_warning_info()->has_sql_condition(sql_errno); } void reset_for_next_command() { get_warning_info()->reset_for_next_command(); } void clear_warning_info(ulonglong id) { get_warning_info()->clear(id); } void opt_clear_warning_info(ulonglong query_id) { get_warning_info()->opt_clear(query_id); } long set_current_row_for_warning(long row) { return get_warning_info()->set_current_row_for_warning(row); } ulong current_row_for_warning() const { return get_warning_info()->current_row_for_warning(); } void inc_current_row_for_warning() { get_warning_info()->inc_current_row_for_warning(); } void reset_current_row_for_warning() { get_warning_info()->reset_current_row_for_warning(); } bool is_warning_info_read_only() const { return get_warning_info()->is_read_only(); } void set_warning_info_read_only(bool read_only_arg) { get_warning_info()->set_read_only(read_only_arg); } ulong error_count() const { return get_warning_info()->error_count(); } ulong warn_count() const { return get_warning_info()->warn_count(); } uint cond_count() const { return get_warning_info()->cond_count(); } Sql_condition_iterator sql_conditions() const { return get_warning_info()->m_warn_list; } void reserve_space(THD *thd, uint count) { get_warning_info()->reserve_space(thd, count); } Sql_condition *push_warning(THD *thd, const Sql_condition *sql_condition) { return get_warning_info()->push_warning(thd, sql_condition); } Sql_condition *push_warning(THD *thd, uint sql_errno_arg, const char* sqlstate, Sql_condition::enum_warning_level level, const Sql_user_condition_identity &ucid, const char* msg) { Sql_condition_identity tmp(sql_errno_arg, sqlstate, level, ucid); return get_warning_info()->push_warning(thd, &tmp, msg); } Sql_condition *push_warning(THD *thd, uint sqlerrno, const char* sqlstate, Sql_condition::enum_warning_level level, const char* msg) { return push_warning(thd, sqlerrno, sqlstate, level, Sql_user_condition_identity(), msg); } void mark_sql_conditions_for_removal() { get_warning_info()->mark_sql_conditions_for_removal(); } void unmark_sql_conditions_from_removal() { get_warning_info()->unmark_sql_conditions_from_removal(); } void remove_marked_sql_conditions() { get_warning_info()->remove_marked_sql_conditions(); } const Sql_condition *get_error_condition() const { return get_warning_info()->get_error_condition(); } void copy_sql_conditions_to_wi(THD *thd, Warning_info *dst_wi) const { dst_wi->append_warning_info(thd, get_warning_info()); } void copy_sql_conditions_from_wi(THD *thd, const Warning_info *src_wi) { get_warning_info()->append_warning_info(thd, src_wi); } void copy_non_errors_from_wi(THD *thd, const Warning_info *src_wi); private: Warning_info *get_warning_info() { return m_wi_stack.front(); } const Warning_info *get_warning_info() const { return m_wi_stack.front(); } private: /** True if status information is sent to the client. */ bool m_is_sent; /** Set to make set_error_status after set_{ok,eof}_status possible. */ bool m_can_overwrite_status; /** Message buffer. Can be used by OK or ERROR status. */ char m_message[MYSQL_ERRMSG_SIZE]; /** The number of rows affected by the last statement. This is semantically close to thd->m_row_count_func, but has a different life cycle. thd->m_row_count_func stores the value returned by function ROW_COUNT() and is cleared only by statements that update its value, such as INSERT, UPDATE, DELETE and few others. This member is cleared at the beginning of the next statement. We could possibly merge the two, but life cycle of thd->m_row_count_func can not be changed. */ ulonglong m_affected_rows; /** Similarly to the previous member, this is a replacement of thd->first_successful_insert_id_in_prev_stmt, which is used to implement LAST_INSERT_ID(). */ ulonglong m_last_insert_id; /** Number of warnings of this last statement. May differ from the number of warnings returned by SHOW WARNINGS e.g. in case the statement doesn't clear the warnings, and doesn't generate them. */ uint m_statement_warn_count; enum_diagnostics_status m_status; my_bool is_bulk_execution; Warning_info m_main_wi; Warning_info_list m_wi_stack; }; /////////////////////////////////////////////////////////////////////////// void convert_error_to_warning(THD *thd); void push_warning(THD *thd, Sql_condition::enum_warning_level level, uint code, const char *msg); void push_warning_printf(THD *thd, Sql_condition::enum_warning_level level, uint code, const char *format, ...); bool mysqld_show_warnings(THD *thd, ulong levels_to_show); size_t convert_error_message(char *to, size_t to_length, CHARSET_INFO *to_cs, const char *from, size_t from_length, CHARSET_INFO *from_cs, uint *errors); extern const LEX_CSTRING warning_level_names[]; bool is_sqlstate_valid(const LEX_CSTRING *sqlstate); /** Checks if the specified SQL-state-string defines COMPLETION condition. This function assumes that the given string contains a valid SQL-state. @param s the condition SQLSTATE. @retval true if the given string defines COMPLETION condition. @retval false otherwise. */ inline bool is_sqlstate_completion(const char *s) { return s[0] == '0' && s[1] == '0'; } #endif // SQL_ERROR_H server/private/tzfile.h000064400000011626151031265040011175 0ustar00#ifndef TZFILE_INCLUDED #define TZFILE_INCLUDED /* Copyright (c) 2004, 2006, 2007 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file is based on public domain code from ftp://elsie.ncih.nist.gov/ Initial source code is in the public domain, so clarified as of 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). */ /* Information about time zone files. */ #ifndef TZDIR #define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */ #endif /* !defined TZDIR */ /* Each file begins with. . . */ #define TZ_MAGIC "TZif" struct tzhead { uchar tzh_magic[4]; /* TZ_MAGIC */ uchar tzh_reserved[16]; /* reserved for future use */ uchar tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ uchar tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ uchar tzh_leapcnt[4]; /* coded number of leap seconds */ uchar tzh_timecnt[4]; /* coded number of transition times */ uchar tzh_typecnt[4]; /* coded number of local time types */ uchar tzh_charcnt[4]; /* coded number of abbr. chars */ }; /* . . .followed by. . . tzh_timecnt (char [4])s coded transition times a la time(2) tzh_timecnt (unsigned char)s types of local time starting at above tzh_typecnt repetitions of one (char [4]) coded UTC offset in seconds one (unsigned char) used to set tm_isdst one (unsigned char) that's an abbreviation list index tzh_charcnt (char)s '\0'-terminated zone abbreviations tzh_leapcnt repetitions of one (char [4]) coded leap second transition times one (char [4]) total correction after above tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition time is standard time, if FALSE, transition time is wall clock time if absent, transition times are assumed to be wall clock time tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition time is UTC, if FALSE, transition time is local time if absent, transition times are assumed to be local time */ /* In the current implementation, we refuse to deal with files that exceed any of the limits below. */ #ifndef TZ_MAX_TIMES /* The TZ_MAX_TIMES value below is enough to handle a bit more than a year's worth of solar time (corrected daily to the nearest second) or 138 years of Pacific Presidential Election time (where there are three time zone transitions every fourth year). */ #define TZ_MAX_TIMES 370 #endif /* !defined TZ_MAX_TIMES */ #ifndef TZ_MAX_TYPES #ifdef SOLAR #define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ #else /* Must be at least 14 for Europe/Riga as of Jan 12 1995, as noted by Earl Chew . */ #define TZ_MAX_TYPES 20 /* Maximum number of local time types */ #endif /* defined SOLAR */ #endif /* !defined TZ_MAX_TYPES */ #ifndef TZ_MAX_CHARS #define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ /* (limited by what unsigned chars can hold) */ #endif /* !defined TZ_MAX_CHARS */ #ifndef TZ_MAX_LEAPS #define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ #endif /* !defined TZ_MAX_LEAPS */ #ifndef TZ_MAX_REV_RANGES #ifdef SOLAR /* Solar (Asia/RiyadhXX) zones need significantly bigger TZ_MAX_REV_RANGES */ #define TZ_MAX_REV_RANGES (TZ_MAX_TIMES*2+TZ_MAX_LEAPS*2+2) #else #define TZ_MAX_REV_RANGES (TZ_MAX_TIMES+TZ_MAX_LEAPS+2) #endif #endif #define SECS_PER_MIN 60 #define MINS_PER_HOUR 60 #define HOURS_PER_DAY 24 #define DAYS_PER_WEEK 7 #define DAYS_PER_NYEAR 365 #define DAYS_PER_LYEAR 366 #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) #define SECS_PER_DAY ((long) SECS_PER_HOUR * HOURS_PER_DAY) #define MONS_PER_YEAR 12 #define TM_YEAR_BASE 1900 #define EPOCH_YEAR 1970 /* Accurate only for the past couple of centuries, that will probably do. */ #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) #endif server/private/parse_file.h000064400000010443151031265040012005 0ustar00/* -*- C++ -*- */ /* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _PARSE_FILE_H_ #define _PARSE_FILE_H_ #include "sql_string.h" // LEX_STRING #include "sql_alloc.h" // Sql_alloc class THD; typedef struct st_mem_root MEM_ROOT; #define PARSE_FILE_TIMESTAMPLENGTH 19 enum file_opt_type { FILE_OPTIONS_STRING, /**< String (LEX_STRING) */ FILE_OPTIONS_ESTRING, /**< Escaped string (LEX_STRING) */ FILE_OPTIONS_ULONGLONG, /**< ulonglong parameter (ulonglong) */ FILE_OPTIONS_VIEW_ALGO, /**< Similar to longlong, but needs conversion */ FILE_OPTIONS_TIMESTAMP, /**< timestamp (LEX_STRING have to be allocated with length 20 (19+1) */ FILE_OPTIONS_STRLIST, /**< list of escaped strings (List) */ FILE_OPTIONS_ULLLIST /**< list of ulonglong values (List) */ }; struct File_option { LEX_CSTRING name; /**< Name of the option */ my_ptrdiff_t offset; /**< offset to base address of value */ file_opt_type type; /**< Option type */ }; /** This hook used to catch no longer supported keys and process them for backward compatibility. */ class Unknown_key_hook { public: Unknown_key_hook() = default; /* Remove gcc warning */ virtual ~Unknown_key_hook() = default; /* Remove gcc warning */ virtual bool process_unknown_string(const char *&unknown_key, uchar* base, MEM_ROOT *mem_root, const char *end)= 0; }; /** Dummy hook for parsers which do not need hook for unknown keys. */ class File_parser_dummy_hook: public Unknown_key_hook { public: File_parser_dummy_hook() = default; /* Remove gcc warning */ bool process_unknown_string(const char *&unknown_key, uchar* base, MEM_ROOT *mem_root, const char *end) override; }; extern File_parser_dummy_hook file_parser_dummy_hook; bool get_file_options_ulllist(const char *&ptr, const char *end, const char *line, uchar* base, File_option *parameter, MEM_ROOT *mem_root); const char * parse_escaped_string(const char *ptr, const char *end, MEM_ROOT *mem_root, LEX_CSTRING *str); class File_parser; File_parser *sql_parse_prepare(const LEX_CSTRING *file_name, MEM_ROOT *mem_root, bool bad_format_errors); my_bool sql_create_definition_file(const LEX_CSTRING *dir, const LEX_CSTRING *file_name, const LEX_CSTRING *type, uchar* base, File_option *parameters); my_bool rename_in_schema_file(THD *thd, const char *schema, const char *old_name, const char *new_db, const char *new_name); int sql_backup_definition_file(const LEX_CSTRING *org_name, LEX_CSTRING *new_name); int sql_restore_definition_file(const LEX_CSTRING *name); class File_parser: public Sql_alloc { char *start, *end; LEX_CSTRING file_type; bool content_ok; public: File_parser() :start(0), end(0), content_ok(0) { file_type.str= 0; file_type.length= 0; } bool ok() { return content_ok; } const LEX_CSTRING *type() const { return &file_type; } my_bool parse(uchar* base, MEM_ROOT *mem_root, struct File_option *parameters, uint required, Unknown_key_hook *hook) const; friend File_parser *sql_parse_prepare(const LEX_CSTRING *file_name, MEM_ROOT *mem_root, bool bad_format_errors); }; #endif /* _PARSE_FILE_H_ */ server/private/semisync.h000064400000004357151031265040011535 0ustar00/* Copyright (C) 2007 Google Inc. Copyright (C) 2008 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SEMISYNC_H #define SEMISYNC_H #include "mysqld.h" #include "log_event.h" #include "replication.h" /** This class is used to trace function calls and other process information */ class Trace { public: static const unsigned long k_trace_function; static const unsigned long k_trace_general; static const unsigned long k_trace_detail; static const unsigned long k_trace_net_wait; unsigned long m_trace_level; /* the level for tracing */ Trace() :m_trace_level(0L) {} Trace(unsigned long trace_level) :m_trace_level(trace_level) {} }; /** Base class for semi-sync master and slave classes */ class Repl_semi_sync_base :public Trace { public: static const unsigned char k_sync_header[2]; /* three byte packet header */ /* Constants in network packet header. */ static const unsigned char k_packet_magic_num; static const unsigned char k_packet_flag_sync; }; /* The layout of a semisync slave reply packet: 1 byte for the magic num 8 bytes for the binlog positon n bytes for the binlog filename, terminated with a '\0' */ #define REPLY_MAGIC_NUM_LEN 1 #define REPLY_BINLOG_POS_LEN 8 #define REPLY_BINLOG_NAME_LEN (FN_REFLEN + 1) #define REPLY_MAGIC_NUM_OFFSET 0 #define REPLY_BINLOG_POS_OFFSET (REPLY_MAGIC_NUM_OFFSET + REPLY_MAGIC_NUM_LEN) #define REPLY_BINLOG_NAME_OFFSET (REPLY_BINLOG_POS_OFFSET + REPLY_BINLOG_POS_LEN) #define REPLY_MESSAGE_MAX_LENGTH \ (REPLY_MAGIC_NUM_LEN + REPLY_BINLOG_POS_LEN + REPLY_BINLOG_NAME_LEN) #endif /* SEMISYNC_H */ server/private/sql_select.h000064400000255502151031265040012041 0ustar00#ifndef SQL_SELECT_INCLUDED #define SQL_SELECT_INCLUDED /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. Copyright (c) 2008, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file @brief classes to use when handling where clause */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "procedure.h" #include "sql_array.h" /* Array */ #include "records.h" /* READ_RECORD */ #include "opt_range.h" /* SQL_SELECT, QUICK_SELECT_I */ #include "filesort.h" #include "cset_narrowing.h" typedef struct st_join_table JOIN_TAB; /* Values in optimize */ #define KEY_OPTIMIZE_EXISTS 1U #define KEY_OPTIMIZE_REF_OR_NULL 2U #define KEY_OPTIMIZE_EQ 4U inline uint get_hash_join_key_no() { return MAX_KEY; } inline bool is_hash_join_key_no(uint key) { return key == MAX_KEY; } typedef struct keyuse_t { TABLE *table; Item *val; /**< or value if no field */ table_map used_tables; uint key, keypart, optimize; key_part_map keypart_map; ha_rows ref_table_rows; /** If true, the comparison this value was created from will not be satisfied if val has NULL 'value'. */ bool null_rejecting; /* !NULL - This KEYUSE was created from an equality that was wrapped into an Item_func_trig_cond. This means the equality (and validity of this KEYUSE element) can be turned on and off. The on/off state is indicted by the pointed value: *cond_guard == TRUE <=> equality condition is on *cond_guard == FALSE <=> equality condition is off NULL - Otherwise (the source equality can't be turned off) */ bool *cond_guard; /* 0..64 <=> This was created from semi-join IN-equality # sj_pred_no. MAX_UINT Otherwise */ uint sj_pred_no; /* If this is NULL than KEYUSE is always enabled. Otherwise it points to the enabling flag for this keyuse (true <=> enabled) */ bool *validity_ref; bool is_for_hash_join() { return is_hash_join_key_no(key); } } KEYUSE; struct KEYUSE_EXT: public KEYUSE { /* This keyuse can be used only when the partial join being extended contains the tables from this table map */ table_map needed_in_prefix; /* The enabling flag for keyuses usable for splitting */ bool validity_var; }; /// Used when finding key fields struct KEY_FIELD { Field *field; Item_bool_func *cond; Item *val; ///< May be empty if diff constant uint level; uint optimize; bool eq_func; /** If true, the condition this struct represents will not be satisfied when val IS NULL. */ bool null_rejecting; bool *cond_guard; /* See KEYUSE::cond_guard */ uint sj_pred_no; /* See KEYUSE::sj_pred_no */ }; #define NO_KEYPART ((uint)(-1)) class store_key; const int NO_REF_PART= uint(-1); typedef struct st_table_ref { bool key_err; /** True if something was read into buffer in join_read_key. */ bool has_record; uint key_parts; ///< num of ... uint key_length; ///< length of key_buff int key; ///< key no uchar *key_buff; ///< value to look for with key uchar *key_buff2; ///< key_buff+key_length store_key **key_copy; // /* Bitmap of key parts which refer to constants. key_copy only has copiers for non-const key parts. */ key_part_map const_ref_part_map; Item **items; ///< val()'s for each keypart /* Array of pointers to trigger variables. Some/all of the pointers may be NULL. The ref access can be used iff for each used key part i, (!cond_guards[i] || *cond_guards[i]) This array is used by subquery code. The subquery code may inject triggered conditions, i.e. conditions that can be 'switched off'. A ref access created from such condition is not valid when at least one of the underlying conditions is switched off (see subquery code for more details) */ bool **cond_guards; /** (null_rejecting & (1< disable the "cache" as doing lookup with the same key value may produce different results (because of Index Condition Pushdown) */ bool disable_cache; /* If true, this ref access was constructed from equalities generated by LATERAL DERIVED (aka GROUP BY splitting) optimization */ bool uses_splitting; bool tmp_table_index_lookup_init(THD *thd, KEY *tmp_key, Item_iterator &it, bool value, uint skip= 0); bool is_access_triggered(); } TABLE_REF; /* The structs which holds the join connections and join states */ enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF, JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL, JT_UNIQUE_SUBQUERY, JT_INDEX_SUBQUERY, JT_INDEX_MERGE, JT_HASH, JT_HASH_RANGE, JT_HASH_NEXT, JT_HASH_INDEX_MERGE}; class JOIN; enum enum_nested_loop_state { NESTED_LOOP_KILLED= -2, NESTED_LOOP_ERROR= -1, NESTED_LOOP_OK= 0, NESTED_LOOP_NO_MORE_ROWS= 1, NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4 }; /* Possible sj_strategy values */ enum sj_strategy_enum { SJ_OPT_NONE=0, SJ_OPT_DUPS_WEEDOUT=1, SJ_OPT_LOOSE_SCAN =2, SJ_OPT_FIRST_MATCH =3, SJ_OPT_MATERIALIZE =4, SJ_OPT_MATERIALIZE_SCAN=5 }; /* Values for JOIN_TAB::packed_info */ #define TAB_INFO_HAVE_VALUE 1U #define TAB_INFO_USING_INDEX 2U #define TAB_INFO_USING_WHERE 4U #define TAB_INFO_FULL_SCAN_ON_NULL 8U typedef enum_nested_loop_state (*Next_select_func)(JOIN *, struct st_join_table *, bool); Next_select_func setup_end_select_func(JOIN *join); int rr_sequential(READ_RECORD *info); int read_record_func_for_rr_and_unpack(READ_RECORD *info); Item *remove_pushed_top_conjuncts(THD *thd, Item *cond); Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond, COND_EQUAL **cond_eq, List &new_conds, Item::cond_result *cond_value); #include "sql_explain.h" /************************************************************************************** * New EXPLAIN structures END *************************************************************************************/ class JOIN_CACHE; class SJ_TMP_TABLE; class JOIN_TAB_RANGE; class AGGR_OP; class Filesort; struct SplM_plan_info; class SplM_opt_info; typedef struct st_join_table { TABLE *table; TABLE_LIST *tab_list; KEYUSE *keyuse; /**< pointer to first used key */ KEY *hj_key; /**< descriptor of the used best hash join key not supported by any index */ SQL_SELECT *select; COND *select_cond; COND *on_precond; /**< part of on condition to check before accessing the first inner table */ QUICK_SELECT_I *quick; /* The value of select_cond before we've attempted to do Index Condition Pushdown. We may need to restore everything back if we first choose one index but then reconsider (see test_if_skip_sort_order() for such scenarios). NULL means no index condition pushdown was performed. */ Item *pre_idx_push_select_cond; /* Pointer to the associated ON expression. on_expr_ref=!NULL except for degenerate joins. Optimization phase: *on_expr_ref!=NULL for tables that are the single tables on the inner side of the outer join (t1 LEFT JOIN t2 ON...) Execution phase: *on_expr_ref!=NULL for tables that are first inner tables within an outer join (which may have multiple tables) */ Item **on_expr_ref; COND_EQUAL *cond_equal; /**< multiple equalities for the on expression */ st_join_table *first_inner; /**< first inner table for including outerjoin */ bool found; /**< true after all matches or null complement */ bool not_null_compl;/**< true before null complement is added */ st_join_table *last_inner; /**< last table table for embedding outer join */ st_join_table *first_upper; /**< first inner table for embedding outer join */ st_join_table *first_unmatched; /**< used for optimization purposes only */ /* For join tabs that are inside an SJM bush: root of the bush */ st_join_table *bush_root_tab; /* TRUE <=> This join_tab is inside an SJM bush and is the last leaf tab here */ bool last_leaf_in_bush; /* ptr - this is a bush, and ptr points to description of child join_tab range NULL - this join tab has no bush children */ JOIN_TAB_RANGE *bush_children; /* Special content for EXPLAIN 'Extra' column or NULL if none */ enum explain_extra_tag info; Table_access_tracker *tracker; Table_access_tracker *jbuf_tracker; Time_and_counter_tracker *jbuf_unpack_tracker; Counter_tracker *jbuf_loops_tracker; /* Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra' column, or 0 if there is no info. */ uint packed_info; // READ_RECORD::Setup_func materialize_table; READ_RECORD::Setup_func read_first_record; Next_select_func next_select; READ_RECORD read_record; /* Currently the following two fields are used only for a [NOT] IN subquery if it is executed by an alternative full table scan when the left operand of the subquery predicate is evaluated to NULL. */ READ_RECORD::Setup_func save_read_first_record;/* to save read_first_record */ READ_RECORD::Read_func save_read_record;/* to save read_record.read_record */ double worst_seeks; key_map const_keys; /**< Keys with constant part */ key_map checked_keys; /**< Keys checked in find_best */ key_map needed_reg; key_map keys; /**< all keys with can be used */ /* Either #rows in the table or 1 for const table. */ ha_rows records; /* Number of records that will be scanned (yes scanned, not returned) by the best 'independent' access method, i.e. table scan or QUICK_*_SELECT) */ ha_rows found_records; /* Cost of accessing the table using "ALL" or range/index_merge access method (but not 'index' for some reason), i.e. this matches method which E(#records) is in found_records. */ double read_time; /* Copy of POSITION::records_read, set by get_best_combination() */ double records_read; /* The selectivity of the conditions that can be pushed to the table */ double cond_selectivity; /* Startup cost for execution */ double startup_cost; double partial_join_cardinality; table_map dependent,key_dependent; /* 1 - use quick select 2 - use "Range checked for each record" */ uint use_quick; /* Index to use. Note: this is valid only for 'index' access, but not range or ref access. */ uint index; uint status; ///< Save status for cache uint used_fields; ulong used_fieldlength; ulong max_used_fieldlength; uint used_blobs; uint used_null_fields; uint used_uneven_bit_fields; enum join_type type; /* If first key part is used for any key in 'key_dependent' */ bool key_start_dependent; bool cached_eq_ref_table,eq_ref_table; bool shortcut_for_distinct; bool sorted; /* If it's not 0 the number stored this field indicates that the index scan has been chosen to access the table data and we expect to scan this number of rows for the table. */ ha_rows limit; TABLE_REF ref; /* TRUE <=> condition pushdown supports other tables presence */ bool icp_other_tables_ok; /* TRUE <=> condition pushed to the index has to be factored out of the condition pushed to the table */ bool idx_cond_fact_out; bool use_join_cache; /* TRUE <=> it is prohibited to join this table using join buffer */ bool no_forced_join_cache; uint used_join_cache_level; JOIN_CACHE *cache; /* Index condition for BKA access join */ Item *cache_idx_cond; SQL_SELECT *cache_select; AGGR_OP *aggr; JOIN *join; /* Embedding SJ-nest (may be not the direct parent), or NULL if none. This variable holds the result of table pullout. */ TABLE_LIST *emb_sj_nest; /* FirstMatch variables (final QEP) */ struct st_join_table *first_sj_inner_tab; struct st_join_table *last_sj_inner_tab; /* Variables for semi-join duplicate elimination */ SJ_TMP_TABLE *flush_weedout_table; SJ_TMP_TABLE *check_weed_out_table; /* for EXPLAIN only: */ SJ_TMP_TABLE *first_weedout_table; /** reference to saved plan and execution statistics */ Explain_table_access *explain_plan; /* If set, means we should stop join enumeration after we've got the first match and return to the specified join tab. May point to join->join_tab[-1] which means stop join execution after the first match. */ struct st_join_table *do_firstmatch; /* ptr - We're doing a LooseScan, this join tab is the first (i.e. "driving") join tab), and ptr points to the last join tab handled by the strategy. loosescan_match_tab->found_match should be checked to see if the current value group had a match. NULL - Not doing a loose scan on this join tab. */ struct st_join_table *loosescan_match_tab; /* TRUE <=> we are inside LooseScan range */ bool inside_loosescan_range; /* Buffer to save index tuple to be able to skip duplicates */ uchar *loosescan_buf; /* Index used by LooseScan (we store it here separately because ref access stores it in tab->ref.key, while range scan stores it in tab->index, etc) */ uint loosescan_key; /* Length of key tuple (depends on #keyparts used) to store in the above */ uint loosescan_key_len; /* Used by LooseScan. TRUE<=> there has been a matching record combination */ bool found_match; /* Used by DuplicateElimination. tab->table->ref must have the rowid whenever we have a current record. */ int keep_current_rowid; /* NestedOuterJoins: Bitmap of nested joins this table is part of */ nested_join_map embedding_map; /* Tmp table info */ TMP_TABLE_PARAM *tmp_table_param; /* Sorting related info */ Filesort *filesort; SORT_INFO *filesort_result; /* Non-NULL value means this join_tab must do window function computation before reading. */ Window_funcs_computation* window_funcs_step; /** List of topmost expressions in the select list. The *next* JOIN_TAB in the plan should use it to obtain correct values. Same applicable to all_fields. These lists are needed because after tmp tables functions will be turned to fields. These variables are pointing to tmp_fields_list[123]. Valid only for tmp tables and the last non-tmp table in the query plan. @see JOIN::make_aggr_tables_info() */ List *fields; /** List of all expressions in the select list */ List *all_fields; /* Pointer to the ref array slice which to switch to before sending records. Valid only for tmp tables. */ Ref_ptr_array *ref_array; /** Number of records saved in tmp table */ ha_rows send_records; /** HAVING condition for checking prior saving a record into tmp table*/ Item *having; /** TRUE <=> remove duplicates on this table. */ bool distinct; /* Semi-join strategy to be used for this join table. This is a copy of POSITION::sj_strategy field. This field is set up by the fix_semijoin_strategies_for_picked_join_order. */ enum sj_strategy_enum sj_strategy; uint n_sj_tables; bool preread_init_done; /* true <=> split optimization has been applied to this materialized table */ bool is_split_derived; /* Bitmap of split materialized derived tables that can be filled just before this join table is to be joined. All parameters of the split derived tables belong to tables preceding this join table. */ table_map split_derived_to_update; /* Cost info to the range filter used when joining this join table (Defined when the best join order has been already chosen) */ Range_rowid_filter_cost_info *range_rowid_filter_info; /* Rowid filter to be used when joining this join table */ Rowid_filter *rowid_filter; /* Becomes true just after the used range filter has been built / filled */ bool is_rowid_filter_built; bool build_range_rowid_filter_if_needed(); void cleanup(); inline bool is_using_loose_index_scan() { const SQL_SELECT *sel= get_sql_select(); return (sel && sel->quick && (sel->quick->get_type() == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)); } bool is_using_agg_loose_index_scan () { const SQL_SELECT *sel= get_sql_select(); return (is_using_loose_index_scan() && ((QUICK_GROUP_MIN_MAX_SELECT *)sel->quick)->is_agg_distinct()); } const SQL_SELECT *get_sql_select() { return filesort ? filesort->select : select; } bool is_inner_table_of_semi_join_with_first_match() { return first_sj_inner_tab != NULL; } bool is_inner_table_of_semijoin() { return emb_sj_nest != NULL; } bool is_inner_table_of_outer_join() { return first_inner != NULL; } bool is_single_inner_of_semi_join_with_first_match() { return first_sj_inner_tab == this && last_sj_inner_tab == this; } bool is_single_inner_of_outer_join() { return first_inner == this && first_inner->last_inner == this; } bool is_first_inner_for_outer_join() { return first_inner == this; } bool use_match_flag() { return is_first_inner_for_outer_join() || first_sj_inner_tab == this ; } bool check_only_first_match() { return is_inner_table_of_semi_join_with_first_match() || (is_inner_table_of_outer_join() && table->reginfo.not_exists_optimize); } bool is_last_inner_table() { return (first_inner && first_inner->last_inner == this) || last_sj_inner_tab == this; } /* Check whether the table belongs to a nest of inner tables of an outer join or to a nest of inner tables of a semi-join */ bool is_nested_inner() { if (first_inner && (first_inner != first_inner->last_inner || first_inner->first_upper)) return TRUE; if (first_sj_inner_tab && first_sj_inner_tab != last_sj_inner_tab) return TRUE; return FALSE; } struct st_join_table *get_first_inner_table() { if (first_inner) return first_inner; return first_sj_inner_tab; } void set_select_cond(COND *to, uint line) { DBUG_PRINT("info", ("select_cond changes %p -> %p at line %u tab %p", select_cond, to, line, this)); select_cond= to; } COND *set_cond(COND *new_cond) { COND *tmp_select_cond= select_cond; set_select_cond(new_cond, __LINE__); if (select) select->cond= new_cond; return tmp_select_cond; } void calc_used_field_length(bool max_fl); ulong get_used_fieldlength() { if (!used_fieldlength) calc_used_field_length(FALSE); return used_fieldlength; } ulong get_max_used_fieldlength() { if (!max_used_fieldlength) calc_used_field_length(TRUE); return max_used_fieldlength; } double get_partial_join_cardinality() { return partial_join_cardinality; } bool hash_join_is_possible(); int make_scan_filter(); bool is_ref_for_hash_join() { return is_hash_join_key_no(ref.key); } KEY *get_keyinfo_by_key_no(uint key) { return (is_hash_join_key_no(key) ? hj_key : table->key_info+key); } double scan_time(); ha_rows get_examined_rows(); bool preread_init(); bool pfs_batch_update(JOIN *join); bool is_sjm_nest() { return MY_TEST(bush_children); } /* If this join_tab reads a non-merged semi-join (also called jtbm), return the select's number. Otherwise, return 0. */ int get_non_merged_semijoin_select() const { Item_in_subselect *subq; if (table->pos_in_table_list && (subq= table->pos_in_table_list->jtbm_subselect)) { return subq->unit->first_select()->select_number; } return 0; /* Not a merged semi-join */ } bool access_from_tables_is_allowed(table_map used_tables, table_map sjm_lookup_tables) { table_map used_sjm_lookup_tables= used_tables & sjm_lookup_tables; return !used_sjm_lookup_tables || (emb_sj_nest && !(used_sjm_lookup_tables & ~emb_sj_nest->sj_inner_tables)); } bool keyuse_is_valid_for_access_in_chosen_plan(JOIN *join, KEYUSE *keyuse); void remove_redundant_bnl_scan_conds(); bool save_explain_data(Explain_table_access *eta, table_map prefix_tables, bool distinct, struct st_join_table *first_top_tab); bool use_order() const; ///< Use ordering provided by chosen index? bool sort_table(); bool remove_duplicates(); void partial_cleanup(); void add_keyuses_for_splitting(); SplM_plan_info *choose_best_splitting(uint idx, table_map remaining_tables, const POSITION *join_positions, table_map *spl_pd_boundary); bool fix_splitting(SplM_plan_info *spl_plan, table_map excluded_tables, bool is_const_table); } JOIN_TAB; #include "sql_join_cache.h" enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); enum_nested_loop_state sub_select(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); enum_nested_loop_state sub_select_postjoin_aggr(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); enum_nested_loop_state end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records); enum_nested_loop_state end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records); class Semi_join_strategy_picker { public: /* Called when starting to build a new join prefix */ virtual void set_empty() = 0; /* Update internal state after another table has been added to the join prefix */ virtual void set_from_prev(POSITION *prev) = 0; virtual bool check_qep(JOIN *join, uint idx, table_map remaining_tables, const JOIN_TAB *new_join_tab, double *record_count, double *read_time, table_map *handled_fanout, sj_strategy_enum *strategy, POSITION *loose_scan_pos) = 0; virtual void mark_used() = 0; virtual ~Semi_join_strategy_picker() = default; }; /* Duplicate Weedout strategy optimization state */ class Duplicate_weedout_picker : public Semi_join_strategy_picker { /* The first table that the strategy will need to handle */ uint first_dupsweedout_table; /* Tables that we will need to have in the prefix to do the weedout step (all inner and all outer that the involved semi-joins are correlated with) */ table_map dupsweedout_tables; bool is_used; public: void set_empty() override { dupsweedout_tables= 0; first_dupsweedout_table= MAX_TABLES; is_used= FALSE; } void set_from_prev(POSITION *prev) override; bool check_qep(JOIN *join, uint idx, table_map remaining_tables, const JOIN_TAB *new_join_tab, double *record_count, double *read_time, table_map *handled_fanout, sj_strategy_enum *stratey, POSITION *loose_scan_pos) override; void mark_used() override { is_used= TRUE; } friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); }; class Firstmatch_picker : public Semi_join_strategy_picker { /* Index of the first inner table that we intend to handle with this strategy */ uint first_firstmatch_table; /* Tables that were not in the join prefix when we've started considering FirstMatch strategy. */ table_map first_firstmatch_rtbl; /* Tables that need to be in the prefix before we can calculate the cost of using FirstMatch strategy. */ table_map firstmatch_need_tables; bool is_used; bool in_firstmatch_prefix() { return (first_firstmatch_table != MAX_TABLES); } void invalidate_firstmatch_prefix() { first_firstmatch_table= MAX_TABLES; } public: void set_empty() override { invalidate_firstmatch_prefix(); is_used= FALSE; } void set_from_prev(POSITION *prev) override; bool check_qep(JOIN *join, uint idx, table_map remaining_tables, const JOIN_TAB *new_join_tab, double *record_count, double *read_time, table_map *handled_fanout, sj_strategy_enum *strategy, POSITION *loose_scan_pos) override; void mark_used() override { is_used= TRUE; } friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); }; class LooseScan_picker : public Semi_join_strategy_picker { public: /* The first (i.e. driving) table we're doing loose scan for */ uint first_loosescan_table; /* Tables that need to be in the prefix before we can calculate the cost of using LooseScan strategy. */ table_map loosescan_need_tables; /* keyno - Planning to do LooseScan on this key. If keyuse is NULL then this is a full index scan, otherwise this is a ref+loosescan scan (and keyno matches the KEUSE's) MAX_KEY - Not doing a LooseScan */ uint loosescan_key; // final (one for strategy instance ) uint loosescan_parts; /* Number of keyparts to be kept distinct */ bool is_used; void set_empty() override { first_loosescan_table= MAX_TABLES; is_used= FALSE; } void set_from_prev(POSITION *prev) override; bool check_qep(JOIN *join, uint idx, table_map remaining_tables, const JOIN_TAB *new_join_tab, double *record_count, double *read_time, table_map *handled_fanout, sj_strategy_enum *strategy, POSITION *loose_scan_pos) override; void mark_used() override { is_used= TRUE; } friend class Loose_scan_opt; friend void best_access_path(JOIN *join, JOIN_TAB *s, table_map remaining_tables, const POSITION *join_positions, uint idx, bool disable_jbuf, double record_count, POSITION *pos, POSITION *loose_scan_pos); friend bool get_best_combination(JOIN *join); friend int setup_semijoin_loosescan(JOIN *join); friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); }; class Sj_materialization_picker : public Semi_join_strategy_picker { bool is_used; /* The last inner table (valid once we're after it) */ uint sjm_scan_last_inner; /* Tables that we need to have in the prefix to calculate the correct cost. Basically, we need all inner tables and outer tables mentioned in the semi-join's ON expression so we can correctly account for fanout. */ table_map sjm_scan_need_tables; public: void set_empty() override { sjm_scan_need_tables= 0; sjm_scan_last_inner= 0; is_used= FALSE; } void set_from_prev(POSITION *prev) override; bool check_qep(JOIN *join, uint idx, table_map remaining_tables, const JOIN_TAB *new_join_tab, double *record_count, double *read_time, table_map *handled_fanout, sj_strategy_enum *strategy, POSITION *loose_scan_pos) override; void mark_used() override { is_used= TRUE; } friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); }; class Range_rowid_filter_cost_info; class Rowid_filter; /** Information about a position of table within a join order. Used in join optimization. */ class POSITION { public: /* The table that's put into join order */ JOIN_TAB *table; /* The "fanout": number of output rows that will be produced (after pushed down selection condition is applied) per each row combination of previous tables. */ double records_read; /* The selectivity of the pushed down conditions */ double cond_selectivity; /* Cost accessing the table in course of the entire complete join execution, i.e. cost of one access method use (e.g. 'range' or 'ref' scan ) times number the access method will be invoked. */ double read_time; double prefix_record_count; /* NULL - 'index' or 'range' or 'index_merge' or 'ALL' access is used. Other - [eq_]ref[_or_null] access is used. Pointer to {t.keypart1 = expr} */ KEYUSE *key; /* Cardinality of current partial join ending with this position */ double partial_join_cardinality; /* Info on splitting plan used at this position */ SplM_plan_info *spl_plan; /* If spl_plan is NULL the value of spl_pd_boundary is 0. Otherwise spl_pd_boundary contains the bitmap of the table from the current partial join ending at this position that starts the sub-sequence of tables S from which no conditions are allowed to be used in the plan spl_plan for the split table joined at this position. */ table_map spl_pd_boundary; /* Cost info for the range filter used at this position */ Range_rowid_filter_cost_info *range_rowid_filter_info; /* If ref-based access is used: bitmap of tables this table depends on */ table_map ref_depend_map; /* tables that may help best_access_path() to find a better key */ table_map key_dependent; /* Bitmap of semi-join inner tables that are in the join prefix and for which there's no provision for how to eliminate semi-join duplicates they produce. */ table_map dups_producing_tables; table_map inner_tables_handled_with_other_sjs; Duplicate_weedout_picker dups_weedout_picker; Firstmatch_picker firstmatch_picker; LooseScan_picker loosescan_picker; Sj_materialization_picker sjmat_picker; /* Cumulative cost and record count for the join prefix */ Cost_estimate prefix_cost; /* Current optimization state: Semi-join strategy to be used for this and preceding join tables. Join optimizer sets this for the *last* join_tab in the duplicate-generating range. That is, in order to interpret this field, one needs to traverse join->[best_]positions array from right to left. When you see a join table with sj_strategy!= SJ_OPT_NONE, some other field (depending on the strategy) tells how many preceding positions this applies to. The values of covered_preceding_positions->sj_strategy must be ignored. */ enum sj_strategy_enum sj_strategy; /* Type of join (EQ_REF, REF etc) */ enum join_type type; /* Valid only after fix_semijoin_strategies_for_picked_join_order() call: if sj_strategy!=SJ_OPT_NONE, this is the number of subsequent tables that are covered by the specified semi-join strategy */ uint n_sj_tables; /* TRUE <=> join buffering will be used. At the moment this is based on *very* imprecise guesses made in best_access_path(). */ bool use_join_buffer; POSITION(); }; typedef Bounds_checked_array Item_null_array; typedef struct st_rollup { enum State { STATE_NONE, STATE_INITED, STATE_READY }; State state; Item_null_array null_items; Ref_ptr_array *ref_pointer_arrays; List *fields; } ROLLUP; class JOIN_TAB_RANGE: public Sql_alloc { public: JOIN_TAB *start; JOIN_TAB *end; }; class Pushdown_query; /** @brief Class to perform postjoin aggregation operations @details The result records are obtained on the put_record() call. The aggrgation process is determined by the write_func, it could be: end_write Simply store all records in tmp table. end_write_group Perform grouping using join->group_fields, records are expected to be sorted. end_update Perform grouping using the key generated on tmp table. Input records aren't expected to be sorted. Tmp table uses the heap engine end_update_unique Same as above, but the engine is myisam. Lazy table initialization is used - the table will be instantiated and rnd/index scan started on the first put_record() call. */ class AGGR_OP :public Sql_alloc { public: JOIN_TAB *join_tab; AGGR_OP(JOIN_TAB *tab) : join_tab(tab), write_func(NULL) {}; enum_nested_loop_state put_record() { return put_record(false); }; /* Send the result of operation further (to a next operation/client) This function is called after all records were put into tmp table. @return return one of enum_nested_loop_state values. */ enum_nested_loop_state end_send(); /** write_func setter */ void set_write_func(Next_select_func new_write_func) { write_func= new_write_func; } private: /** Write function that would be used for saving records in tmp table. */ Next_select_func write_func; enum_nested_loop_state put_record(bool end_of_records); bool prepare_tmp_table(); }; class JOIN :public Sql_alloc { private: JOIN(const JOIN &rhs); /**< not implemented */ JOIN& operator=(const JOIN &rhs); /**< not implemented */ protected: /** The subset of the state of a JOIN that represents an optimized query execution plan. Allows saving/restoring different JOIN plans for the same query. */ class Join_plan_state { public: DYNAMIC_ARRAY keyuse; /* Copy of the JOIN::keyuse array. */ POSITION *best_positions; /* Copy of JOIN::best_positions */ /* Copies of the JOIN_TAB::keyuse pointers for each JOIN_TAB. */ KEYUSE **join_tab_keyuse; /* Copies of JOIN_TAB::checked_keys for each JOIN_TAB. */ key_map *join_tab_checked_keys; SJ_MATERIALIZATION_INFO **sj_mat_info; my_bool error; public: Join_plan_state(uint tables) : error(0) { keyuse.elements= 0; keyuse.buffer= NULL; keyuse.malloc_flags= 0; best_positions= 0; /* To detect errors */ error= my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME), &best_positions, sizeof(*best_positions) * (tables + 1), &join_tab_keyuse, sizeof(*join_tab_keyuse) * tables, &join_tab_checked_keys, sizeof(*join_tab_checked_keys) * tables, &sj_mat_info, sizeof(sj_mat_info) * tables, NullS) == 0; } Join_plan_state(JOIN *join); ~Join_plan_state() { delete_dynamic(&keyuse); my_free(best_positions); } }; /* Results of reoptimizing a JOIN via JOIN::reoptimize(). */ enum enum_reopt_result { REOPT_NEW_PLAN, /* there is a new reoptimized plan */ REOPT_OLD_PLAN, /* no new improved plan can be found, use the old one */ REOPT_ERROR, /* an irrecovarable error occurred during reoptimization */ REOPT_NONE /* not yet reoptimized */ }; /* Support for plan reoptimization with rewritten conditions. */ enum_reopt_result reoptimize(Item *added_where, table_map join_tables, Join_plan_state *save_to); /* Choose a subquery plan for a table-less subquery. */ bool choose_tableless_subquery_plan(); void handle_implicit_grouping_with_window_funcs(); public: void save_query_plan(Join_plan_state *save_to); void reset_query_plan(); void restore_query_plan(Join_plan_state *restore_from); public: JOIN_TAB *join_tab, **best_ref; /* List of fields that aren't under an aggregate function */ List non_agg_fields; JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs List join_tab_ranges; /* Base tables participating in the join. After join optimization is done, the tables are stored in the join order (but the only really important part is that const tables are first). */ TABLE **table; /** The table which has an index that allows to produce the requried ordering. A special value of 0x1 means that the ordering will be produced by passing 1st non-const table to filesort(). NULL means no such table exists. */ TABLE *sort_by_table; /* If true, there is ORDER BY x LIMIT n clause and for certain join orders, it is possible to short-cut the join execution, i.e. stop it as soon as n output rows were produced. See join_limit_shortcut_is_applicable(). */ bool limit_shortcut_applicable; /* Used during join optimization: if true, we're building a join order that will short-cut join execution as soon as #LIMIT rows are produced. */ bool limit_optimization_mode; /* Number of tables in the join. (In MySQL, it is named 'tables' and is also the number of elements in join->join_tab array. In MariaDB, the latter is not true, so we've renamed the variable) */ uint table_count; uint outer_tables; /**< Number of tables that are not inside semijoin */ uint const_tables; /* Number of tables in the top join_tab array. Normally this matches (join_tab_ranges.head()->end - join_tab_ranges.head()->start). We keep it here so that it is saved/restored with JOIN::restore_tmp. */ uint top_join_tab_count; uint aggr_tables; ///< Number of post-join tmp tables uint send_group_parts; /* This represents the number of items in ORDER BY *after* removing all const items. This is computed before other optimizations take place, such as removal of ORDER BY when it is a prefix of GROUP BY, for example: GROUP BY a, b ORDER BY a This is used when deciding to send rows, by examining the correct number of items in the group_fields list when ORDER BY was previously eliminated. */ uint with_ties_order_count; /* True if the query has GROUP BY. (that is, if group_by != NULL. when DISTINCT is converted into GROUP BY, it will set this, too. It is not clear why we need a separate var from group_list) */ bool group; bool need_distinct; /** Indicates that grouping will be performed on the result set during query execution. This field belongs to query execution. If 'sort_and_group' is set, then the optimizer is going to use on of the following algorithms to resolve GROUP BY. - If one table, sort the table and then calculate groups on the fly. - If more than one table, create a temporary table to hold the join, sort it and then resolve group by on the fly. The 'on the fly' calculation is done in end_send_group() @see make_group_fields, alloc_group_fields, JOIN::exec, setup_end_select_func */ bool sort_and_group; bool first_record,full_join, no_field_update; bool hash_join; bool do_send_rows; table_map const_table_map; /** Bitmap of semijoin tables that the current partial plan decided to materialize and access by lookups */ table_map sjm_lookup_tables; /** Bitmap of semijoin tables that the chosen plan decided to materialize to scan the results of materialization */ table_map sjm_scan_tables; /* Constant tables for which we have found a row (as opposed to those for which we didn't). */ table_map found_const_table_map; /* Tables removed by table elimination. Set to 0 before the elimination. */ table_map eliminated_tables; /* Bitmap of all inner tables from outer joins (set at start of make_join_statistics) */ table_map outer_join; /* Bitmap of tables used in the select list items */ table_map select_list_used_tables; /* Tables that has HA_NON_COMPARABLE_ROWID (does not support rowid) set */ table_map not_usable_rowid_map; ha_rows send_records,found_records,join_examined_rows, accepted_rows; /* LIMIT for the JOIN operation. When not using aggregation or DISITNCT, this is the same as select's LIMIT clause specifies. Note that this doesn't take sql_calc_found_rows into account. */ ha_rows row_limit; /* How many output rows should be produced after GROUP BY. (if sql_calc_found_rows is used, LIMIT is ignored) */ ha_rows select_limit; /* Number of duplicate rows found in UNION. */ ha_rows duplicate_rows; /** Used to fetch no more than given amount of rows per one fetch operation of server side cursor. The value is checked in end_send and end_send_group in fashion, similar to offset_limit_cnt: - fetch_limit= HA_POS_ERROR if there is no cursor. - when we open a cursor, we set fetch_limit to 0, - on each fetch iteration we add num_rows to fetch to fetch_limit NOTE: currently always HA_POS_ERROR. */ ha_rows fetch_limit; /* Finally picked QEP. This is result of join optimization */ POSITION *best_positions; Pushdown_query *pushdown_query; JOIN_TAB *original_join_tab; uint original_table_count; /******* Join optimization state members start *******/ /* pointer - we're doing optimization for a semi-join materialization nest. NULL - otherwise */ TABLE_LIST *emb_sjm_nest; /* Current join optimization state */ POSITION *positions; /* Bitmap of nested joins embedding the position at the end of the current partial join (valid only during join optimizer run). */ nested_join_map cur_embedding_map; /* Bitmap of inner tables of semi-join nests that have a proper subset of their tables in the current join prefix. That is, of those semi-join nests that have their tables both in and outside of the join prefix. (Note: tables that are constants but have not been pulled out of semi-join nests are not considered part of semi-join nests) */ table_map cur_sj_inner_tables; #ifndef DBUG_OFF void dbug_verify_sj_inner_tables(uint n_positions) const; int dbug_join_tab_array_size; #endif /* We also maintain a stack of join optimization states in * join->positions[] */ /******* Join optimization state members end *******/ /* Tables within complex firstmatch ranges (i.e. those where inner tables are interleaved with outer tables). Join buffering cannot be used for these. */ table_map complex_firstmatch_tables; Next_select_func first_select; /* The cost of best complete join plan found so far during optimization, after optimization phase - cost of picked join order (not taking into account the changes made by test_if_skip_sort_order()). */ double best_read; /* Estimated result rows (fanout) of the join operation. If this is a subquery that is reexecuted multiple times, this value includes the estiamted # of reexecutions. This value is equal to the multiplication of all join->positions[i].records_read of a JOIN. */ double join_record_count; List *fields; /* Used only for FETCH ... WITH TIES to identify peers. */ List order_fields; /* Used during GROUP BY operations to identify when a group has changed. */ List group_fields, group_fields_cache; THD *thd; Item_sum **sum_funcs, ***sum_funcs_end; /** second copy of sumfuncs (for queries with 2 temporary tables */ Item_sum **sum_funcs2, ***sum_funcs_end2; Procedure *procedure; Item *having; Item *tmp_having; ///< To store having when processed temporary table Item *having_history; ///< Store having for explain ORDER *group_list_for_estimates; bool having_is_correlated; ulonglong select_options; /* Bitmap of allowed types of the join caches that can be used for join operations */ uint allowed_join_cache_types; bool allowed_semijoin_with_cache; bool allowed_outer_join_with_cache; /* Maximum level of the join caches that can be used for join operations */ uint max_allowed_join_cache_level; select_result *result; TMP_TABLE_PARAM tmp_table_param; MYSQL_LOCK *lock; /// unit structure (with global parameters) for this select SELECT_LEX_UNIT *unit; /// select that processed SELECT_LEX *select_lex; /** TRUE <=> optimizer must not mark any table as a constant table. This is needed for subqueries in form "a IN (SELECT .. UNION SELECT ..): when we optimize the select that reads the results of the union from a temporary table, we must not mark the temp. table as constant because the number of rows in it may vary from one subquery execution to another. */ bool no_const_tables; /* This flag is set if we call no_rows_in_result() as par of end_group(). This is used as a simple speed optimization to avoiding calling restore_no_rows_in_result() in ::reinit() */ bool no_rows_in_result_called; /** This is set if SQL_CALC_ROWS was calculated by filesort() and should be taken from the appropriate JOIN_TAB */ bool filesort_found_rows; bool subq_exit_fl; ROLLUP rollup; ///< Used with rollup bool mixed_implicit_grouping; bool select_distinct; ///< Set if SELECT DISTINCT /** If we have the GROUP BY statement in the query, but the group_list was emptied by optimizer, this flag is TRUE. It happens when fields in the GROUP BY are from constant table */ bool group_optimized_away; /* simple_xxxxx is set if ORDER/GROUP BY doesn't include any references to other tables than the first non-constant table in the JOIN. It's also set if ORDER/GROUP BY is empty. Used for deciding for or against using a temporary table to compute GROUP/ORDER BY. */ bool simple_order, simple_group; /* ordered_index_usage is set if an ordered index access should be used instead of a filesort when computing ORDER/GROUP BY. */ enum { ordered_index_void, // No ordered index avail. ordered_index_group_by, // Use index for GROUP BY ordered_index_order_by // Use index for ORDER BY } ordered_index_usage; /** Is set only in case if we have a GROUP BY clause and no ORDER BY after constant elimination of 'order'. */ bool no_order; /** Is set if we have a GROUP BY and we have ORDER BY on a constant. */ bool skip_sort_order; bool need_tmp; bool hidden_group_fields; /* TRUE if there was full cleunap of the JOIN */ bool cleaned; DYNAMIC_ARRAY keyuse; Item::cond_result cond_value, having_value; /** Impossible where after reading const tables (set in make_join_statistics()) */ bool impossible_where; /* All fields used in the query processing. Initially this is a list of fields from the query's SQL text. Then, ORDER/GROUP BY and Window Function code add columns that need to be saved to be available in the post-group-by context. These extra columns are added to the front, because this->fields_list points to the suffix of this list. */ List all_fields; ///Above list changed to use temporary table List tmp_all_fields1, tmp_all_fields2, tmp_all_fields3; ///Part, shared with list above, emulate following list List tmp_fields_list1, tmp_fields_list2, tmp_fields_list3; /* The original field list as it was passed to mysql_select(). This refers to select_lex->item_list. CAUTION: this list is a suffix of this->all_fields list, that is, it shares elements with that list! */ List &fields_list; List procedure_fields_list; int error; ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select COND *conds; // ---"--- Item *conds_history; // store WHERE for explain COND *outer_ref_cond; /// *join_list; ///< list of joined tables in reverse order COND_EQUAL *cond_equal; COND_EQUAL *having_equal; /* Constant codition computed during optimization, but evaluated during join execution. Typically expensive conditions that should not be evaluated at optimization time. */ Item *exec_const_cond; /* Constant ORDER and/or GROUP expressions that contain subqueries. Such expressions need to evaluated to verify that the subquery indeed returns a single row. The evaluation of such expressions is delayed until query execution. */ List exec_const_order_group_cond; SQL_SELECT *select; ///ref_pointer_array contains five "slices" of the same length: |========|========|========|========|========| ref_ptrs items0 items1 items2 items3 */ Ref_ptr_array ref_ptrs; // Copy of the initial slice above, to be used with different lists Ref_ptr_array items0, items1, items2, items3; // Used by rollup, to restore ref_ptrs after overwriting it. Ref_ptr_array current_ref_ptrs; const char *zero_result_cause; ///< not 0 if exec must return zero result bool union_part; ///< this subselect is part of union enum join_optimization_state { NOT_OPTIMIZED=0, OPTIMIZATION_IN_PROGRESS=1, OPTIMIZATION_PHASE_1_DONE=2, OPTIMIZATION_DONE=3}; // state of JOIN optimization enum join_optimization_state optimization_state; bool initialized; ///< flag to avoid double init_execution calls Explain_select *explain; enum { QEP_NOT_PRESENT_YET, QEP_AVAILABLE, QEP_DELETED} have_query_plan; // if keep_current_rowid=true, whether they should be saved in temporary table bool tmp_table_keep_current_rowid; /* Additional WHERE and HAVING predicates to be considered for IN=>EXISTS subquery transformation of a JOIN object. */ Item *in_to_exists_where; Item *in_to_exists_having; /* Temporary tables used to weed-out semi-join duplicates */ List
sj_tmp_tables; /* SJM nests that are executed with SJ-Materialization strategy */ List sjm_info_list; /** TRUE <=> ref_pointer_array is set to items3. */ bool set_group_rpa; /** Exec time only: TRUE <=> current group has been sent */ bool group_sent; /** TRUE if the query contains an aggregate function but has no GROUP BY clause. */ bool implicit_grouping; bool with_two_phase_optimization; /* Saved execution plan for this join */ Join_plan_state *save_qep; /* Info on splittability of the table materialized by this plan*/ SplM_opt_info *spl_opt_info; /* Contains info on keyuses usable for splitting */ Dynamic_array *ext_keyuses_for_splitting; JOIN_TAB *sort_and_group_aggr_tab; /* Flag is set to true if select_lex was found to be degenerated before the optimize_cond() call in JOIN::optimize_inner() method. */ bool is_orig_degenerated; JOIN(THD *thd_arg, List &fields_arg, ulonglong select_options_arg, select_result *result_arg) :fields_list(fields_arg) { init(thd_arg, fields_arg, select_options_arg, result_arg); } void init(THD *thd_arg, List &fields_arg, ulonglong select_options_arg, select_result *result_arg); /* True if the plan guarantees that it will be returned zero or one row */ bool only_const_tables() { return const_tables == table_count; } /* Number of tables actually joined at the top level */ uint exec_join_tab_cnt() { return tables_list ? top_join_tab_count : 0; } /* Number of tables in the join which also includes the temporary tables created for GROUP BY, DISTINCT , WINDOW FUNCTION etc. */ uint total_join_tab_cnt() { return exec_join_tab_cnt() + aggr_tables - 1; } int prepare(TABLE_LIST *tables, COND *conds, uint og_num, ORDER *order, bool skip_order_by, ORDER *group, Item *having, ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit); bool prepare_stage2(); int optimize(); int optimize_inner(); int optimize_stage2(); bool build_explain(); int reinit(); int init_execution(); void exec(); void exec_inner(); bool prepare_result(List **columns_list); int destroy(); void restore_tmp(); bool alloc_func_list(); bool flatten_subqueries(); bool optimize_unflattened_subqueries(); bool optimize_constant_subqueries(); bool make_range_rowid_filters(); bool init_range_rowid_filters(); bool make_sum_func_list(List &all_fields, List &send_fields, bool before_group_by); /// Initialzes a slice, see comments for ref_ptrs above. Ref_ptr_array ref_ptr_array_slice(size_t slice_num) { size_t slice_sz= select_lex->ref_pointer_array.size() / 5U; DBUG_ASSERT(select_lex->ref_pointer_array.size() % 5 == 0); DBUG_ASSERT(slice_num < 5U); return Ref_ptr_array(&select_lex->ref_pointer_array[slice_num * slice_sz], slice_sz); } /** Overwrites one slice with the contents of another slice. In the normal case, dst and src have the same size(). However: the rollup slices may have smaller size than slice_sz. */ void copy_ref_ptr_array(Ref_ptr_array dst_arr, Ref_ptr_array src_arr) { DBUG_ASSERT(dst_arr.size() >= src_arr.size()); if (src_arr.size() == 0) return; void *dest= dst_arr.array(); const void *src= src_arr.array(); memcpy(dest, src, src_arr.size() * src_arr.element_size()); } /// Overwrites 'ref_ptrs' and remembers the the source as 'current'. void set_items_ref_array(Ref_ptr_array src_arr) { copy_ref_ptr_array(ref_ptrs, src_arr); current_ref_ptrs= src_arr; } /// Initializes 'items0' and remembers that it is 'current'. void init_items_ref_array() { items0= ref_ptr_array_slice(1); copy_ref_ptr_array(items0, ref_ptrs); current_ref_ptrs= items0; } bool rollup_init(); bool rollup_process_const_fields(); bool rollup_make_fields(List &all_fields, List &fields, Item_sum ***func); int rollup_send_data(uint idx); int rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param, TABLE *table); void join_free(); /** Cleanup this JOIN, possibly for reuse */ void cleanup(bool full); void clear(table_map *cleared_tables); void inline clear_sum_funcs(); bool send_row_on_empty_set() { return (do_send_rows && implicit_grouping && !group_optimized_away && having_value != Item::COND_FALSE); } bool empty_result() { return (zero_result_cause && !implicit_grouping); } bool change_result(select_result *new_result, select_result *old_result); bool is_top_level_join() const { return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 || select_lex == unit->fake_select_lex)); } void cache_const_exprs(); inline table_map all_tables_map() { return (table_map(1) << table_count) - 1; } void drop_unused_derived_keys(); bool get_best_combination(); bool add_sorting_to_table(JOIN_TAB *tab, ORDER *order); inline void eval_select_list_used_tables(); /* Return the table for which an index scan can be used to satisfy the sort order needed by the ORDER BY/(implicit) GROUP BY clause */ JOIN_TAB *get_sort_by_join_tab() { return (need_tmp || !sort_by_table || skip_sort_order || ((group || tmp_table_param.sum_func_count) && !group_list)) ? NULL : join_tab+const_tables; } bool setup_subquery_caches(); bool shrink_join_buffers(JOIN_TAB *jt, ulonglong curr_space, ulonglong needed_space); void set_allowed_join_cache_types(); bool is_allowed_hash_join_access() { return MY_TEST(allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) && max_allowed_join_cache_level > JOIN_CACHE_HASHED_BIT; } /* Check if we need to create a temporary table. This has to be done if all tables are not already read (const tables) and one of the following conditions holds: - We are using DISTINCT (simple distinct's are already optimized away) - We are using an ORDER BY or GROUP BY on fields not in the first table - We are using different ORDER BY and GROUP BY orders - The user wants us to buffer the result. - We are using WINDOW functions. When the WITH ROLLUP modifier is present, we cannot skip temporary table creation for the DISTINCT clause just because there are only const tables. */ bool test_if_need_tmp_table() { return ((const_tables != table_count && ((select_distinct || !simple_order || !simple_group) || (group_list && order) || MY_TEST(select_options & OPTION_BUFFER_RESULT))) || (rollup.state != ROLLUP::STATE_NONE && select_distinct) || select_lex->have_window_funcs()); } bool choose_subquery_plan(table_map join_tables); void get_partial_cost_and_fanout(int end_tab_idx, table_map filter_map, double *read_time_arg, double *record_count_arg); void get_prefix_cost_and_fanout(uint n_tables, double *read_time_arg, double *record_count_arg); double get_examined_rows(); /* defined in opt_subselect.cc */ bool transform_max_min_subquery(); /* True if this JOIN is a subquery under an IN predicate. */ bool is_in_subquery() { return (unit->item && unit->item->is_in_predicate()); } bool save_explain_data(Explain_query *output, bool can_overwrite, bool need_tmp_table, bool need_order, bool distinct); int save_explain_data_intern(Explain_query *output, bool need_tmp_table, bool need_order, bool distinct, const char *message); JOIN_TAB *first_breadth_first_tab() { return join_tab; } bool check_two_phase_optimization(THD *thd); bool inject_cond_into_where(Item *injected_cond); bool check_for_splittable_materialized(); void add_keyuses_for_splitting(); bool inject_best_splitting_cond(table_map remaining_tables); bool fix_all_splittings_in_plan(); bool inject_splitting_cond_for_all_tables_with_split_opt(); void make_notnull_conds_for_range_scans(); bool transform_in_predicates_into_in_subq(THD *thd); bool optimize_upper_rownum_func(); private: /** Create a temporary table to be used for processing DISTINCT/ORDER BY/GROUP BY. @note Will modify JOIN object wrt sort/group attributes @param tab the JOIN_TAB object to attach created table to @param tmp_table_fields List of items that will be used to define column types of the table. @param tmp_table_group Group key to use for temporary table, NULL if none. @param save_sum_fields If true, do not replace Item_sum items in @c tmp_fields list with Item_field items referring to fields in temporary table. @returns false on success, true on failure */ bool create_postjoin_aggr_table(JOIN_TAB *tab, List *tmp_table_fields, ORDER *tmp_table_group, bool save_sum_fields, bool distinct, bool keep_row_ordermake); /** Optimize distinct when used on a subset of the tables. E.g.,: SELECT DISTINCT t1.a FROM t1,t2 WHERE t1.b=t2.b In this case we can stop scanning t2 when we have found one t1.a */ void optimize_distinct(); void cleanup_item_list(List &items) const; bool add_having_as_table_cond(JOIN_TAB *tab); bool make_aggr_tables_info(); bool add_fields_for_current_rowid(JOIN_TAB *cur, List *fields); void free_pushdown_handlers(List& join_list); void init_join_cache_and_keyread(); bool prepare_sum_aggregators(THD *thd,Item_sum **func_ptr, bool need_distinct); bool transform_in_predicates_into_equalities(THD *thd); bool transform_all_conds_and_on_exprs(THD *thd, Item_transformer transformer); bool transform_all_conds_and_on_exprs_in_join_list(THD *thd, List *join_list, Item_transformer transformer); }; enum enum_with_bush_roots { WITH_BUSH_ROOTS, WITHOUT_BUSH_ROOTS}; enum enum_with_const_tables { WITH_CONST_TABLES, WITHOUT_CONST_TABLES}; JOIN_TAB *first_linear_tab(JOIN *join, enum enum_with_bush_roots include_bush_roots, enum enum_with_const_tables const_tbls); JOIN_TAB *next_linear_tab(JOIN* join, JOIN_TAB* tab, enum enum_with_bush_roots include_bush_roots); JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables with_const); JOIN_TAB *next_top_level_tab(JOIN *join, JOIN_TAB *tab); typedef struct st_select_check { uint const_ref,reg_ref; } SELECT_CHECK; extern const char *join_type_str[]; /* Extern functions in sql_select.cc */ void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, List &fields, bool reset_with_sum_func); bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, Ref_ptr_array ref_pointer_array, List &new_list1, List &new_list2, uint elements, List &fields); void copy_fields(TMP_TABLE_PARAM *param); bool copy_funcs(Item **func_ptr, const THD *thd); uint find_shortest_key(TABLE *table, const key_map *usable_keys); bool is_indexed_agg_distinct(JOIN *join, List *out_args); /* functions from opt_sum.cc */ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order); int opt_sum_query(THD* thd, List &tables, List &all_fields, COND *conds); /* from sql_delete.cc, used by opt_range.cc */ extern "C" int refpos_order_cmp(void *arg, const void *a,const void *b); /** class to copying an field/item to a key struct */ class store_key :public Sql_alloc { public: bool null_key; /* TRUE <=> the value of the key has a null part */ enum store_key_result { STORE_KEY_OK, STORE_KEY_FATAL, STORE_KEY_CONV }; enum Type { FIELD_STORE_KEY, ITEM_STORE_KEY, CONST_ITEM_STORE_KEY }; store_key(THD *thd, Field *field_arg, uchar *ptr, uchar *null, uint length) :null_key(0), null_ptr(null), err(0) { to_field=field_arg->new_key_field(thd->mem_root, field_arg->table, ptr, length, null, 1); } store_key(store_key &arg) :Sql_alloc(), null_key(arg.null_key), to_field(arg.to_field), null_ptr(arg.null_ptr), err(arg.err) {} virtual ~store_key() = default; /** Not actually needed */ virtual enum Type type() const=0; virtual const char *name() const=0; virtual bool store_key_is_const() { return false; } /** @brief sets ignore truncation warnings mode and calls the real copy method @details this function makes sure truncation warnings when preparing the key buffers don't end up as errors (because of an enclosing INSERT/UPDATE). */ enum store_key_result copy(THD *thd) { enum_check_fields org_count_cuted_fields= thd->count_cuted_fields; Use_relaxed_field_copy urfc(to_field->table->in_use); /* If needed, perform CharsetNarrowing for making ref access lookup keys. */ Utf8_narrow do_narrow(to_field, do_cset_narrowing); store_key_result result= copy_inner(); do_narrow.stop(); thd->count_cuted_fields= org_count_cuted_fields; return result; } protected: Field *to_field; // Store data here uchar *null_ptr; uchar err; /* This is set to true if we need to do Charset Narrowing when making a lookup key. */ bool do_cset_narrowing= false; virtual enum store_key_result copy_inner()=0; }; class store_key_field: public store_key { Copy_field copy_field; const char *field_name; public: store_key_field(THD *thd, Field *to_field_arg, uchar *ptr, uchar *null_ptr_arg, uint length, Field *from_field, const char *name_arg) :store_key(thd, to_field_arg,ptr, null_ptr_arg ? null_ptr_arg : from_field->maybe_null() ? &err : (uchar*) 0, length), field_name(name_arg) { if (to_field) { copy_field.set(to_field,from_field,0); setup_charset_narrowing(); } } enum Type type() const override { return FIELD_STORE_KEY; } const char *name() const override { return field_name; } void change_source_field(Item_field *fld_item) { copy_field.set(to_field, fld_item->field, 0); field_name= fld_item->full_name(); setup_charset_narrowing(); } /* Setup CharsetNarrowing if necessary */ void setup_charset_narrowing() { do_cset_narrowing= Utf8_narrow::should_do_narrowing(copy_field.to_field, copy_field.from_field->charset()); } protected: enum store_key_result copy_inner() override { TABLE *table= copy_field.to_field->table; MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->write_set); /* It looks like the next statement is needed only for a simplified hash function over key values used now in BNLH join. When the implementation of this function will be replaced for a proper full version this statement probably should be removed. */ bzero(copy_field.to_ptr,copy_field.to_length); copy_field.do_copy(©_field); dbug_tmp_restore_column_map(&table->write_set, old_map); null_key= to_field->is_null(); return err != 0 ? STORE_KEY_FATAL : STORE_KEY_OK; } }; class store_key_item :public store_key { protected: Item *item; /* Flag that forces usage of save_val() method which save value of the item instead of save_in_field() method which saves result. */ bool use_value; public: store_key_item(THD *thd, Field *to_field_arg, uchar *ptr, uchar *null_ptr_arg, uint length, Item *item_arg, bool val) :store_key(thd, to_field_arg, ptr, null_ptr_arg ? null_ptr_arg : item_arg->maybe_null() ? &err : (uchar*) 0, length), item(item_arg), use_value(val) { /* Setup CharsetNarrowing to be done if necessary */ do_cset_narrowing= Utf8_narrow::should_do_narrowing(to_field, item->collation.collation); } store_key_item(store_key &arg, Item *new_item, bool val) :store_key(arg), item(new_item), use_value(val) {} enum Type type() const override { return ITEM_STORE_KEY; } const char *name() const override { return "func"; } protected: enum store_key_result copy_inner() override { TABLE *table= to_field->table; MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->write_set); int res= FALSE; /* It looks like the next statement is needed only for a simplified hash function over key values used now in BNLH join. When the implementation of this function will be replaced for a proper full version this statement probably should be removed. */ to_field->reset(); if (use_value) item->save_val(to_field); else res= item->save_in_field(to_field, 1); /* Item::save_in_field() may call Item::val_xxx(). And if this is a subquery we need to check for errors executing it and react accordingly */ if (!res && table->in_use->is_error()) res= 1; /* STORE_KEY_FATAL */ dbug_tmp_restore_column_map(&table->write_set, old_map); null_key= to_field->is_null() || item->null_value; return ((err != 0 || res < 0 || res > 2) ? STORE_KEY_FATAL : (store_key_result) res); } }; class store_key_const_item :public store_key_item { bool inited; public: store_key_const_item(THD *thd, Field *to_field_arg, uchar *ptr, uchar *null_ptr_arg, uint length, Item *item_arg) :store_key_item(thd, to_field_arg, ptr, null_ptr_arg ? null_ptr_arg : item_arg->maybe_null() ? &err : (uchar*) 0, length, item_arg, FALSE), inited(0) { } store_key_const_item(store_key &arg, Item *new_item) :store_key_item(arg, new_item, FALSE), inited(0) {} enum Type type() const override { return CONST_ITEM_STORE_KEY; } const char *name() const override { return "const"; } bool store_key_is_const() override { return true; } protected: enum store_key_result copy_inner() override { int res; if (!inited) { inited=1; TABLE *table= to_field->table; MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->write_set); if ((res= item->save_in_field(to_field, 1))) { if (!err) err= res < 0 ? 1 : res; /* 1=STORE_KEY_FATAL */ } /* Item::save_in_field() may call Item::val_xxx(). And if this is a subquery we need to check for errors executing it and react accordingly */ if (!err && to_field->table->in_use->is_error()) err= 1; /* STORE_KEY_FATAL */ dbug_tmp_restore_column_map(&table->write_set, old_map); } null_key= to_field->is_null() || item->null_value; return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err); } }; void best_access_path(JOIN *join, JOIN_TAB *s, table_map remaining_tables, const POSITION *join_positions, uint idx, bool disable_jbuf, double record_count, POSITION *pos, POSITION *loose_scan_pos); bool cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref); bool error_if_full_join(JOIN *join); int report_error(TABLE *table, int error); int safe_index_read(JOIN_TAB *tab); int get_quick_record(SQL_SELECT *select); int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, ORDER *order, bool from_window_spec= false); int setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, ORDER *order, bool *hidden_group_fields, bool from_window_spec= false); bool fix_inner_refs(THD *thd, List &all_fields, SELECT_LEX *select, Ref_ptr_array ref_pointer_array); int join_read_key2(THD *thd, struct st_join_table *tab, TABLE *table, struct st_table_ref *table_ref); bool handle_select(THD *thd, LEX *lex, select_result *result, ulong setup_tables_done_option); bool mysql_select(THD *thd, TABLE_LIST *tables, List &list, COND *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, ulonglong select_type, select_result *result, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex); void free_underlaid_joins(THD *thd, SELECT_LEX *select); bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result); /* General routine to change field->ptr of a NULL-terminated array of Field objects. Useful when needed to call val_int, val_str or similar and the field data is not in table->record[0] but in some other structure. set_key_field_ptr changes all fields of an index using a key_info object. All methods presume that there is at least one field to change. */ class Virtual_tmp_table: public TABLE { /** Destruct collected fields. This method can be called on errors, when we could not make the virtual temporary table completely, e.g. when some of the fields could not be created or added. This is needed to avoid memory leaks, as some fields can be BLOB variants and thus can have String onboard. Strings must be destructed as they store data on the heap (not on MEM_ROOT). */ void destruct_fields() { for (uint i= 0; i < s->fields; i++) { field[i]->free(); delete field[i]; // to invoke the field destructor } s->fields= 0; // safety } protected: /** The number of the fields that are going to be in the table. We remember the number of the fields at init() time, and at open() we check that all of the fields were really added. */ uint m_alloced_field_count; /** Setup field pointers and null-bit pointers. */ void setup_field_pointers(); public: /** Create a new empty virtual temporary table on the thread mem_root. After creation, the caller must: - call init() - populate the table with new fields using add(). - call open(). @param thd - Current thread. */ static void *operator new(size_t size, THD *thd) throw(); static void operator delete(void *ptr, size_t size) { TRASH_FREE(ptr, size); } static void operator delete(void *, THD *) throw(){} Virtual_tmp_table(THD *thd) : m_alloced_field_count(0) { reset(); temp_pool_slot= MY_BIT_NONE; in_use= thd; copy_blobs= true; alias.set("", 0, &my_charset_bin); } ~Virtual_tmp_table() { if (s) destruct_fields(); } /** Allocate components for the given number of fields. - fields[] - s->blob_fields[], - bitmaps: def_read_set, def_write_set, tmp_set, eq_join_set, cond_set. @param field_count - The number of fields we plan to add to the table. @returns false - on success. @returns true - on error. */ bool init(uint field_count); /** Add one Field to the end of the field array, update members: s->reclength, s->fields, s->blob_fields, s->null_fuelds. */ bool add(Field *new_field) { DBUG_ASSERT(s->fields < m_alloced_field_count); new_field->init(this); field[s->fields]= new_field; s->reclength+= new_field->pack_length(); if (!(new_field->flags & NOT_NULL_FLAG)) s->null_fields++; if (new_field->flags & BLOB_FLAG) { // Note, s->blob_fields was incremented in Field_blob::Field_blob DBUG_ASSERT(s->blob_fields); DBUG_ASSERT(s->blob_fields <= m_alloced_field_count); s->blob_field[s->blob_fields - 1]= s->fields; } new_field->field_index= s->fields++; return false; } /** Add fields from a Spvar_definition list @returns false - on success. @returns true - on error. */ bool add(List &field_list); /** Open a virtual table for read/write: - Setup end markers in TABLE::field and TABLE_SHARE::blob_fields, - Allocate a buffer in TABLE::record[0]. - Set field pointers (Field::ptr, Field::null_pos, Field::null_bit) to the allocated record. This method is called when all of the fields have been added to the table. After calling this method the table is ready for read and write operations. @return false - on success @return true - on error (e.g. could not allocate the record buffer). */ bool open(); void set_all_fields_to_null() { for (uint i= 0; i < s->fields; i++) field[i]->set_null(); } /** Set all fields from a compatible item list. The number of fields in "this" must be equal to the number of elements in "value". */ bool sp_set_all_fields_from_item_list(THD *thd, List &items); /** Set all fields from a compatible item. The number of fields in "this" must be the same with the number of elements in "value". */ bool sp_set_all_fields_from_item(THD *thd, Item *value); /** Find a ROW element index by its name Assumes that "this" is used as a storage for a ROW-type SP variable. @param [OUT] idx - the index of the found field is returned here @param [IN] field_name - find a field with this name @return true - on error (the field was not found) @return false - on success (idx[0] was set to the field index) */ bool sp_find_field_by_name(uint *idx, const LEX_CSTRING &name) const; /** Find a ROW element index by its name. If the element is not found, and error is issued. @param [OUT] idx - the index of the found field is returned here @param [IN] var_name - the name of the ROW variable (for error reporting) @param [IN] field_name - find a field with this name @return true - on error (the field was not found) @return false - on success (idx[0] was set to the field index) */ bool sp_find_field_by_name_or_error(uint *idx, const LEX_CSTRING &var_name, const LEX_CSTRING &field_name) const; }; /** Create a reduced TABLE object with properly set up Field list from a list of field definitions. The created table doesn't have a table handler associated with it, has no keys, no group/distinct, no copy_funcs array. The sole purpose of this TABLE object is to use the power of Field class to read/write data to/from table->record[0]. Then one can store the record in any container (RB tree, hash, etc). The table is created in THD mem_root, so are the table's fields. Consequently, if you don't BLOB fields, you don't need to free it. @param thd connection handle @param field_list list of column definitions @return 0 if out of memory, or a TABLE object ready for read and write in case of success */ inline Virtual_tmp_table * create_virtual_tmp_table(THD *thd, List &field_list) { Virtual_tmp_table *table; if (!(table= new(thd) Virtual_tmp_table(thd))) return NULL; /* If "simulate_create_virtual_tmp_table_out_of_memory" debug option is enabled, we now enable "simulate_out_of_memory". This effectively makes table->init() fail on OOM inside multi_alloc_root(). This is done to test that ~Virtual_tmp_table() called from the "delete" below correcly handles OOM. */ DBUG_EXECUTE_IF("simulate_create_virtual_tmp_table_out_of_memory", DBUG_SET("+d,simulate_out_of_memory");); if (table->init(field_list.elements) || table->add(field_list) || table->open()) { delete table; return NULL; } return table; } /** Create a new virtual temporary table consisting of a single field. SUM(DISTINCT expr) and similar numeric aggregate functions use this. @param thd - Current thread @param field - The field that will be added into the table. @return NULL - On error. @return !NULL - A pointer to the created table that is ready for read and write. */ inline TABLE * create_virtual_tmp_table(THD *thd, Field *field) { Virtual_tmp_table *table; DBUG_ASSERT(field); if (!(table= new(thd) Virtual_tmp_table(thd))) return NULL; if (table->init(1) || table->add(field) || table->open()) { delete table; return NULL; } return table; } int test_if_item_cache_changed(List &list); int join_init_read_record(JOIN_TAB *tab); void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key); inline Item * and_items(THD *thd, Item* cond, Item *item) { return (cond ? (new (thd->mem_root) Item_cond_and(thd, cond, item)) : item); } inline Item * or_items(THD *thd, Item* cond, Item *item) { return (cond ? (new (thd->mem_root) Item_cond_or(thd, cond, item)) : item); } bool choose_plan(JOIN *join, table_map join_tables); void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab, table_map last_remaining_tables, bool first_alt, uint no_jbuf_before, double *outer_rec_count, double *reopt_cost); Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field, bool *inherited_fl); extern bool test_if_ref(Item *, Item_field *left_item,Item *right_item); inline bool optimizer_flag(const THD *thd, ulonglong flag) { return (thd->variables.optimizer_switch & flag); } /* int print_fake_select_lex_join(select_result_sink *result, bool on_the_fly, SELECT_LEX *select_lex, uint8 select_options); */ uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select, ha_rows limit, ha_rows *scanned_limit, bool *need_sort, bool *reverse); ORDER *simple_remove_const(ORDER *order, COND *where); bool const_expression_in_where(COND *cond, Item *comp_item, Field *comp_field= NULL, Item **const_item= NULL); bool cond_is_datetime_is_null(Item *cond); bool cond_has_datetime_is_null(Item *cond); /* Table elimination entry point function */ void eliminate_tables(JOIN *join); /* Index Condition Pushdown entry point function */ void push_index_cond(JOIN_TAB *tab, uint keyno); #define OPT_LINK_EQUAL_FIELDS 1 /* EXPLAIN-related utility functions */ int print_explain_message_line(select_result_sink *result, uint8 options, bool is_analyze, uint select_number, const char *select_type, ha_rows *rows, const char *message); void explain_append_mrr_info(QUICK_RANGE_SELECT *quick, String *res); int append_possible_keys(MEM_ROOT *alloc, String_list &list, TABLE *table, key_map possible_keys); void unpack_to_base_table_fields(TABLE *table); /**************************************************************************** Temporary table support for SQL Runtime ***************************************************************************/ #define STRING_TOTAL_LENGTH_TO_PACK_ROWS 128 #define AVG_STRING_LENGTH_TO_PACK_ROWS 64 #define RATIO_TO_PACK_ROWS 2 #define MIN_STRING_LENGTH_TO_PACK_ROWS 10 void calc_group_buffer(TMP_TABLE_PARAM *param, ORDER *group); TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, ORDER *group, bool distinct, bool save_sum_fields, ulonglong select_options, ha_rows rows_limit, const LEX_CSTRING *alias, bool do_not_open=FALSE, bool keep_row_order= FALSE); TABLE *create_tmp_table_for_schema(THD *thd, TMP_TABLE_PARAM *param, const ST_SCHEMA_TABLE &schema_table, longlong select_options, const LEX_CSTRING &alias, bool do_not_open, bool keep_row_order); void free_tmp_table(THD *thd, TABLE *entry); bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, TMP_ENGINE_COLUMNDEF *start_recinfo, TMP_ENGINE_COLUMNDEF **recinfo, int error, bool ignore_last_dupp_key_error, bool *is_duplicate); bool create_internal_tmp_table(TABLE *table, KEY *keyinfo, TMP_ENGINE_COLUMNDEF *start_recinfo, TMP_ENGINE_COLUMNDEF **recinfo, ulonglong options); bool instantiate_tmp_table(TABLE *table, KEY *keyinfo, TMP_ENGINE_COLUMNDEF *start_recinfo, TMP_ENGINE_COLUMNDEF **recinfo, ulonglong options); bool open_tmp_table(TABLE *table); double prev_record_reads(const POSITION *positions, uint idx, table_map found_ref); void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List *tlist); double get_tmp_table_lookup_cost(THD *thd, double row_count, uint row_size); double get_tmp_table_write_cost(THD *thd, double row_count, uint row_size); void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array); bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse, bool skip_unprefixed_keyparts); struct st_cond_statistic { Item *cond; Field *field_arg; ulong positive; }; typedef struct st_cond_statistic COND_STATISTIC; ulong check_selectivity(THD *thd, ulong rows_to_read, TABLE *table, List *conds); class Pushdown_query: public Sql_alloc { public: SELECT_LEX *select_lex; bool store_data_in_temp_table; group_by_handler *handler; Item *having; Pushdown_query(SELECT_LEX *select_lex_arg, group_by_handler *handler_arg) : select_lex(select_lex_arg), store_data_in_temp_table(0), handler(handler_arg), having(0) {} ~Pushdown_query() { delete handler; } /* Function that calls the above scan functions */ int execute(JOIN *); }; class derived_handler; class Pushdown_derived: public Sql_alloc { public: TABLE_LIST *derived; derived_handler *handler; Pushdown_derived(TABLE_LIST *tbl, derived_handler *h); int execute(); }; class select_handler; bool test_if_order_compatible(SQL_I_List &a, SQL_I_List &b); int test_if_group_changed(List &list); int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort); JOIN_TAB *first_explain_order_tab(JOIN* join); JOIN_TAB *next_explain_order_tab(JOIN* join, JOIN_TAB* tab); bool is_eliminated_table(table_map eliminated_tables, TABLE_LIST *tbl); bool check_simple_equality(THD *thd, const Item::Context &ctx, Item *left_item, Item *right_item, COND_EQUAL *cond_equal); void propagate_new_equalities(THD *thd, Item *cond, List *new_equalities, COND_EQUAL *inherited, bool *is_simplifiable_cond); #define PREV_BITS(type, N_BITS) ((type)my_set_bits(N_BITS)) #endif /* SQL_SELECT_INCLUDED */ server/private/ft_global.h000064400000006051151031265040011625 0ustar00/* Copyright (c) 2000-2005, 2007 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Written by Sergei A. Golubchik, who has a shared copyright to this code */ /* some definitions for full-text indices */ /* #include "myisam.h" */ #ifndef _ft_global_h #define _ft_global_h #ifdef __cplusplus extern "C" { #endif #include #define HA_FT_MAXBYTELEN 254 #define HA_FT_MAXCHARLEN (HA_FT_MAXBYTELEN/3) #define DEFAULT_FTB_SYNTAX "+ -><()~*:\"\"&|" typedef struct st_ft_info FT_INFO; struct _ft_vft { int (*read_next)(FT_INFO *, char *); float (*find_relevance)(FT_INFO *, uchar *, uint); void (*close_search)(FT_INFO *); float (*get_relevance)(FT_INFO *); void (*reinit_search)(FT_INFO *); }; typedef struct st_ft_info_ext FT_INFO_EXT; struct _ft_vft_ext { uint (*get_version)(); // Extended API version ulonglong (*get_flags)(); ulonglong (*get_docid)(FT_INFO_EXT *); ulonglong (*count_matches)(FT_INFO_EXT *); }; /* Flags for extended FT API */ #define FTS_ORDERED_RESULT (1LL << 1) #define FTS_DOCID_IN_RESULT (1LL << 2) #define FTS_DOC_ID_COL_NAME "FTS_DOC_ID" #ifndef FT_CORE struct st_ft_info { struct _ft_vft *please; /* INTERCAL style :-) */ }; struct st_ft_info_ext { struct _ft_vft *please; /* INTERCAL style :-) */ struct _ft_vft_ext *could_you; }; #endif extern const char *ft_stopword_file; extern const char *ft_precompiled_stopwords[]; extern ulong ft_min_word_len; extern ulong ft_max_word_len; extern ulong ft_query_expansion_limit; extern const char *ft_boolean_syntax; extern struct st_mysql_ftparser ft_default_parser; int ft_init_stopwords(void); void ft_free_stopwords(void); #define FT_NL 0 #define FT_BOOL 1 #define FT_SORTED 2 #define FT_EXPAND 4 /* query expansion */ FT_INFO *ft_init_search(uint,void *, uint, uchar *, size_t, CHARSET_INFO *, uchar *); my_bool ft_boolean_check_syntax_string(const uchar *, size_t length, CHARSET_INFO *cs); /* Internal symbols for fulltext between maria and MyISAM */ #define HA_FT_WTYPE HA_KEYTYPE_FLOAT #define HA_FT_WLEN 4 #define FT_SEGS 2 #define ft_sintXkorr(A) mi_sint4korr(A) #define ft_intXstore(T,A) mi_int4store(T,A) extern const HA_KEYSEG ft_keysegs[FT_SEGS]; typedef union {int32 i; float f;} FT_WEIGTH; #ifdef __cplusplus } #endif #endif server/private/item_subselect.h000064400000163421151031265040012710 0ustar00#ifndef ITEM_SUBSELECT_INCLUDED #define ITEM_SUBSELECT_INCLUDED /* Copyright (c) 2002, 2011, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* subselect Item */ #include "item.h" #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include class st_select_lex; class st_select_lex_unit; class JOIN; class select_result_interceptor; class subselect_engine; class subselect_hash_sj_engine; class Item_bool_func2; class Comp_creator; class With_element; class Field_pair; typedef class st_select_lex SELECT_LEX; /** Convenience typedef used in this file, and further used by any files including this file. */ typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); class Cached_item; class Subq_materialization_tracker; class Explain_subq_materialization; /* base class for subselects */ class Item_subselect :public Item_result_field, protected Used_tables_and_const_cache { /* Set to TRUE if the value is assigned for the subselect FALSE: subquery not executed or the subquery returns an empty result */ bool value_assigned; bool own_engine; /* the engine was not taken from other Item_subselect */ protected: /* thread handler, will be assigned in fix_fields only */ THD *thd; /* old engine if engine was changed */ subselect_engine *old_engine; /* allowed number of columns (1 for single value subqueries) */ uint max_columns; /* where subquery is placed */ enum_parsing_place parsing_place; /* work with 'substitution' */ bool have_to_be_excluded; bool inside_first_fix_fields; bool done_first_fix_fields; Item *expr_cache; /* Set to TRUE if at optimization or execution time we determine that this item's value is a constant. We need this member because it is not possible to substitute 'this' with a constant item. */ bool forced_const; /* Set to the result of the last call of is_expensive() */ bool expensive_fl; #ifndef DBUG_OFF /* Count the number of times this subquery predicate has been executed. */ uint exec_counter; #endif public: /* Used inside Item_subselect::fix_fields() according to this scenario: > Item_subselect::fix_fields > engine->prepare > child_join->prepare (Here we realize we need to do the rewrite and set substitution= some new Item, eg. Item_in_optimizer ) < child_join->prepare < engine->prepare *ref= substitution; substitution= NULL; < Item_subselect::fix_fields */ /* TODO make this protected member again. */ Item *substitution; /* engine that perform execution of subselect (single select or union) */ /* TODO make this protected member again. */ subselect_engine *engine; /* unit of subquery */ st_select_lex_unit *unit; /* Cached buffers used when calling filesort in sub queries */ Filesort_buffer filesort_buffer; LEX_STRING sortbuffer; /* A reference from inside subquery predicate to somewhere outside of it */ class Ref_to_outside : public Sql_alloc { public: st_select_lex *select; /* Select where the reference is pointing to */ /* What is being referred. This may be NULL when we're referring to an aggregate function. */ Item *item; }; /* References from within this subquery to somewhere outside of it (i.e. to parent select, grandparent select, etc) */ List upper_refs; st_select_lex *parent_select; /* TRUE<=>Table Elimination has made it redundant to evaluate this select (and so it is not part of QEP, etc) */ bool eliminated; /* subquery is transformed */ bool changed; /* TRUE <=> The underlying SELECT is correlated w.r.t some ancestor select */ bool is_correlated; /* TRUE <=> the subquery contains a recursive reference in the FROM list of one of its selects. In this case some of subquery optimization strategies cannot be applied for the subquery; */ bool with_recursive_reference; /* To link Item_subselects containing references to the same recursive CTE */ Item_subselect *next_with_rec_ref; enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS, EXISTS_SUBS, IN_SUBS, ALL_SUBS, ANY_SUBS}; Item_subselect(THD *thd); virtual subs_type substype() { return UNKNOWN_SUBS; } bool is_exists_predicate() { return substype() == Item_subselect::EXISTS_SUBS; } bool is_in_predicate() { return get_IN_subquery() != NULL; } /* We need this method, because some compilers do not allow 'this' pointer in constructor initialization list, but we need to pass a pointer to subselect Item class to select_result_interceptor's constructor. */ virtual void init (st_select_lex *select_lex, select_result_interceptor *result); ~Item_subselect(); void cleanup() override; virtual void reset() { eliminated= FALSE; null_value= 1; } /** Set the subquery result to a default value consistent with the semantics of the result row produced for queries with implicit grouping. */ void no_rows_in_result() override= 0; virtual bool select_transformer(JOIN *join); bool assigned() { return value_assigned; } void assigned(bool a) { value_assigned= a; } enum Type type() const override; bool is_null() override { update_null_value(); return null_value; } bool fix_fields(THD *thd, Item **ref) override; bool mark_as_dependent(THD *thd, st_select_lex *select, Item *item); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; void recalc_used_tables(st_select_lex *new_parent, bool after_pullout); virtual bool exec(); /* If subquery optimization or execution determines that the subquery has an empty result, mark the subquery predicate as a constant value. */ void make_const() { used_tables_cache= 0; const_item_cache= 0; forced_const= TRUE; } virtual bool fix_length_and_dec(); table_map used_tables() const override; table_map not_null_tables() const override { return 0; } bool const_item() const override; inline table_map get_used_tables_cache() { return used_tables_cache; } Item *get_tmp_table_item(THD *thd) override; void update_used_tables() override; void print(String *str, enum_query_type query_type) override; virtual bool have_guarded_conds() { return FALSE; } bool change_engine(subselect_engine *eng) { old_engine= engine; engine= eng; return eng == 0; } bool engine_changed(subselect_engine *eng) { return engine != eng; } /* True if this subquery has been already evaluated. Implemented only for single select and union subqueries only. */ bool is_evaluated() const; bool is_uncacheable() const; bool is_expensive() override; /* Used by max/min subquery to initialize value presence registration mechanism. Engine call this method before rexecution query. */ virtual void reset_value_registration() {} enum_parsing_place place() { return parsing_place; } bool walk(Item_processor processor, bool walk_subquery, void *arg) override; bool unknown_splocal_processor(void *arg) override; bool mark_as_eliminated_processor(void *arg) override; bool eliminate_subselect_processor(void *arg) override; bool enumerate_field_refs_processor(void *arg) override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("select ...", arg, VCOL_IMPOSSIBLE); } /** Callback to test if an IN predicate is expensive. @notes The return value affects the behavior of make_cond_for_table(). @retval TRUE if the predicate is expensive @retval FALSE otherwise */ bool is_expensive_processor(void *arg) override { return is_expensive(); } bool update_table_bitmaps_processor(void *arg) override; /** Get the SELECT_LEX structure associated with this Item. @return the SELECT_LEX structure associated with this Item */ st_select_lex* get_select_lex(); bool expr_cache_is_needed(THD *) override; void get_cache_parameters(List ¶meters) override; bool is_subquery_processor (void *opt_arg) override { return 1; } bool exists2in_processor(void *opt_arg) override { return 0; } bool limit_index_condition_pushdown_processor(void *opt_arg) override { return TRUE; } bool subselect_table_finder_processor(void *arg) override; void register_as_with_rec_ref(With_element *with_elem); void init_expr_cache_tracker(THD *thd); Item* do_build_clone(THD *thd) const override { return nullptr; } Item *do_get_copy(THD *thd) const override { return 0; } st_select_lex *wrap_tvc_into_select(THD *thd, st_select_lex *tvc_sl); friend class select_result_interceptor; friend class Item_in_optimizer; friend bool Item_field::fix_fields(THD *, Item **); friend int Item_field::fix_outer_field(THD *, Field **, Item **); friend bool Item_ref::fix_fields(THD *, Item **); friend void mark_select_range_as_dependent(THD*, st_select_lex*, st_select_lex*, Field*, Item*, Item_ident*, bool); friend bool convert_join_subqueries_to_semijoins(JOIN *join); }; /* single value subselect */ class Item_cache; class Item_singlerow_subselect :public Item_subselect { protected: Item_cache *value, **row; public: Item_singlerow_subselect(THD *thd_arg, st_select_lex *select_lex); Item_singlerow_subselect(THD *thd_arg): Item_subselect(thd_arg), value(0), row (0) {} void cleanup() override; subs_type substype() override { return SINGLEROW_SUBS; } void reset() override; void no_rows_in_result() override; bool select_transformer(JOIN *join) override; void store(uint i, Item* item); double val_real() override; longlong val_int() override; String *val_str(String *) override; bool val_native(THD *thd, Native *) override; my_decimal *val_decimal(my_decimal *) override; bool val_bool() override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; const Type_handler *type_handler() const override; bool fix_length_and_dec() override; uint cols() const override; Item* element_index(uint i) override { return reinterpret_cast(row[i]); } Item** addr(uint i) override { return (Item**)row + i; } bool check_cols(uint c) override; bool null_inside() override; void bring_value() override; /** This method is used to implement a special case of semantic tree rewriting, mandated by a SQL:2003 exception in the specification. The only caller of this method is handle_sql2003_note184_exception(), see the code there for more details. Note that this method breaks the object internal integrity, by removing it's association with the corresponding SELECT_LEX, making this object orphan from the parse tree. No other method, beside the destructor, should be called on this object, as it is now invalid. @return the SELECT_LEX structure that was given in the constructor. */ st_select_lex* invalidate_and_restore_select_lex(); Item* expr_cache_insert_transformer(THD *thd, uchar *unused) override; friend class select_singlerow_subselect; }; /* used in static ALL/ANY optimization */ class select_max_min_finder_subselect; class Item_maxmin_subselect :public Item_singlerow_subselect { protected: bool max; bool was_values; // Set if we have found at least one row public: Item_maxmin_subselect(THD *thd, Item_subselect *parent, st_select_lex *select_lex, bool max); void print(String *str, enum_query_type query_type) override; void cleanup() override; bool any_value() { return was_values; } void register_value() { was_values= TRUE; } void reset_value_registration() override { was_values= FALSE; } void no_rows_in_result() override; }; /* exists subselect */ class Item_exists_subselect :public Item_subselect { protected: Item_func_not *upper_not; bool value; /* value of this item (boolean: exists/not-exists) */ bool abort_on_null; void init_length_and_dec(); bool select_prepare_to_be_in(); public: /* Used by subquery optimizations to keep track about in which clause this subquery predicate is located: NO_JOIN_NEST - the predicate is an AND-part of the WHERE join nest pointer - the predicate is an AND-part of ON expression of a join nest NULL - for all other locations */ TABLE_LIST *emb_on_expr_nest; /** Reference on the Item_in_optimizer wrapper of this subquery */ Item_in_optimizer *optimizer; /* true if we got this from EXISTS or to IN */ bool exists_transformed; Item_exists_subselect(THD *thd_arg, st_select_lex *select_lex); Item_exists_subselect(THD *thd_arg): Item_subselect(thd_arg), upper_not(NULL), abort_on_null(0), emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0) {} subs_type substype() override { return EXISTS_SUBS; } void reset() override { eliminated= FALSE; value= 0; } void no_rows_in_result() override; const Type_handler *type_handler() const override { return &type_handler_bool; } longlong val_int() override; double val_real() override; String *val_str(String*) override; my_decimal *val_decimal(my_decimal *) override; bool val_bool() override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_int(thd, ltime, fuzzydate); } bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override; void print(String *str, enum_query_type query_type) override; bool select_transformer(JOIN *join) override; void top_level_item() override { abort_on_null=1; } bool is_top_level_item() const override { return abort_on_null; } bool exists2in_processor(void *opt_arg) override; Item* expr_cache_insert_transformer(THD *thd, uchar *unused) override; void mark_as_condition_AND_part(TABLE_LIST *embedding) override { emb_on_expr_nest= embedding; } void under_not(Item_func_not *upper) override { upper_not= upper; }; void set_exists_transformed() { exists_transformed= TRUE; } friend class select_exists_subselect; friend class subselect_uniquesubquery_engine; friend class subselect_indexsubquery_engine; }; TABLE_LIST * const NO_JOIN_NEST=(TABLE_LIST*)0x1; /* Possible methods to execute an IN predicate. These are set by the optimizer based on user-set optimizer switches, semantic analysis and cost comparison. */ #define SUBS_NOT_TRANSFORMED 0 /* No execution method was chosen for this IN. */ /* The Final decision about the strategy is made. */ #define SUBS_STRATEGY_CHOSEN 1 #define SUBS_SEMI_JOIN 2 /* IN was converted to semi-join. */ #define SUBS_IN_TO_EXISTS 4 /* IN was converted to correlated EXISTS. */ #define SUBS_MATERIALIZATION 8 /* Execute IN via subquery materialization. */ /* Partial matching substrategies of MATERIALIZATION. */ #define SUBS_PARTIAL_MATCH_ROWID_MERGE 16 #define SUBS_PARTIAL_MATCH_TABLE_SCAN 32 /* ALL/ANY will be transformed with max/min optimization */ /* The subquery has not aggregates, transform it into a MAX/MIN query. */ #define SUBS_MAXMIN_INJECTED 64 /* The subquery has aggregates, use a special max/min subselect engine. */ #define SUBS_MAXMIN_ENGINE 128 /** Representation of IN subquery predicates of the form "left_expr IN (SELECT ...)". @details This class has: - A "subquery execution engine" (as a subclass of Item_subselect) that allows it to evaluate subqueries. (and this class participates in execution by having was_null variable where part of execution result is stored. - Transformation methods (todo: more on this). This class is not used directly, it is "wrapped" into Item_in_optimizer which provides some small bits of subquery evaluation. */ class Item_in_subselect :public Item_exists_subselect { protected: /* Cache of the left operand of the subquery predicate. Allocated in the runtime memory root, for each execution, thus need not be freed. */ List *left_expr_cache; bool first_execution; /* expr & optimizer used in subselect rewriting to store Item for all JOIN in UNION */ Item *expr; bool was_null; /* A bitmap of possible execution strategies for an IN predicate. */ uchar in_strategy; /* Tracker collecting execution parameters of a materialized subquery */ Subq_materialization_tracker *materialization_tracker; protected: /* Used to trigger on/off conditions that were pushed down to subselect */ bool *pushed_cond_guards; Comp_creator *func; protected: bool init_cond_guards(); bool select_in_like_transformer(JOIN *join); bool single_value_transformer(JOIN *join); bool row_value_transformer(JOIN * join); bool fix_having(Item *having, st_select_lex *select_lex); bool create_single_in_to_exists_cond(JOIN * join, Item **where_item, Item **having_item); bool create_row_in_to_exists_cond(JOIN * join, Item **where_item, Item **having_item); Item *left_expr; /* Important for PS/SP: left_expr_orig is the item that left_expr originally pointed at. That item is allocated on the statement arena, while left_expr could later be changed to something on the execution arena. */ Item *left_expr_orig; public: /* Priority of this predicate in the convert-to-semi-join-nest process. */ int sj_convert_priority; /* May be TRUE only for the candidates to semi-join conversion */ bool do_not_convert_to_sj; /* Types of left_expr and subquery's select list allow to perform subquery materialization. Currently, we set this to FALSE when it as well could be TRUE. This is to be properly addressed with fix for BUG#36752. */ bool types_allow_materialization; /* Same as above, but they also allow to scan the materialized table. */ bool sjm_scan_allowed; /* JoinTaB Materialization (JTBM) members */ /* TRUE <=> This subselect has been converted into non-mergeable semi-join table. */ bool is_jtbm_merged; /* (Applicable if is_jtbm_merged==TRUE) Time required to run the materialized join */ double jtbm_read_time; /* (Applicable if is_jtbm_merged==TRUE) Number of output rows in materialized join */ double jtbm_record_count; /* (Applicable if is_jtbm_merged==TRUE) TRUE <=> The materialized subselect is a degenerate subselect which produces 0 or 1 rows, which we know at optimization phase. Examples: 1. subquery has "Impossible WHERE": SELECT * FROM ot WHERE ot.column IN (SELECT it.col FROM it WHERE 2 > 3) 2. Subquery produces one row which opt_sum.cc is able to get with one lookup: SELECT * FROM ot WHERE ot.column IN (SELECT MAX(it.key_col) FROM it) */ bool is_jtbm_const_tab; /* (Applicable if is_jtbm_const_tab==TRUE) Whether the subquery has produced the row (or not) */ bool jtbm_const_row_found; /* TRUE<=>this is a flattenable semi-join, false otherwise. */ bool is_flattenable_semijoin; /* TRUE<=>registered in the list of semijoins in outer select */ bool is_registered_semijoin; List corresponding_fields; /* Used to determine how this subselect item is represented in the item tree, in case there is a need to locate it there and replace with something else. Two options are possible: 1. This item is there 'as-is'. 1. This item is wrapped within Item_in_optimizer. */ Item *original_item() { return (is_flattenable_semijoin && !exists_transformed ? (Item*)this : (Item*)optimizer); } bool *get_cond_guard(int i) { return pushed_cond_guards ? pushed_cond_guards + i : NULL; } void set_cond_guard_var(int i, bool v) { if ( pushed_cond_guards) pushed_cond_guards[i]= v; } bool have_guarded_conds() override { return MY_TEST(pushed_cond_guards); } Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery /* SET to TRUE if IN subquery is converted from an IN predicate */ bool converted_from_in_predicate; Item_in_subselect(THD *thd_arg, Item * left_expr, st_select_lex *select_lex); Item_in_subselect(THD *thd_arg): Item_exists_subselect(thd_arg), left_expr_cache(0), first_execution(TRUE), in_strategy(SUBS_NOT_TRANSFORMED), materialization_tracker(NULL), pushed_cond_guards(NULL), func(NULL), do_not_convert_to_sj(FALSE), is_jtbm_merged(FALSE), is_jtbm_const_tab(FALSE), upper_item(0), converted_from_in_predicate(FALSE) {} void cleanup() override; subs_type substype() override { return IN_SUBS; } void reset() override { eliminated= FALSE; value= 0; null_value= 0; was_null= 0; } bool select_transformer(JOIN *join) override; bool create_in_to_exists_cond(JOIN *join_arg); bool inject_in_to_exists_cond(JOIN *join_arg); bool exec() override; longlong val_int() override; double val_real() override; String *val_str(String*) override; my_decimal *val_decimal(my_decimal *) override; bool val_bool() override; bool test_limit(st_select_lex_unit *unit); void print(String *str, enum_query_type query_type) override; enum precedence precedence() const override { return IN_PRECEDENCE; } bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override; void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; bool const_item() const override { return Item_subselect::const_item() && left_expr->const_item(); } void update_used_tables() override; bool setup_mat_engine(); bool init_left_expr_cache(); /* Inform 'this' that it was computed, and contains a valid result. */ void set_first_execution() { if (first_execution) first_execution= FALSE; } bool expr_cache_is_needed(THD *thd) override; inline bool left_expr_has_null(); void disable_cond_guard_for_const_null_left_expr(int i) { if (left_expr->can_eval_in_optimize()) { if (left_expr->element_index(i)->is_null()) set_cond_guard_var(i,FALSE); } } int optimize(double *out_rows, double *cost); /* Return the identifier that we could use to identify the subquery for the user. */ int get_identifier(); void block_conversion_to_sj () { do_not_convert_to_sj= TRUE; } bool test_strategy(uchar strategy) { return MY_TEST(in_strategy & strategy); } /** Test that the IN strategy was chosen for execution. This is so when the CHOSEN flag is ON, and there is no other strategy. */ bool test_set_strategy(uchar strategy) { DBUG_ASSERT(strategy == SUBS_SEMI_JOIN || strategy == SUBS_IN_TO_EXISTS || strategy == SUBS_MATERIALIZATION || strategy == SUBS_PARTIAL_MATCH_ROWID_MERGE || strategy == SUBS_PARTIAL_MATCH_TABLE_SCAN || strategy == SUBS_MAXMIN_INJECTED || strategy == SUBS_MAXMIN_ENGINE); return ((in_strategy & SUBS_STRATEGY_CHOSEN) && (in_strategy & ~SUBS_STRATEGY_CHOSEN) == strategy); } bool is_set_strategy() { return MY_TEST(in_strategy & SUBS_STRATEGY_CHOSEN); } bool has_strategy() { return in_strategy != SUBS_NOT_TRANSFORMED; } void add_strategy (uchar strategy) { DBUG_ENTER("Item_in_subselect::add_strategy"); DBUG_PRINT("enter", ("current: %u add: %u", (uint) in_strategy, (uint) strategy)); DBUG_ASSERT(strategy != SUBS_NOT_TRANSFORMED); DBUG_ASSERT(!(strategy & SUBS_STRATEGY_CHOSEN)); /* TODO: PS re-execution breaks this condition, because check_and_do_in_subquery_rewrites() is called for each reexecution and re-adds the same strategies. DBUG_ASSERT(!(in_strategy & SUBS_STRATEGY_CHOSEN)); */ in_strategy|= strategy; DBUG_VOID_RETURN; } void reset_strategy(uchar strategy) { DBUG_ENTER("Item_in_subselect::reset_strategy"); DBUG_PRINT("enter", ("current: %u new: %u", (uint) in_strategy, (uint) strategy)); DBUG_ASSERT(strategy != SUBS_NOT_TRANSFORMED); in_strategy= strategy; DBUG_VOID_RETURN; } void set_strategy(uchar strategy) { DBUG_ENTER("Item_in_subselect::set_strategy"); DBUG_PRINT("enter", ("current: %u set: %u", (uint) in_strategy, (uint) (SUBS_STRATEGY_CHOSEN | strategy))); /* Check that only one strategy is set for execution. */ DBUG_ASSERT(strategy == SUBS_SEMI_JOIN || strategy == SUBS_IN_TO_EXISTS || strategy == SUBS_MATERIALIZATION || strategy == SUBS_PARTIAL_MATCH_ROWID_MERGE || strategy == SUBS_PARTIAL_MATCH_TABLE_SCAN || strategy == SUBS_MAXMIN_INJECTED || strategy == SUBS_MAXMIN_ENGINE); in_strategy= (SUBS_STRATEGY_CHOSEN | strategy); DBUG_VOID_RETURN; } bool walk(Item_processor processor, bool walk_subquery, void *arg) override { return left_expr->walk(processor, walk_subquery, arg) || Item_subselect::walk(processor, walk_subquery, arg); } bool exists2in_processor(void *opt_arg __attribute__((unused))) override { return 0; }; bool pushdown_cond_for_in_subquery(THD *thd, Item *cond); Item_in_subselect *get_IN_subquery() override { return this; } inline Item** left_exp_ptr() { return &left_expr; } inline Item* left_exp() const { return left_expr; } inline Item* left_exp_orig() const { return left_expr_orig; } void init_subq_materialization_tracker(THD *thd); Subq_materialization_tracker *get_materialization_tracker() const { return materialization_tracker; } friend class Item_ref_null_helper; friend class Item_is_not_null_test; friend class Item_in_optimizer; friend class subselect_indexsubquery_engine; friend class subselect_hash_sj_engine; friend class subselect_partial_match_engine; friend class Item_exists_subselect; }; /* ALL/ANY/SOME subselect */ class Item_allany_subselect :public Item_in_subselect { public: chooser_compare_func_creator func_creator; bool all; Item_allany_subselect(THD *thd_arg, Item * left_expr, chooser_compare_func_creator fc, st_select_lex *select_lex, bool all); void cleanup() override; // only ALL subquery has upper not subs_type substype() override { return all?ALL_SUBS:ANY_SUBS; } bool select_transformer(JOIN *join) override; void create_comp_func(bool invert) { func= func_creator(invert); } void print(String *str, enum_query_type query_type) override; enum precedence precedence() const override { return CMP_PRECEDENCE; } bool is_maxmin_applicable(JOIN *join); bool transform_into_max_min(JOIN *join); void no_rows_in_result() override; }; class subselect_engine: public Sql_alloc, public Type_handler_hybrid_field_type { protected: select_result_interceptor *result; /* results storage class */ THD *thd; /* pointer to current THD */ Item_subselect *item; /* item, that use this engine */ bool maybe_null; /* may be null (first item in select) */ public: enum enum_engine_type {ABSTRACT_ENGINE, SINGLE_SELECT_ENGINE, UNION_ENGINE, UNIQUESUBQUERY_ENGINE, INDEXSUBQUERY_ENGINE, HASH_SJ_ENGINE, ROWID_MERGE_ENGINE, TABLE_SCAN_ENGINE, SINGLE_COLUMN_ENGINE}; subselect_engine(Item_subselect *si, select_result_interceptor *res): Type_handler_hybrid_field_type(&type_handler_varchar), thd(NULL) { result= res; item= si; maybe_null= 0; } virtual ~subselect_engine() = default;; // to satisfy compiler virtual void cleanup()= 0; /* Also sets "thd" for subselect_engine::result. Should be called before prepare(). */ void set_thd(THD *thd_arg); THD * get_thd() { return thd ? thd : current_thd; } virtual int prepare(THD *)= 0; virtual bool fix_length_and_dec(Item_cache** row)= 0; /* Execute the engine SYNOPSIS exec() DESCRIPTION Execute the engine. The result of execution is subquery value that is either captured by previously set up select_result-based 'sink' or stored somewhere by the exec() method itself. A required side effect: If at least one pushed-down predicate is disabled, subselect_engine->no_rows() must return correct result after the exec() call. RETURN 0 - OK 1 - Either an execution error, or the engine was "changed", and the caller should call exec() again for the new engine. */ virtual int exec()= 0; virtual uint cols() const= 0; /* return number of columns in select */ virtual uint8 uncacheable()= 0; /* query is uncacheable */ virtual void exclude()= 0; virtual bool may_be_null() { return maybe_null; }; virtual table_map upper_select_const_tables()= 0; static table_map calc_const_tables(TABLE_LIST *); static table_map calc_const_tables(List &list); virtual void print(String *str, enum_query_type query_type)= 0; virtual bool change_result(Item_subselect *si, select_result_interceptor *result, bool temp= FALSE)= 0; virtual bool no_tables() const = 0; /* Return true we can guarantee that the subquery will always return one row. */ virtual bool always_returns_one_row() const { return false; } virtual bool is_executed() const { return FALSE; } /* Check if subquery produced any rows during last query execution */ virtual bool no_rows() = 0; virtual enum_engine_type engine_type() { return ABSTRACT_ENGINE; } virtual int get_identifier() { DBUG_ASSERT(0); return 0; } virtual void force_reexecution() {} protected: bool set_row(List &item_list, Item_cache **row); }; class subselect_single_select_engine: public subselect_engine { bool prepared; /* simple subselect is prepared */ bool executed; /* simple subselect is executed */ st_select_lex *select_lex; /* corresponding select_lex */ JOIN * join; /* corresponding JOIN structure */ public: subselect_single_select_engine(st_select_lex *select, select_result_interceptor *result, Item_subselect *item); void cleanup() override; int prepare(THD *thd) override; bool fix_length_and_dec(Item_cache** row) override; int exec() override; uint cols() const override; uint8 uncacheable() override; void exclude() override; table_map upper_select_const_tables() override; void print(String *str, enum_query_type query_type) override; bool change_result(Item_subselect *si, select_result_interceptor *result, bool temp) override; bool no_tables() const override; bool always_returns_one_row() const override; bool may_be_null() override; bool is_executed() const override { return executed; } bool no_rows() override; enum_engine_type engine_type() override { return SINGLE_SELECT_ENGINE; } int get_identifier() override; void force_reexecution() override; void change_select(st_select_lex *new_select) { select_lex= new_select; } friend class subselect_hash_sj_engine; friend class Item_in_subselect; friend bool execute_degenerate_jtbm_semi_join(THD *thd, TABLE_LIST *tbl, Item_in_subselect *subq_pred, List &eq_list); }; class subselect_union_engine: public subselect_engine { st_select_lex_unit *unit; /* corresponding unit structure */ public: subselect_union_engine(st_select_lex_unit *u, select_result_interceptor *result, Item_subselect *item); void cleanup() override; int prepare(THD *) override; bool fix_length_and_dec(Item_cache** row) override; int exec() override; uint cols() const override; uint8 uncacheable() override; void exclude() override; table_map upper_select_const_tables() override; void print(String *str, enum_query_type query_type) override; bool change_result(Item_subselect *si, select_result_interceptor *result, bool temp= FALSE) override; bool no_tables() const override; bool is_executed() const override; void force_reexecution() override; bool no_rows() override; enum_engine_type engine_type() override { return UNION_ENGINE; } }; struct st_join_table; /* A subquery execution engine that evaluates the subquery by doing one index lookup in a unique index. This engine is used to resolve subqueries in forms outer_expr IN (SELECT tbl.unique_key FROM tbl WHERE subq_where) or, tuple-based: (oe1, .. oeN) IN (SELECT uniq_key_part1, ... uniq_key_partK FROM tbl WHERE subqwhere) i.e. the subquery is a single table SELECT without GROUP BY, aggregate functions, etc. */ class subselect_uniquesubquery_engine: public subselect_engine { protected: st_join_table *tab; Item *cond; /* The WHERE condition of subselect */ /* TRUE<=> last execution produced empty set. Valid only when left expression is NULL. */ bool empty_result_set; public: // constructor can assign THD because it will be called after JOIN::prepare subselect_uniquesubquery_engine(THD *thd_arg, st_join_table *tab_arg, Item_in_subselect *subs, Item *where) :subselect_engine(subs, 0), tab(tab_arg), cond(where) { thd= thd_arg; DBUG_ASSERT(subs); } ~subselect_uniquesubquery_engine(); void cleanup() override; int prepare(THD *) override; bool fix_length_and_dec(Item_cache** row) override; int exec() override; uint cols() const override { return 1; } uint8 uncacheable() override { return UNCACHEABLE_DEPENDENT_INJECTED; } void exclude() override; table_map upper_select_const_tables() override { return 0; } void print(String *str, enum_query_type query_type) override; bool change_result(Item_subselect *si, select_result_interceptor *result, bool temp= FALSE) override; bool no_tables() const override; int index_lookup(); /* TIMOUR: this method needs refactoring. */ int scan_table(); bool copy_ref_key(bool skip_constants); bool no_rows() override { return empty_result_set; } enum_engine_type engine_type() override { return UNIQUESUBQUERY_ENGINE; } }; class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine { /* FALSE for 'ref', TRUE for 'ref-or-null'. */ bool check_null; /* The "having" clause. This clause (further referred to as "artificial having") was inserted by subquery transformation code. It contains Item(s) that have a side-effect: they record whether the subquery has produced a row with NULL certain components. We need to use it for cases like (oe1, oe2) IN (SELECT t.key, t.no_key FROM t1) where we do index lookup on t.key=oe1 but need also to check if there was a row such that t.no_key IS NULL. NOTE: This is currently here and not in the uniquesubquery_engine. Ideally it should have been in uniquesubquery_engine in order to allow execution of subqueries like (oe1, oe2) IN (SELECT primary_key, non_key_maybe_null_field FROM tbl) We could use uniquesubquery_engine for the first component and let Item_is_not_null_test( non_key_maybe_null_field) to handle the second. However, subqueries like the above are currently not handled by index lookup-based subquery engines, the engine applicability check misses them: it doesn't switch the engine for case of artificial having and [eq_]ref access (only for artificial having + ref_or_null or no having). The above example subquery is handled as a full-blown SELECT with eq_ref access to one table. Due to this limitation, the "artificial having" currently needs to be checked by only in indexsubquery_engine. */ Item *having; public: // constructor can assign THD because it will be called after JOIN::prepare subselect_indexsubquery_engine(THD *thd_arg, st_join_table *tab_arg, Item_in_subselect *subs, Item *where, Item *having_arg, bool chk_null) :subselect_uniquesubquery_engine(thd_arg, tab_arg, subs, where), check_null(chk_null), having(having_arg) { DBUG_ASSERT(subs); } int exec() override; void print (String *str, enum_query_type query_type) override; enum_engine_type engine_type() override { return INDEXSUBQUERY_ENGINE; } }; /* This function is actually defined in sql_parse.cc, but it depends on chooser_compare_func_creator defined in this file. */ Item * all_any_subquery_creator(THD *thd, Item *left_expr, chooser_compare_func_creator cmp, bool all, SELECT_LEX *select_lex); inline bool Item_subselect::is_evaluated() const { return engine->is_executed(); } inline bool Item_subselect::is_uncacheable() const { return engine->uncacheable(); } /** Compute an IN predicate via a hash semi-join. This class is responsible for the materialization of the subquery, and the selection of the correct and optimal execution method (e.g. direct index lookup, or partial matching) for the IN predicate. */ class subselect_hash_sj_engine : public subselect_engine { public: /* The table into which the subquery is materialized. */ TABLE *tmp_table; /* TRUE if the subquery was materialized into a temp table. */ bool is_materialized; /* The old engine already chosen at parse time and stored in permanent memory. Through this member we can re-create and re-prepare materialize_join for each execution of a prepared statement. We also reuse the functionality of subselect_single_select_engine::[prepare | cols]. */ subselect_single_select_engine *materialize_engine; /* QEP to execute the subquery and materialize its result into a temporary table. Created during the first call to exec(). */ JOIN *materialize_join; /* A conjunction of all the equality conditions between all pairs of expressions that are arguments of an IN predicate. We need these to post-filter some IN results because index lookups sometimes match values that are actually not equal to the search key in SQL terms. */ Item_cond_and *semi_join_conds; Name_resolution_context *semi_join_conds_context; subselect_hash_sj_engine(THD *thd_arg, Item_in_subselect *in_predicate, subselect_single_select_engine *old_engine) : subselect_engine(in_predicate, NULL), tmp_table(NULL), is_materialized(FALSE), materialize_engine(old_engine), materialize_join(NULL), semi_join_conds(NULL), lookup_engine(NULL), count_partial_match_columns(0), count_null_only_columns(0), count_columns_with_nulls(0), strategy(UNDEFINED) { DBUG_ASSERT(in_predicate); } ~subselect_hash_sj_engine(); bool init(List *tmp_columns, uint subquery_id); void cleanup() override; int prepare(THD *) override; int exec() override; void print(String *str, enum_query_type query_type) override; uint cols() const override { return materialize_engine->cols(); } uint8 uncacheable() override { return materialize_engine->uncacheable(); } table_map upper_select_const_tables() override { return 0; } bool no_rows() override { return !tmp_table->file->stats.records; } enum_engine_type engine_type() override { return HASH_SJ_ENGINE; } /* TODO: factor out all these methods in a base subselect_index_engine class because all of them have dummy implementations and should never be called. */ bool fix_length_and_dec(Item_cache** row) override;//=>base class void exclude() override; //=>base class //=>base class bool change_result(Item_subselect *si, select_result_interceptor *result, bool temp= FALSE) override; bool no_tables() const override;//=>base class /* Possible execution strategies that can be used to compute hash semi-join.*/ enum exec_strategy { UNDEFINED= 0, COMPLETE_MATCH, /* Use regular index lookups. */ PARTIAL_MATCH, /* Use some partial matching strategy. */ PARTIAL_MATCH_MERGE, /* Use partial matching through index merging. */ PARTIAL_MATCH_SCAN, /* Use partial matching through table scan. */ SINGLE_COLUMN_MATCH, /* Use simplified matching when there is only one field involved. */ CONST_RETURN_NULL, /* The result of IN predicate is constant NULL */ IMPOSSIBLE /* Subquery materialization is not applicable. */ }; protected: /* The engine used to compute the IN predicate. */ subselect_engine *lookup_engine; /* Keyparts of the only non-NULL composite index in a rowid merge. */ MY_BITMAP non_null_key_parts; /* Keyparts of the single column indexes with NULL, one keypart per index. */ MY_BITMAP partial_match_key_parts; uint count_partial_match_columns; uint count_null_only_columns; uint count_columns_with_nulls; /* The chosen execution strategy. Computed after materialization. */ exec_strategy strategy; exec_strategy get_strategy_using_schema(); exec_strategy get_strategy_using_data(); ulonglong rowid_merge_buff_size(bool has_non_null_key, bool has_covering_null_row, MY_BITMAP *partial_match_key_parts); void choose_partial_match_strategy(uint field_count, bool has_non_null_key, bool has_covering_null_row, MY_BITMAP *partial_match_key_parts); bool make_semi_join_conds(); subselect_uniquesubquery_engine* make_unique_engine(); }; /* Distinguish the type of (0-based) row numbers from the type of the index into an array of row numbers. */ typedef ha_rows rownum_t; /* An Ordered_key is an in-memory table index that allows O(log(N)) time lookups of a multi-part key. If the index is over a single column, then this column may contain NULLs, and the NULLs are stored and tested separately for NULL in O(1) via is_null(). Multi-part indexes assume that the indexed columns do not contain NULLs. TODO: = Due to the unnatural assymetry between single and multi-part indexes, it makes sense to somehow refactor or extend the class. = This class can be refactored into a base abstract interface, and two subclasses: - one to represent single-column indexes, and - another to represent multi-column indexes. Such separation would allow slightly more efficient implementation of the single-column indexes. = The current design requires such indexes to be fully recreated for each PS (re)execution, however most of the comprising objects can be reused. */ class Ordered_key : public Sql_alloc { protected: /* Index of the key in an array of keys. This index allows to construct (sub)sets of keys represented by bitmaps. */ uint keyid; /* The table being indexed. */ TABLE *tbl; /* The columns being indexed. */ Item_field **key_columns; /* Number of elements in 'key_columns' (number of key parts). */ uint key_column_count; /* An expression, or sequence of expressions that forms the search key. The search key is a sequence when it is Item_row. Each element of the sequence is accessible via Item::element_index(int i). */ Item *search_key; /* Value index related members. */ /* The actual value index, consists of a sorted sequence of row numbers. */ rownum_t *key_buff; /* Number of elements in key_buff. */ ha_rows key_buff_elements; /* Current element in 'key_buff'. */ ha_rows cur_key_idx; /* Mapping from row numbers to row ids. The element row_num_to_rowid[i] contains a buffer with the rowid for the row numbered 'i'. The memory for this member is not maintanined by this class because all Ordered_key indexes of the same table share the same mapping. */ uchar *row_num_to_rowid; /* A sequence of predicates to compare the search key with the corresponding columns of a table row from the index. */ Item_func_lt **compare_pred; /* Null index related members. */ MY_BITMAP null_key; /* Count of NULLs per column. */ ha_rows null_count; /* The row number that contains the first NULL in a column. */ rownum_t min_null_row; /* The row number that contains the last NULL in a column. */ rownum_t max_null_row; protected: bool alloc_keys_buffers(); /* Quick sort comparison function that compares two rows of the same table indentfied with their row numbers. */ int cmp_keys_by_row_data(const rownum_t a, const rownum_t b) const; static int cmp_keys_by_row_data_and_rownum(void *key, const void *a, const void *b); int cmp_key_with_search_key(rownum_t row_num); public: Ordered_key(uint keyid_arg, TABLE *tbl_arg, Item *search_key_arg, ha_rows null_count_arg, ha_rows min_null_row_arg, ha_rows max_null_row_arg, uchar *row_num_to_rowid_arg); ~Ordered_key(); void cleanup(); /* Initialize a multi-column index. */ bool init(MY_BITMAP *columns_to_index); /* Initialize a single-column index. */ bool init(int col_idx); uint get_column_count() const { return key_column_count; } uint get_keyid() const { return keyid; } Field *get_field(uint i) const { DBUG_ASSERT(i < key_column_count); return key_columns[i]->field; } rownum_t get_min_null_row() const { return min_null_row; } rownum_t get_max_null_row() const { return max_null_row; } MY_BITMAP * get_null_key() { return &null_key; } ha_rows get_null_count() const { return null_count; } ha_rows get_key_buff_elements() const { return key_buff_elements; } /* Get the search key element that corresponds to the i-th key part of this index. */ Item *get_search_key(uint i) const { return search_key->element_index(key_columns[i]->field->field_index); } void add_key(rownum_t row_num) { /* The caller must know how many elements to add. */ DBUG_ASSERT(key_buff_elements && cur_key_idx < key_buff_elements); key_buff[cur_key_idx]= row_num; ++cur_key_idx; } bool sort_keys(); inline double null_selectivity() const; /* Position the current element at the first row that matches the key. The key itself is propagated by evaluating the current value(s) of this->search_key. */ bool lookup(); /* Move the current index cursor to the first key. */ void first() { DBUG_ASSERT(key_buff_elements); cur_key_idx= 0; } /* TODO */ bool next_same(); /* Move the current index cursor to the next key. */ bool next() { DBUG_ASSERT(key_buff_elements); if (cur_key_idx < key_buff_elements - 1) { ++cur_key_idx; return TRUE; } return FALSE; }; /* Return the current index element. */ rownum_t current() const { DBUG_ASSERT(key_buff_elements && cur_key_idx < key_buff_elements); return key_buff[cur_key_idx]; } void set_null(rownum_t row_num) { bitmap_set_bit(&null_key, (uint)row_num); } bool is_null(rownum_t row_num) const { /* Indexes consisting of only NULLs do not have a bitmap buffer at all. Their only initialized member is 'n_bits', which is equal to the number of temp table rows. */ if (null_count == tbl->file->stats.records) { DBUG_ASSERT(tbl->file->stats.records == null_key.n_bits); return TRUE; } if (row_num > max_null_row || row_num < min_null_row) return FALSE; return bitmap_is_set(&null_key, (uint)row_num); } void print(String *str) const; }; class subselect_partial_match_engine : public subselect_engine { protected: /* The temporary table that contains a materialized subquery. */ TABLE *tmp_table; /* The engine used to check whether an IN predicate is TRUE or not. If not TRUE, then subselect_rowid_merge_engine further distinguishes between FALSE and UNKNOWN. */ subselect_uniquesubquery_engine *lookup_engine; /* A list of equalities between each pair of IN operands. */ List *equi_join_conds; /* True if there is an all NULL row in tmp_table. If so, then if there is no complete match, there is a guaranteed partial match. */ bool has_covering_null_row; /* True if all nullable columns of tmp_table consist of only NULL values. If so, then if there is a match in the non-null columns, there is a guaranteed partial match. */ bool has_covering_null_columns; uint count_columns_with_nulls; protected: virtual bool partial_match()= 0; public: subselect_partial_match_engine(THD *thd, subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg, bool has_covering_null_row_arg, bool has_covering_null_columns_arg, uint count_columns_with_nulls_arg); int prepare(THD *thd_arg) override { set_thd(thd_arg); return 0; } int exec() override; bool fix_length_and_dec(Item_cache**) override { return FALSE; } uint cols() const override { /* TODO: what is the correct value? */ return 1; } uint8 uncacheable() override { return UNCACHEABLE_DEPENDENT; } void exclude() override {} table_map upper_select_const_tables() override { return 0; } bool change_result(Item_subselect*, select_result_interceptor*, bool temp= FALSE) override { DBUG_ASSERT(FALSE); return false; } bool no_tables() const override { return false; } bool no_rows() override { /* TODO: It is completely unclear what is the semantics of this method. The current result is computed so that the call to no_rows() from Item_in_optimizer::val_int() sets Item_in_optimizer::null_value correctly. */ return !(item->get_IN_subquery()->null_value); } void print(String*, enum_query_type) override; friend void subselect_hash_sj_engine::cleanup(); }; class subselect_rowid_merge_engine: public subselect_partial_match_engine { protected: /* Mapping from row numbers to row ids. The rowids are stored sequentially in the array - rowid[i] is located in row_num_to_rowid + i * rowid_length. */ uchar *row_num_to_rowid; /* A subset of all the keys for which there is a match for the same row. Used during execution. Computed for each outer reference */ MY_BITMAP matching_keys; /* The columns of the outer reference that are NULL. Computed for each outer reference. */ MY_BITMAP matching_outer_cols; /* Indexes of row numbers, sorted by . If an index may contain NULLs, the NULLs are stored efficiently in a bitmap. The indexes are sorted by the selectivity of their NULL sub-indexes, the one with the fewer NULLs is first. Thus, if there is any index on non-NULL columns, it is contained in keys[0]. */ Ordered_key **merge_keys; /* The number of elements in merge_keys. */ uint merge_keys_count; /* The NULL bitmaps of merge keys.*/ MY_BITMAP **null_bitmaps; /* An index on all non-NULL columns of 'tmp_table'. The index has the logical form: <[v_i1 | ... | v_ik], rownum>. It allows to find the row number where the columns c_i1,...,c1_k contain the values v_i1,...,v_ik. If such an index exists, it is always the first element of 'merge_keys'. */ Ordered_key *non_null_key; /* Priority queue of Ordered_key indexes, one per NULLable column. This queue is used by the partial match algorithm in method exec(). */ QUEUE pq; protected: /* Comparison function to compare keys in order of decreasing bitmap selectivity. */ static int cmp_keys_by_null_selectivity(const void *k1, const void *k2); /* Comparison function used by the priority queue pq, the 'smaller' key is the one with the smaller current row number. */ static int cmp_keys_by_cur_rownum(void *, const void *k1, const void *k2); bool test_null_row(rownum_t row_num); bool exists_complementing_null_row(MY_BITMAP *keys_to_complement); bool partial_match() override; public: subselect_rowid_merge_engine(THD *thd, subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, uint merge_keys_count_arg, bool has_covering_null_row_arg, bool has_covering_null_columns_arg, uint count_columns_with_nulls_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg) :subselect_partial_match_engine(thd, engine_arg, tmp_table_arg, item_arg, result_arg, equi_join_conds_arg, has_covering_null_row_arg, has_covering_null_columns_arg, count_columns_with_nulls_arg), merge_keys_count(merge_keys_count_arg), non_null_key(NULL) {} ~subselect_rowid_merge_engine(); bool init(MY_BITMAP *non_null_key_parts, MY_BITMAP *partial_match_key_parts); void cleanup() override; enum_engine_type engine_type() override { return ROWID_MERGE_ENGINE; } }; class subselect_table_scan_engine: public subselect_partial_match_engine { protected: bool partial_match() override; public: subselect_table_scan_engine(THD *thd, subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg, bool has_covering_null_row_arg, bool has_covering_null_columns_arg, uint count_columns_with_nulls_arg); void cleanup() override; enum_engine_type engine_type() override { return TABLE_SCAN_ENGINE; } }; /* An engine to handle NULL-aware Materialization for subqueries that compare one column: col1 IN (SELECT t2.col2 FROM t2 ...) When only one column is used, we need to handle NULL values of col1 and col2 but don't need to perform "partial" matches when only a subset of compared columns is NULL. This allows to save on some data structures. */ class subselect_single_column_match_engine: public subselect_partial_match_engine { protected: bool partial_match() override; public: subselect_single_column_match_engine(THD *thd, subselect_uniquesubquery_engine *engine_arg, TABLE *tmp_table_arg, Item_subselect *item_arg, select_result_interceptor *result_arg, List *equi_join_conds_arg, bool has_covering_null_row_arg, bool has_covering_null_columns_arg, uint count_columns_with_nulls_arg); void cleanup() override {} enum_engine_type engine_type() override { return SINGLE_COLUMN_ENGINE; } }; /** @brief Subquery materialization tracker @details Used to track various parameters of the materialized subquery execution, such as the execution strategy, sizes of buffers employed, etc */ class Subq_materialization_tracker { public: using Strategy = subselect_hash_sj_engine::exec_strategy; Subq_materialization_tracker(MEM_ROOT *mem_root) : exec_strategy(Strategy::UNDEFINED), partial_match_buffer_size(0), partial_match_array_sizes(mem_root), loops_count(0), index_lookups_count(0), partial_matches_count(0) {} void report_partial_merge_keys(Ordered_key **merge_keys, uint merge_keys_count); void report_exec_strategy(Strategy es) { exec_strategy= es; } void report_partial_match_buffer_size(longlong sz) { partial_match_buffer_size= sz; } void increment_loops_count() { loops_count++; } void increment_index_lookups() { index_lookups_count++; } void increment_partial_matches() { partial_matches_count++; } void print_json_members(Json_writer *writer) const; private: Strategy exec_strategy; ulonglong partial_match_buffer_size; Dynamic_array partial_match_array_sizes; /* Number of times subquery predicate was evaluated */ ulonglong loops_count; /* Number of times we made a lookup in the materialized temptable (we do this when all parts of left_expr are not NULLs) */ ulonglong index_lookups_count; /* Number of times we had to check for a partial match (either by scanning the materialized subquery or by doing a merge) */ ulonglong partial_matches_count; const char *get_exec_strategy() const { switch (exec_strategy) { case Strategy::UNDEFINED: return "undefined"; case Strategy::COMPLETE_MATCH: return "index_lookup"; case Strategy::PARTIAL_MATCH_MERGE: return "index_lookup;array merge for partial match"; case Strategy::PARTIAL_MATCH_SCAN: return "index_lookup;full scan for partial match"; case Strategy::SINGLE_COLUMN_MATCH: return "null-aware index_lookup"; case Strategy::CONST_RETURN_NULL: return "return NULL"; default: return "unsupported"; } } }; #endif /* ITEM_SUBSELECT_INCLUDED */ server/private/sql_cursor.h000064400000004414151031265040012071 0ustar00/* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _sql_cursor_h_ #define _sql_cursor_h_ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class interface */ #endif #include "sql_class.h" /* Query_arena */ class JOIN; /** @file Declarations for implementation of server side cursors. Only read-only non-scrollable cursors are currently implemented. */ /** Server_side_cursor -- an interface for materialized implementation of cursors. All cursors are self-contained (created in their own memory root). For that reason they must be deleted only using a pointer to Server_side_cursor, not to its base class. */ class Server_side_cursor: protected Query_arena { protected: /** Row destination used for fetch */ select_result *result; public: Server_side_cursor(MEM_ROOT *mem_root_arg, select_result *result_arg) :Query_arena(mem_root_arg, STMT_INITIALIZED), result(result_arg) {} virtual bool is_open() const= 0; virtual int open(JOIN *top_level_join)= 0; virtual void fetch(ulong num_rows)= 0; virtual void close()= 0; virtual bool export_structure(THD *thd, Row_definition_list *defs) { DBUG_ASSERT(0); return true; } virtual ~Server_side_cursor(); static void *operator new(size_t size, MEM_ROOT *mem_root) { return alloc_root(mem_root, size); } static void operator delete(void *ptr, size_t size); static void operator delete(void *, MEM_ROOT *){} }; int mysql_open_cursor(THD *thd, select_result *result, Server_side_cursor **res); #endif /* _sql_cusor_h_ */ server/private/opt_trace.h000064400000020456151031265040011661 0ustar00#ifndef OPT_TRACE_INCLUDED #define OPT_TRACE_INCLUDED /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "opt_trace_context.h" // Opt_trace_context #include "sql_lex.h" #include "my_json_writer.h" #include "sql_select.h" class Item; class THD; struct TABLE_LIST; /* User-visible information about a trace. */ struct Opt_trace_info { /** String containing trace. If trace has been end()ed, this is 0-terminated, which is only to aid debugging or unit testing; this property is not relied upon in normal server usage. If trace has not been ended, this is not 0-terminated. That rare case can happen when a substatement reads OPTIMIZER_TRACE (at that stage, the top statement is still executing so its trace is not ended yet, but may still be read by the sub-statement). */ const char *trace_ptr; size_t trace_length; //// String containing original query. const char *query_ptr; size_t query_length; const CHARSET_INFO *query_charset; ///< charset of query string /** How many bytes this trace is missing (for traces which were truncated because of @@@@optimizer-trace-max-mem-size). The trace is not extended beyond trace-max-mem-size. */ size_t missing_bytes; /* Whether user lacks privilege to see this trace. If this is set to TRUE, then we return an empty trace */ bool missing_priv; }; /** Instantiate this class to start tracing a THD's actions (generally at a statement's start), and to set the "original" query (not transformed, as sent by client) for the new trace. Destructor will end the trace. @param thd the THD @param tbl list of tables read/written by the statement. @param sql_command SQL command being prepared or executed @param set_vars what variables are set by this command (only used if sql_command is SQLCOM_SET_OPTION) @param query query @param length query's length @param charset charset which was used to encode this query */ class Opt_trace_start { public: Opt_trace_start(THD *thd_arg): ctx(&thd_arg->opt_trace), traceable(false) {} void init(THD *thd, TABLE_LIST *tbl, enum enum_sql_command sql_command, List *set_vars, const char *query, size_t query_length, const CHARSET_INFO *query_charset); ~Opt_trace_start(); private: Opt_trace_context *const ctx; /* True: the query will be traced False: otherwise */ bool traceable; }; /** Prints SELECT query to optimizer trace. It is not the original query (as in @c Opt_trace_context::set_query()) but a printout of the parse tree (Item-s). @param thd the THD @param select_lex query's parse tree @param trace_object Json_writer object to which the query will be added */ void opt_trace_print_expanded_query(THD *thd, SELECT_LEX *select_lex, Json_writer_object *trace_object); void add_table_scan_values_to_trace(THD *thd, JOIN_TAB *tab); void trace_plan_prefix(JOIN *join, uint idx, table_map join_tables); void print_final_join_order(JOIN *join); void print_best_access_for_table(THD *thd, POSITION *pos, enum join_type type); void trace_condition(THD * thd, const char *name, const char *transform_type, Item *item, const char *table_name= nullptr); /* Security related (need to add a proper comment here) */ /** If the security context is not that of the connected user, inform the trace system that a privilege is missing. With one exception: see below. @param thd This serves to eliminate the following issue. Any information readable by a SELECT may theoretically end up in the trace. And a SELECT may read information from other places than tables: - from views (reading their bodies) - from stored routines (reading their bodies) - from files (reading their content), with LOAD_FILE() - from the list of connections (reading their queries...), with I_S.PROCESSLIST. If the connected user has EXECUTE privilege on a routine which does a security context change, the routine can retrieve information internally (if allowed by the SUID context's privileges), and present only a portion of it to the connected user. But with tracing on, all information is possibly in the trace. So the connected user receives more information than the routine's definer intended to provide. Fixing this issue would require adding, near many privilege checks in the server, a new optimizer-trace-specific check done against the connected user's context, to verify that the connected user has the right to see the retrieved information. Instead, our chosen simpler solution is that if we see a security context change where SUID user is not the connected user, we disable tracing. With only one safe exception: if the connected user has all global privileges (because then she/he can find any information anyway). By "all global privileges" we mean everything but WITH GRANT OPTION (that latter one isn't related to information gathering). Read access to I_S.OPTIMIZER_TRACE by another user than the connected user is restricted: @see fill_optimizer_trace_info(). */ void opt_trace_disable_if_no_security_context_access(THD *thd); void opt_trace_disable_if_no_tables_access(THD *thd, TABLE_LIST *tbl); /** If tracing is on, checks additional privileges for a view, to make sure that the user has the right to do SHOW CREATE VIEW. For that: - this function checks SHOW VIEW - SELECT is tested in opt_trace_disable_if_no_tables_access() - SELECT + SHOW VIEW is sufficient for SHOW CREATE VIEW. We also check underlying tables. If a privilege is missing, notifies the trace system. This function should be called when the view's underlying tables have not yet been merged. @param thd THD context @param view view to check @param underlying_tables underlying tables/views of 'view' */ void opt_trace_disable_if_no_view_access(THD *thd, TABLE_LIST *view, TABLE_LIST *underlying_tables); /** If tracing is on, checks additional privileges on a stored routine, to make sure that the user has the right to do SHOW CREATE PROCEDURE/FUNCTION. For that, we use the same checks as in those SHOW commands. If a privilege is missing, notifies the trace system. This function is not redundant with opt_trace_disable_if_no_security_context_access(). Indeed, for a SQL SECURITY INVOKER routine, there is no context change, but we must still verify that the invoker can do SHOW CREATE. For triggers, see note in sp_head::execute_trigger(). @param thd @param sp routine to check */ void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp); /** Fills information_schema.OPTIMIZER_TRACE with rows (one per trace) @retval 0 ok @retval 1 error */ int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *); #define OPT_TRACE_TRANSFORM(thd, object_level0, object_level1, \ select_number, from, to) \ Json_writer_object object_level0(thd); \ Json_writer_object object_level1(thd, "transformation"); \ object_level1.add_select_number(select_number).add("from", from).add("to", to); #define OPT_TRACE_VIEWS_TRANSFORM(thd, object_level0, object_level1, \ derived, name, select_number, algorithm) \ Json_writer_object trace_wrapper(thd); \ Json_writer_object trace_derived(thd, derived); \ trace_derived.add("table", name).add_select_number(select_number) \ .add("algorithm", algorithm); #endif server/private/wsrep_mysqld.h000064400000051572151031265040012435 0ustar00/* Copyright 2008-2023 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef WSREP_MYSQLD_H #define WSREP_MYSQLD_H #include #ifdef WITH_WSREP #include #include "mysql/service_wsrep.h" #include #include #include "log.h" #include "mysqld.h" typedef struct st_mysql_show_var SHOW_VAR; #include #include "mdl.h" #include "sql_table.h" #include "wsrep_mysqld_c.h" #include "wsrep/provider.hpp" #include "wsrep/streaming_context.hpp" #include "wsrep_api.h" #include #define WSREP_UNDEFINED_TRX_ID ULONGLONG_MAX class THD; // Global wsrep parameters // MySQL wsrep options extern const char* wsrep_provider; extern const char* wsrep_provider_options; extern const char* wsrep_cluster_name; extern const char* wsrep_cluster_address; extern const char* wsrep_node_name; extern const char* wsrep_node_address; extern const char* wsrep_node_incoming_address; extern const char* wsrep_data_home_dir; extern const char* wsrep_dbug_option; extern long wsrep_slave_threads; extern int wsrep_slave_count_change; extern ulong wsrep_debug; extern my_bool wsrep_convert_LOCK_to_trx; extern ulong wsrep_retry_autocommit; extern my_bool wsrep_auto_increment_control; extern my_bool wsrep_drupal_282555_workaround; extern my_bool wsrep_incremental_data_collection; extern const char* wsrep_start_position; extern ulong wsrep_max_ws_size; extern ulong wsrep_max_ws_rows; extern const char* wsrep_notify_cmd; extern my_bool wsrep_certify_nonPK; extern long int wsrep_protocol_version; extern my_bool wsrep_desync; extern ulong wsrep_reject_queries; extern my_bool wsrep_recovery; extern my_bool wsrep_replicate_myisam; extern my_bool wsrep_log_conflicts; extern ulong wsrep_mysql_replication_bundle; extern my_bool wsrep_load_data_splitting; extern my_bool wsrep_restart_slave; extern my_bool wsrep_restart_slave_activated; extern my_bool wsrep_slave_FK_checks; extern my_bool wsrep_slave_UK_checks; extern ulong wsrep_trx_fragment_unit; extern ulong wsrep_SR_store_type; extern uint wsrep_ignore_apply_errors; extern ulong wsrep_running_threads; extern ulong wsrep_running_applier_threads; extern ulong wsrep_running_rollbacker_threads; extern bool wsrep_new_cluster; extern bool wsrep_gtid_mode; extern uint32 wsrep_gtid_domain_id; extern std::atomic wsrep_thread_create_failed; extern ulonglong wsrep_mode; extern my_bool wsrep_strict_ddl; enum enum_wsrep_reject_types { WSREP_REJECT_NONE, /* nothing rejected */ WSREP_REJECT_ALL, /* reject all queries, with UNKNOWN_COMMAND error */ WSREP_REJECT_ALL_KILL /* kill existing connections and reject all queries*/ }; enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU, WSREP_OSU_NONE, }; enum enum_wsrep_sync_wait { WSREP_SYNC_WAIT_NONE= 0x0, // select, begin WSREP_SYNC_WAIT_BEFORE_READ= 0x1, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE= 0x2, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE= 0x4, WSREP_SYNC_WAIT_BEFORE_SHOW= 0x8, WSREP_SYNC_WAIT_MAX= 0xF }; enum enum_wsrep_ignore_apply_error { WSREP_IGNORE_ERRORS_NONE= 0x0, WSREP_IGNORE_ERRORS_ON_RECONCILING_DDL= 0x1, WSREP_IGNORE_ERRORS_ON_RECONCILING_DML= 0x2, WSREP_IGNORE_ERRORS_ON_DDL= 0x4, WSREP_IGNORE_ERRORS_MAX= 0x7 }; /* wsrep_mode features */ enum enum_wsrep_mode { WSREP_MODE_STRICT_REPLICATION= (1ULL << 0), WSREP_MODE_BINLOG_ROW_FORMAT_ONLY= (1ULL << 1), WSREP_MODE_REQUIRED_PRIMARY_KEY= (1ULL << 2), WSREP_MODE_REPLICATE_MYISAM= (1ULL << 3), WSREP_MODE_REPLICATE_ARIA= (1ULL << 4), WSREP_MODE_DISALLOW_LOCAL_GTID= (1ULL << 5), WSREP_MODE_BF_MARIABACKUP= (1ULL << 6) }; // Streaming Replication #define WSREP_FRAG_BYTES 0 #define WSREP_FRAG_ROWS 1 #define WSREP_FRAG_STATEMENTS 2 #define WSREP_SR_STORE_NONE 0 #define WSREP_SR_STORE_TABLE 1 extern const char *wsrep_fragment_units[]; extern const char *wsrep_SR_store_types[]; // MySQL status variables extern my_bool wsrep_connected; extern const char* wsrep_cluster_state_uuid; extern long long wsrep_cluster_conf_id; extern const char* wsrep_cluster_status; extern long wsrep_cluster_size; extern long wsrep_local_index; extern long long wsrep_local_bf_aborts; extern const char* wsrep_provider_name; extern const char* wsrep_provider_version; extern const char* wsrep_provider_vendor; extern char* wsrep_provider_capabilities; extern char* wsrep_cluster_capabilities; int wsrep_show_status(THD *thd, SHOW_VAR *var, void *buff, system_status_var *status_var, enum_var_type scope); int wsrep_show_ready(THD *thd, SHOW_VAR *var, void *buff, system_status_var *, enum_var_type); void wsrep_free_status(THD *thd); void wsrep_update_cluster_state_uuid(const char* str); /* Filters out --wsrep-new-cluster oprtion from argv[] * should be called in the very beginning of main() */ void wsrep_filter_new_cluster (int* argc, char* argv[]); int wsrep_init(); void wsrep_deinit(bool free_options); /* Initialize wsrep thread LOCKs and CONDs */ void wsrep_thr_init(); /* Destroy wsrep thread LOCKs and CONDs */ void wsrep_thr_deinit(); void wsrep_recover(); bool wsrep_before_SE(); // initialize wsrep before storage // engines (true) or after (false) /* wsrep initialization sequence at startup * @param before wsrep_before_SE() value */ void wsrep_init_startup(bool before); /* Recover streaming transactions from fragment storage */ void wsrep_recover_sr_from_storage(THD *); // Other wsrep global variables extern my_bool wsrep_inited; // whether wsrep is initialized ? extern bool wsrep_service_started; extern "C" void wsrep_fire_rollbacker(THD *thd); extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); extern "C" time_t wsrep_thd_query_start(THD *thd); extern void wsrep_close_client_connections(my_bool wait_to_end, THD *except_caller_thd= NULL); extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); extern int wsrep_wait_committing_connections_close(int wait_time); extern void wsrep_close_applier(THD *thd); extern void wsrep_wait_appliers_close(THD *thd); extern void wsrep_close_applier_threads(int count); /* new defines */ extern void wsrep_stop_replication(THD *thd); extern bool wsrep_start_replication(const char *wsrep_cluster_address); extern void wsrep_shutdown_replication(); extern bool wsrep_check_mode (enum_wsrep_mode mask); extern bool wsrep_check_mode_after_open_table (THD *thd, const handlerton *hton, TABLE_LIST *tables); extern bool wsrep_check_mode_before_cmd_execute (THD *thd); extern bool wsrep_must_sync_wait (THD* thd, uint mask= WSREP_SYNC_WAIT_BEFORE_READ); extern bool wsrep_sync_wait (THD* thd, uint mask= WSREP_SYNC_WAIT_BEFORE_READ); extern bool wsrep_sync_wait (THD* thd, enum enum_sql_command command); extern enum wsrep::provider::status wsrep_sync_wait_upto (THD* thd, wsrep_gtid_t* upto, int timeout); extern int wsrep_check_opts(); extern void wsrep_prepend_PATH (const char* path); extern bool wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* table, wsrep::key_array* keys); extern bool wsrep_reload_ssl(); /* Other global variables */ extern wsrep_seqno_t wsrep_locked_seqno; /* A wrapper function for MySQL log functions. The call will prefix the log message with WSREP and forward the result buffer to fun. */ void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...); #define WSREP_SYNC_WAIT(thd_, before_) \ { if (WSREP_CLIENT(thd_) && \ wsrep_sync_wait(thd_, before_)) goto wsrep_error_label; } #define WSREP_MYSQL_DB (char *)"mysql" #define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) \ if (WSREP_ON && WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) \ goto wsrep_error_label; #define WSREP_TO_ISOLATION_BEGIN_CREATE(db_, table_, table_list_, create_info_) \ if (WSREP_ON && WSREP(thd) && \ wsrep_to_isolation_begin(thd, db_, table_, \ table_list_, nullptr, nullptr, create_info_))\ goto wsrep_error_label; #define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, fk_tables_, create_info_) \ if (WSREP(thd) && wsrep_thd_is_local(thd) && \ wsrep_to_isolation_begin(thd, db_, table_, \ table_list_, alter_info_, fk_tables_, create_info_)) #define WSREP_TO_ISOLATION_END \ if ((WSREP(thd) && wsrep_thd_is_local_toi(thd)) || \ wsrep_thd_is_in_rsu(thd)) \ wsrep_to_isolation_end(thd); /* Checks if lex->no_write_to_binlog is set for statements that use LOCAL or NO_WRITE_TO_BINLOG. */ #define WSREP_TO_ISOLATION_BEGIN_WRTCHK(db_, table_, table_list_) \ if (WSREP(thd) && !thd->lex->no_write_to_binlog \ && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) \ goto wsrep_error_label; #define WSREP_PROVIDER_EXISTS (WSREP_PROVIDER_EXISTS_) static inline bool wsrep_cluster_address_exists() { if (mysqld_server_started) mysql_mutex_assert_owner(&LOCK_global_system_variables); return wsrep_cluster_address && wsrep_cluster_address[0]; } extern my_bool wsrep_ready_get(); extern void wsrep_ready_wait(); extern mysql_mutex_t LOCK_wsrep_ready; extern mysql_cond_t COND_wsrep_ready; extern mysql_mutex_t LOCK_wsrep_sst; extern mysql_cond_t COND_wsrep_sst; extern mysql_mutex_t LOCK_wsrep_sst_init; extern mysql_cond_t COND_wsrep_sst_init; extern int wsrep_replaying; extern mysql_mutex_t LOCK_wsrep_replaying; extern mysql_cond_t COND_wsrep_replaying; extern mysql_mutex_t LOCK_wsrep_slave_threads; extern mysql_cond_t COND_wsrep_slave_threads; extern mysql_mutex_t LOCK_wsrep_gtid_wait_upto; extern mysql_mutex_t LOCK_wsrep_cluster_config; extern mysql_mutex_t LOCK_wsrep_desync; extern mysql_mutex_t LOCK_wsrep_SR_pool; extern mysql_mutex_t LOCK_wsrep_SR_store; extern mysql_mutex_t LOCK_wsrep_config_state; extern mysql_mutex_t LOCK_wsrep_group_commit; extern mysql_mutex_t LOCK_wsrep_joiner_monitor; extern mysql_mutex_t LOCK_wsrep_donor_monitor; extern mysql_cond_t COND_wsrep_joiner_monitor; extern mysql_cond_t COND_wsrep_donor_monitor; extern int wsrep_to_isolation; #ifdef GTID_SUPPORT extern rpl_sidno wsrep_sidno; #endif /* GTID_SUPPORT */ extern my_bool wsrep_preordered_opt; #ifdef HAVE_PSI_INTERFACE extern PSI_cond_key key_COND_wsrep_thd; extern PSI_mutex_key key_LOCK_wsrep_ready; extern PSI_mutex_key key_COND_wsrep_ready; extern PSI_mutex_key key_LOCK_wsrep_sst; extern PSI_cond_key key_COND_wsrep_sst; extern PSI_mutex_key key_LOCK_wsrep_sst_init; extern PSI_cond_key key_COND_wsrep_sst_init; extern PSI_mutex_key key_LOCK_wsrep_sst_thread; extern PSI_cond_key key_COND_wsrep_sst_thread; extern PSI_mutex_key key_LOCK_wsrep_replaying; extern PSI_cond_key key_COND_wsrep_replaying; extern PSI_mutex_key key_LOCK_wsrep_slave_threads; extern PSI_cond_key key_COND_wsrep_slave_threads; extern PSI_mutex_key key_LOCK_wsrep_gtid_wait_upto; extern PSI_cond_key key_COND_wsrep_gtid_wait_upto; extern PSI_mutex_key key_LOCK_wsrep_cluster_config; extern PSI_mutex_key key_LOCK_wsrep_desync; extern PSI_mutex_key key_LOCK_wsrep_SR_pool; extern PSI_mutex_key key_LOCK_wsrep_SR_store; extern PSI_mutex_key key_LOCK_wsrep_global_seqno; extern PSI_mutex_key key_LOCK_wsrep_thd_queue; extern PSI_cond_key key_COND_wsrep_thd_queue; extern PSI_mutex_key key_LOCK_wsrep_joiner_monitor; extern PSI_mutex_key key_LOCK_wsrep_donor_monitor; extern PSI_file_key key_file_wsrep_gra_log; extern PSI_thread_key key_wsrep_sst_joiner; extern PSI_thread_key key_wsrep_sst_donor; extern PSI_thread_key key_wsrep_rollbacker; extern PSI_thread_key key_wsrep_applier; extern PSI_thread_key key_wsrep_sst_joiner_monitor; extern PSI_thread_key key_wsrep_sst_donor_monitor; #endif /* HAVE_PSI_INTERFACE */ struct TABLE_LIST; class Alter_info; int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, const TABLE_LIST* table_list, const Alter_info* alter_info= nullptr, const wsrep::key_array *fk_tables= nullptr, const HA_CREATE_INFO* create_info= nullptr); bool wsrep_should_replicate_ddl(THD* thd, const handlerton *hton); bool wsrep_should_replicate_ddl_iterate(THD* thd, const TABLE_LIST* table_list); void wsrep_to_isolation_end(THD *thd); bool wsrep_append_SR_keys(THD *thd); int wsrep_to_buf_helper( THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len); int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len); int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len); void wsrep_init_sidno(const wsrep_uuid_t&); bool wsrep_node_is_donor(); bool wsrep_node_is_synced(); void wsrep_init_SR(); void wsrep_verify_SE_checkpoint(const wsrep_uuid_t& uuid, wsrep_seqno_t seqno); int wsrep_replay_from_SR_store(THD*, const wsrep_trx_meta_t&); class Log_event; int wsrep_ignored_error_code(Log_event* ev, int error); int wsrep_must_ignore_error(THD* thd); struct wsrep_server_gtid_t { uint32 domain_id; uint32 server_id; uint64 seqno; }; class Wsrep_gtid_server { public: uint32 domain_id; uint32 server_id; Wsrep_gtid_server() : m_force_signal(false) , m_seqno(0) , m_committed_seqno(0) { } void gtid(const wsrep_server_gtid_t& gtid) { domain_id= gtid.domain_id; server_id= gtid.server_id; m_seqno= gtid.seqno; } wsrep_server_gtid_t gtid() { wsrep_server_gtid_t gtid; gtid.domain_id= domain_id; gtid.server_id= server_id; gtid.seqno= m_seqno; return gtid; } void seqno(const uint64 seqno) { m_seqno= seqno; } uint64 seqno() const { return m_seqno; } uint64 seqno_committed() const { return m_committed_seqno; } uint64 seqno_inc() { m_seqno++; return m_seqno; } const wsrep_server_gtid_t& undefined() { return m_undefined; } int wait_gtid_upto(const uint64_t seqno, uint timeout) { int wait_result= 0; struct timespec wait_time; int ret= 0; mysql_cond_t wait_cond; mysql_cond_init(key_COND_wsrep_gtid_wait_upto, &wait_cond, NULL); set_timespec(wait_time, timeout); mysql_mutex_lock(&LOCK_wsrep_gtid_wait_upto); std::multimap::iterator it; if (seqno > m_seqno) { try { it= m_wait_map.insert(std::make_pair(seqno, &wait_cond)); } catch (std::bad_alloc& e) { ret= ENOMEM; } while (!ret && (m_committed_seqno < seqno) && !m_force_signal) { wait_result= mysql_cond_timedwait(&wait_cond, &LOCK_wsrep_gtid_wait_upto, &wait_time); if (wait_result == ETIMEDOUT || wait_result == ETIME) { ret= wait_result; break; } } if (ret != ENOMEM) { m_wait_map.erase(it); } } mysql_mutex_unlock(&LOCK_wsrep_gtid_wait_upto); mysql_cond_destroy(&wait_cond); return ret; } void signal_waiters(uint64 seqno, bool signal_all) { mysql_mutex_lock(&LOCK_wsrep_gtid_wait_upto); if (!signal_all && (m_committed_seqno >= seqno)) { mysql_mutex_unlock(&LOCK_wsrep_gtid_wait_upto); return; } m_force_signal= true; std::multimap::iterator it_end; std::multimap::iterator it_begin; if (signal_all) { it_end= m_wait_map.end(); } else { it_end= m_wait_map.upper_bound(seqno); } if (m_committed_seqno < seqno) { m_committed_seqno= seqno; } for (it_begin = m_wait_map.begin(); it_begin != it_end; ++it_begin) { mysql_cond_signal(it_begin->second); } m_force_signal= false; mysql_mutex_unlock(&LOCK_wsrep_gtid_wait_upto); } private: const wsrep_server_gtid_t m_undefined= {0,0,0}; std::multimap m_wait_map; bool m_force_signal; Atomic_counter m_seqno; Atomic_counter m_committed_seqno; }; extern Wsrep_gtid_server wsrep_gtid_server; void wsrep_init_gtid(); bool wsrep_check_gtid_seqno(const uint32&, const uint32&, uint64&); bool wsrep_get_binlog_gtid_seqno(wsrep_server_gtid_t&); int wsrep_append_table_keys(THD* thd, TABLE_LIST* first_table, TABLE_LIST* table_list, Wsrep_service_key_type key_type); extern void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx, const MDL_ticket *ticket, const MDL_key *key); enum wsrep_thread_type { WSREP_APPLIER_THREAD=1, WSREP_ROLLBACKER_THREAD=2 }; typedef void (*wsrep_thd_processor_fun)(THD*, void *); class Wsrep_thd_args { public: Wsrep_thd_args(wsrep_thd_processor_fun fun, wsrep_thread_type thread_type, pthread_t thread_id) : fun_ (fun), thread_type_ (thread_type), thread_id_ (thread_id) { } wsrep_thd_processor_fun fun() { return fun_; } pthread_t* thread_id() {return &thread_id_; } enum wsrep_thread_type thread_type() {return thread_type_;} private: Wsrep_thd_args(const Wsrep_thd_args&); Wsrep_thd_args& operator=(const Wsrep_thd_args&); wsrep_thd_processor_fun fun_; enum wsrep_thread_type thread_type_; pthread_t thread_id_; }; void* start_wsrep_THD(void*); void wsrep_close_threads(THD *thd); bool wsrep_is_show_query(enum enum_sql_command command); void wsrep_replay_transaction(THD *thd); bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, HA_CREATE_INFO *create_info); bool wsrep_node_is_donor(); bool wsrep_node_is_synced(); /** * Check if the wsrep provider (ie the Galera library) is capable of * doing streaming replication. * @return true if SR capable */ bool wsrep_provider_is_SR_capable(); /** * Initialize WSREP server instance. * * @return Zero on success, non-zero on error. */ int wsrep_init_server(); /** * Initialize WSREP globals. This should be done after server initialization * is complete and the server has joined to the cluster. * */ void wsrep_init_globals(); /** * Deinit and release WSREP resources. */ void wsrep_deinit_server(); /** * Convert streaming fragment unit (WSREP_FRAG_BYTES, WSREP_FRAG_ROWS...) * to corresponding wsrep-lib fragment_unit */ enum wsrep::streaming_context::fragment_unit wsrep_fragment_unit(ulong unit); wsrep::key wsrep_prepare_key_for_toi(const char* db, const char* table, enum wsrep::key::type type); void wsrep_wait_ready(THD *thd); void wsrep_ready_set(bool ready_value); /** * Returns true if the given list of tables contains at least one * non-temporary table. */ bool wsrep_table_list_has_non_temp_tables(THD *thd, TABLE_LIST *tables); /** * Append foreign key to wsrep. * * @param thd Thread object * @param fk Foreign Key Info * * @return true if error, otherwise false. */ bool wsrep_foreign_key_append(THD *thd, FOREIGN_KEY_INFO *fk); #else /* !WITH_WSREP */ /* These macros are needed to compile MariaDB without WSREP support * (e.g. embedded) */ #define WSREP_PROVIDER_EXISTS (0) #define wsrep_emulate_bin_log (0) #define wsrep_to_isolation (0) #define wsrep_before_SE() (0) #define wsrep_init_startup(X) #define wsrep_check_opts() (0) #define wsrep_thr_init() do {} while(0) #define wsrep_thr_deinit() do {} while(0) #define wsrep_init_globals() do {} while(0) #define wsrep_create_appliers(X) do {} while(0) #define wsrep_cluster_address_exists() (false) #define WSREP_MYSQL_DB (0) #define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) do { } while(0) #define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, fk_tables_) #define WSREP_TO_ISOLATION_END #define WSREP_TO_ISOLATION_BEGIN_WRTCHK(db_, table_, table_list_) #define WSREP_SYNC_WAIT(thd_, before_) #endif /* WITH_WSREP */ #endif /* WSREP_MYSQLD_H */ server/private/sql_type.h000064400001101015151031265040011531 0ustar00#ifndef SQL_TYPE_H_INCLUDED #define SQL_TYPE_H_INCLUDED /* Copyright (c) 2015 MariaDB Foundation. Copyright (c) 2015, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "mysqld.h" #include "lex_string.h" #include "sql_array.h" #include "sql_const.h" #include "sql_time.h" #include "sql_type_string.h" #include "sql_type_real.h" #include "compat56.h" #include "log_event_data_type.h" C_MODE_START #include C_MODE_END class Field; class Column_definition; class Column_definition_attributes; class Key_part_spec; class Item; class Item_const; class Item_literal; class Item_param; class Item_cache; class Item_copy; class Item_func_or_sum; class Item_sum; class Item_sum_hybrid; class Item_sum_sum; class Item_sum_avg; class Item_sum_variance; class Item_func_hex; class Item_hybrid_func; class Item_func_min_max; class Item_func_hybrid_field_type; class Item_bool_func2; class Item_bool_rowready_func2; class Item_func_between; class Item_func_in; class Item_func_round; class Item_func_int_val; class Item_func_abs; class Item_func_neg; class Item_func_signed; class Item_func_unsigned; class Item_double_typecast; class Item_float_typecast; class Item_decimal_typecast; class Item_char_typecast; class Item_time_typecast; class Item_date_typecast; class Item_datetime_typecast; class Item_func_plus; class Item_func_minus; class Item_func_mul; class Item_func_div; class Item_func_mod; class Item_type_holder; class cmp_item; class in_vector; class Type_handler_data; class Type_handler_hybrid_field_type; class Sort_param; class Arg_comparator; class Spvar_definition; class st_value; class Protocol; class handler; struct TABLE; struct SORT_FIELD_ATTR; struct SORT_FIELD; class Vers_history_point; class Virtual_column_info; class Conv_source; class ST_FIELD_INFO; class Type_collection; class Create_func; #define my_charset_numeric my_charset_latin1 enum protocol_send_type_t { PROTOCOL_SEND_STRING, PROTOCOL_SEND_FLOAT, PROTOCOL_SEND_DOUBLE, PROTOCOL_SEND_TINY, PROTOCOL_SEND_SHORT, PROTOCOL_SEND_LONG, PROTOCOL_SEND_LONGLONG, PROTOCOL_SEND_DATETIME, PROTOCOL_SEND_DATE, PROTOCOL_SEND_TIME }; enum scalar_comparison_op { SCALAR_CMP_EQ, SCALAR_CMP_EQUAL, SCALAR_CMP_LT, SCALAR_CMP_LE, SCALAR_CMP_GE, SCALAR_CMP_GT }; /* This enum is intentionally defined as "class" to disallow its implicit cast as "bool". This is needed to avoid pre-MDEV-32203 constructs like: if (field->can_optimize_range(...)) do_optimization(); to merge automatically as such - that would change the meaning to the opposite. The pre-MDEV-32203 code must to be changed to: if (field->can_optimize_range(...) == Data_type_compatibility::OK) do_optimization(); */ enum class Data_type_compatibility { OK, INCOMPATIBLE_DATA_TYPE, INCOMPATIBLE_COLLATION }; static inline const LEX_CSTRING scalar_comparison_op_to_lex_cstring(scalar_comparison_op op) { switch (op) { case SCALAR_CMP_EQ: return LEX_CSTRING{STRING_WITH_LEN("=")}; case SCALAR_CMP_EQUAL: return LEX_CSTRING{STRING_WITH_LEN("<=>")}; case SCALAR_CMP_LT: return LEX_CSTRING{STRING_WITH_LEN("<")}; case SCALAR_CMP_LE: return LEX_CSTRING{STRING_WITH_LEN("<=")}; case SCALAR_CMP_GE: return LEX_CSTRING{STRING_WITH_LEN(">=")}; case SCALAR_CMP_GT: return LEX_CSTRING{STRING_WITH_LEN(">")}; } DBUG_ASSERT(0); return LEX_CSTRING{STRING_WITH_LEN("")}; } class Hasher { ulong m_nr1; ulong m_nr2; public: Hasher(): m_nr1(1), m_nr2(4) { } void add_null() { m_nr1^= (m_nr1 << 1) | 1; } void add(CHARSET_INFO *cs, const uchar *str, size_t length) { cs->coll->hash_sort(cs, str, length, &m_nr1, &m_nr2); } void add(CHARSET_INFO *cs, const char *str, size_t length) { add(cs, (const uchar *) str, length); } uint32 finalize() const { return (uint32) m_nr1; } }; enum partition_value_print_mode_t { PARTITION_VALUE_PRINT_MODE_SHOW= 0, PARTITION_VALUE_PRINT_MODE_FRM= 1 }; enum column_definition_type_t { COLUMN_DEFINITION_TABLE_FIELD, COLUMN_DEFINITION_ROUTINE_PARAM, COLUMN_DEFINITION_ROUTINE_LOCAL, COLUMN_DEFINITION_FUNCTION_RETURN }; class Send_field_extended_metadata { LEX_CSTRING m_attr[MARIADB_FIELD_ATTR_LAST+1]; public: Send_field_extended_metadata() { bzero(this, sizeof(*this)); } bool set_data_type_name(const LEX_CSTRING &str) { m_attr[MARIADB_FIELD_ATTR_DATA_TYPE_NAME]= str; return false; } bool set_format_name(const LEX_CSTRING &str) { m_attr[MARIADB_FIELD_ATTR_FORMAT_NAME]= str; return false; } bool has_extended_metadata() const { for (uint i= 0; i <= MARIADB_FIELD_ATTR_LAST; i++) { if (m_attr[i].str) return true; } return false; } const LEX_CSTRING &attr(uint i) const { DBUG_ASSERT(i <= MARIADB_FIELD_ATTR_LAST); return m_attr[i]; } }; class Data_type_statistics { public: uint m_uneven_bit_length; uint m_fixed_string_total_length; uint m_fixed_string_count; uint m_variable_string_total_length; uint m_variable_string_count; uint m_blob_count; Data_type_statistics() :m_uneven_bit_length(0), m_fixed_string_total_length(0), m_fixed_string_count(0), m_variable_string_total_length(0), m_variable_string_count(0), m_blob_count(0) { } uint string_count() const { return m_fixed_string_count + m_variable_string_count; } uint string_total_length() const { return m_fixed_string_total_length + m_variable_string_total_length; } }; class Typelib: public TYPELIB { public: Typelib(uint count, const char **type_names, unsigned int *type_lengths) { TYPELIB::count= count; TYPELIB::name= ""; TYPELIB::type_names= type_names; TYPELIB::type_lengths= type_lengths; } uint max_octet_length() const { uint max_length= 0; for (uint i= 0; i < TYPELIB::count; i++) { const uint length= TYPELIB::type_lengths[i]; set_if_bigger(max_length, length); } return max_length; } }; template class TypelibBuffer: public Typelib { const char *m_type_names[sz + 1]; uint m_type_lengths[sz + 1]; public: TypelibBuffer(uint count, const LEX_CSTRING *values) :Typelib(count, m_type_names, m_type_lengths) { DBUG_ASSERT(sz >= count); for (uint i= 0; i < count; i++) { DBUG_ASSERT(values[i].str != NULL); m_type_names[i]= values[i].str; m_type_lengths[i]= (uint) values[i].length; } m_type_names[sz]= NullS; // End marker m_type_lengths[sz]= 0; // End marker } TypelibBuffer(const LEX_CSTRING *values) :TypelibBuffer(sz, values) { } }; /* A helper class to store column attributes that are inherited by columns (from the table level) when not specified explicitly. */ class Column_derived_attributes { /* Table level CHARACTER SET and COLLATE value: CREATE TABLE t1 (a VARCHAR(1), b CHAR(2)) CHARACTER SET latin1; All character string columns (CHAR, VARCHAR, TEXT) inherit CHARACTER SET from the table level. */ CHARSET_INFO *m_charset; public: explicit Column_derived_attributes(CHARSET_INFO *cs) :m_charset(cs) { } CHARSET_INFO *charset() const { return m_charset; } }; /* A helper class to store requests for changes in multiple column data types during ALTER. */ class Column_bulk_alter_attributes { /* Target CHARACTER SET specification in ALTER .. CONVERT, e.g. ALTER TABLE t1 CONVERT TO CHARACTER SET utf8; All character string columns (CHAR, VARCHAR, TEXT) get converted to the "CONVERT TO CHARACTER SET". */ CHARSET_INFO *m_alter_table_convert_to_charset; public: explicit Column_bulk_alter_attributes(CHARSET_INFO *convert) :m_alter_table_convert_to_charset(convert) { } CHARSET_INFO *alter_table_convert_to_charset() const { return m_alter_table_convert_to_charset; } }; class Native: public Binary_string { public: Native(char *str, size_t len) :Binary_string(str, len) { } }; template class NativeBuffer: public Native { char buff[buff_sz]; public: NativeBuffer() : Native(buff, buff_sz) { length(0); } }; class String_ptr { protected: String *m_string_ptr; public: String_ptr(String *str) :m_string_ptr(str) { } String_ptr(Item *item, String *buffer); const String *string() const { DBUG_ASSERT(m_string_ptr); return m_string_ptr; } bool is_null() const { return m_string_ptr == NULL; } }; class Ascii_ptr: public String_ptr { public: Ascii_ptr(Item *item, String *buffer); }; template class String_ptr_and_buffer: public StringBuffer, public String_ptr { public: String_ptr_and_buffer(Item *item) :String_ptr(item, this) { } }; template class Ascii_ptr_and_buffer: public StringBuffer, public Ascii_ptr { public: Ascii_ptr_and_buffer(Item *item) :Ascii_ptr(item, this) { } }; class Dec_ptr { protected: my_decimal *m_ptr; Dec_ptr() = default; public: Dec_ptr(my_decimal *ptr) :m_ptr(ptr) { } bool is_null() const { return m_ptr == NULL; } const my_decimal *ptr() const { return m_ptr; } const my_decimal *ptr_or(const my_decimal *def) const { return m_ptr ? m_ptr : def; } my_decimal *to_decimal(my_decimal *to) const { if (!m_ptr) return NULL; *to= *m_ptr; return to; } double to_double() const { return m_ptr ? m_ptr->to_double() : 0.0; } longlong to_longlong(bool unsigned_flag) { return m_ptr ? m_ptr->to_longlong(unsigned_flag) : 0; } Longlong_null to_xlonglong_null() { return m_ptr ? Longlong_null(m_ptr->to_xlonglong()) : Longlong_null(); } bool to_bool() const { return m_ptr ? m_ptr->to_bool() : false; } String *to_string(String *to) const { return m_ptr ? m_ptr->to_string(to) : NULL; } String *to_string(String *to, uint prec, uint dec, char filler) { return m_ptr ? m_ptr->to_string(to, prec, dec, filler) : NULL; } int to_binary(uchar *bin, int prec, decimal_digits_t scale) const { return (m_ptr ? m_ptr : &decimal_zero)->to_binary(bin, prec, scale); } int cmp(const my_decimal *dec) const { DBUG_ASSERT(m_ptr); DBUG_ASSERT(dec); return m_ptr->cmp(dec); } int cmp(const Dec_ptr &other) const { return cmp(other.m_ptr); } }; // A helper class to handle results of val_decimal(), date_op(), etc. class Dec_ptr_and_buffer: public Dec_ptr { protected: my_decimal m_buffer; public: /* scale is int as it can be negative here */ int round_to(my_decimal *to, int scale, decimal_round_mode mode) { DBUG_ASSERT(m_ptr); return m_ptr->round_to(to, scale, mode); } int round_self(decimal_digits_t scale, decimal_round_mode mode) { return round_to(&m_buffer, scale, mode); } int round_self_if_needed(int scale, decimal_round_mode mode) { if (scale >= m_ptr->frac) return E_DEC_OK; int res= m_ptr->round_to(&m_buffer, scale, mode); m_ptr= &m_buffer; return res; } String *to_string_round(String *to, decimal_digits_t dec) { /* decimal_round() allows from==to So it's save even if m_ptr points to m_buffer before this call: */ return m_ptr ? m_ptr->to_string_round(to, dec, &m_buffer) : NULL; } }; // A helper class to handle val_decimal() results. class VDec: public Dec_ptr_and_buffer { public: VDec(): Dec_ptr_and_buffer() { } VDec(Item *item); void set(Item *a); }; // A helper class to handler decimal_op() results. class VDec_op: public Dec_ptr_and_buffer { public: VDec_op(Item_func_hybrid_field_type *item); }; /* Get and cache val_decimal() values for two items. If the first value appears to be NULL, the second value is not evaluated. */ class VDec2_lazy { public: VDec m_a; VDec m_b; VDec2_lazy(Item *a, Item *b) :m_a(a) { if (!m_a.is_null()) m_b.set(b); } bool has_null() const { return m_a.is_null() || m_b.is_null(); } }; /** Class Sec6 represents a fixed point value with 6 fractional digits. Used e.g. to convert double and my_decimal values to TIME/DATETIME. */ class Sec6 { protected: ulonglong m_sec; // The integer part, between 0 and LONGLONG_MAX ulong m_usec; // The fractional part, between 0 and 999999 bool m_neg; // false if positive, true of negative bool m_truncated; // Indicates if the constructor truncated the value void make_from_decimal(const my_decimal *d, ulong *nanoseconds); void make_from_double(double d, ulong *nanoseconds); void make_from_int(const Longlong_hybrid &nr) { m_neg= nr.neg(); m_sec= nr.abs(); m_usec= 0; m_truncated= false; } void reset() { m_sec= m_usec= m_neg= m_truncated= 0; } Sec6() = default; bool add_nanoseconds(uint nanoseconds) { DBUG_ASSERT(nanoseconds <= 1000000000); if (nanoseconds < 500) return false; m_usec+= (nanoseconds + 500) / 1000; if (m_usec < 1000000) return false; m_usec%= 1000000; return true; } public: explicit Sec6(double nr) { ulong nanoseconds; make_from_double(nr, &nanoseconds); } explicit Sec6(const my_decimal *d) { ulong nanoseconds; make_from_decimal(d, &nanoseconds); } explicit Sec6(const Longlong_hybrid &nr) { make_from_int(nr); } explicit Sec6(longlong nr, bool unsigned_val) { make_from_int(Longlong_hybrid(nr, unsigned_val)); } bool neg() const { return m_neg; } bool truncated() const { return m_truncated; } ulonglong sec() const { return m_sec; } long usec() const { return m_usec; } /** Converts Sec6 to MYSQL_TIME @param thd current thd @param [out] warn conversion warnings will be written here @param [out] ltime converted value will be written here @param fuzzydate conversion flags (TIME_INVALID_DATE, etc) @returns false for success, true for a failure */ bool convert_to_mysql_time(THD *thd, int *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const; protected: bool to_interval_hhmmssff_only(MYSQL_TIME *to, int *warn) const { return number_to_time_only(m_neg, m_sec, m_usec, TIME_MAX_INTERVAL_HOUR, to, warn); } bool to_datetime_or_to_interval_hhmmssff(MYSQL_TIME *to, int *warn) const { /* Convert a number to a time interval. The following formats are understood: - 0 <= x <= 999999995959 - parse as hhhhmmss - 999999995959 < x <= 99991231235959 - parse as YYYYMMDDhhmmss (YYMMDDhhmmss) (YYYYMMDDhhmmss) Note, these formats are NOT understood: - YYMMDD - overlaps with INTERVAL range - YYYYMMDD - overlaps with INTERVAL range - YYMMDDhhmmss - overlaps with INTERVAL range, partially (see TIME_MAX_INTERVAL_HOUR) If we ever need wider intervals, this code switching between full datetime and interval-only should be rewised. */ DBUG_ASSERT(TIME_MAX_INTERVAL_HOUR <= 999999995959); /* (YYMMDDhhmmss) */ if (m_sec > 999999995959ULL && m_sec <= 99991231235959ULL && m_neg == 0) return to_datetime_or_date(to, warn, TIME_INVALID_DATES); if (m_sec / 10000 > TIME_MAX_INTERVAL_HOUR) { *warn= MYSQL_TIME_WARN_OUT_OF_RANGE; return true; } return to_interval_hhmmssff_only(to, warn); } public: // [-][DD]hhhmmss.ff, YYMMDDhhmmss.ff, YYYYMMDDhhmmss.ff bool to_datetime_or_time(MYSQL_TIME *to, int *warn, date_conv_mode_t mode) const { bool rc= m_sec > 9999999 && m_sec <= 99991231235959ULL && !m_neg ? ::number_to_datetime_or_date(m_sec, m_usec, to, ulonglong(mode & TIME_MODE_FOR_XXX_TO_DATE), warn) < 0 : ::number_to_time_only(m_neg, m_sec, m_usec, TIME_MAX_HOUR, to, warn); DBUG_ASSERT(*warn || !rc); return rc; } /* Convert a number in formats YYYYMMDDhhmmss.ff or YYMMDDhhmmss.ff to TIMESTAMP'YYYY-MM-DD hh:mm:ss.ff' */ bool to_datetime_or_date(MYSQL_TIME *to, int *warn, date_conv_mode_t flags) const { if (m_neg) { *warn= MYSQL_TIME_WARN_OUT_OF_RANGE; return true; } bool rc= number_to_datetime_or_date(m_sec, m_usec, to, ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), warn) == -1; DBUG_ASSERT(*warn || !rc); return rc; } // Convert elapsed seconds to TIME bool sec_to_time(MYSQL_TIME *ltime, uint dec) const { set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); ltime->neg= m_neg; if (m_sec > TIME_MAX_VALUE_SECONDS) { // use check_time_range() to set ltime to the max value depending on dec int unused; ltime->hour= TIME_MAX_HOUR + 1; check_time_range(ltime, dec, &unused); return true; } DBUG_ASSERT(usec() <= TIME_MAX_SECOND_PART); ltime->hour= (uint) (m_sec / 3600); ltime->minute= (uint) (m_sec % 3600) / 60; ltime->second= (uint) m_sec % 60; ltime->second_part= m_usec; return false; } Sec6 &trunc(uint dec) { m_usec-= my_time_fraction_remainder(m_usec, dec); return *this; } size_t to_string(char *to, size_t nbytes) const { return m_usec ? my_snprintf(to, nbytes, "%s%llu.%06lu", m_neg ? "-" : "", m_sec, m_usec) : my_snprintf(to, nbytes, "%s%llu", m_neg ? "-" : "", m_sec); } void make_truncated_warning(THD *thd, const char *type_str) const; }; class Sec9: public Sec6 { protected: ulong m_nsec; // Nanoseconds 0..999 void make_from_int(const Longlong_hybrid &nr) { Sec6::make_from_int(nr); m_nsec= 0; } Sec9() = default; public: Sec9(const my_decimal *d) { Sec6::make_from_decimal(d, &m_nsec); } Sec9(double d) { Sec6::make_from_double(d, &m_nsec); } ulong nsec() const { return m_nsec; } Sec9 &trunc(uint dec) { m_nsec= 0; Sec6::trunc(dec); return *this; } Sec9 &round(uint dec); Sec9 &round(uint dec, time_round_mode_t mode) { return mode == TIME_FRAC_TRUNCATE ? trunc(dec) : round(dec); } }; class VSec9: protected Sec9 { bool m_is_null; Sec9& to_sec9() { DBUG_ASSERT(!is_null()); return *this; } public: VSec9(THD *thd, Item *item, const char *type_str, ulonglong limit); bool is_null() const { return m_is_null; } const Sec9& to_const_sec9() const { DBUG_ASSERT(!is_null()); return *this; } bool neg() const { return to_const_sec9().neg(); } bool truncated() const { return to_const_sec9().truncated(); } ulonglong sec() const { return to_const_sec9().sec(); } long usec() const { return to_const_sec9().usec(); } bool sec_to_time(MYSQL_TIME *ltime, uint dec) const { return to_const_sec9().sec_to_time(ltime, dec); } void make_truncated_warning(THD *thd, const char *type_str) const { return to_const_sec9().make_truncated_warning(thd, type_str); } Sec9 &round(uint dec) { return to_sec9().round(dec); } Sec9 &round(uint dec, time_round_mode_t mode) { return to_sec9().round(dec, mode); } }; /* A heler class to perform additive operations between two MYSQL_TIME structures and return the result as a combination of seconds, microseconds and sign. */ class Sec6_add { ulonglong m_sec; // number of seconds ulong m_usec; // number of microseconds bool m_neg; // false if positive, true if negative bool m_error; // false if the value is OK, true otherwise void to_hh24mmssff(MYSQL_TIME *ltime, timestamp_type tstype) const { bzero(ltime, sizeof(*ltime)); ltime->neg= m_neg; calc_time_from_sec(ltime, (ulong) (m_sec % SECONDS_IN_24H), m_usec); ltime->time_type= tstype; } public: /* @param ltime1 - the first value to add (must be a valid DATE,TIME,DATETIME) @param ltime2 - the second value to add (must be a valid TIME) @param sign - the sign of the operation (+1 for addition, -1 for subtraction) */ Sec6_add(const MYSQL_TIME *ltime1, const MYSQL_TIME *ltime2, int sign) { DBUG_ASSERT(sign == -1 || sign == 1); DBUG_ASSERT(!ltime1->neg || ltime1->time_type == MYSQL_TIMESTAMP_TIME); if (!(m_error= (ltime2->time_type != MYSQL_TIMESTAMP_TIME))) { if (ltime1->neg != ltime2->neg) sign= -sign; m_neg= calc_time_diff(ltime1, ltime2, -sign, &m_sec, &m_usec); if (ltime1->neg && (m_sec || m_usec)) m_neg= !m_neg; // Swap sign } } bool to_time(THD *thd, MYSQL_TIME *ltime, uint decimals) const { if (m_error) return true; to_hh24mmssff(ltime, MYSQL_TIMESTAMP_TIME); ltime->hour+= static_cast(to_days_abs() * 24); return adjust_time_range_with_warn(thd, ltime, decimals); } bool to_datetime(MYSQL_TIME *ltime) const { if (m_error || m_neg) return true; to_hh24mmssff(ltime, MYSQL_TIMESTAMP_DATETIME); return get_date_from_daynr(to_days_abs(), <ime->year, <ime->month, <ime->day) || !ltime->day; } long to_days_abs() const { return (long) (m_sec / SECONDS_IN_24H); } }; class Year { protected: uint m_year; bool m_truncated; uint year_precision(const Item *item) const; public: Year(): m_year(0), m_truncated(false) { } Year(longlong value, bool unsigned_flag, uint length); uint year() const { return m_year; } uint to_YYYYMMDD() const { return m_year * 10000; } bool truncated() const { return m_truncated; } }; class Year_null: public Year, public Null_flag { public: Year_null(const Longlong_null &nr, bool unsigned_flag, uint length) :Year(nr.is_null() ? 0 : nr.value(), unsigned_flag, length), Null_flag(nr.is_null()) { } }; class VYear: public Year_null { public: VYear(Item *item); }; class VYear_op: public Year_null { public: VYear_op(Item_func_hybrid_field_type *item); }; class Double_null: public Null_flag { protected: double m_value; public: Double_null(double value, bool is_null) :Null_flag(is_null), m_value(value) { } double value() const { return m_value; } }; class Temporal: protected MYSQL_TIME { public: class Status: public MYSQL_TIME_STATUS { public: Status() { my_time_status_init(this); } }; class Warn: public ErrBuff, public Status { public: void push_conversion_warnings(THD *thd, bool totally_useless_value, date_mode_t mode, timestamp_type tstype, const char *db_name, const char *table_name, const char *name) { const char *typestr= tstype >= 0 ? type_name_by_timestamp_type(tstype) : mode & (TIME_INTERVAL_hhmmssff | TIME_INTERVAL_DAY) ? "interval" : mode & TIME_TIME_ONLY ? "time" : "datetime"; Temporal::push_conversion_warnings(thd, totally_useless_value, warnings, typestr, db_name, table_name, name, ptr()); } }; class Warn_push: public Warn { THD * const m_thd; const char * const m_db_name; const char * const m_table_name; const char * const m_name; const MYSQL_TIME * const m_ltime; const date_mode_t m_mode; public: Warn_push(THD *thd, const char *db_name, const char *table_name, const char *name, const MYSQL_TIME *ltime, date_mode_t mode) : m_thd(thd), m_db_name(db_name), m_table_name(table_name), m_name(name), m_ltime(ltime), m_mode(mode) { } ~Warn_push() { if (warnings) push_conversion_warnings(m_thd, m_ltime->time_type < 0, m_mode, m_ltime->time_type, m_db_name, m_table_name, m_name); } }; public: static date_conv_mode_t sql_mode_for_dates(THD *thd); static time_round_mode_t default_round_mode(THD *thd); class Options: public date_mode_t { public: explicit Options(date_mode_t flags) :date_mode_t(flags) { } Options(date_conv_mode_t flags, time_round_mode_t round_mode) :date_mode_t(flags | round_mode) { DBUG_ASSERT(ulonglong(flags) <= UINT_MAX32); } Options(date_conv_mode_t flags, THD *thd) :Options(flags, default_round_mode(thd)) { } }; bool is_valid_temporal() const { DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR); return time_type != MYSQL_TIMESTAMP_NONE; } static const char *type_name_by_timestamp_type(timestamp_type time_type) { switch (time_type) { case MYSQL_TIMESTAMP_DATE: return "date"; case MYSQL_TIMESTAMP_TIME: return "time"; case MYSQL_TIMESTAMP_DATETIME: // FALLTHROUGH default: break; } return "datetime"; } static void push_conversion_warnings(THD *thd, bool totally_useless_value, int warn, const char *type_name, const char *db_name, const char *table_name, const char *field_name, const char *value); /* This method is used if the item was not null but convertion to TIME/DATE/DATETIME failed. We return a zero date if allowed, otherwise - null. */ void make_fuzzy_date(int *warn, date_conv_mode_t fuzzydate) { /* In the following scenario: - The caller expected to get a TIME value - Item returned a not NULL string or numeric value - But then conversion from string or number to TIME failed we need to change the default time_type from MYSQL_TIMESTAMP_DATE (which was set in bzero) to MYSQL_TIMESTAMP_TIME and therefore return TIME'00:00:00' rather than DATE'0000-00-00'. If we don't do this, methods like Item::get_time_with_conversion() will erroneously subtract CURRENT_DATE from '0000-00-00 00:00:00' and return TIME'-838:59:59' instead of TIME'00:00:00' as a result. */ timestamp_type tstype= !(fuzzydate & TIME_FUZZY_DATES) ? MYSQL_TIMESTAMP_NONE : fuzzydate & TIME_TIME_ONLY ? MYSQL_TIMESTAMP_TIME : MYSQL_TIMESTAMP_DATETIME; set_zero_time(this, tstype); } protected: my_decimal *bad_to_decimal(my_decimal *to) const; my_decimal *to_decimal(my_decimal *to) const; static double to_double(bool negate, ulonglong num, ulong frac) { double d= static_cast(num) + static_cast(frac) / TIME_SECOND_PART_FACTOR; return negate ? -d : d; } longlong to_packed() const { return ::pack_time(this); } void make_from_out_of_range(int *warn) { *warn= MYSQL_TIME_WARN_OUT_OF_RANGE; time_type= MYSQL_TIMESTAMP_NONE; } void make_from_sec6(THD *thd, MYSQL_TIME_STATUS *st, const Sec6 &nr, date_mode_t mode) { if (nr.convert_to_mysql_time(thd, &st->warnings, this, mode)) make_fuzzy_date(&st->warnings, date_conv_mode_t(mode)); } void make_from_sec9(THD *thd, MYSQL_TIME_STATUS *st, const Sec9 &nr, date_mode_t mode) { if (nr.convert_to_mysql_time(thd, &st->warnings, this, mode) || add_nanoseconds(thd, &st->warnings, mode, nr.nsec())) make_fuzzy_date(&st->warnings, date_conv_mode_t(mode)); } void make_from_str(THD *thd, Warn *warn, const char *str, size_t length, CHARSET_INFO *cs, date_mode_t fuzzydate); void make_from_double(THD *thd, Warn *warn, double nr, date_mode_t mode) { make_from_sec9(thd, warn, Sec9(nr), mode); if (warn->warnings) warn->set_double(nr); } void make_from_longlong_hybrid(THD *thd, Warn *warn, const Longlong_hybrid &nr, date_mode_t mode) { /* Note: conversion from an integer to TIME can overflow to '838:59:59.999999', so the conversion result can have fractional digits. */ make_from_sec6(thd, warn, Sec6(nr), mode); if (warn->warnings) warn->set_longlong(nr); } void make_from_decimal(THD *thd, Warn *warn, const my_decimal *nr, date_mode_t mode) { make_from_sec9(thd, warn, Sec9(nr), mode); if (warn->warnings) warn->set_decimal(nr); } bool ascii_to_temporal(MYSQL_TIME_STATUS *st, const char *str, size_t length, date_mode_t mode) { if (mode & (TIME_INTERVAL_hhmmssff | TIME_INTERVAL_DAY)) return ascii_to_datetime_or_date_or_interval_DDhhmmssff(st, str, length, mode); if (mode & TIME_TIME_ONLY) return ascii_to_datetime_or_date_or_time(st, str, length, mode); return ascii_to_datetime_or_date(st, str, length, mode); } bool ascii_to_datetime_or_date_or_interval_DDhhmmssff(MYSQL_TIME_STATUS *st, const char *str, size_t length, date_mode_t mode) { longlong cflags= ulonglong(mode & TIME_MODE_FOR_XXX_TO_DATE); bool rc= mode & TIME_INTERVAL_DAY ? ::str_to_datetime_or_date_or_interval_day(str, length, this, cflags, st, TIME_MAX_INTERVAL_HOUR, TIME_MAX_INTERVAL_HOUR) : ::str_to_datetime_or_date_or_interval_hhmmssff(str, length, this, cflags, st, TIME_MAX_INTERVAL_HOUR, TIME_MAX_INTERVAL_HOUR); DBUG_ASSERT(!rc || st->warnings); return rc; } bool ascii_to_datetime_or_date_or_time(MYSQL_TIME_STATUS *status, const char *str, size_t length, date_mode_t fuzzydate) { ulonglong cflags= ulonglong(fuzzydate & TIME_MODE_FOR_XXX_TO_DATE); bool rc= ::str_to_datetime_or_date_or_time(str, length, this, cflags, status, TIME_MAX_HOUR, UINT_MAX32); DBUG_ASSERT(!rc || status->warnings); return rc; } bool ascii_to_datetime_or_date(MYSQL_TIME_STATUS *status, const char *str, size_t length, date_mode_t fuzzydate) { DBUG_ASSERT(bool(fuzzydate & TIME_TIME_ONLY) == false); bool rc= ::str_to_datetime_or_date(str, length, this, ulonglong(fuzzydate & TIME_MODE_FOR_XXX_TO_DATE), status); DBUG_ASSERT(!rc || status->warnings); return rc; } // Character set aware versions for string conversion routines bool str_to_temporal(THD *thd, MYSQL_TIME_STATUS *st, const char *str, size_t length, CHARSET_INFO *cs, date_mode_t fuzzydate); bool str_to_datetime_or_date_or_time(THD *thd, MYSQL_TIME_STATUS *st, const char *str, size_t length, CHARSET_INFO *cs, date_mode_t mode); bool str_to_datetime_or_date(THD *thd, MYSQL_TIME_STATUS *st, const char *str, size_t length, CHARSET_INFO *cs, date_mode_t mode); bool has_valid_mmssff() const { return minute <= TIME_MAX_MINUTE && second <= TIME_MAX_SECOND && second_part <= TIME_MAX_SECOND_PART; } bool has_zero_YYYYMM() const { return year == 0 && month == 0; } bool has_zero_YYYYMMDD() const { return year == 0 && month == 0 && day == 0; } bool check_date(date_conv_mode_t flags, int *warn) const { return ::check_date(this, flags, warn); } void time_hhmmssff_set_max(uint max_hour) { hour= max_hour; minute= TIME_MAX_MINUTE; second= TIME_MAX_SECOND; second_part= TIME_MAX_SECOND_PART; } /* Add nanoseconds to ssff retval true if seconds overflowed (the caller should increment minutes) false if no overflow happened */ bool add_nanoseconds_ssff(uint nanoseconds) { DBUG_ASSERT(nanoseconds <= 1000000000); if (nanoseconds < 500) return false; second_part+= (nanoseconds + 500) / 1000; if (second_part < 1000000) return false; second_part%= 1000000; if (second < 59) { second++; return false; } second= 0; return true; } /* Add nanoseconds to mmssff retval true if hours overflowed (the caller should increment hours) false if no overflow happened */ bool add_nanoseconds_mmssff(uint nanoseconds) { if (!add_nanoseconds_ssff(nanoseconds)) return false; if (minute < 59) { minute++; return false; } minute= 0; return true; } void time_round_or_set_max(uint dec, int *warn, ulong max_hour, ulong nsec); bool datetime_add_nanoseconds_or_invalidate(THD *thd, int *warn, ulong nsec); bool datetime_round_or_invalidate(THD *thd, uint dec, int *warn, ulong nsec); bool add_nanoseconds_with_round(THD *thd, int *warn, date_conv_mode_t mode, ulong nsec); bool add_nanoseconds(THD *thd, int *warn, date_mode_t mode, ulong nsec) { date_conv_mode_t cmode= date_conv_mode_t(mode); return time_round_mode_t(mode) == TIME_FRAC_ROUND ? add_nanoseconds_with_round(thd, warn, cmode, nsec) : false; } public: static void *operator new(size_t size, MYSQL_TIME *ltime) throw() { DBUG_ASSERT(size == sizeof(MYSQL_TIME)); return ltime; } static void operator delete(void *ptr, MYSQL_TIME *ltime) { } long fraction_remainder(uint dec) const { return my_time_fraction_remainder(second_part, dec); } }; /* Use this class when you need to get a MYSQL_TIME from an Item using Item's native timestamp type, without automatic timestamp type conversion. */ class Temporal_hybrid: public Temporal { public: class Options: public Temporal::Options { public: Options(THD *thd) :Temporal::Options(sql_mode_for_dates(thd), default_round_mode(thd)) { } Options(date_conv_mode_t flags, time_round_mode_t round_mode) :Temporal::Options(flags, round_mode) { } explicit Options(const Temporal::Options &opt) :Temporal::Options(opt) { } explicit Options(date_mode_t fuzzydate) :Temporal::Options(fuzzydate) { } }; public: // Contructors for Item Temporal_hybrid(THD *thd, Item *item, date_mode_t fuzzydate); Temporal_hybrid(THD *thd, Item *item) :Temporal_hybrid(thd, item, Options(thd)) { } Temporal_hybrid(Item *item) :Temporal_hybrid(current_thd, item) { } // Constructors for non-NULL values Temporal_hybrid(THD *thd, Warn *warn, const char *str, size_t length, CHARSET_INFO *cs, date_mode_t fuzzydate) { make_from_str(thd, warn, str, length, cs, fuzzydate); } Temporal_hybrid(THD *thd, Warn *warn, const Longlong_hybrid &nr, date_mode_t fuzzydate) { make_from_longlong_hybrid(thd, warn, nr, fuzzydate); } Temporal_hybrid(THD *thd, Warn *warn, double nr, date_mode_t fuzzydate) { make_from_double(thd, warn, nr, fuzzydate); } // Constructors for nullable values Temporal_hybrid(THD *thd, Warn *warn, const String *str, date_mode_t mode) { if (!str) time_type= MYSQL_TIMESTAMP_NONE; else make_from_str(thd, warn, str->ptr(), str->length(), str->charset(), mode); } Temporal_hybrid(THD *thd, Warn *warn, const Longlong_hybrid_null &nr, date_mode_t fuzzydate) { if (nr.is_null()) time_type= MYSQL_TIMESTAMP_NONE; else make_from_longlong_hybrid(thd, warn, nr, fuzzydate); } Temporal_hybrid(THD *thd, Warn *warn, const Double_null &nr, date_mode_t mode) { if (nr.is_null()) time_type= MYSQL_TIMESTAMP_NONE; else make_from_double(thd, warn, nr.value(), mode); } Temporal_hybrid(THD *thd, Warn *warn, const my_decimal *nr, date_mode_t mode) { if (!nr) time_type= MYSQL_TIMESTAMP_NONE; else make_from_decimal(thd, warn, nr, mode); } // End of constuctors bool copy_valid_value_to_mysql_time(MYSQL_TIME *ltime) const { DBUG_ASSERT(is_valid_temporal()); *ltime= *this; return false; } longlong to_longlong() const { if (!is_valid_temporal()) return 0; ulonglong v= TIME_to_ulonglong(this); return neg ? -(longlong) v : (longlong) v; } double to_double() const { return is_valid_temporal() ? TIME_to_double(this) : 0; } my_decimal *to_decimal(my_decimal *to) { return is_valid_temporal() ? Temporal::to_decimal(to) : bad_to_decimal(to); } String *to_string(String *str, uint dec) const { if (!is_valid_temporal()) return NULL; str->set_charset(&my_charset_numeric); if (!str->alloc(MAX_DATE_STRING_REP_LENGTH)) str->length(my_TIME_to_str(this, const_cast(str->ptr()), dec)); return str; } const MYSQL_TIME *get_mysql_time() const { DBUG_ASSERT(is_valid_temporal()); return this; } }; /* This class resembles the SQL standard , used in extract expressions, e.g: EXTRACT(DAY FROM dt) ::= EXTRACT FROM ::= | */ class Extract_source: public Temporal_hybrid { /* Convert a TIME value to DAY-TIME interval, e.g. for extraction: EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc. Moves full days from ltime->hour to ltime->day. */ void time_to_daytime_interval() { DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_TIME); DBUG_ASSERT(has_zero_YYYYMMDD()); MYSQL_TIME::day= MYSQL_TIME::hour / 24; MYSQL_TIME::hour%= 24; } bool is_valid_extract_source_slow() const { return is_valid_temporal() && MYSQL_TIME::hour < 24 && (has_zero_YYYYMM() || time_type != MYSQL_TIMESTAMP_TIME); } bool is_valid_value_slow() const { return time_type == MYSQL_TIMESTAMP_NONE || is_valid_extract_source_slow(); } public: Extract_source(THD *thd, Item *item, date_mode_t mode) :Temporal_hybrid(thd, item, mode) { if (MYSQL_TIME::time_type == MYSQL_TIMESTAMP_TIME) time_to_daytime_interval(); DBUG_ASSERT(is_valid_value_slow()); } inline const MYSQL_TIME *get_mysql_time() const { DBUG_ASSERT(is_valid_extract_source_slow()); return this; } bool is_valid_extract_source() const { return is_valid_temporal(); } int sign() const { return get_mysql_time()->neg ? -1 : 1; } uint year() const { return get_mysql_time()->year; } uint month() const { return get_mysql_time()->month; } int day() const { return (int) get_mysql_time()->day * sign(); } int hour() const { return (int) get_mysql_time()->hour * sign(); } int minute() const { return (int) get_mysql_time()->minute * sign(); } int second() const { return (int) get_mysql_time()->second * sign(); } int microsecond() const { return (int) get_mysql_time()->second_part * sign(); } uint year_month() const { return year() * 100 + month(); } uint quarter() const { return (month() + 2)/3; } uint week(THD *thd) const; longlong second_microsecond() const { return (second() * 1000000LL + microsecond()); } // DAY TO XXX longlong day_hour() const { return (longlong) day() * 100LL + hour(); } longlong day_minute() const { return day_hour() * 100LL + minute(); } longlong day_second() const { return day_minute() * 100LL + second(); } longlong day_microsecond() const { return day_second() * 1000000LL + microsecond(); } // HOUR TO XXX int hour_minute() const { return hour() * 100 + minute(); } int hour_second() const { return hour_minute() * 100 + second(); } longlong hour_microsecond() const { return hour_second() * 1000000LL + microsecond(); } // MINUTE TO XXX int minute_second() const { return minute() * 100 + second(); } longlong minute_microsecond() const { return minute_second() * 1000000LL + microsecond(); } }; /* This class is used for the "time_interval" argument of these SQL functions: TIMESTAMP(tm,time_interval) ADDTIME(tm,time_interval) Features: - DATE and DATETIME formats are treated as errors - Preserves hours for TIME format as is, without limiting to TIME_MAX_HOUR */ class Interval_DDhhmmssff: public Temporal { static const LEX_CSTRING m_type_name; bool str_to_DDhhmmssff(MYSQL_TIME_STATUS *status, const char *str, size_t length, CHARSET_INFO *cs, ulong max_hour); void push_warning_wrong_or_truncated_value(THD *thd, const ErrConv &str, int warnings); bool is_valid_interval_DDhhmmssff_slow() const { return time_type == MYSQL_TIMESTAMP_TIME && has_zero_YYYYMMDD() && has_valid_mmssff(); } bool is_valid_value_slow() const { return time_type == MYSQL_TIMESTAMP_NONE || is_valid_interval_DDhhmmssff_slow(); } public: // Get fractional second precision from an Item static uint fsp(THD *thd, Item *item); /* Maximum useful HOUR value: TIMESTAMP'0001-01-01 00:00:00' + '87649415:59:59' = '9999-12-31 23:59:59' This gives maximum possible interval values: - '87649415:59:59.999999' (in 'hh:mm:ss.ff' format) - '3652058 23:59:59.999999' (in 'DD hh:mm:ss.ff' format) */ static uint max_useful_hour() { return TIME_MAX_INTERVAL_HOUR; } static uint max_int_part_char_length() { // e.g. '+3652058 23:59:59' return 1/*sign*/ + TIME_MAX_INTERVAL_DAY_CHAR_LENGTH + 1 + 8/*hh:mm:ss*/; } static uint max_char_length(uint fsp) { DBUG_ASSERT(fsp <= TIME_SECOND_PART_DIGITS); return max_int_part_char_length() + (fsp ? 1 : 0) + fsp; } public: Interval_DDhhmmssff(THD *thd, Status *st, bool push_warnings, Item *item, ulong max_hour, time_round_mode_t mode, uint dec); Interval_DDhhmmssff(THD *thd, Item *item, uint dec) { Status st; new(this) Interval_DDhhmmssff(thd, &st, true, item, max_useful_hour(), default_round_mode(thd), dec); } Interval_DDhhmmssff(THD *thd, Item *item) :Interval_DDhhmmssff(thd, item, TIME_SECOND_PART_DIGITS) { } const MYSQL_TIME *get_mysql_time() const { DBUG_ASSERT(is_valid_interval_DDhhmmssff_slow()); return this; } bool is_valid_interval_DDhhmmssff() const { return time_type == MYSQL_TIMESTAMP_TIME; } bool is_valid_value() const { return time_type == MYSQL_TIMESTAMP_NONE || is_valid_interval_DDhhmmssff(); } String *to_string(String *str, uint dec) const { if (!is_valid_interval_DDhhmmssff()) return NULL; str->set_charset(&my_charset_numeric); if (!str->alloc(MAX_DATE_STRING_REP_LENGTH)) str->length(my_interval_DDhhmmssff_to_str(this, const_cast(str->ptr()), dec)); return str; } }; class Schema; /** Class Time is designed to store valid TIME values. 1. Valid value: a. MYSQL_TIMESTAMP_TIME - a valid TIME within the supported TIME range b. MYSQL_TIMESTAMP_NONE - an undefined value 2. Invalid value (internally only): a. MYSQL_TIMESTAMP_TIME outside of the supported TIME range a. MYSQL_TIMESTAMP_{DATE|DATETIME|ERROR} Temporarily Time is allowed to have an invalid value, but only internally, during initialization time. All constructors and modification methods must leave the Time value as described above (see "Valid values"). Time derives from MYSQL_TIME privately to make sure it is accessed externally only in the valid state. */ class Time: public Temporal { static uint binary_length_to_precision(uint length); public: enum datetime_to_time_mode_t { DATETIME_TO_TIME_DISALLOW, DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS, DATETIME_TO_TIME_YYYYMMDD_TRUNCATE, DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY, DATETIME_TO_TIME_MINUS_CURRENT_DATE }; class Options: public Temporal::Options { datetime_to_time_mode_t m_datetime_to_time_mode; public: Options(THD *thd) :Temporal::Options(default_flags_for_get_date(), default_round_mode(thd)), m_datetime_to_time_mode(default_datetime_to_time_mode()) { } Options(date_conv_mode_t flags, THD *thd) :Temporal::Options(flags, default_round_mode(thd)), m_datetime_to_time_mode(default_datetime_to_time_mode()) { } Options(date_conv_mode_t flags, THD *thd, datetime_to_time_mode_t dtmode) :Temporal::Options(flags, default_round_mode(thd)), m_datetime_to_time_mode(dtmode) { } Options(date_conv_mode_t fuzzydate, time_round_mode_t round_mode, datetime_to_time_mode_t datetime_to_time_mode) :Temporal::Options(fuzzydate, round_mode), m_datetime_to_time_mode(datetime_to_time_mode) { } datetime_to_time_mode_t datetime_to_time_mode() const { return m_datetime_to_time_mode; } static datetime_to_time_mode_t default_datetime_to_time_mode() { return DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS; } }; /* CAST(AS TIME) historically does not mix days to hours. This is different comparing to how implicit conversion in Field::store_time_dec() works (e.g. on INSERT). */ class Options_for_cast: public Options { public: Options_for_cast(THD *thd) :Options(default_flags_for_get_date(), default_round_mode(thd), DATETIME_TO_TIME_YYYYMMDD_TRUNCATE) { } Options_for_cast(date_mode_t mode, THD *thd) :Options(default_flags_for_get_date() | (mode & TIME_FUZZY_DATES), default_round_mode(thd), DATETIME_TO_TIME_YYYYMMDD_TRUNCATE) { } }; class Options_for_round: public Options { public: Options_for_round(time_round_mode_t round_mode= TIME_FRAC_TRUNCATE) :Options(Time::default_flags_for_get_date(), round_mode, Time::DATETIME_TO_TIME_DISALLOW) { } }; class Options_cmp: public Options { public: Options_cmp(THD *thd) :Options(comparison_flags_for_get_date(), thd) { } Options_cmp(THD *thd, datetime_to_time_mode_t dtmode) :Options(comparison_flags_for_get_date(), default_round_mode(thd), dtmode) { } }; private: bool is_valid_value_slow() const { return time_type == MYSQL_TIMESTAMP_NONE || is_valid_time_slow(); } bool is_valid_time_slow() const { return time_type == MYSQL_TIMESTAMP_TIME && has_zero_YYYYMMDD() && has_valid_mmssff(); } void hhmmssff_copy(const MYSQL_TIME *from) { hour= from->hour; minute= from->minute; second= from->second; second_part= from->second_part; } void datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(int *warn, uint from_year, uint from_month, uint from_day) { if (from_year != 0 || from_month != 0) *warn|= MYSQL_TIME_NOTE_TRUNCATED; else hour+= from_day * 24; } /* The result is calculated effectively similar to: TIMEDIFF(dt, CAST(CURRENT_DATE AS DATETIME)) If the difference does not fit to the supported TIME range, it's truncated. */ void datetime_to_time_minus_current_date(THD *thd) { MYSQL_TIME current_date, tmp; set_current_date(thd, ¤t_date); calc_time_diff(this, ¤t_date, 1, &tmp, date_mode_t(0)); static_cast(this)[0]= tmp; int warnings= 0; (void) check_time_range(this, TIME_SECOND_PART_DIGITS, &warnings); DBUG_ASSERT(is_valid_time()); } /* Convert a valid DATE or DATETIME to TIME. Before this call, "this" must be a valid DATE or DATETIME value, e.g. returned from Item::get_date(), str_to_xxx(), number_to_xxx(). After this call, "this" is a valid TIME value. */ void valid_datetime_to_valid_time(THD *thd, int *warn, const Options opt) { DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATE || time_type == MYSQL_TIMESTAMP_DATETIME); /* We're dealing with a DATE or DATETIME returned from str_to_xxx(), number_to_xxx() or unpack_time(). Do some asserts to make sure the result hour value after mixing days to hours does not go out of the valid TIME range. The maximum hour value after mixing days will be 31*24+23=767, which is within the supported TIME range. Thus no adjust_time_range_or_invalidate() is needed here. */ DBUG_ASSERT(day < 32); DBUG_ASSERT(hour < 24); if (opt.datetime_to_time_mode() == DATETIME_TO_TIME_MINUS_CURRENT_DATE) { datetime_to_time_minus_current_date(thd); } else { if (opt.datetime_to_time_mode() == DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS) datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(warn, year, month, day); year= month= day= 0; time_type= MYSQL_TIMESTAMP_TIME; } DBUG_ASSERT(is_valid_time_slow()); } /** Convert valid DATE/DATETIME to valid TIME if needed. This method is called after Item::get_date(), str_to_xxx(), number_to_xxx(). which can return only valid TIME/DATE/DATETIME values. Before this call, "this" is: - either a valid TIME/DATE/DATETIME value (within the supported range for the corresponding type), - or MYSQL_TIMESTAMP_NONE After this call, "this" is: - either a valid TIME (within the supported TIME range), - or MYSQL_TIMESTAMP_NONE */ void valid_MYSQL_TIME_to_valid_value(THD *thd, int *warn, const Options opt) { switch (time_type) { case MYSQL_TIMESTAMP_DATE: case MYSQL_TIMESTAMP_DATETIME: if (opt.datetime_to_time_mode() == DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY && (year || month || day)) make_from_out_of_range(warn); else if (opt.datetime_to_time_mode() == DATETIME_TO_TIME_DISALLOW) make_from_out_of_range(warn); else valid_datetime_to_valid_time(thd, warn, opt); break; case MYSQL_TIMESTAMP_NONE: break; case MYSQL_TIMESTAMP_ERROR: set_zero_time(this, MYSQL_TIMESTAMP_TIME); break; case MYSQL_TIMESTAMP_TIME: DBUG_ASSERT(is_valid_time_slow()); break; } } /* This method is called after number_to_xxx() and str_to_xxx(), which can return DATE or DATETIME values. Convert to TIME if needed. We trust that xxx_to_time() returns a valid TIME/DATE/DATETIME value, so here we need to do only simple validation. */ void xxx_to_time_result_to_valid_value(THD *thd, int *warn, const Options opt) { // str_to_xxx(), number_to_xxx() never return MYSQL_TIMESTAMP_ERROR DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR); valid_MYSQL_TIME_to_valid_value(thd, warn, opt); } void adjust_time_range_or_invalidate(int *warn) { if (check_time_range(this, TIME_SECOND_PART_DIGITS, warn)) time_type= MYSQL_TIMESTAMP_NONE; DBUG_ASSERT(is_valid_value_slow()); } public: void round_or_set_max(uint dec, int *warn, ulong nsec); private: void round_or_set_max(uint dec, int *warn); /* All make_from_xxx() methods initialize *warn. The old value gets lost. */ void make_from_datetime_move_day_to_hour(int *warn, const MYSQL_TIME *from); void make_from_datetime_with_days_diff(int *warn, const MYSQL_TIME *from, long curdays); void make_from_time(int *warn, const MYSQL_TIME *from); void make_from_datetime(int *warn, const MYSQL_TIME *from, long curdays); void make_from_item(THD *thd, int *warn, Item *item, const Options opt); public: /* All constructors that accept an "int *warn" parameter initialize *warn. The old value gets lost. */ Time(int *warn, bool neg, ulonglong hour, uint minute, const Sec6 &second); Time() { time_type= MYSQL_TIMESTAMP_NONE; } Time(const Native &native); Time(THD *thd, const MYSQL_TIME *ltime, const Options opt) { *(static_cast(this))= *ltime; DBUG_ASSERT(is_valid_temporal()); int warn= 0; valid_MYSQL_TIME_to_valid_value(thd, &warn, opt); } Time(Item *item) :Time(current_thd, item) { } Time(THD *thd, Item *item, const Options opt) { int warn; make_from_item(thd, &warn, item, opt); } Time(THD *thd, Item *item) :Time(thd, item, Options(thd)) { } Time(int *warn, const MYSQL_TIME *from, long curdays); Time(THD *thd, MYSQL_TIME_STATUS *status, const char *str, size_t len, CHARSET_INFO *cs, const Options opt) { if (str_to_datetime_or_date_or_time(thd, status, str, len, cs, opt)) time_type= MYSQL_TIMESTAMP_NONE; // The below call will optionally add notes to already collected warnings: else xxx_to_time_result_to_valid_value(thd, &status->warnings, opt); } protected: Time(THD *thd, int *warn, const Sec6 &nr, const Options opt) { if (nr.to_datetime_or_time(this, warn, TIME_INVALID_DATES)) time_type= MYSQL_TIMESTAMP_NONE; xxx_to_time_result_to_valid_value(thd, warn, opt); } Time(THD *thd, int *warn, const Sec9 &nr, const Options &opt) :Time(thd, warn, static_cast(nr), opt) { if (is_valid_time() && time_round_mode_t(opt) == TIME_FRAC_ROUND) round_or_set_max(6, warn, nr.nsec()); } public: Time(THD *thd, int *warn, const Longlong_hybrid &nr, const Options &opt) :Time(thd, warn, Sec6(nr), opt) { } Time(THD *thd, int *warn, double nr, const Options &opt) :Time(thd, warn, Sec9(nr), opt) { } Time(THD *thd, int *warn, const my_decimal *d, const Options &opt) :Time(thd, warn, Sec9(d), opt) { } Time(THD *thd, Item *item, const Options opt, uint dec) :Time(thd, item, opt) { round(dec, time_round_mode_t(opt)); } Time(int *warn, const MYSQL_TIME *from, long curdays, const Time::Options &opt, uint dec) :Time(warn, from, curdays) { round(dec, time_round_mode_t(opt), warn); } Time(int *warn, bool neg, ulonglong hour, uint minute, const Sec9 &second, time_round_mode_t mode, uint dec) :Time(warn, neg, hour, minute, second) { DBUG_ASSERT(is_valid_time()); if ((ulonglong) mode == (ulonglong) TIME_FRAC_ROUND) round_or_set_max(6, warn, second.nsec()); round(dec, mode, warn); } Time(THD *thd, MYSQL_TIME_STATUS *status, const char *str, size_t len, CHARSET_INFO *cs, const Options &opt, uint dec) :Time(thd, status, str, len, cs, opt) { round(dec, time_round_mode_t(opt), &status->warnings); } Time(THD *thd, int *warn, const Longlong_hybrid &nr, const Options &opt, uint dec) :Time(thd, warn, nr, opt) { /* Decimal digit truncation is needed here in case if nr was out of the supported TIME range, so "this" was set to '838:59:59.999999'. We always do truncation (not rounding) here, independently from "opt". */ trunc(dec); } Time(THD *thd, int *warn, double nr, const Options &opt, uint dec) :Time(thd, warn, nr, opt) { round(dec, time_round_mode_t(opt), warn); } Time(THD *thd, int *warn, const my_decimal *d, const Options &opt, uint dec) :Time(thd, warn, d, opt) { round(dec, time_round_mode_t(opt), warn); } static date_conv_mode_t default_flags_for_get_date() { return TIME_TIME_ONLY | TIME_INVALID_DATES; } static date_conv_mode_t comparison_flags_for_get_date() { return TIME_TIME_ONLY | TIME_INVALID_DATES | TIME_FUZZY_DATES; } bool is_valid_time() const { DBUG_ASSERT(is_valid_value_slow()); return time_type == MYSQL_TIMESTAMP_TIME; } const MYSQL_TIME *get_mysql_time() const { DBUG_ASSERT(is_valid_time_slow()); return this; } bool copy_to_mysql_time(MYSQL_TIME *ltime) const { if (time_type == MYSQL_TIMESTAMP_NONE) { ltime->time_type= MYSQL_TIMESTAMP_NONE; return true; } DBUG_ASSERT(is_valid_time_slow()); *ltime= *this; return false; } int cmp(const Time *other) const { DBUG_ASSERT(is_valid_time_slow()); DBUG_ASSERT(other->is_valid_time_slow()); longlong p0= to_packed(); longlong p1= other->to_packed(); if (p0 < p1) return -1; if (p0 > p1) return 1; return 0; } longlong to_seconds_abs() const { DBUG_ASSERT(is_valid_time_slow()); return hour * 3600L + minute * 60 + second; } longlong to_seconds() const { return neg ? -to_seconds_abs() : to_seconds_abs(); } bool to_bool() const { return is_valid_time() && (TIME_to_ulonglong_time(this) != 0 || second_part != 0); } longlong to_longlong() const { if (!is_valid_time()) return 0; ulonglong v= TIME_to_ulonglong_time(this); return neg ? -(longlong) v : (longlong) v; } double to_double() const { return !is_valid_time() ? 0 : Temporal::to_double(neg, TIME_to_ulonglong_time(this), second_part); } bool to_native(Native *to, uint decimals) const; String *to_string(String *str, uint dec) const { if (!is_valid_time()) return NULL; str->set_charset(&my_charset_numeric); if (!str->alloc(MAX_DATE_STRING_REP_LENGTH)) str->length(my_time_to_str(this, const_cast(str->ptr()), dec)); return str; } my_decimal *to_decimal(my_decimal *to) { return is_valid_time() ? Temporal::to_decimal(to) : bad_to_decimal(to); } longlong to_packed() const { return is_valid_time() ? Temporal::to_packed() : 0; } longlong valid_time_to_packed() const { DBUG_ASSERT(is_valid_time_slow()); return Temporal::to_packed(); } long fraction_remainder(uint dec) const { DBUG_ASSERT(is_valid_time()); return Temporal::fraction_remainder(dec); } Time &trunc(uint dec) { if (is_valid_time()) my_time_trunc(this, dec); DBUG_ASSERT(is_valid_value_slow()); return *this; } Time &ceiling(int *warn) { if (is_valid_time()) { if (neg) my_time_trunc(this, 0); else if (second_part) round_or_set_max(0, warn, 999999999); } DBUG_ASSERT(is_valid_value_slow()); return *this; } Time &ceiling() { int warn= 0; return ceiling(&warn); } Time &floor(int *warn) { if (is_valid_time()) { if (!neg) my_time_trunc(this, 0); else if (second_part) round_or_set_max(0, warn, 999999999); } DBUG_ASSERT(is_valid_value_slow()); return *this; } Time &floor() { int warn= 0; return floor(&warn); } Time &round(uint dec, int *warn) { if (is_valid_time()) round_or_set_max(dec, warn); DBUG_ASSERT(is_valid_value_slow()); return *this; } Time &round(uint dec, time_round_mode_t mode, int *warn) { switch (mode.mode()) { case time_round_mode_t::FRAC_NONE: DBUG_ASSERT(fraction_remainder(dec) == 0); return trunc(dec); case time_round_mode_t::FRAC_TRUNCATE: return trunc(dec); case time_round_mode_t::FRAC_ROUND: return round(dec, warn); } return *this; } Time &round(uint dec, time_round_mode_t mode) { int warn= 0; return round(dec, mode, &warn); } }; /** Class Temporal_with_date is designed to store valid DATE or DATETIME values. See also class Time. 1. Valid value: a. MYSQL_TIMESTAMP_{DATE|DATETIME} - a valid DATE or DATETIME value b. MYSQL_TIMESTAMP_NONE - an undefined value 2. Invalid value (internally only): a. MYSQL_TIMESTAMP_{DATE|DATETIME} - a DATE or DATETIME value, but with MYSQL_TIME members outside of the valid/supported range b. MYSQL_TIMESTAMP_TIME - a TIME value c. MYSQL_TIMESTAMP_ERROR - error Temporarily is allowed to have an invalid value, but only internally, during initialization time. All constructors and modification methods must leave the value as described above (see "Valid value"). Derives from MYSQL_TIME using "protected" inheritance to make sure it is accessed externally only in the valid state. */ class Temporal_with_date: public Temporal { public: class Options: public Temporal::Options { public: Options(date_conv_mode_t fuzzydate, time_round_mode_t mode): Temporal::Options(fuzzydate, mode) {} explicit Options(const Temporal::Options &opt) :Temporal::Options(opt) { } explicit Options(date_mode_t mode) :Temporal::Options(mode) { } }; protected: void check_date_or_invalidate(int *warn, date_conv_mode_t flags); void make_from_item(THD *thd, Item *item, date_mode_t flags); ulong daynr() const { return (ulong) ::calc_daynr((uint) year, (uint) month, (uint) day); } int weekday(bool sunday_first_day_of_week) const { return ::calc_weekday(daynr(), sunday_first_day_of_week); } ulong dayofyear() const { return (ulong) (daynr() - ::calc_daynr(year, 1, 1) + 1); } uint quarter() const { return (month + 2) / 3; } uint week(uint week_behaviour) const { uint year; return calc_week(this, week_behaviour, &year); } uint yearweek(uint week_behaviour) const { uint year; uint week= calc_week(this, week_behaviour, &year); return week + year * 100; } public: Temporal_with_date() { time_type= MYSQL_TIMESTAMP_NONE; } Temporal_with_date(THD *thd, Item *item, date_mode_t fuzzydate) { make_from_item(thd, item, fuzzydate); } Temporal_with_date(int *warn, const Sec6 &nr, date_mode_t flags) { DBUG_ASSERT(bool(flags & TIME_TIME_ONLY) == false); if (nr.to_datetime_or_date(this, warn, date_conv_mode_t(flags))) time_type= MYSQL_TIMESTAMP_NONE; } Temporal_with_date(THD *thd, MYSQL_TIME_STATUS *status, const char *str, size_t len, CHARSET_INFO *cs, date_mode_t flags) { DBUG_ASSERT(bool(flags & TIME_TIME_ONLY) == false); if (str_to_datetime_or_date(thd, status, str, len, cs, flags)) time_type= MYSQL_TIMESTAMP_NONE; } public: bool check_date_with_warn(THD *thd, date_conv_mode_t flags) { return ::check_date_with_warn(thd, this, flags, MYSQL_TIMESTAMP_ERROR); } bool check_date_with_warn(THD *thd) { return ::check_date_with_warn(thd, this, Temporal::sql_mode_for_dates(thd), MYSQL_TIMESTAMP_ERROR); } static date_conv_mode_t comparison_flags_for_get_date() { return TIME_INVALID_DATES | TIME_FUZZY_DATES; } }; /** Class Date is designed to store valid DATE values. All constructors and modification methods leave instances of this class in one of the following valid states: a. MYSQL_TIMESTAMP_DATE - a DATE with all MYSQL_TIME members properly set b. MYSQL_TIMESTAMP_NONE - an undefined value. Other MYSQL_TIMESTAMP_XXX are not possible. MYSQL_TIMESTAMP_DATE with MYSQL_TIME members improperly set is not possible. */ class Date: public Temporal_with_date { bool is_valid_value_slow() const { return time_type == MYSQL_TIMESTAMP_NONE || is_valid_date_slow(); } bool is_valid_date_slow() const { DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATE); return !check_datetime_range(this); } public: class Options: public Temporal_with_date::Options { public: explicit Options(date_conv_mode_t fuzzydate) :Temporal_with_date::Options(fuzzydate, TIME_FRAC_TRUNCATE) { } Options(THD *thd, time_round_mode_t mode) :Temporal_with_date::Options(sql_mode_for_dates(thd), mode) { } explicit Options(THD *thd) :Temporal_with_date::Options(sql_mode_for_dates(thd), TIME_FRAC_TRUNCATE) { } explicit Options(date_mode_t fuzzydate) :Temporal_with_date::Options(fuzzydate) { } }; public: Date(Item *item, date_mode_t fuzzydate) :Date(current_thd, item, fuzzydate) { } Date(THD *thd, Item *item, date_mode_t fuzzydate) :Temporal_with_date(thd, item, fuzzydate) { if (time_type == MYSQL_TIMESTAMP_DATETIME) datetime_to_date(this); DBUG_ASSERT(is_valid_value_slow()); } Date(THD *thd, Item *item, date_conv_mode_t fuzzydate) :Date(thd, item, Options(fuzzydate)) { } Date(THD *thd, Item *item) :Temporal_with_date(Date(thd, item, Options(thd, TIME_FRAC_TRUNCATE))) { } Date(Item *item) :Temporal_with_date(Date(current_thd, item)) { } Date(const Temporal_with_date *d) :Temporal_with_date(*d) { datetime_to_date(this); DBUG_ASSERT(is_valid_date_slow()); } explicit Date(const Temporal_hybrid *from) { from->copy_valid_value_to_mysql_time(this); DBUG_ASSERT(is_valid_date_slow()); } bool is_valid_date() const { DBUG_ASSERT(is_valid_value_slow()); return time_type == MYSQL_TIMESTAMP_DATE; } bool check_date(date_conv_mode_t flags, int *warnings) const { DBUG_ASSERT(is_valid_date_slow()); return ::check_date(this, (year || month || day), ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), warnings); } bool check_date(THD *thd, int *warnings) const { return check_date(Temporal::sql_mode_for_dates(thd), warnings); } bool check_date(date_conv_mode_t flags) const { int dummy; /* unused */ return check_date(flags, &dummy); } bool check_date(THD *thd) const { int dummy; return check_date(Temporal::sql_mode_for_dates(thd), &dummy); } const MYSQL_TIME *get_mysql_time() const { DBUG_ASSERT(is_valid_date_slow()); return this; } bool copy_to_mysql_time(MYSQL_TIME *ltime) const { if (time_type == MYSQL_TIMESTAMP_NONE) { ltime->time_type= MYSQL_TIMESTAMP_NONE; return true; } DBUG_ASSERT(is_valid_date_slow()); *ltime= *this; return false; } ulong daynr() const { DBUG_ASSERT(is_valid_date_slow()); return Temporal_with_date::daynr(); } ulong dayofyear() const { DBUG_ASSERT(is_valid_date_slow()); return Temporal_with_date::dayofyear(); } uint quarter() const { DBUG_ASSERT(is_valid_date_slow()); return Temporal_with_date::quarter(); } uint week(uint week_behaviour) const { DBUG_ASSERT(is_valid_date_slow()); return Temporal_with_date::week(week_behaviour); } uint yearweek(uint week_behaviour) const { DBUG_ASSERT(is_valid_date_slow()); return Temporal_with_date::yearweek(week_behaviour); } longlong valid_date_to_packed() const { DBUG_ASSERT(is_valid_date_slow()); return Temporal::to_packed(); } bool to_bool() const { return to_longlong() != 0; } longlong to_longlong() const { return is_valid_date() ? (longlong) TIME_to_ulonglong_date(this) : 0LL; } double to_double() const { return (double) to_longlong(); } String *to_string(String *str) const { if (!is_valid_date()) return NULL; str->set_charset(&my_charset_numeric); if (!str->alloc(MAX_DATE_STRING_REP_LENGTH)) str->length(my_date_to_str(this, const_cast(str->ptr()))); return str; } my_decimal *to_decimal(my_decimal *to) { return is_valid_date() ? Temporal::to_decimal(to) : bad_to_decimal(to); } }; /** Class Datetime is designed to store valid DATETIME values. All constructors and modification methods leave instances of this class in one of the following valid states: a. MYSQL_TIMESTAMP_DATETIME - a DATETIME with all members properly set b. MYSQL_TIMESTAMP_NONE - an undefined value. Other MYSQL_TIMESTAMP_XXX are not possible. MYSQL_TIMESTAMP_DATETIME with MYSQL_TIME members improperly set is not possible. */ class Datetime: public Temporal_with_date { bool is_valid_value_slow() const { return time_type == MYSQL_TIMESTAMP_NONE || is_valid_datetime_slow(); } bool is_valid_datetime_slow() const { DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATETIME); return !check_datetime_range(this); } bool add_nanoseconds_or_invalidate(THD *thd, int *warn, ulong nsec) { DBUG_ASSERT(is_valid_datetime_slow()); bool rc= Temporal::datetime_add_nanoseconds_or_invalidate(thd, warn, nsec); DBUG_ASSERT(is_valid_value_slow()); return rc; } void date_to_datetime_if_needed() { if (time_type == MYSQL_TIMESTAMP_DATE) date_to_datetime(this); } void make_from_time(THD *thd, int *warn, const MYSQL_TIME *from, date_conv_mode_t flags); void make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from, date_conv_mode_t flags); bool round_or_invalidate(THD *thd, uint dec, int *warn); bool round_or_invalidate(THD *thd, uint dec, int *warn, ulong nsec) { DBUG_ASSERT(is_valid_datetime_slow()); bool rc= Temporal::datetime_round_or_invalidate(thd, dec, warn, nsec); DBUG_ASSERT(is_valid_value_slow()); return rc; } public: class Options: public Temporal_with_date::Options { public: Options(date_conv_mode_t fuzzydate, time_round_mode_t nanosecond_rounding) :Temporal_with_date::Options(fuzzydate, nanosecond_rounding) { } Options(THD *thd) :Temporal_with_date::Options(sql_mode_for_dates(thd), default_round_mode(thd)) { } Options(THD *thd, time_round_mode_t rounding_mode) :Temporal_with_date::Options(sql_mode_for_dates(thd), rounding_mode) { } Options(date_conv_mode_t fuzzydate, THD *thd) :Temporal_with_date::Options(fuzzydate, default_round_mode(thd)) { } }; class Options_cmp: public Options { public: Options_cmp(THD *thd) :Options(comparison_flags_for_get_date(), thd) { } }; static Datetime zero() { int warn; static Longlong_hybrid nr(0, false); return Datetime(&warn, nr, date_mode_t(0)); } public: Datetime() // NULL value :Temporal_with_date() { } Datetime(THD *thd, Item *item, date_mode_t fuzzydate) :Temporal_with_date(thd, item, fuzzydate) { date_to_datetime_if_needed(); DBUG_ASSERT(is_valid_value_slow()); } Datetime(THD *thd, Item *item) :Temporal_with_date(Datetime(thd, item, Options(thd))) { } Datetime(Item *item) :Datetime(current_thd, item) { } Datetime(THD *thd, int *warn, const MYSQL_TIME *from, date_conv_mode_t flags); Datetime(THD *thd, MYSQL_TIME_STATUS *status, const char *str, size_t len, CHARSET_INFO *cs, const date_mode_t fuzzydate) :Temporal_with_date(thd, status, str, len, cs, fuzzydate) { date_to_datetime_if_needed(); DBUG_ASSERT(is_valid_value_slow()); } protected: Datetime(int *warn, const Sec6 &nr, date_mode_t flags) :Temporal_with_date(warn, nr, flags) { date_to_datetime_if_needed(); DBUG_ASSERT(is_valid_value_slow()); } Datetime(THD *thd, int *warn, const Sec9 &nr, date_mode_t fuzzydate) :Datetime(warn, static_cast(nr), fuzzydate) { if (is_valid_datetime() && time_round_mode_t(fuzzydate) == TIME_FRAC_ROUND) round_or_invalidate(thd, 6, warn, nr.nsec()); DBUG_ASSERT(is_valid_value_slow()); } public: Datetime(int *warn, const Longlong_hybrid &nr, date_mode_t mode) :Datetime(warn, Sec6(nr), mode) { } Datetime(THD *thd, int *warn, double nr, date_mode_t fuzzydate) :Datetime(thd, warn, Sec9(nr), fuzzydate) { } Datetime(THD *thd, int *warn, const my_decimal *d, date_mode_t fuzzydate) :Datetime(thd, warn, Sec9(d), fuzzydate) { } Datetime(THD *thd, const timeval &tv); Datetime(THD *thd, Item *item, date_mode_t fuzzydate, uint dec) :Datetime(thd, item, fuzzydate) { int warn= 0; round(thd, dec, time_round_mode_t(fuzzydate), &warn); } Datetime(THD *thd, MYSQL_TIME_STATUS *status, const char *str, size_t len, CHARSET_INFO *cs, date_mode_t fuzzydate, uint dec) :Datetime(thd, status, str, len, cs, fuzzydate) { round(thd, dec, time_round_mode_t(fuzzydate), &status->warnings); } Datetime(THD *thd, int *warn, double nr, date_mode_t fuzzydate, uint dec) :Datetime(thd, warn, nr, fuzzydate) { round(thd, dec, time_round_mode_t(fuzzydate), warn); } Datetime(THD *thd, int *warn, const my_decimal *d, date_mode_t fuzzydate, uint dec) :Datetime(thd, warn, d, fuzzydate) { round(thd, dec, time_round_mode_t(fuzzydate), warn); } Datetime(THD *thd, int *warn, const MYSQL_TIME *from, date_mode_t fuzzydate, uint dec) :Datetime(thd, warn, from, date_conv_mode_t(fuzzydate) & ~TIME_TIME_ONLY) { round(thd, dec, time_round_mode_t(fuzzydate), warn); } explicit Datetime(const Temporal_hybrid *from) { from->copy_valid_value_to_mysql_time(this); DBUG_ASSERT(is_valid_datetime_slow()); } explicit Datetime(const MYSQL_TIME *from) { *(static_cast(this))= *from; DBUG_ASSERT(is_valid_datetime_slow()); } Datetime(my_time_t unix_time, ulong second_part, const Time_zone* time_zone); bool is_valid_datetime() const { /* Here we quickly check for the type only. If the type is valid, the rest of value must also be valid. */ DBUG_ASSERT(is_valid_value_slow()); return time_type == MYSQL_TIMESTAMP_DATETIME; } bool check_date(date_conv_mode_t flags, int *warnings) const { DBUG_ASSERT(is_valid_datetime_slow()); return ::check_date(this, (year || month || day), ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), warnings); } bool check_date(date_conv_mode_t flags) const { int dummy; /* unused */ return check_date(flags, &dummy); } bool check_date(THD *thd) const { return check_date(Temporal::sql_mode_for_dates(thd)); } bool hhmmssff_is_zero() const { DBUG_ASSERT(is_valid_datetime_slow()); return hour == 0 && minute == 0 && second == 0 && second_part == 0; } ulong daynr() const { DBUG_ASSERT(is_valid_datetime_slow()); return Temporal_with_date::daynr(); } int weekday(bool sunday_first_day_of_week) const { DBUG_ASSERT(is_valid_datetime_slow()); return Temporal_with_date::weekday(sunday_first_day_of_week); } ulong dayofyear() const { DBUG_ASSERT(is_valid_datetime_slow()); return Temporal_with_date::dayofyear(); } uint quarter() const { DBUG_ASSERT(is_valid_datetime_slow()); return Temporal_with_date::quarter(); } uint week(uint week_behaviour) const { DBUG_ASSERT(is_valid_datetime_slow()); return Temporal_with_date::week(week_behaviour); } uint yearweek(uint week_behaviour) const { DBUG_ASSERT(is_valid_datetime_slow()); return Temporal_with_date::yearweek(week_behaviour); } longlong hhmmss_to_seconds_abs() const { DBUG_ASSERT(is_valid_datetime_slow()); return hour * 3600L + minute * 60 + second; } longlong hhmmss_to_seconds() const { return neg ? -hhmmss_to_seconds_abs() : hhmmss_to_seconds_abs(); } longlong to_seconds() const { return hhmmss_to_seconds() + (longlong) daynr() * 24L * 3600L; } const MYSQL_TIME *get_mysql_time() const { DBUG_ASSERT(is_valid_datetime_slow()); return this; } bool copy_to_mysql_time(MYSQL_TIME *ltime) const { if (time_type == MYSQL_TIMESTAMP_NONE) { ltime->time_type= MYSQL_TIMESTAMP_NONE; return true; } DBUG_ASSERT(is_valid_datetime_slow()); *ltime= *this; return false; } /** Copy without data loss, with an optional DATETIME to DATE conversion. If the value of the "type" argument is MYSQL_TIMESTAMP_DATE, then "this" must be a datetime with a zero hhmmssff part. */ bool copy_to_mysql_time(MYSQL_TIME *ltime, timestamp_type type) { DBUG_ASSERT(type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME); if (copy_to_mysql_time(ltime)) return true; DBUG_ASSERT(type != MYSQL_TIMESTAMP_DATE || hhmmssff_is_zero()); ltime->time_type= type; return false; } bool to_bool() const { return is_valid_datetime() && (TIME_to_ulonglong_datetime(this) != 0 || second_part != 0); } longlong to_longlong() const { return is_valid_datetime() ? (longlong) TIME_to_ulonglong_datetime(this) : 0LL; } double to_double() const { return !is_valid_datetime() ? 0 : Temporal::to_double(neg, TIME_to_ulonglong_datetime(this), second_part); } String *to_string(String *str, uint dec) const { if (!is_valid_datetime()) return NULL; str->set_charset(&my_charset_numeric); if (!str->alloc(MAX_DATE_STRING_REP_LENGTH)) str->length(my_datetime_to_str(this, const_cast(str->ptr()), dec)); return str; } my_decimal *to_decimal(my_decimal *to) { return is_valid_datetime() ? Temporal::to_decimal(to) : bad_to_decimal(to); } longlong to_packed() const { return is_valid_datetime() ? Temporal::to_packed() : 0; } longlong valid_datetime_to_packed() const { DBUG_ASSERT(is_valid_datetime_slow()); return Temporal::to_packed(); } long fraction_remainder(uint dec) const { DBUG_ASSERT(is_valid_datetime()); return Temporal::fraction_remainder(dec); } Datetime &trunc(uint dec) { if (is_valid_datetime()) my_datetime_trunc(this, dec); DBUG_ASSERT(is_valid_value_slow()); return *this; } Datetime &ceiling(THD *thd, int *warn) { if (is_valid_datetime() && second_part) round_or_invalidate(thd, 0, warn, 999999999); DBUG_ASSERT(is_valid_value_slow()); return *this; } Datetime &ceiling(THD *thd) { int warn= 0; return ceiling(thd, &warn); } Datetime &round(THD *thd, uint dec, int *warn) { if (is_valid_datetime()) round_or_invalidate(thd, dec, warn); DBUG_ASSERT(is_valid_value_slow()); return *this; } Datetime &round(THD *thd, uint dec, time_round_mode_t mode, int *warn) { switch (mode.mode()) { case time_round_mode_t::FRAC_NONE: DBUG_ASSERT(fraction_remainder(dec) == 0); return trunc(dec); case time_round_mode_t::FRAC_TRUNCATE: return trunc(dec); case time_round_mode_t::FRAC_ROUND: return round(thd, dec, warn); } return *this; } Datetime &round(THD *thd, uint dec, time_round_mode_t mode) { int warn= 0; return round(thd, dec, mode, &warn); } }; /* Datetime to be created from an Item who is known to be of a temporal data type. For temporal data types we don't need nanosecond rounding or truncation, as their precision is limited. */ class Datetime_from_temporal: public Datetime { public: // The constructor DBUG_ASSERTs on a proper Item data type. Datetime_from_temporal(THD *thd, Item *temporal, date_conv_mode_t flags); }; /* Datetime to be created from an Item who is known not to have digits outside of the specified scale. So it's not important which rounding method to use. TRUNCATE should work. Typically, Item is of a temporal data type, but this is not strictly required. */ class Datetime_truncation_not_needed: public Datetime { public: Datetime_truncation_not_needed(THD *thd, Item *item, date_conv_mode_t mode); Datetime_truncation_not_needed(THD *thd, Item *item, date_mode_t mode) :Datetime_truncation_not_needed(thd, item, date_conv_mode_t(mode)) { } }; class Timestamp: protected Timeval { static uint binary_length_to_precision(uint length); protected: void round_or_set_max(uint dec, int *warn); bool add_nanoseconds_usec(uint nanoseconds) { DBUG_ASSERT(nanoseconds <= 1000000000); if (nanoseconds < 500) return false; tv_usec+= (nanoseconds + 500) / 1000; if (tv_usec < 1000000) return false; tv_usec%= 1000000; return true; } public: static date_conv_mode_t sql_mode_for_timestamp(THD *thd); static time_round_mode_t default_round_mode(THD *thd); class DatetimeOptions: public date_mode_t { public: DatetimeOptions(date_conv_mode_t fuzzydate, time_round_mode_t round_mode) :date_mode_t(fuzzydate | round_mode) { } DatetimeOptions(THD *thd) :DatetimeOptions(sql_mode_for_timestamp(thd), default_round_mode(thd)) { } }; public: Timestamp(my_time_t timestamp, ulong sec_part) :Timeval(timestamp, sec_part) { } explicit Timestamp(const timeval &tv) :Timeval(tv) { } explicit Timestamp(const Native &native); Timestamp(THD *thd, const MYSQL_TIME *ltime, uint *error_code); const struct timeval &tv() const { return *this; } int cmp(const Timestamp &other) const { return tv_sec < other.tv_sec ? -1 : tv_sec > other.tv_sec ? +1 : tv_usec < other.tv_usec ? -1 : tv_usec > other.tv_usec ? +1 : 0; } bool to_TIME(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) const; bool to_native(Native *to, uint decimals) const; Datetime to_datetime(THD *thd) const { return Datetime(thd, *this); } long fraction_remainder(uint dec) const { return my_time_fraction_remainder(tv_usec, dec); } Timestamp &trunc(uint dec) { my_timeval_trunc(this, dec); return *this; } Timestamp &round(uint dec, int *warn) { round_or_set_max(dec, warn); return *this; } Timestamp &round(uint dec, time_round_mode_t mode, int *warn) { switch (mode.mode()) { case time_round_mode_t::FRAC_NONE: DBUG_ASSERT(fraction_remainder(dec) == 0); return trunc(dec); case time_round_mode_t::FRAC_TRUNCATE: return trunc(dec); case time_round_mode_t::FRAC_ROUND: return round(dec, warn); } return *this; } Timestamp &round(uint dec, time_round_mode_t mode) { int warn= 0; return round(dec, mode, &warn); } }; /** A helper class to store MariaDB TIMESTAMP values, which can be: - real TIMESTAMP (seconds and microseconds since epoch), or - zero datetime '0000-00-00 00:00:00.000000' */ class Timestamp_or_zero_datetime: protected Timestamp { bool m_is_zero_datetime; public: Timestamp_or_zero_datetime() :Timestamp(0,0), m_is_zero_datetime(true) { } Timestamp_or_zero_datetime(const Native &native) :Timestamp(native.length() ? Timestamp(native) : Timestamp(0,0)), m_is_zero_datetime(native.length() == 0) { } Timestamp_or_zero_datetime(const Timestamp &tm, bool is_zero_datetime) :Timestamp(tm), m_is_zero_datetime(is_zero_datetime) { } Timestamp_or_zero_datetime(THD *thd, const MYSQL_TIME *ltime, uint *err_code); Datetime to_datetime(THD *thd) const { if (is_zero_datetime()) return Datetime::zero(); return Timestamp::to_datetime(thd); } bool to_bool() const { return !m_is_zero_datetime; } bool is_zero_datetime() const { return m_is_zero_datetime; } void trunc(uint decimals) { if (!is_zero_datetime()) Timestamp::trunc(decimals); } int cmp(const Timestamp_or_zero_datetime &other) const { if (is_zero_datetime()) return other.is_zero_datetime() ? 0 : -1; if (other.is_zero_datetime()) return 1; return Timestamp::cmp(other); } bool to_TIME(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) const; /* Convert to native format: - Real timestamps are encoded in the same way how Field_timestamp2 stores values (big endian seconds followed by big endian microseconds) - Zero datetime '0000-00-00 00:00:00.000000' is encoded as empty string. Two native values are binary comparable. */ bool to_native(Native *to, uint decimals) const; }; /** A helper class to store non-null MariaDB TIMESTAMP values in the native binary encoded representation. */ class Timestamp_or_zero_datetime_native: public NativeBuffer { public: Timestamp_or_zero_datetime_native() = default; Timestamp_or_zero_datetime_native(const Timestamp_or_zero_datetime &ts, uint decimals) { if (ts.to_native(this, decimals)) length(0); // safety } int save_in_field(Field *field, uint decimals) const; Datetime to_datetime(THD *thd) const { return is_zero_datetime() ? Datetime::zero() : Datetime(thd, Timestamp(*this).tv()); } bool is_zero_datetime() const { return length() == 0; } }; /** A helper class to store nullable MariaDB TIMESTAMP values in the native binary encoded representation. */ class Timestamp_or_zero_datetime_native_null: public Timestamp_or_zero_datetime_native, public Null_flag { public: // With optional data type conversion Timestamp_or_zero_datetime_native_null(THD *thd, Item *item, bool conv); // Without data type conversion: item is known to be of the TIMESTAMP type Timestamp_or_zero_datetime_native_null(THD *thd, Item *item) :Timestamp_or_zero_datetime_native_null(thd, item, false) { } Datetime to_datetime(THD *thd) const { return is_null() ? Datetime() : Timestamp_or_zero_datetime_native::to_datetime(thd); } void to_TIME(THD *thd, MYSQL_TIME *to) { DBUG_ASSERT(!is_null()); Datetime::Options opt(TIME_CONV_NONE, TIME_FRAC_NONE); Timestamp_or_zero_datetime(*this).to_TIME(thd, to, opt); } bool is_zero_datetime() const { DBUG_ASSERT(!is_null()); return Timestamp_or_zero_datetime_native::is_zero_datetime(); } }; /* Flags for collation aggregation modes, used in TDCollation::agg(): MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value (i.e. constant). MY_COLL_ALLOW_CONV - allow any kind of conversion (combination of the above two) MY_COLL_ALLOW_NUMERIC_CONV - if all items were numbers, convert to @@character_set_connection MY_COLL_DISALLOW_NONE - don't allow return DERIVATION_NONE (e.g. when aggregating for comparison) MY_COLL_CMP_CONV - combination of MY_COLL_ALLOW_CONV and MY_COLL_DISALLOW_NONE */ #define MY_COLL_ALLOW_SUPERSET_CONV 1 #define MY_COLL_ALLOW_COERCIBLE_CONV 2 #define MY_COLL_DISALLOW_NONE 4 #define MY_COLL_ALLOW_NUMERIC_CONV 8 #define MY_COLL_ALLOW_CONV (MY_COLL_ALLOW_SUPERSET_CONV | MY_COLL_ALLOW_COERCIBLE_CONV) #define MY_COLL_CMP_CONV (MY_COLL_ALLOW_CONV | MY_COLL_DISALLOW_NONE) #define MY_REPERTOIRE_NUMERIC MY_REPERTOIRE_ASCII static inline my_repertoire_t operator|(const my_repertoire_t a, const my_repertoire_t b) { return (my_repertoire_t) ((uint) a | (uint) b); } static inline my_repertoire_t &operator|=(my_repertoire_t &a, const my_repertoire_t b) { return a= (my_repertoire_t) ((uint) a | (uint) b); } enum Derivation { DERIVATION_IGNORABLE= 6, DERIVATION_NUMERIC= 5, DERIVATION_COERCIBLE= 4, DERIVATION_SYSCONST= 3, DERIVATION_IMPLICIT= 2, DERIVATION_NONE= 1, DERIVATION_EXPLICIT= 0 }; /** "Declared Type Collation" A combination of collation and its derivation. */ class DTCollation { public: CHARSET_INFO *collation; enum Derivation derivation; my_repertoire_t repertoire; void set_repertoire_from_charset(CHARSET_INFO *cs) { repertoire= cs->state & MY_CS_PUREASCII ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30; } DTCollation() { collation= &my_charset_bin; derivation= DERIVATION_NONE; repertoire= MY_REPERTOIRE_UNICODE30; } DTCollation(CHARSET_INFO *collation_arg) { /* This constructor version is used in combination with Field constructors, to pass "CHARSET_INFO" instead of the full DTCollation. Therefore, derivation is set to DERIVATION_IMPLICIT, which is the proper derivation for table fields. We should eventually remove all code pieces that pass "CHARSET_INFO" (e.g. in storage engine sources) and fix to pass the full DTCollation instead. Then, this constructor can be removed. */ collation= collation_arg; derivation= DERIVATION_IMPLICIT; repertoire= my_charset_repertoire(collation_arg); } DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg) { collation= collation_arg; derivation= derivation_arg; set_repertoire_from_charset(collation_arg); } DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg, my_repertoire_t repertoire_arg) :collation(collation_arg), derivation(derivation_arg), repertoire(repertoire_arg) { } void set(const DTCollation &dt) { *this= dt; } void set(CHARSET_INFO *collation_arg, Derivation derivation_arg) { collation= collation_arg; derivation= derivation_arg; set_repertoire_from_charset(collation_arg); } void set(CHARSET_INFO *collation_arg, Derivation derivation_arg, my_repertoire_t repertoire_arg) { collation= collation_arg; derivation= derivation_arg; repertoire= repertoire_arg; } void set(CHARSET_INFO *collation_arg) { collation= collation_arg; set_repertoire_from_charset(collation_arg); } void set(Derivation derivation_arg) { derivation= derivation_arg; } bool aggregate(const DTCollation &dt, uint flags= 0); bool set(DTCollation &dt1, DTCollation &dt2, uint flags= 0) { set(dt1); return aggregate(dt2, flags); } const char *derivation_name() const { switch(derivation) { case DERIVATION_NUMERIC: return "NUMERIC"; case DERIVATION_IGNORABLE: return "IGNORABLE"; case DERIVATION_COERCIBLE: return "COERCIBLE"; case DERIVATION_IMPLICIT: return "IMPLICIT"; case DERIVATION_SYSCONST: return "SYSCONST"; case DERIVATION_EXPLICIT: return "EXPLICIT"; case DERIVATION_NONE: return "NONE"; default: return "UNKNOWN"; } } int sortcmp(const Binary_string *s, const Binary_string *t) const { return collation->strnncollsp(s->ptr(), s->length(), t->ptr(), t->length()); } }; class DTCollation_numeric: public DTCollation { public: DTCollation_numeric() :DTCollation(charset_info(), DERIVATION_NUMERIC, MY_REPERTOIRE_NUMERIC) { } static const CHARSET_INFO *charset_info() { return &my_charset_numeric; } static const DTCollation & singleton(); }; static inline uint32 char_to_byte_length_safe(size_t char_length_arg, uint32 mbmaxlen_arg) { ulonglong tmp= ((ulonglong) char_length_arg) * mbmaxlen_arg; return tmp > UINT_MAX32 ? (uint32) UINT_MAX32 : static_cast(tmp); } class Type_numeric_attributes { public: static uint count_unsigned(Item **item, uint nitems); static uint32 find_max_char_length(Item **item, uint nitems); static uint32 find_max_octet_length(Item **item, uint nitems); static decimal_digits_t find_max_decimal_int_part(Item **item, uint nitems); static decimal_digits_t find_max_decimals(Item **item, uint nitems); public: /* The maximum value length in characters multiplied by collation->mbmaxlen. Almost always it's the maximum value length in bytes. */ uint32 max_length; decimal_digits_t decimals; bool unsigned_flag; public: Type_numeric_attributes() :max_length(0), decimals(0), unsigned_flag(false) { } Type_numeric_attributes(uint32 max_length_arg, decimal_digits_t decimals_arg, bool unsigned_flag_arg) :max_length(max_length_arg), decimals(decimals_arg), unsigned_flag(unsigned_flag_arg) { } protected: void aggregate_numeric_attributes_real(Item **item, uint nitems); void aggregate_numeric_attributes_decimal(Item **item, uint nitems, bool unsigned_arg); }; class Type_temporal_attributes: public Type_numeric_attributes { public: Type_temporal_attributes(uint32 int_part_length, decimal_digits_t dec, bool unsigned_arg) :Type_numeric_attributes(int_part_length + (dec ? 1 : 0), MY_MIN(dec, (decimal_digits_t) TIME_SECOND_PART_DIGITS), unsigned_arg) { max_length+= decimals; } }; class Type_temporal_attributes_not_fixed_dec: public Type_numeric_attributes { public: Type_temporal_attributes_not_fixed_dec(uint32 int_part_length, decimal_digits_t dec, bool unsigned_flag) :Type_numeric_attributes(int_part_length, dec, unsigned_flag) { if (decimals == NOT_FIXED_DEC) max_length+= TIME_SECOND_PART_DIGITS + 1; else if (decimals) { set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); max_length+= decimals + 1; } } }; /** A class to store type attributes for the standard data types. Does not include attributes for the extended data types such as ENUM, SET, GEOMETRY. */ class Type_std_attributes: public Type_numeric_attributes { public: DTCollation collation; Type_std_attributes() :collation(&my_charset_bin, DERIVATION_COERCIBLE) { } Type_std_attributes(const Type_numeric_attributes &nattr, const DTCollation &dtc) :Type_numeric_attributes(nattr), collation(dtc) { } void set(const Type_std_attributes *other) { *this= *other; } void set(const Type_std_attributes &other) { *this= other; } void set(const Type_numeric_attributes &nattr, const DTCollation &dtc) { *this= Type_std_attributes(nattr, dtc); } uint32 max_char_length() const { return max_length / collation.collation->mbmaxlen; } void fix_length_and_charset(uint32 max_char_length_arg, CHARSET_INFO *cs) { max_length= char_to_byte_length_safe(max_char_length_arg, cs->mbmaxlen); collation.collation= cs; } void fix_char_length(uint32 max_char_length_arg) { max_length= char_to_byte_length_safe(max_char_length_arg, collation.collation->mbmaxlen); } void fix_attributes_temporal(uint32 int_part_length, decimal_digits_t dec) { *this= Type_std_attributes( Type_temporal_attributes(int_part_length, dec, false), DTCollation_numeric()); } void fix_attributes_date() { fix_attributes_temporal(MAX_DATE_WIDTH, 0); } void fix_attributes_time(decimal_digits_t dec) { fix_attributes_temporal(MIN_TIME_WIDTH, dec); } void fix_attributes_datetime(decimal_digits_t dec) { fix_attributes_temporal(MAX_DATETIME_WIDTH, dec); } void aggregate_attributes_int(Item **items, uint nitems) { collation= DTCollation_numeric(); fix_char_length(find_max_char_length(items, nitems)); unsigned_flag= count_unsigned(items, nitems) > 0; decimals= 0; } void aggregate_attributes_real(Item **items, uint nitems) { collation= DTCollation_numeric(); aggregate_numeric_attributes_real(items, nitems); } void aggregate_attributes_decimal(Item **items, uint nitems, bool unsigned_arg) { collation= DTCollation_numeric(); aggregate_numeric_attributes_decimal(items, nitems, (unsigned_flag= unsigned_arg)); } bool aggregate_attributes_string(const LEX_CSTRING &func_name, Item **item, uint nitems); void aggregate_attributes_temporal(uint int_part_length, Item **item, uint nitems) { fix_attributes_temporal(int_part_length, find_max_decimals(item, nitems)); } bool agg_item_collations(DTCollation &c, const LEX_CSTRING &name, Item **items, uint nitems, uint flags, int item_sep); struct Single_coll_err { const DTCollation& coll; bool first; }; bool agg_item_set_converter(const DTCollation &coll, const LEX_CSTRING &name, Item **args, uint nargs, uint flags, int item_sep, const Single_coll_err *single_item_err= NULL); /* Collect arguments' character sets together. We allow to apply automatic character set conversion in some cases. The conditions when conversion is possible are: - arguments A and B have different charsets - A wins according to coercibility rules (i.e. a column is stronger than a string constant, an explicit COLLATE clause is stronger than a column) - character set of A is either superset for character set of B, or B is a string constant which can be converted into the character set of A without data loss. If all of the above is true, then it's possible to convert B into the character set of A, and then compare according to the collation of A. For functions with more than two arguments: collect(A,B,C) ::= collect(collect(A,B),C) Since this function calls THD::change_item_tree() on the passed Item ** pointers, it is necessary to pass the original Item **'s, not copies. Otherwise their values will not be properly restored (see BUG#20769). If the items are not consecutive (eg. args[2] and args[5]), use the item_sep argument, ie. agg_item_charsets(coll, fname, &args[2], 2, flags, 3) */ bool agg_arg_charsets(DTCollation &c, const LEX_CSTRING &func_name, Item **items, uint nitems, uint flags, int item_sep) { if (agg_item_collations(c, func_name, items, nitems, flags, item_sep)) return true; return agg_item_set_converter(c, func_name, items, nitems, flags, item_sep); } /* Aggregate arguments for string result, e.g: CONCAT(a,b) - convert to @@character_set_connection if all arguments are numbers - allow DERIVATION_NONE */ bool agg_arg_charsets_for_string_result(DTCollation &c, const LEX_CSTRING &func_name, Item **items, uint nitems, int item_sep) { uint flags= MY_COLL_ALLOW_SUPERSET_CONV | MY_COLL_ALLOW_COERCIBLE_CONV | MY_COLL_ALLOW_NUMERIC_CONV; return agg_arg_charsets(c, func_name, items, nitems, flags, item_sep); } /* Aggregate arguments for string result, when some comparison is involved internally, e.g: REPLACE(a,b,c) - convert to @@character_set_connection if all arguments are numbers - disallow DERIVATION_NONE */ bool agg_arg_charsets_for_string_result_with_comparison(DTCollation &c, const LEX_CSTRING &func_name, Item **items, uint nitems, int item_sep) { uint flags= MY_COLL_ALLOW_SUPERSET_CONV | MY_COLL_ALLOW_COERCIBLE_CONV | MY_COLL_ALLOW_NUMERIC_CONV | MY_COLL_DISALLOW_NONE; return agg_arg_charsets(c, func_name, items, nitems, flags, item_sep); } /* Aggregate arguments for comparison, e.g: a=b, a LIKE b, a RLIKE b - don't convert to @@character_set_connection if all arguments are numbers - don't allow DERIVATION_NONE */ bool agg_arg_charsets_for_comparison(DTCollation &c, const LEX_CSTRING &func_name, Item **items, uint nitems, int item_sep) { uint flags= MY_COLL_ALLOW_SUPERSET_CONV | MY_COLL_ALLOW_COERCIBLE_CONV | MY_COLL_DISALLOW_NONE; return agg_arg_charsets(c, func_name, items, nitems, flags, item_sep); } }; class Type_all_attributes: public Type_std_attributes { public: Type_all_attributes() = default; Type_all_attributes(const Type_all_attributes &) = default; virtual ~Type_all_attributes() = default; virtual void set_type_maybe_null(bool maybe_null_arg)= 0; virtual uint32 character_octet_length() const { return max_length; } // Returns total number of decimal digits virtual decimal_digits_t decimal_precision() const= 0; virtual const TYPELIB *get_typelib() const= 0; virtual void set_typelib(const TYPELIB *typelib)= 0; }; class Type_cmp_attributes { public: virtual ~Type_cmp_attributes() = default; virtual CHARSET_INFO *compare_collation() const= 0; }; class Type_cast_attributes { CHARSET_INFO *m_charset; ulonglong m_length; ulonglong m_decimals; bool m_length_specified; bool m_decimals_specified; public: Type_cast_attributes(const char *c_len, const char *c_dec, CHARSET_INFO *cs) :m_charset(cs), m_length(0), m_decimals(0), m_length_specified(false), m_decimals_specified(false) { set_length_and_dec(c_len, c_dec); } Type_cast_attributes(CHARSET_INFO *cs) :m_charset(cs), m_length(0), m_decimals(0), m_length_specified(false), m_decimals_specified(false) { } void set_length_and_dec(const char *c_len, const char *c_dec) { int error; /* We don't have to check for error here as sql_yacc.yy has guaranteed that the values are in range of ulonglong */ if ((m_length_specified= (c_len != NULL))) m_length= (ulonglong) my_strtoll10(c_len, NULL, &error); if ((m_decimals_specified= (c_dec != NULL))) m_decimals= (ulonglong) my_strtoll10(c_dec, NULL, &error); } CHARSET_INFO *charset() const { return m_charset; } bool length_specified() const { return m_length_specified; } bool decimals_specified() const { return m_decimals_specified; } ulonglong length() const { return m_length; } ulonglong decimals() const { return m_decimals; } }; class Name: private LEX_CSTRING { public: Name(const char *str_arg, uint length_arg) { DBUG_ASSERT(length_arg < UINT_MAX32); LEX_CSTRING::str= str_arg; LEX_CSTRING::length= length_arg; } Name(const LEX_CSTRING &lcs) { LEX_CSTRING::str= lcs.str; LEX_CSTRING::length= lcs.length; } const char *ptr() const { return LEX_CSTRING::str; } uint length() const { return (uint) LEX_CSTRING::length; } const LEX_CSTRING &lex_cstring() const { return *this; } bool eq(const LEX_CSTRING &other) const { return !system_charset_info->strnncoll(LEX_CSTRING::str, LEX_CSTRING::length, other.str, other.length); } }; class Bit_addr { /** Byte where the bit is stored inside a record. If the corresponding Field is a NOT NULL field, this member is NULL. */ uchar *m_ptr; /** Offset of the bit inside m_ptr[0], in the range 0..7. */ uchar m_offs; public: Bit_addr() :m_ptr(NULL), m_offs(0) { } Bit_addr(uchar *ptr, uchar offs) :m_ptr(ptr), m_offs(offs) { DBUG_ASSERT(ptr || offs == 0); DBUG_ASSERT(offs < 8); } Bit_addr(bool maybe_null) :m_ptr(maybe_null ? (uchar *) "" : NULL), m_offs(0) { } uchar *ptr() const { return m_ptr; } uchar offs() const { return m_offs; } uchar bit() const { return static_cast(m_ptr ? 1U << m_offs : 0); } void inc() { DBUG_ASSERT(m_ptr); m_ptr+= (m_offs == 7); m_offs= (m_offs + 1) & 7; } }; class Record_addr { uchar *m_ptr; // Position of the field in the record Bit_addr m_null; // Position and offset of the null bit public: Record_addr(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg) :m_ptr(ptr_arg), m_null(null_ptr_arg, null_bit_arg) { } Record_addr(uchar *ptr, const Bit_addr &null) :m_ptr(ptr), m_null(null) { } Record_addr(bool maybe_null) :m_ptr(NULL), m_null(maybe_null) { } uchar *ptr() const { return m_ptr; } const Bit_addr &null() const { return m_null; } uchar *null_ptr() const { return m_null.ptr(); } uchar null_bit() const { return m_null.bit(); } }; class Information_schema_numeric_attributes { enum enum_attr { ATTR_NONE= 0, ATTR_PRECISION= 1, ATTR_SCALE= 2, ATTR_PRECISION_AND_SCALE= (ATTR_PRECISION|ATTR_SCALE) }; uint m_precision; decimal_digits_t m_scale; enum_attr m_available_attributes; public: Information_schema_numeric_attributes() :m_precision(0), m_scale(0), m_available_attributes(ATTR_NONE) { } Information_schema_numeric_attributes(uint precision) :m_precision(precision), m_scale(0), m_available_attributes(ATTR_PRECISION) { } Information_schema_numeric_attributes(uint precision, decimal_digits_t scale) :m_precision(precision), m_scale(scale), m_available_attributes(ATTR_PRECISION_AND_SCALE) { } bool has_precision() const { return m_available_attributes & ATTR_PRECISION; } bool has_scale() const { return m_available_attributes & ATTR_SCALE; } uint precision() const { DBUG_ASSERT(has_precision()); return (uint) m_precision; } decimal_digits_t scale() const { DBUG_ASSERT(has_scale()); return m_scale; } }; class Information_schema_character_attributes { uint32 m_octet_length; uint32 m_char_length; bool m_is_set; public: Information_schema_character_attributes() :m_octet_length(0), m_char_length(0), m_is_set(false) { } Information_schema_character_attributes(uint32 octet_length, uint32 char_length) :m_octet_length(octet_length), m_char_length(char_length), m_is_set(true) { } bool has_octet_length() const { return m_is_set; } bool has_char_length() const { return m_is_set; } uint32 octet_length() const { DBUG_ASSERT(has_octet_length()); return m_octet_length; } uint char_length() const { DBUG_ASSERT(has_char_length()); return m_char_length; } }; enum vers_kind_t { VERS_UNDEFINED= 0, VERS_TIMESTAMP, VERS_TRX_ID }; class Vers_type_handler { protected: Vers_type_handler() = default; public: virtual ~Vers_type_handler() = default; virtual vers_kind_t kind() const { DBUG_ASSERT(0); return VERS_UNDEFINED; } virtual bool check_sys_fields(const LEX_CSTRING &table_name, const Column_definition *row_start, const Column_definition *row_end) const= 0; }; class Vers_type_timestamp: public Vers_type_handler { public: vers_kind_t kind() const override { return VERS_TIMESTAMP; } bool check_sys_fields(const LEX_CSTRING &table_name, const Column_definition *row_start, const Column_definition *row_end) const override; }; extern Vers_type_timestamp vers_type_timestamp; class Vers_type_trx: public Vers_type_handler { public: vers_kind_t kind() const override { return VERS_TRX_ID; } bool check_sys_fields(const LEX_CSTRING &table_name, const Column_definition *row_start, const Column_definition *row_end) const override; }; extern MYSQL_PLUGIN_IMPORT Vers_type_trx vers_type_trx; class Type_handler { Name m_name; protected: String *print_item_value_csstr(THD *thd, Item *item, String *str) const; String *print_item_value_temporal(THD *thd, Item *item, String *str, const Name &type_name, String *buf) const; void make_sort_key_longlong(uchar *to, bool maybe_null, bool null_value, bool unsigned_flag, longlong value) const; void store_sort_key_longlong(uchar *to, bool unsigned_flag, longlong value) const; uint make_packed_sort_key_longlong(uchar *to, bool maybe_null, bool null_value, bool unsigned_flag, longlong value, const SORT_FIELD_ATTR *sort_field) const; bool Item_func_or_sum_illegal_param(const LEX_CSTRING &name) const; bool Item_func_or_sum_illegal_param(const Item_func_or_sum *) const; bool check_null(const Item *item, st_value *value) const; bool Item_send_str(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_tiny(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_short(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_long(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_longlong(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_float(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_double(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_time(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_date(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_timestamp(Item *item, Protocol *protocol, st_value *buf) const; bool Item_send_datetime(Item *item, Protocol *protocol, st_value *buf) const; bool Column_definition_prepare_stage2_legacy(Column_definition *c, enum_field_types type) const; bool Column_definition_prepare_stage2_legacy_num(Column_definition *c, enum_field_types type) const; bool Column_definition_prepare_stage2_legacy_real(Column_definition *c, enum_field_types type) const; public: static const Type_handler *handler_by_name(THD *thd, const LEX_CSTRING &name); static const Type_handler *handler_by_name_or_error(THD *thd, const LEX_CSTRING &name); static const Type_handler *handler_by_log_event_data_type( THD *thd, const Log_event_data_type &type); static const Type_handler *odbc_literal_type_handler(const LEX_CSTRING *str); static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); static const Type_handler *bit_and_int_mixture_handler(uint max_char_len); static const Type_handler *type_handler_long_or_longlong(uint max_char_len, bool unsigned_flag); /** Return a string type handler for Item If too_big_for_varchar() returns a BLOB variant, according to length. If max_length > 0 create a VARCHAR(n) If max_length == 0 create a CHAR(0) @param item - the Item to get the handler to. */ static const Type_handler *varstring_type_handler(const Item *item); static const Type_handler *blob_type_handler(const Item *item); static const Type_handler *get_handler_by_field_type(enum_field_types type); static const Type_handler *get_handler_by_real_type(enum_field_types type); static const Type_collection * type_collection_for_aggregation(const Type_handler *h1, const Type_handler *h2); virtual const Type_collection *type_collection() const; static const Type_handler *aggregate_for_result_traditional(const Type_handler *h1, const Type_handler *h2); virtual Schema *schema() const; static void partition_field_type_not_allowed(const LEX_CSTRING &field_name); static bool partition_field_check_result_type(Item *item, Item_result expected_type); static const Name & version_mysql56(); static const Name & version_mariadb53(); void set_name(Name n) { DBUG_ASSERT(!m_name.ptr()); m_name= n; } const Name name() const { return m_name; } virtual const Name version() const; virtual const Name &default_value() const= 0; virtual uint32 flags() const { return 0; } virtual ulong KEY_pack_flags(uint column_nr) const { return 0; } bool is_unsigned() const { return flags() & UNSIGNED_FLAG; } virtual enum_field_types field_type() const= 0; virtual enum_field_types real_field_type() const { return field_type(); } /** Type code which is used for merging of traditional data types for result (for UNION and for hybrid functions such as COALESCE). Mapping can be done both ways: old->new, new->old, depending on the particular data type implementation: - type_handler_var_string (MySQL-4.1 old VARCHAR) is converted to new VARCHAR before merging. field_type_merge_rules[][] returns new VARCHAR. - type_handler_newdate is converted to old DATE before merging. field_type_merge_rules[][] returns NEWDATE. - Temporal type_handler_xxx2 (new MySQL-5.6 types) are converted to corresponding old type codes before merging (e.g. TIME2->TIME). field_type_merge_rules[][] returns old type codes (e.g. TIME). Then old types codes are supposed to convert to new type codes somehow, but they do not. So UNION and COALESCE create old columns. This is a bug and should be fixed eventually. */ virtual enum_field_types traditional_merge_field_type() const { DBUG_ASSERT(is_traditional_scalar_type()); return field_type(); } virtual enum_field_types type_code_for_protocol() const { return field_type(); } virtual protocol_send_type_t protocol_send_type() const= 0; virtual bool Item_append_extended_type_info(Send_field_extended_metadata *to, const Item *item) const { return false; } virtual Item_result result_type() const= 0; virtual Item_result cmp_type() const= 0; virtual enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const= 0; virtual enum_mysql_timestamp_type mysql_timestamp_type() const { return MYSQL_TIMESTAMP_ERROR; } /* Return true if the native format is fully implemented for a data type: - Field_xxx::val_native() - Item_xxx::val_native() for all classes supporting this data type - Type_handler_xxx::cmp_native() */ virtual bool is_val_native_ready() const { return false; } /* If operations such as: UPDATE t1 SET binary_string_field=this_type_field; should store this_type_field->val_native() rather than this_type_field->val_str(). */ virtual bool convert_to_binary_using_val_native() const { return false; } virtual bool is_timestamp_type() const { return false; } virtual bool is_order_clause_position_type() const { return false; } virtual bool is_limit_clause_valid_type() const { return false; } /* Returns true if this data type supports a hack that WHERE notnull_column IS NULL finds zero values, e.g.: WHERE date_notnull_column IS NULL -> WHERE date_notnull_column = '0000-00-00' */ virtual bool cond_notnull_field_isnull_to_field_eq_zero() const { return false; } /** Check whether a field type can be partially indexed by a key. @param type field type @retval true Type can have a prefixed key @retval false Type can not have a prefixed key */ virtual bool type_can_have_key_part() const { return false; } virtual bool type_can_have_auto_increment_attribute() const { return false; } virtual uint max_octet_length() const { return 0; } /** Prepared statement long data: Check whether this parameter data type is compatible with long data. Used to detect whether a long data stream has been supplied to a incompatible data type. */ virtual bool is_param_long_data_type() const { return false; } /* The base type handler "this" is derived from. "This" inherits aggregation rules from the base type handler. */ virtual const Type_handler *type_handler_base() const { return NULL; } const Type_handler *type_handler_base_or_self() const { const Type_handler *res= type_handler_base(); return res ? res : this; } virtual const Type_handler *type_handler_for_comparison() const= 0; virtual const Type_handler *type_handler_for_native_format() const { return this; } virtual const Type_handler *type_handler_for_item_field() const { return this; } virtual const Type_handler *type_handler_for_tmp_table(const Item *) const { return this; } virtual const Type_handler *type_handler_for_union(const Item *) const { return this; } virtual const Type_handler *cast_to_int_type_handler() const { return this; } virtual const Type_handler *type_handler_unsigned() const { return this; } virtual const Type_handler *type_handler_signed() const { return this; } virtual bool partition_field_check(const LEX_CSTRING &field_name, Item *) const { partition_field_type_not_allowed(field_name); return true; } virtual bool partition_field_append_value(String *str, Item *item_expr, CHARSET_INFO *field_cs, partition_value_print_mode_t mode) const; virtual int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const= 0; virtual CHARSET_INFO *charset_for_protocol(const Item *item) const; virtual const Type_handler* type_handler_adjusted_to_max_octet_length(uint max_octet_length, CHARSET_INFO *cs) const { return this; } virtual bool adjust_spparam_type(Spvar_definition *def, Item *from) const { return false; } Type_handler() : m_name(0,0) {} virtual ~Type_handler() = default; /** Determines MariaDB traditional scalar data types that always present in the server. */ bool is_traditional_scalar_type() const; virtual bool is_scalar_type() const { return true; } virtual bool can_return_int() const { return true; } virtual bool can_return_decimal() const { return true; } virtual bool can_return_real() const { return true; } virtual bool can_return_str() const { return true; } virtual bool can_return_text() const { return true; } virtual bool can_return_date() const { return true; } virtual bool can_return_time() const { return true; } virtual bool can_return_extract_source(interval_type type) const; virtual bool is_bool_type() const { return false; } virtual bool is_general_purpose_string_type() const { return false; } virtual decimal_digits_t Item_time_precision(THD *thd, Item *item) const; virtual decimal_digits_t Item_datetime_precision(THD *thd, Item *item) const; virtual decimal_digits_t Item_decimal_scale(const Item *item) const; virtual decimal_digits_t Item_decimal_precision(const Item *item) const= 0; /* Returns how many digits a divisor adds into a division result. See Item::divisor_precision_increment() in item.h for more comments. */ virtual decimal_digits_t Item_divisor_precision_increment(const Item *) const; /** Makes a temporary table Field to handle numeric aggregate functions, e.g. SUM(DISTINCT expr), AVG(DISTINCT expr), etc. */ virtual Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; /** Makes a temporary table Field to handle RBR replication type conversion. @param TABLE - The conversion table the field is going to be added to. It's used to access to table->in_use->mem_root, to create the new field on the table memory root, as well as to increment statistics in table->share (e.g. table->s->blob_count). @param metadata - Metadata from the binary log. @param target - The field in the target table on the slave. Note, the data types of "target" and of "this" are not necessarily always the same, in general case it's possible that: this->field_type() != target->field_type() and/or this->real_type( ) != target->real_type() This method decodes metadata according to this->real_type() and creates a new field also according to this->real_type(). In some cases it lurks into "target", to get some extra information, e.g.: - unsigned_flag for numeric fields - charset() for string fields - typelib and field_length for SET and ENUM - geom_type and srid for GEOMETRY This information is not available in the binary log, so we assume that these fields are the same on the master and on the slave. */ virtual Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const= 0; virtual void show_binlog_type(const Conv_source &src, const Field &dst, String *str) const; virtual uint32 max_display_length_for_field(const Conv_source &src) const= 0; /* Performs the final data type validation for a UNION element, after the regular "aggregation for result" was done. */ virtual bool union_element_finalize(Item_type_holder* item) const { return false; } virtual Log_event_data_type user_var_log_event_data_type(uint charset_nr) const { return Log_event_data_type({NULL,0}/*data type name*/, result_type(), charset_nr, is_unsigned()); } virtual uint Column_definition_gis_options_image(uchar *buff, const Column_definition &def) const { return 0; } virtual bool Column_definition_data_type_info_image(Binary_string *to, const Column_definition &def) const; // Check if the implicit default value is Ok in the current sql_mode virtual bool validate_implicit_default_value(THD *thd, const Column_definition &def) const; // Automatic upgrade, e.g. for ALTER TABLE t1 FORCE virtual void Column_definition_implicit_upgrade(Column_definition *c) const { } // Validate CHECK constraint after the parser virtual bool Column_definition_validate_check_constraint(THD *thd, Column_definition *c) const; // Set attributes in the parser virtual bool Column_definition_set_attributes(THD *thd, Column_definition *def, const Lex_field_type_st &attr, CHARSET_INFO *cs, column_definition_type_t type) const; // Fix attributes after the parser virtual bool Column_definition_fix_attributes(Column_definition *c) const= 0; /* Fix attributes from an existing field. Used for: - ALTER TABLE (for columns that do not change) - DECLARE var TYPE OF t1.col1; (anchored SP variables) */ virtual void Column_definition_reuse_fix_attributes(THD *thd, Column_definition *c, const Field *field) const { } virtual bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const; virtual bool Column_definition_bulk_alter(Column_definition *c, const Column_derived_attributes *derived_attr, const Column_bulk_alter_attributes *bulk_alter_attr) const { return false; } /* This method is called on queries like: CREATE TABLE t2 (a INT) AS SELECT a FROM t1; I.e. column "a" is queried from another table, but its data type is redefined. @param OUT def - The column definition to be redefined @param IN dup - The column definition to take the data type from (i.e. "a INT" in the above example). @param IN file - Table owner handler. If it does not support certain data types, some conversion can be applied. I.g. true BIT to BIT-AS-CHAR. @param IN schema - the owner schema definition, e.g. for the default character set and collation. @retval true - on error @retval false - on success */ virtual bool Column_definition_redefine_stage1(Column_definition *def, const Column_definition *dup, const handler *file) const; virtual bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const= 0; virtual bool Key_part_spec_init_primary(Key_part_spec *part, const Column_definition &def, const handler *file) const; virtual bool Key_part_spec_init_unique(Key_part_spec *part, const Column_definition &def, const handler *file, bool *has_key_needed) const; virtual bool Key_part_spec_init_multiple(Key_part_spec *part, const Column_definition &def, const handler *file) const; virtual bool Key_part_spec_init_foreign(Key_part_spec *part, const Column_definition &def, const handler *file) const; virtual bool Key_part_spec_init_spatial(Key_part_spec *part, const Column_definition &def) const; virtual bool Key_part_spec_init_ft(Key_part_spec *part, const Column_definition &def) const { return true; // Error } virtual Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const= 0; Field *make_and_init_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; virtual Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const { DBUG_ASSERT(0); return NULL; } virtual Field * make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const= 0; virtual void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const; virtual const Type_handler *type_handler_frm_unpack(const uchar *buffer) const { return this; } virtual bool Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, TABLE_SHARE *share, const uchar *buffer, LEX_CUSTRING *gis_options) const; /* Create a fixed size key part for a sort key */ virtual void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const= 0; /* create a compact size key part for a sort key */ virtual uint make_packed_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const=0; virtual void sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const= 0; virtual bool is_packable() const { return false; } virtual uint32 max_display_length(const Item *item) const= 0; virtual uint32 Item_decimal_notation_int_digits(const Item *item) const { return 0; } virtual uint32 calc_pack_length(uint32 length) const= 0; virtual uint calc_key_length(const Column_definition &def) const; virtual void Item_update_null_value(Item *item) const= 0; virtual bool Item_save_in_value(THD *thd, Item *item, st_value *value) const= 0; virtual void Item_param_setup_conversion(THD *thd, Item_param *) const {} virtual void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const; virtual bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *value) const= 0; virtual bool Item_param_val_native(THD *thd, Item_param *item, Native *to) const; virtual bool Item_send(Item *item, Protocol *p, st_value *buf) const= 0; virtual int Item_save_in_field(Item *item, Field *field, bool no_conversions) const= 0; /** Return a string representation of the Item value. @param thd thread handle @param str string buffer for representation of the value @note If the item has a string result type, the string is escaped according to its character set. @retval NULL on error @retval non-NULL a pointer to a a valid string on success */ virtual String *print_item_value(THD *thd, Item *item, String *str) const= 0; /** Check if WHERE expr=value AND expr=const can be rewritten as: WHERE const=value AND expr=const "this" is the comparison handler that is used by "target". @param target - the predicate expr=value, whose "expr" argument will be replaced to "const". @param target_expr - the target's "expr" which will be replaced to "const". @param target_value - the target's second argument, it will remain unchanged. @param source - the equality predicate expr=const (or expr<=>const) that can be used to rewrite the "target" part (under certain conditions, see the code). @param source_expr - the source's "expr". It should be exactly equal to the target's "expr" to make condition rewrite possible. @param source_const - the source's "const" argument, it will be inserted into "target" instead of "expr". */ virtual bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const= 0; /* @brief Check if an IN subquery allows materialization or not @param inner expression on the inner side of the IN subquery outer expression on the outer side of the IN subquery is_in_predicate SET to true if IN subquery was converted from an IN predicate or we are checking if materialization strategy can be used for an IN predicate */ virtual bool subquery_type_allows_materialization(const Item *inner, const Item *outer, bool is_in_predicate) const= 0; /** Make a simple constant replacement item for a constant "src", so the new item can futher be used for comparison with "cmp", e.g.: src = cmp -> replacement = cmp "this" is the type handler that is used to compare "src" and "cmp". @param thd - current thread, for mem_root @param src - The item that we want to replace. It's a const item, but it can be complex enough to calculate on every row. @param cmp - The src's comparand. @retval - a pointer to the created replacement Item @retval - NULL, if could not create a replacement (e.g. on EOM). NULL is also returned for ROWs, because instead of replacing a Item_row to a new Item_row, Type_handler_row just replaces its elements. */ virtual Item *make_const_item_for_comparison(THD *thd, Item *src, const Item *cmp) const= 0; virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0; virtual Item *make_constructor_item(THD *thd, List *args) const { return NULL; } /** A builder for literals with data type name prefix, e.g.: TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'. @param thd The current thread @param str Character literal @param length Length of str @param cs Character set of the string @param send_error Whether to generate an error on failure @retval A pointer to a new Item on success NULL on error (wrong literal value, EOM) */ virtual Item_literal *create_literal_item(THD *thd, const char *str, size_t length, CHARSET_INFO *cs, bool send_error) const { MY_ASSERT_UNREACHABLE(); return nullptr; } Item_literal *create_literal_item(THD *thd, const String *str, bool send_error) const { return create_literal_item(thd, str->ptr(), str->length(), str->charset(), send_error); } virtual Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const { MY_ASSERT_UNREACHABLE(); return nullptr; } virtual Item_copy *create_item_copy(THD *thd, Item *item) const; virtual int cmp_native(const Native &a, const Native &b) const { MY_ASSERT_UNREACHABLE(); return 0; } virtual bool set_comparator_func(THD *thd, Arg_comparator *cmp) const= 0; virtual bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const { return false; } virtual bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const= 0; virtual bool Item_bool_rowready_func2_fix_length_and_dec(THD *thd, Item_bool_rowready_func2 *func) const; virtual bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const= 0; virtual bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func, Item **items, uint nitems) const; virtual bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const= 0; virtual bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const= 0; virtual bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const= 0; virtual bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const= 0; virtual bool Item_val_native_with_conversion(THD *thd, Item *item, Native *to) const { return true; } virtual bool Item_val_native_with_conversion_result(THD *thd, Item *item, Native *to) const { return true; } virtual bool Item_val_bool(Item *item) const= 0; virtual void Item_get_date(THD *thd, Item *item, Temporal::Warn *buff, MYSQL_TIME *ltime, date_mode_t fuzzydate) const= 0; bool Item_get_date_with_warn(THD *thd, Item *item, MYSQL_TIME *ltime, date_mode_t fuzzydate) const; virtual longlong Item_val_int_signed_typecast(Item *item) const= 0; virtual longlong Item_val_int_unsigned_typecast(Item *item) const= 0; virtual String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const= 0; virtual String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const= 0; virtual double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) const= 0; virtual longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) const= 0; virtual my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const= 0; virtual void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const= 0; bool Item_func_hybrid_field_type_get_date_with_warn(THD *thd, Item_func_hybrid_field_type *, MYSQL_TIME *, date_mode_t) const; virtual String *Item_func_min_max_val_str(Item_func_min_max *, String *) const= 0; virtual double Item_func_min_max_val_real(Item_func_min_max *) const= 0; virtual longlong Item_func_min_max_val_int(Item_func_min_max *) const= 0; virtual my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const= 0; virtual bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *, date_mode_t fuzzydate) const= 0; virtual bool Item_func_between_fix_length_and_dec(Item_func_between *func) const= 0; virtual longlong Item_func_between_val_int(Item_func_between *func) const= 0; virtual cmp_item * make_cmp_item(THD *thd, CHARSET_INFO *cs) const= 0; virtual in_vector * make_in_vector(THD *thd, const Item_func_in *func, uint nargs) const= 0; virtual bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *) const= 0; virtual bool Item_func_round_fix_length_and_dec(Item_func_round *round) const= 0; virtual bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *func) const= 0; virtual bool Item_func_abs_fix_length_and_dec(Item_func_abs *func) const= 0; virtual bool Item_func_neg_fix_length_and_dec(Item_func_neg *func) const= 0; virtual bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const; virtual bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const; virtual bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) const; virtual bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *item) const; virtual bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item) const; virtual bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const; virtual bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const; virtual bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const; virtual bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item) const; virtual bool Item_func_plus_fix_length_and_dec(Item_func_plus *func) const= 0; virtual bool Item_func_minus_fix_length_and_dec(Item_func_minus *func) const= 0; virtual bool Item_func_mul_fix_length_and_dec(Item_func_mul *func) const= 0; virtual bool Item_func_div_fix_length_and_dec(Item_func_div *func) const= 0; virtual bool Item_func_mod_fix_length_and_dec(Item_func_mod *func) const= 0; virtual const Vers_type_handler *vers() const { return NULL; } }; /* Special handler for ROW */ class Type_handler_row: public Type_handler { public: virtual ~Type_handler_row() = default; const Name &default_value() const override; bool validate_implicit_default_value(THD *, const Column_definition &) const override { MY_ASSERT_UNREACHABLE(); return true; } const Type_collection *type_collection() const override; bool is_scalar_type() const override { return false; } bool can_return_int() const override { return false; } bool can_return_decimal() const override { return false; } bool can_return_real() const override { return false; } bool can_return_str() const override { return false; } bool can_return_text() const override { return false; } bool can_return_date() const override { return false; } bool can_return_time() const override { return false; } enum_field_types field_type() const override { MY_ASSERT_UNREACHABLE(); return MYSQL_TYPE_NULL; }; protocol_send_type_t protocol_send_type() const override { MY_ASSERT_UNREACHABLE(); return PROTOCOL_SEND_STRING; } Item_result result_type() const override { return ROW_RESULT; } Item_result cmp_type() const override { return ROW_RESULT; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *) const override { MY_ASSERT_UNREACHABLE(); return DYN_COL_NULL; } const Type_handler *type_handler_for_comparison() const override; int stored_field_cmp_to_item(THD *, Field *, Item *) const override { MY_ASSERT_UNREACHABLE(); return 0; } bool subquery_type_allows_materialization(const Item *, const Item *, bool) const override { MY_ASSERT_UNREACHABLE(); return false; } Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override { MY_ASSERT_UNREACHABLE(); return nullptr; } Field *make_conversion_table_field(MEM_ROOT *, TABLE *, uint, const Field *) const override { MY_ASSERT_UNREACHABLE(); return nullptr; } bool Column_definition_fix_attributes(Column_definition *) const override { return false; } void Column_definition_reuse_fix_attributes(THD *, Column_definition *, const Field *) const override { MY_ASSERT_UNREACHABLE(); } bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const override; bool Column_definition_redefine_stage1(Column_definition *, const Column_definition *, const handler *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Column_definition_prepare_stage2(Column_definition *, handler *, ulonglong) const override { return false; } Field *make_table_field(MEM_ROOT *, const LEX_CSTRING *, const Record_addr &, const Type_all_attributes &, TABLE_SHARE *) const override { MY_ASSERT_UNREACHABLE(); return nullptr; } Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override { MY_ASSERT_UNREACHABLE(); } uint make_packed_sort_key_part(uchar *, Item *, const SORT_FIELD_ATTR *, String *) const override { MY_ASSERT_UNREACHABLE(); return 0; } void sort_length(THD *, const Type_std_attributes *, SORT_FIELD_ATTR *) const override { MY_ASSERT_UNREACHABLE(); } uint32 max_display_length(const Item *) const override { MY_ASSERT_UNREACHABLE(); return 0; } uint32 max_display_length_for_field(const Conv_source &) const override { MY_ASSERT_UNREACHABLE(); return 0; } uint32 calc_pack_length(uint32) const override { MY_ASSERT_UNREACHABLE(); return 0; } bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const override; decimal_digits_t Item_decimal_precision(const Item *) const override { MY_ASSERT_UNREACHABLE(); return DECIMAL_MAX_PRECISION; } bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override; bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *value) const override; bool Item_send(Item *, Protocol *, st_value *) const override { MY_ASSERT_UNREACHABLE(); return true; } void Item_update_null_value(Item *item) const override; int Item_save_in_field(Item *, Field *, bool) const override { MY_ASSERT_UNREACHABLE(); return 1; } String *print_item_value(THD *thd, Item *item, String *str) const override; bool can_change_cond_ref_to_const(Item_bool_func2 *, Item *, Item *, Item_bool_func2 *, Item *, Item *) const override { MY_ASSERT_UNREACHABLE(); return false; } Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; Item_copy *create_item_copy(THD *, Item *) const override { MY_ASSERT_UNREACHABLE(); return nullptr; } bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_val_bool(Item *item) const override { MY_ASSERT_UNREACHABLE(); return false; } void Item_get_date(THD *, Item *, Temporal::Warn *, MYSQL_TIME *ltime, date_mode_t) const override { MY_ASSERT_UNREACHABLE(); set_zero_time(ltime, MYSQL_TIMESTAMP_NONE); } longlong Item_val_int_signed_typecast(Item *) const override { MY_ASSERT_UNREACHABLE(); return 0; } longlong Item_val_int_unsigned_typecast(Item *) const override { MY_ASSERT_UNREACHABLE(); return 0; } String *Item_func_hex_val_str_ascii(Item_func_hex *, String *) const override { MY_ASSERT_UNREACHABLE(); return nullptr; } String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const override { MY_ASSERT_UNREACHABLE(); return nullptr; } double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) const override { MY_ASSERT_UNREACHABLE(); return 0.0; } longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) const override { MY_ASSERT_UNREACHABLE(); return 0; } my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const override { MY_ASSERT_UNREACHABLE(); return nullptr; } void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, Temporal::Warn *, MYSQL_TIME *ltime, date_mode_t) const override { MY_ASSERT_UNREACHABLE(); set_zero_time(ltime, MYSQL_TIMESTAMP_NONE); } String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override { MY_ASSERT_UNREACHABLE(); return nullptr; } double Item_func_min_max_val_real(Item_func_min_max *) const override { MY_ASSERT_UNREACHABLE(); return 0; } longlong Item_func_min_max_val_int(Item_func_min_max *) const override { MY_ASSERT_UNREACHABLE(); return 0; } my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override { MY_ASSERT_UNREACHABLE(); return nullptr; } bool Item_func_min_max_get_date(THD *, Item_func_min_max*, MYSQL_TIME *, date_mode_t) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_func_between_fix_length_and_dec(Item_func_between *) const override { MY_ASSERT_UNREACHABLE(); return true; } longlong Item_func_between_val_int(Item_func_between *func) const override; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const override; bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override; bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *) const override { MY_ASSERT_UNREACHABLE(); return true; } bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override; bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override; bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override; bool Item_func_div_fix_length_and_dec(Item_func_div *) const override; bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override; }; /* A common parent class for numeric data type handlers */ class Type_handler_numeric: public Type_handler { public: const Name &default_value() const override; String *print_item_value(THD *thd, Item *item, String *str) const override; bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const override; double Item_func_min_max_val_real(Item_func_min_max *) const override; longlong Item_func_min_max_val_int(Item_func_min_max *) const override; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *, date_mode_t fuzzydate) const override; virtual ~Type_handler_numeric() = default; bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const override; bool Item_func_between_fix_length_and_dec(Item_func_between *func) const override; bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const override; }; /*** Abstract classes for every XXX_RESULT */ class Type_handler_real_result: public Type_handler_numeric { public: Item_result result_type() const override{ return REAL_RESULT; } Item_result cmp_type() const override { return REAL_RESULT; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const override { return DYN_COL_DOUBLE; } virtual ~Type_handler_real_result() = default; const Type_handler *type_handler_for_comparison() const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; void Column_definition_reuse_fix_attributes(THD *thd, Column_definition *c, const Field *field) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; bool Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, TABLE_SHARE *share, const uchar *buffer, LEX_CUSTRING *gis_options) const override; int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override; bool subquery_type_allows_materialization(const Item *inner, const Item *outer, bool is_in_predicate) const override; void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; uint make_packed_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; void sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const override; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const override; decimal_digits_t Item_decimal_precision(const Item *item) const override; bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override; bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *value) const override; void Item_update_null_value(Item *item) const override; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const override; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const override; bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func, Item **items, uint nitems) const override; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override; bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const override; bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const override; bool Item_val_bool(Item *item) const override; void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const override; longlong Item_val_int_signed_typecast(Item *item) const override; longlong Item_val_int_unsigned_typecast(Item *item) const override; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const override; double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) const override; longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) const override; my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const override; void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const override; longlong Item_func_between_val_int(Item_func_between *func) const override; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const override; bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override; bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override; bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override; bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override; bool Item_func_div_fix_length_and_dec(Item_func_div *) const override; bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override; }; class Type_handler_decimal_result: public Type_handler_numeric { public: protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_STRING; } Item_result result_type() const override { return DECIMAL_RESULT; } Item_result cmp_type() const override { return DECIMAL_RESULT; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *) const override { return DYN_COL_DECIMAL; } virtual ~Type_handler_decimal_result() = default; const Type_handler *type_handler_for_comparison() const override; int stored_field_cmp_to_item(THD *, Field *field, Item *item) const override { VDec item_val(item); return item_val.is_null() ? 0 : my_decimal(field).cmp(item_val.ptr()); } bool subquery_type_allows_materialization(const Item *inner, const Item *outer, bool is_in_predicate) const override; Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override; void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; uint make_packed_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; bool Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, TABLE_SHARE *share, const uchar *buffer, LEX_CUSTRING *gis_options) const override; void sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override; uint32 max_display_length(const Item *item) const override; uint32 Item_decimal_notation_int_digits(const Item *item) const override; Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const override; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const override { VDec va(a), vb(b); return va.ptr() && vb.ptr() && !va.cmp(vb); } decimal_digits_t Item_decimal_precision(const Item *item) const override; bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *value) const override; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_str(item, protocol, buf); } void Item_update_null_value(Item *item) const override; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const override; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance*) const override; bool Item_val_bool(Item *item) const override { return VDec(item).to_bool(); } void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const override; longlong Item_val_int_signed_typecast(Item *item) const override; longlong Item_val_int_unsigned_typecast(Item *item) const override { return VDec(item).to_longlong(true); } String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const override; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const override; double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) const override; longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) const override; my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const override; void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const override; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; longlong Item_func_between_val_int(Item_func_between *func) const override; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const override; bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override; bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override; bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override; bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override; bool Item_func_div_fix_length_and_dec(Item_func_div *) const override; bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override; }; class Type_limits_int { private: uint32 m_precision; uint32 m_char_length; public: Type_limits_int(uint32 prec, uint32 nchars) :m_precision(prec), m_char_length(nchars) { } uint32 precision() const { return m_precision; } uint32 char_length() const { return m_char_length; } }; /* UNDIGNED TINYINT: 0..255 digits=3 nchars=3 SIGNED TINYINT : -128..127 digits=3 nchars=4 */ class Type_limits_uint8: public Type_limits_int { public: Type_limits_uint8() :Type_limits_int(MAX_TINYINT_WIDTH, MAX_TINYINT_WIDTH) { } }; class Type_limits_sint8: public Type_limits_int { public: Type_limits_sint8() :Type_limits_int(MAX_TINYINT_WIDTH, MAX_TINYINT_WIDTH + 1) { } }; /* UNDIGNED SMALLINT: 0..65535 digits=5 nchars=5 SIGNED SMALLINT: -32768..32767 digits=5 nchars=6 */ class Type_limits_uint16: public Type_limits_int { public: Type_limits_uint16() :Type_limits_int(MAX_SMALLINT_WIDTH, MAX_SMALLINT_WIDTH) { } }; class Type_limits_sint16: public Type_limits_int { public: Type_limits_sint16() :Type_limits_int(MAX_SMALLINT_WIDTH, MAX_SMALLINT_WIDTH + 1) { } }; /* MEDIUMINT UNSIGNED 0 .. 16777215 digits=8 char_length=8 MEDIUMINT SIGNED: -8388608 .. 8388607 digits=7 char_length=8 */ class Type_limits_uint24: public Type_limits_int { public: Type_limits_uint24() :Type_limits_int(MAX_MEDIUMINT_WIDTH, MAX_MEDIUMINT_WIDTH) { } }; class Type_limits_sint24: public Type_limits_int { public: Type_limits_sint24() :Type_limits_int(MAX_MEDIUMINT_WIDTH - 1, MAX_MEDIUMINT_WIDTH) { } }; /* UNSIGNED INT: 0..4294967295 digits=10 nchars=10 SIGNED INT: -2147483648..2147483647 digits=10 nchars=11 */ class Type_limits_uint32: public Type_limits_int { public: Type_limits_uint32() :Type_limits_int(MAX_INT_WIDTH, MAX_INT_WIDTH) { } }; class Type_limits_sint32: public Type_limits_int { public: Type_limits_sint32() :Type_limits_int(MAX_INT_WIDTH, MAX_INT_WIDTH + 1) { } }; /* UNSIGNED BIGINT: 0..18446744073709551615 digits=20 nchars=20 SIGNED BIGINT: -9223372036854775808..9223372036854775807 digits=19 nchars=20 */ class Type_limits_uint64: public Type_limits_int { public: Type_limits_uint64(): Type_limits_int(MAX_BIGINT_WIDTH, MAX_BIGINT_WIDTH) { } }; class Type_limits_sint64: public Type_limits_int { public: Type_limits_sint64() :Type_limits_int(MAX_BIGINT_WIDTH - 1, MAX_BIGINT_WIDTH) { } }; class Type_handler_int_result: public Type_handler_numeric { public: Item_result result_type() const override { return INT_RESULT; } Item_result cmp_type() const override { return INT_RESULT; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const override { return attr->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT; } bool is_order_clause_position_type() const override { return true; } bool is_limit_clause_valid_type() const override { return true; } virtual ~Type_handler_int_result() = default; const Type_handler *type_handler_for_comparison() const override; int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override; bool subquery_type_allows_materialization(const Item *inner, const Item *outer, bool is_in_predicate) const override; Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; uint make_packed_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; void sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const override; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const override; decimal_digits_t Item_decimal_precision(const Item *item) const override; bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override; bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *value) const override; void Item_update_null_value(Item *item) const override; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const override; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override; bool Item_val_bool(Item *item) const override; void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const override; longlong Item_val_int_signed_typecast(Item *item) const override; longlong Item_val_int_unsigned_typecast(Item *item) const override; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const override; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const override; double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) const override; longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) const override; my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const override; void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const override; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; longlong Item_func_between_val_int(Item_func_between *func) const override; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const override; bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override; bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override; bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override; bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override; bool Item_func_div_fix_length_and_dec(Item_func_div *) const override; bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override; const Vers_type_handler *vers() const override { return &vers_type_trx; } }; class Type_handler_general_purpose_int: public Type_handler_int_result { public: bool type_can_have_auto_increment_attribute() const override { return true; } virtual const Type_limits_int *type_limits_int() const= 0; uint32 max_display_length(const Item *item) const override { return type_limits_int()->char_length(); } uint32 Item_decimal_notation_int_digits(const Item *item) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; bool partition_field_check(const LEX_CSTRING &, Item *item_expr) const override { return partition_field_check_result_type(item_expr, INT_RESULT); } bool partition_field_append_value(String *str, Item *item_expr, CHARSET_INFO *field_cs, partition_value_print_mode_t) const override; const Vers_type_handler *vers() const override { return &vers_type_trx; } }; class Type_handler_temporal_result: public Type_handler { protected: decimal_digits_t Item_decimal_scale_with_seconds(const Item *item) const; decimal_digits_t Item_divisor_precision_increment_with_seconds(const Item *) const; public: Item_result result_type() const override { return STRING_RESULT; } Item_result cmp_type() const override { return TIME_RESULT; } virtual ~Type_handler_temporal_result() = default; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; uint make_packed_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; void sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override; bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const override; bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const override; bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *value) const override; uint32 max_display_length(const Item *item) const override; uint32 Item_decimal_notation_int_digits(const Item *item) const override; bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const override; bool subquery_type_allows_materialization(const Item *inner, const Item *outer, bool is_in_predicate) const override; bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func, Item **items, uint nitems) const override; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *)const override; bool Item_val_bool(Item *item) const override; void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const override; longlong Item_val_int_signed_typecast(Item *item) const override; longlong Item_val_int_unsigned_typecast(Item *item) const override; String *Item_func_hex_val_str_ascii(Item_func_hex *, String *)const override; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const override; double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) const override; longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) const override; my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const override; void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, Temporal::Warn *, MYSQL_TIME *, date_mode_t) const override; bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *, date_mode_t) const override; bool Item_func_between_fix_length_and_dec(Item_func_between *)const override; bool Item_func_in_fix_comparator_compatible_types(THD *, Item_func_in *) const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override; bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override; bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override; bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override; bool Item_func_div_fix_length_and_dec(Item_func_div *) const override; bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override; const Vers_type_handler *vers() const override; }; class Type_handler_string_result: public Type_handler { decimal_digits_t Item_temporal_precision(THD *thd, Item *item, bool is_time) const; public: const Name &default_value() const override; protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_STRING; } Item_result result_type() const override { return STRING_RESULT; } Item_result cmp_type() const override { return STRING_RESULT; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *) const override { return DYN_COL_STRING; } CHARSET_INFO *charset_for_protocol(const Item *item) const override; virtual ~Type_handler_string_result() = default; const Type_handler *type_handler_for_comparison() const override; int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override; const Type_handler * type_handler_adjusted_to_max_octet_length(uint max_octet_length, CHARSET_INFO *cs) const override; void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; uint make_packed_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; void sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override; bool is_packable() const override { return true; } bool union_element_finalize(Item_type_holder* item) const override; uint calc_key_length(const Column_definition &def) const override; bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const override; bool Column_definition_redefine_stage1(Column_definition *def, const Column_definition *dup, const handler *file) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; uint32 max_display_length(const Item *item) const override; /* The next method returns 309 for long stringified doubles in scientific notation, e.g. FORMAT('1e308', 2). */ uint32 Item_decimal_notation_int_digits(const Item *item) const override { return 309; } bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const override; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const override; decimal_digits_t Item_time_precision(THD *thd, Item *item) const override { return Item_temporal_precision(thd, item, true); } decimal_digits_t Item_datetime_precision(THD *thd, Item *item) const override { return Item_temporal_precision(thd, item, false); } decimal_digits_t Item_decimal_precision(const Item *item) const override; void Item_update_null_value(Item *item) const override; bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override; void Item_param_setup_conversion(THD *thd, Item_param *) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *value) const override; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_str(item, protocol, buf); } int Item_save_in_field(Item *item, Field *field, bool no_conversions) const override; String *print_item_value(THD *thd, Item *item, String *str) const override { return print_item_value_csstr(thd, item, str); } bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const override; bool subquery_type_allows_materialization(const Item *inner, const Item *outer, bool is_in_predicate) const override; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override; bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const override; bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const override; bool Item_val_bool(Item *item) const override; void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const override; longlong Item_val_int_signed_typecast(Item *item) const override; longlong Item_val_int_unsigned_typecast(Item *item) const override; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const override; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const override; double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) const override; longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) const override; my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const override; void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const override; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; double Item_func_min_max_val_real(Item_func_min_max *) const override; longlong Item_func_min_max_val_int(Item_func_min_max *) const override; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *, date_mode_t fuzzydate) const override; bool Item_func_between_fix_length_and_dec(Item_func_between *func) const override; longlong Item_func_between_val_int(Item_func_between *func) const override; bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const override; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const override; bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override; bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override; bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override; bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override; bool Item_func_div_fix_length_and_dec(Item_func_div *) const override; bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override; const Vers_type_handler *vers() const override; }; class Type_handler_general_purpose_string: public Type_handler_string_result { public: bool is_general_purpose_string_type() const override { return true; } bool Column_definition_bulk_alter(Column_definition *c, const Column_derived_attributes *derived_attr, const Column_bulk_alter_attributes *bulk_alter_attr) const override; }; /*** Instantiable classes for every MYSQL_TYPE_XXX There are no Type_handler_xxx for the following types: - MYSQL_TYPE_VAR_STRING (old VARCHAR) - mapped to MYSQL_TYPE_VARSTRING - MYSQL_TYPE_ENUM - mapped to MYSQL_TYPE_VARSTRING - MYSQL_TYPE_SET: - mapped to MYSQL_TYPE_VARSTRING because the functionality that currently uses Type_handler (e.g. hybrid type functions) does not need to distinguish between these types and VARCHAR. For example: CREATE TABLE t2 AS SELECT COALESCE(enum_column) FROM t1; creates a VARCHAR column. There most likely be Type_handler_enum and Type_handler_set later, when the Type_handler infrastructure gets used in more pieces of the code. */ class Type_handler_tiny: public Type_handler_general_purpose_int { public: virtual ~Type_handler_tiny() = default; enum_field_types field_type() const override { return MYSQL_TYPE_TINY; } const Type_handler *type_handler_unsigned() const override; const Type_handler *type_handler_signed() const override; protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_TINY; } const Type_limits_int *type_limits_int() const override; uint32 calc_pack_length(uint32 length) const override { return 1; } uint32 max_display_length_for_field(const Conv_source &src) const override { return 4; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_tiny(item, protocol, buf); } Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TINY); } Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; }; class Type_handler_utiny: public Type_handler_tiny { public: uint flags() const override { return UNSIGNED_FLAG; } const Type_limits_int *type_limits_int() const override; }; class Type_handler_short: public Type_handler_general_purpose_int { public: virtual ~Type_handler_short() = default; enum_field_types field_type() const override { return MYSQL_TYPE_SHORT; } const Type_handler *type_handler_unsigned() const override; const Type_handler *type_handler_signed() const override; protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_SHORT; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_short(item, protocol, buf); } const Type_limits_int *type_limits_int() const override; uint32 max_display_length_for_field(const Conv_source &src) const override { return 6; } uint32 calc_pack_length(uint32 length) const override{ return 2; } Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_SHORT); } Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; }; class Type_handler_ushort: public Type_handler_short { public: uint flags() const override { return UNSIGNED_FLAG; } const Type_limits_int *type_limits_int() const override; }; class Type_handler_long: public Type_handler_general_purpose_int { public: virtual ~Type_handler_long() = default; enum_field_types field_type() const override { return MYSQL_TYPE_LONG; } const Type_handler *type_handler_unsigned() const override; const Type_handler *type_handler_signed() const override; protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_LONG; } const Type_limits_int *type_limits_int() const override; uint32 max_display_length_for_field(const Conv_source &src) const override { return 11; } uint32 calc_pack_length(uint32 length) const override { return 4; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_long(item, protocol, buf); } Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_LONG); } Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; }; /* The expression of this type reports itself as signed, however it's known not to return negative values. Items of this data type count only digits in Item::max_length, without adding +1 for the sign. This allows expressions of this type convert nicely to VARCHAR and DECIMAL. For example, YEAR(now()) is: - VARCHAR(4) in a string context - DECIMAL(4,0) in a decimal context - but INT(5) in an integer context */ class Type_handler_long_ge0: public Type_handler_long { public: decimal_digits_t Item_decimal_precision(const Item *item) const override; bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const override; bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_ulong: public Type_handler_long { public: uint flags() const override { return UNSIGNED_FLAG; } const Type_limits_int *type_limits_int() const override; }; class Type_handler_bool: public Type_handler_long { public: bool is_bool_type() const override { return true; } const Type_handler *type_handler_unsigned() const override; const Type_handler *type_handler_signed() const override; void Item_update_null_value(Item *item) const override; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const override; }; class Type_handler_longlong: public Type_handler_general_purpose_int { public: virtual ~Type_handler_longlong() = default; enum_field_types field_type() const override{ return MYSQL_TYPE_LONGLONG; } const Type_handler *type_handler_unsigned() const override; const Type_handler *type_handler_signed() const override; protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_LONGLONG; } const Type_limits_int *type_limits_int() const override; uint32 max_display_length_for_field(const Conv_source &src) const override { return 20; } uint32 calc_pack_length(uint32 length) const override { return 8; } Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_longlong(item, protocol, buf); } Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_LONGLONG); } Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; }; class Type_handler_ulonglong: public Type_handler_longlong { public: uint flags() const override { return UNSIGNED_FLAG; } const Type_limits_int *type_limits_int() const override; }; class Type_handler_vers_trx_id: public Type_handler_ulonglong { public: virtual ~Type_handler_vers_trx_id() = default; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; }; class Type_handler_int24: public Type_handler_general_purpose_int { public: virtual ~Type_handler_int24() = default; enum_field_types field_type() const override { return MYSQL_TYPE_INT24; } const Type_handler *type_handler_unsigned() const override; const Type_handler *type_handler_signed() const override; protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_LONG; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_long(item, protocol, buf); } const Type_limits_int *type_limits_int() const override; uint32 max_display_length_for_field(const Conv_source &src) const override { return 9; } uint32 calc_pack_length(uint32 length) const override { return 3; } Field *make_conversion_table_field(MEM_ROOT *mem_root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_INT24); } Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_uint24: public Type_handler_int24 { public: uint flags() const override { return UNSIGNED_FLAG; } const Type_limits_int *type_limits_int() const override; }; class Type_handler_year: public Type_handler_int_result { public: virtual ~Type_handler_year() = default; enum_field_types field_type() const override { return MYSQL_TYPE_YEAR; } uint flags() const override { return UNSIGNED_FLAG; } protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_SHORT; } uint32 max_display_length(const Item *item) const override; uint32 Item_decimal_notation_int_digits(const Item *item) const override { return 4; }; uint32 max_display_length_for_field(const Conv_source &src) const override { return 4; } uint32 calc_pack_length(uint32 length) const override { return 1; } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_short(item, protocol, buf); } Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; void Column_definition_reuse_fix_attributes(THD *thd, Column_definition *c, const Field *field) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_YEAR); } Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *)const override; void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const override; void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *item, Temporal::Warn *, MYSQL_TIME *to, date_mode_t fuzzydate) const override; const Vers_type_handler *vers() const override { return NULL; } }; class Type_handler_bit: public Type_handler_int_result { public: virtual ~Type_handler_bit() = default; enum_field_types field_type() const override { return MYSQL_TYPE_BIT; } uint flags() const override { return UNSIGNED_FLAG; } protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_STRING; } uint32 max_display_length(const Item *item) const override; uint32 Item_decimal_notation_int_digits(const Item *item) const override; static uint32 Bit_decimal_notation_int_digits_by_nbits(uint nbits); uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override { return length / 8; } uint calc_key_length(const Column_definition &def) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_str(item, protocol, buf); } String *print_item_value(THD *thd, Item *item, String *str) const override { return print_item_value_csstr(thd, item, str); } void show_binlog_type(const Conv_source &src, const Field &, String *str) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const override; bool Column_definition_redefine_stage1(Column_definition *def, const Column_definition *dup, const handler *file) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_float: public Type_handler_real_result { public: virtual ~Type_handler_float() = default; enum_field_types field_type() const override { return MYSQL_TYPE_FLOAT; } protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_FLOAT; } bool type_can_have_auto_increment_attribute() const override { return true; } uint32 max_display_length(const Item *item) const override { return 25; } uint32 max_display_length_for_field(const Conv_source &src) const override { return 12; } uint32 Item_decimal_notation_int_digits(const Item *item) const override { return 39; } uint32 calc_pack_length(uint32 length) const override { return sizeof(float); } Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_float(item, protocol, buf); } Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_real(c, MYSQL_TYPE_FLOAT); } Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const override; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; }; class Type_handler_double: public Type_handler_real_result { public: virtual ~Type_handler_double() = default; enum_field_types field_type() const override { return MYSQL_TYPE_DOUBLE; } protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_DOUBLE; } bool type_can_have_auto_increment_attribute() const override { return true; } uint32 max_display_length(const Item *item) const override { return 53; } uint32 Item_decimal_notation_int_digits(const Item *item) const override { return 309; } uint32 max_display_length_for_field(const Conv_source &src) const override { return 22; } uint32 calc_pack_length(uint32 length) const override { return sizeof(double); } Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_double(item, protocol, buf); } Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_real(c, MYSQL_TYPE_DOUBLE); } Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const override; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; }; class Type_handler_time_common: public Type_handler_temporal_result { public: virtual ~Type_handler_time_common() = default; const Name &default_value() const override; enum_field_types field_type() const override { return MYSQL_TYPE_TIME; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const override { return DYN_COL_TIME; } protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_TIME; } enum_mysql_timestamp_type mysql_timestamp_type() const override { return MYSQL_TIMESTAMP_TIME; } bool is_val_native_ready() const override { return true; } const Type_handler *type_handler_for_native_format() const override; int cmp_native(const Native &a, const Native &b) const override; bool Item_val_native_with_conversion(THD *thd, Item *, Native *to) const override; bool Item_val_native_with_conversion_result(THD *thd, Item *, Native *to) const override; bool Item_param_val_native(THD *thd, Item_param *item, Native *to) const override; bool partition_field_check(const LEX_CSTRING &, Item *item_expr) const override { return partition_field_check_result_type(item_expr, STRING_RESULT); } Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Item_literal *create_literal_item(THD *thd, const char *str, size_t length, CHARSET_INFO *cs, bool send_error) const override; Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const override; decimal_digits_t Item_decimal_scale(const Item *item) const override { return Item_decimal_scale_with_seconds(item); } decimal_digits_t Item_decimal_precision(const Item *item) const override; decimal_digits_t Item_divisor_precision_increment(const Item *item) const override { return Item_divisor_precision_increment_with_seconds(item); } const Type_handler *type_handler_for_comparison() const override; int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override; void Column_definition_implicit_upgrade(Column_definition *c) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, TABLE_SHARE *share, const uchar *buffer, LEX_CUSTRING *gis_options) const override; bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_time(item, protocol, buf); } void Item_update_null_value(Item *item) const override; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const override; String *print_item_value(THD *thd, Item *item, String *str) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; longlong Item_val_int_unsigned_typecast(Item *item) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, String *) const override; double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) const override; longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) const override; my_decimal *Item_func_hybrid_field_type_val_decimal( Item_func_hybrid_field_type *, my_decimal *) const override; void Item_func_hybrid_field_type_get_date(THD *, Item_func_hybrid_field_type *, Temporal::Warn *, MYSQL_TIME *, date_mode_t fuzzydate) const override; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; double Item_func_min_max_val_real(Item_func_min_max *) const override; longlong Item_func_min_max_val_int(Item_func_min_max *) const override; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *, date_mode_t fuzzydate) const override; longlong Item_func_between_val_int(Item_func_between *func) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const override; bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; }; class Type_handler_time: public Type_handler_time_common { /* number of bytes to store TIME(N) */ static uint m_hires_bytes[MAX_DATETIME_PRECISION+1]; public: static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; } virtual ~Type_handler_time() = default; const Name version() const override { return version_mariadb53(); } uint32 max_display_length_for_field(const Conv_source &src) const override { return MIN_TIME_WIDTH; } uint32 calc_pack_length(uint32 length) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_TIME); } Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_time2: public Type_handler_time_common { public: virtual ~Type_handler_time2() = default; const Name version() const override { return version_mysql56(); } enum_field_types real_field_type() const override { return MYSQL_TYPE_TIME2; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_TIME2); } Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_temporal_with_date: public Type_handler_temporal_result { public: virtual ~Type_handler_temporal_with_date() = default; Item_literal *create_literal_item(THD *thd, const char *str, size_t length, CHARSET_INFO *cs, bool send_error) const override; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const override; int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override; bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_date(item, protocol, buf); } void Item_update_null_value(Item *item) const override; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const override; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const override; bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const override; longlong Item_func_between_val_int(Item_func_between *func) const override; }; class Type_handler_date_common: public Type_handler_temporal_with_date { public: virtual ~Type_handler_date_common() = default; const Name &default_value() const override; const Type_handler *type_handler_for_comparison() const override; enum_field_types field_type() const override { return MYSQL_TYPE_DATE; } uint32 max_display_length_for_field(const Conv_source &src) const override { return 3; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const override { return DYN_COL_DATE; } protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_DATE; } enum_mysql_timestamp_type mysql_timestamp_type() const override { return MYSQL_TIMESTAMP_DATE; } bool cond_notnull_field_isnull_to_field_eq_zero() const override { return true; } bool partition_field_check(const LEX_CSTRING &, Item *item_expr) const override { return partition_field_check_result_type(item_expr, STRING_RESULT); } Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Item_literal *create_literal_item(THD *thd, const char *str, size_t length, CHARSET_INFO *cs, bool send_error) const override; Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override; bool validate_implicit_default_value(THD *thd, const Column_definition &def) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; decimal_digits_t Item_decimal_precision(const Item *item) const override; String *print_item_value(THD *thd, Item *item, String *str) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; double Item_func_min_max_val_real(Item_func_min_max *) const override; longlong Item_func_min_max_val_int(Item_func_min_max *) const override; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func, Item **items, uint nitems) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; }; class Type_handler_date: public Type_handler_date_common { public: virtual ~Type_handler_date() = default; uint32 calc_pack_length(uint32 length) const override { return 4; } Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATE); } Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_newdate: public Type_handler_date_common { public: virtual ~Type_handler_newdate() = default; enum_field_types real_field_type() const override { return MYSQL_TYPE_NEWDATE; } uint32 calc_pack_length(uint32 length) const override { return 3; } Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NEWDATE); } Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_datetime_common: public Type_handler_temporal_with_date { public: virtual ~Type_handler_datetime_common() = default; const Name &default_value() const override; const Type_handler *type_handler_for_comparison() const override; enum_field_types field_type() const override { return MYSQL_TYPE_DATETIME; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const override { return DYN_COL_DATETIME; } protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_DATETIME; } enum_mysql_timestamp_type mysql_timestamp_type() const override { return MYSQL_TIMESTAMP_DATETIME; } bool cond_notnull_field_isnull_to_field_eq_zero() const override { return true; } bool partition_field_check(const LEX_CSTRING &, Item *item_expr) const override { return partition_field_check_result_type(item_expr, STRING_RESULT); } Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override; bool validate_implicit_default_value(THD *thd, const Column_definition &def) const override; void Column_definition_implicit_upgrade(Column_definition *c) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, TABLE_SHARE *share, const uchar *buffer, LEX_CUSTRING *gis_options) const override; decimal_digits_t Item_decimal_scale(const Item *item) const override { return Item_decimal_scale_with_seconds(item); } decimal_digits_t Item_decimal_precision(const Item *item) const override; decimal_digits_t Item_divisor_precision_increment(const Item *item) const override { return Item_divisor_precision_increment_with_seconds(item); } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_datetime(item, protocol, buf); } String *print_item_value(THD *thd, Item *item, String *str) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; double Item_func_min_max_val_real(Item_func_min_max *) const override; longlong Item_func_min_max_val_int(Item_func_min_max *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; }; class Type_handler_datetime: public Type_handler_datetime_common { /* number of bytes to store DATETIME(N) */ static uint m_hires_bytes[MAX_DATETIME_PRECISION + 1]; public: static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; } virtual ~Type_handler_datetime() = default; const Name version() const override { return version_mariadb53(); } uint32 max_display_length_for_field(const Conv_source &src) const override { return MAX_DATETIME_WIDTH; } uint32 calc_pack_length(uint32 length) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATETIME); } Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_datetime2: public Type_handler_datetime_common { public: virtual ~Type_handler_datetime2() = default; const Name version() const override { return version_mysql56(); } enum_field_types real_field_type() const override { return MYSQL_TYPE_DATETIME2; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATETIME2); } Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_timestamp_common: public Type_handler_temporal_with_date { protected: bool TIME_to_native(THD *, const MYSQL_TIME *from, Native *to, uint dec) const; public: virtual ~Type_handler_timestamp_common() = default; const Name &default_value() const override; const Type_handler *type_handler_for_comparison() const override; const Type_handler *type_handler_for_native_format() const override; enum_field_types field_type() const override { return MYSQL_TYPE_TIMESTAMP; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const override { return DYN_COL_DATETIME; } protocol_send_type_t protocol_send_type() const override { return PROTOCOL_SEND_DATETIME; } enum_mysql_timestamp_type mysql_timestamp_type() const override { return MYSQL_TIMESTAMP_DATETIME; } bool is_val_native_ready() const override { return true; } bool is_timestamp_type() const override { return true; } void Column_definition_implicit_upgrade(Column_definition *c) const override; bool Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, TABLE_SHARE *share, const uchar *buffer, LEX_CUSTRING *gis_options) const override; bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const override; bool Item_val_native_with_conversion(THD *thd, Item *, Native *to) const override; bool Item_val_native_with_conversion_result(THD *thd, Item *, Native *to) const override; bool Item_param_val_native(THD *thd, Item_param *item, Native *to) const override; int cmp_native(const Native &a, const Native &b) const override; longlong Item_func_between_val_int(Item_func_between *func) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const override; void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; uint make_packed_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, String *tmp) const override; void sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; decimal_digits_t Item_decimal_scale(const Item *item) const override { return Item_decimal_scale_with_seconds(item); } decimal_digits_t Item_decimal_precision(const Item *item) const override; decimal_digits_t Item_divisor_precision_increment(const Item *item) const override { return Item_divisor_precision_increment_with_seconds(item); } bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override { return Item_send_timestamp(item, protocol, buf); } int Item_save_in_field(Item *item, Field *field, bool no_conversions) const override; String *print_item_value(THD *thd, Item *item, String *str) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; Item_copy *create_item_copy(THD *thd, Item *item) const override; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; double Item_func_min_max_val_real(Item_func_min_max *) const override; longlong Item_func_min_max_val_int(Item_func_min_max *) const override; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *, date_mode_t fuzzydate) const override; }; class Type_handler_timestamp: public Type_handler_timestamp_common { /* number of bytes to store second_part part of the TIMESTAMP(N) */ static uint m_sec_part_bytes[MAX_DATETIME_PRECISION + 1]; public: static uint sec_part_bytes(uint dec) { return m_sec_part_bytes[dec]; } virtual ~Type_handler_timestamp() = default; const Name version() const override { return version_mariadb53(); } uint32 max_display_length_for_field(const Conv_source &src) const override { return MAX_DATETIME_WIDTH; } uint32 calc_pack_length(uint32 length) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TIMESTAMP); } Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_timestamp2: public Type_handler_timestamp_common { public: virtual ~Type_handler_timestamp2() = default; const Name version() const override { return version_mysql56(); } enum_field_types real_field_type() const override { return MYSQL_TYPE_TIMESTAMP2; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TIMESTAMP2); } Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_olddecimal: public Type_handler_decimal_result { public: virtual ~Type_handler_olddecimal() = default; enum_field_types field_type() const override { return MYSQL_TYPE_DECIMAL; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override { return length; } const Type_handler *type_handler_for_tmp_table(const Item *item) const override; const Type_handler *type_handler_for_union(const Item *item) const override; void show_binlog_type(const Conv_source &src, const Field &, String *str) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_DECIMAL); } Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_newdecimal: public Type_handler_decimal_result { public: virtual ~Type_handler_newdecimal() = default; enum_field_types field_type() const override { return MYSQL_TYPE_NEWDECIMAL; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; uint calc_key_length(const Column_definition &def) const override; void show_binlog_type(const Conv_source &src, const Field &, String *str) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const override; bool Column_definition_redefine_stage1(Column_definition *def, const Column_definition *dup, const handler *file) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_null: public Type_handler_general_purpose_string { public: virtual ~Type_handler_null() = default; enum_field_types field_type() const override { return MYSQL_TYPE_NULL; } enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const override { return DYN_COL_NULL; } const Type_handler *type_handler_for_comparison() const override; const Type_handler *type_handler_for_tmp_table(const Item *item) const override; const Type_handler *type_handler_for_union(const Item *) const override; uint32 max_display_length(const Item *item) const override { return 0; } uint32 max_display_length_for_field(const Conv_source &src) const override { return 0; } uint32 calc_pack_length(uint32 length) const override { return 0; } bool Item_const_eq(const Item_const *a, const Item_const *b, bool binary_cmp) const override; bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override; bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool union_element_finalize(Item_type_holder* item) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const override; bool Column_definition_redefine_stage1(Column_definition *def, const Column_definition *dup, const handler *file) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NULL); } void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; class Type_handler_longstr: public Type_handler_general_purpose_string { public: bool type_can_have_key_part() const override { return true; } }; class Type_handler_string: public Type_handler_longstr { public: virtual ~Type_handler_string() = default; enum_field_types field_type() const override { return MYSQL_TYPE_STRING; } ulong KEY_pack_flags(uint column_nr) const override { return HA_PACK_KEY; } bool is_param_long_data_type() const override { return true; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override { return length; } const Type_handler *type_handler_for_tmp_table(const Item *item) const override { return varstring_type_handler(item); } bool partition_field_check(const LEX_CSTRING &, Item *item_expr) const override { return partition_field_check_result_type(item_expr, STRING_RESULT); } void show_binlog_type(const Conv_source &src, const Field &dst, String *str) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_set_attributes(THD *thd, Column_definition *def, const Lex_field_type_st &attr, CHARSET_INFO *cs, column_definition_type_t type) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override; bool Key_part_spec_init_ft(Key_part_spec *part, const Column_definition &def) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; /* Old varchar */ class Type_handler_var_string: public Type_handler_string { public: virtual ~Type_handler_var_string() = default; enum_field_types field_type() const override { return MYSQL_TYPE_VAR_STRING; } enum_field_types real_field_type() const override { return MYSQL_TYPE_STRING; } enum_field_types traditional_merge_field_type() const override { return MYSQL_TYPE_VARCHAR; } const Type_handler *type_handler_for_tmp_table(const Item *item) const override { return varstring_type_handler(item); } uint32 max_display_length_for_field(const Conv_source &src) const override; void show_binlog_type(const Conv_source &src, const Field &dst, String *str) const override; void Column_definition_implicit_upgrade(Column_definition *c) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override { return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_STRING); } const Type_handler *type_handler_for_union(const Item *item) const override { return varstring_type_handler(item); } }; class Type_handler_varchar: public Type_handler_longstr { public: virtual ~Type_handler_varchar() = default; enum_field_types field_type() const override { return MYSQL_TYPE_VARCHAR; } ulong KEY_pack_flags(uint column_nr) const override { if (column_nr == 0) return HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY; return HA_PACK_KEY; } enum_field_types type_code_for_protocol() const override { return MYSQL_TYPE_VAR_STRING; // Keep things compatible for old clients } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override { return (length + (length < 256 ? 1: 2)); } const Type_handler *type_handler_for_tmp_table(const Item *item) const override { return varstring_type_handler(item); } const Type_handler *type_handler_for_union(const Item *item) const override { return varstring_type_handler(item); } bool is_param_long_data_type() const override { return true; } bool partition_field_check(const LEX_CSTRING &, Item *item_expr) const override { return partition_field_check_result_type(item_expr, STRING_RESULT); } void show_binlog_type(const Conv_source &src, const Field &dst, String *str) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_set_attributes(THD *thd, Column_definition *def, const Lex_field_type_st &attr, CHARSET_INFO *cs, column_definition_type_t type) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override; bool Key_part_spec_init_ft(Key_part_spec *part, const Column_definition &def) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; bool adjust_spparam_type(Spvar_definition *def, Item *from) const override; }; class Type_handler_hex_hybrid: public Type_handler_varchar { public: virtual ~Type_handler_hex_hybrid() = default; const Type_handler *cast_to_int_type_handler() const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; }; class Type_handler_varchar_compressed: public Type_handler_varchar { public: enum_field_types real_field_type() const override { return MYSQL_TYPE_VARCHAR_COMPRESSED; } ulong KEY_pack_flags(uint column_nr) const override { MY_ASSERT_UNREACHABLE(); return 0; } uint32 max_display_length_for_field(const Conv_source &src) const override; bool partition_field_check(const LEX_CSTRING &field_name, Item *) const override { partition_field_type_not_allowed(field_name); return true; } void show_binlog_type(const Conv_source &src, const Field &dst, String *str) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const override { DBUG_ASSERT(0); return DYN_COL_STRING; } }; class Type_handler_blob_common: public Type_handler_longstr { public: virtual ~Type_handler_blob_common() = default; virtual uint length_bytes() const= 0; ulong KEY_pack_flags(uint column_nr) const override { if (column_nr == 0) return HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY; return HA_PACK_KEY; } Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; const Type_handler *type_handler_for_tmp_table(const Item *item) const override { return blob_type_handler(item); } const Type_handler *type_handler_for_union(const Item *item) const override { return blob_type_handler(item); } bool subquery_type_allows_materialization(const Item *, const Item *, bool) const override { return false; // Materialization does not work with BLOB columns } bool is_param_long_data_type() const override { return true; } uint calc_key_length(const Column_definition &def) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; bool Key_part_spec_init_ft(Key_part_spec *part, const Column_definition &def) const override; bool Key_part_spec_init_primary(Key_part_spec *part, const Column_definition &def, const handler *file) const override; bool Key_part_spec_init_unique(Key_part_spec *part, const Column_definition &def, const handler *file, bool *has_key_needed) const override; bool Key_part_spec_init_multiple(Key_part_spec *part, const Column_definition &def, const handler *file) const override; bool Key_part_spec_init_foreign(Key_part_spec *part, const Column_definition &def, const handler *file) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; void Item_param_setup_conversion(THD *thd, Item_param *) const override; bool partition_field_check(const LEX_CSTRING &field_name, Item *item_expr) const override; Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; const Vers_type_handler *vers() const override; }; class Type_handler_tiny_blob: public Type_handler_blob_common { public: virtual ~Type_handler_tiny_blob() = default; uint length_bytes() const override { return 1; } enum_field_types field_type() const override { return MYSQL_TYPE_TINY_BLOB; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; uint max_octet_length() const override { return UINT_MAX8; } }; class Type_handler_medium_blob: public Type_handler_blob_common { public: virtual ~Type_handler_medium_blob() = default; uint length_bytes() const override { return 3; } enum_field_types field_type() const override { return MYSQL_TYPE_MEDIUM_BLOB; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; uint max_octet_length() const override { return UINT_MAX24; } }; class Type_handler_long_blob: public Type_handler_blob_common { public: virtual ~Type_handler_long_blob() = default; uint length_bytes() const override { return 4; } enum_field_types field_type() const override { return MYSQL_TYPE_LONG_BLOB; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; uint max_octet_length() const override { return UINT_MAX32; } }; class Type_handler_blob: public Type_handler_blob_common { public: virtual ~Type_handler_blob() = default; uint length_bytes() const override { return 2; } enum_field_types field_type() const override { return MYSQL_TYPE_BLOB; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; uint max_octet_length() const override { return UINT_MAX16; } }; class Type_handler_blob_compressed: public Type_handler_blob { public: enum_field_types real_field_type() const override { return MYSQL_TYPE_BLOB_COMPRESSED; } ulong KEY_pack_flags(uint) const override { MY_ASSERT_UNREACHABLE(); return 0; } uint32 max_display_length_for_field(const Conv_source &src) const override; void show_binlog_type(const Conv_source &src, const Field &, String *str) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; enum_dynamic_column_type dyncol_type(const Type_all_attributes *) const override { DBUG_ASSERT(0); return DYN_COL_STRING; } }; class Type_handler_typelib: public Type_handler_general_purpose_string { public: virtual ~Type_handler_typelib() = default; enum_field_types field_type() const override { return MYSQL_TYPE_STRING; } const Type_handler *type_handler_for_item_field() const override; const Type_handler *cast_to_int_type_handler() const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; uint32 max_display_length_for_field(const Conv_source &src) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const override; void Column_definition_reuse_fix_attributes(THD *thd, Column_definition *c, const Field *field) const override; bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const override; bool Column_definition_redefine_stage1(Column_definition *def, const Column_definition *dup, const handler *file) const override; void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; const Vers_type_handler *vers() const override { return NULL; } }; class Type_handler_enum: public Type_handler_typelib { public: virtual ~Type_handler_enum() = default; enum_field_types real_field_type() const override { return MYSQL_TYPE_ENUM; } enum_field_types traditional_merge_field_type() const override { return MYSQL_TYPE_ENUM; } uint32 calc_pack_length(uint32 length) const override; uint calc_key_length(const Column_definition &def) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; Field *make_schema_field(MEM_ROOT *root, TABLE *table, const Record_addr &addr, const ST_FIELD_INFO &def) const override; }; class Type_handler_set: public Type_handler_typelib { public: virtual ~Type_handler_set() = default; enum_field_types real_field_type() const override { return MYSQL_TYPE_SET; } enum_field_types traditional_merge_field_type() const override { return MYSQL_TYPE_SET; } uint32 calc_pack_length(uint32 length) const override; uint calc_key_length(const Column_definition &def) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; }; // A pseudo type handler, mostly for test purposes for now class Type_handler_interval_DDhhmmssff: public Type_handler_long_blob { public: Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override; }; class Function_collection { public: virtual ~Function_collection() = default; virtual bool init()= 0; virtual void cleanup()= 0; virtual Create_func *find_native_function_builder(THD *thd, const LEX_CSTRING &name) const= 0; }; class Type_collection { public: virtual ~Type_collection() = default; virtual bool init(Type_handler_data *) { return false; } virtual const Type_handler *aggregate_for_result(const Type_handler *h1, const Type_handler *h2) const= 0; virtual const Type_handler *aggregate_for_comparison(const Type_handler *h1, const Type_handler *h2) const= 0; virtual const Type_handler *aggregate_for_min_max(const Type_handler *h1, const Type_handler *h2) const= 0; virtual const Type_handler *aggregate_for_num_op(const Type_handler *h1, const Type_handler *h2) const= 0; }; /** A handler for hybrid type functions, e.g. COALESCE(), IF(), IFNULL(), NULLIF(), CASE, numeric operators, UNIX_TIMESTAMP(), TIME_TO_SEC(). Makes sure that field_type(), cmp_type() and result_type() are always in sync to each other for hybrid functions. */ class Type_handler_hybrid_field_type { const Type_handler *m_type_handler; bool aggregate_for_min_max(const Type_handler *other); public: Type_handler_hybrid_field_type(); Type_handler_hybrid_field_type(const Type_handler *handler) :m_type_handler(handler) { } Type_handler_hybrid_field_type(const Type_handler_hybrid_field_type *other) :m_type_handler(other->m_type_handler) { } void swap(Type_handler_hybrid_field_type &other) { swap_variables(const Type_handler *, m_type_handler, other.m_type_handler); } const Type_handler *type_handler() const { return m_type_handler; } enum_field_types real_field_type() const { return m_type_handler->real_field_type(); } Item_result cmp_type() const { return m_type_handler->cmp_type(); } enum_mysql_timestamp_type mysql_timestamp_type() const { return m_type_handler->mysql_timestamp_type(); } bool is_timestamp_type() const { return m_type_handler->is_timestamp_type(); } void set_handler(const Type_handler *other) { m_type_handler= other; } const Type_handler *set_handler_by_field_type(enum_field_types type) { return (m_type_handler= Type_handler::get_handler_by_field_type(type)); } const Type_handler *set_handler_by_real_type(enum_field_types type) { return (m_type_handler= Type_handler::get_handler_by_real_type(type)); } bool aggregate_for_comparison(const Type_handler *other); bool aggregate_for_comparison(const LEX_CSTRING &funcname, Item **items, uint nitems, bool treat_int_to_uint_as_decimal); bool aggregate_for_result(const Type_handler *other); bool aggregate_for_result(const LEX_CSTRING &funcname, Item **item, uint nitems, bool treat_bit_as_number); bool aggregate_for_min_max(const LEX_CSTRING &funcname, Item **item, uint nitems); bool aggregate_for_num_op(const class Type_aggregator *aggregator, const Type_handler *h0, const Type_handler *h1); }; class Type_handler_pair { const Type_handler *m_a; const Type_handler *m_b; public: Type_handler_pair(const Type_handler *a, const Type_handler *b) :m_a(a), m_b(b) { } const Type_handler *a() const { return m_a; } const Type_handler *b() const { return m_b; } /* Change both handlers to their parent data type handlers, if available. For example, VARCHAR/JSON -> VARCHAR. @returns The number of handlers changed (0,1 or 2). */ bool to_base() { bool rc= false; const Type_handler *na= m_a->type_handler_base(); const Type_handler *nb= m_b->type_handler_base(); if (na) { m_a= na; rc= true; } if (nb) { m_b= nb; rc= true; } return rc; } }; /* Helper template to simplify creating builtin types with names. Plugin types inherit from Type_handler_xxx types that do not set the name in the constructor, as sql_plugin.cc sets the type name from the plugin name. */ template class Named_type_handler : public TypeHandler { public: Named_type_handler(const char *n) : TypeHandler() { Type_handler::set_name(Name(n, static_cast(strlen(n)))); } }; extern Named_type_handler type_handler_row; extern Named_type_handler type_handler_null; extern Named_type_handler type_handler_float; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_double; extern Named_type_handler type_handler_bit; extern Named_type_handler type_handler_enum; extern Named_type_handler type_handler_set; extern Named_type_handler type_handler_string; extern Named_type_handler type_handler_var_string; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_varchar; extern Named_type_handler type_handler_varchar_compressed; extern Named_type_handler type_handler_hex_hybrid; extern Named_type_handler type_handler_tiny_blob; extern Named_type_handler type_handler_medium_blob; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_long_blob; extern Named_type_handler type_handler_blob; extern Named_type_handler type_handler_blob_compressed; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_bool; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_stiny; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_sshort; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_sint24; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_slong; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_slong_ge0; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_slonglong; extern Named_type_handler type_handler_utiny; extern Named_type_handler type_handler_ushort; extern Named_type_handler type_handler_uint24; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_ulong; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_ulonglong; extern Named_type_handler type_handler_vers_trx_id; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_newdecimal; extern Named_type_handler type_handler_olddecimal; extern Named_type_handler type_handler_year; extern Named_type_handler type_handler_year2; extern Named_type_handler type_handler_newdate; extern Named_type_handler type_handler_date; extern Named_type_handler type_handler_time; extern Named_type_handler type_handler_time2; extern Named_type_handler type_handler_datetime; extern Named_type_handler type_handler_datetime2; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_timestamp; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_timestamp2; extern Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff; class Type_aggregator { bool m_is_commutative; public: class Pair { public: const Type_handler *m_handler1; const Type_handler *m_handler2; const Type_handler *m_result; Pair() = default; Pair(const Type_handler *handler1, const Type_handler *handler2, const Type_handler *result) :m_handler1(handler1), m_handler2(handler2), m_result(result) { } bool eq(const Type_handler *handler1, const Type_handler *handler2) const { return m_handler1 == handler1 && m_handler2 == handler2; } }; static const Type_handler * find_handler_in_array(const Type_aggregator::Pair *pairs, const Type_handler *h1, const Type_handler *h2, bool commutative) { for (const Type_aggregator::Pair *p= pairs; p->m_result; p++) { if (p->eq(h1, h2)) return p->m_result; if (commutative && p->eq(h2, h1)) return p->m_result; } return NULL; } private: Dynamic_array m_array; const Pair* find_pair(const Type_handler *handler1, const Type_handler *handler2) const; public: Type_aggregator(bool is_commutative= false) :m_is_commutative(is_commutative), m_array(PSI_INSTRUMENT_MEM) { } bool add(const Type_handler *handler1, const Type_handler *handler2, const Type_handler *result) { return m_array.append(Pair(handler1, handler2, result)); } const Type_handler *find_handler(const Type_handler *handler1, const Type_handler *handler2) const { const Pair* el= find_pair(handler1, handler2); return el ? el->m_result : NULL; } bool is_commutative() const { return m_is_commutative; } }; class Type_aggregator_commutative: public Type_aggregator { public: Type_aggregator_commutative() :Type_aggregator(true) { } }; class Type_handler_data { public: Type_aggregator_commutative m_type_aggregator_for_result; Type_aggregator_commutative m_type_aggregator_for_comparison; Type_aggregator_commutative m_type_aggregator_for_plus; Type_aggregator_commutative m_type_aggregator_for_mul; Type_aggregator m_type_aggregator_for_minus; Type_aggregator m_type_aggregator_for_div; Type_aggregator m_type_aggregator_for_mod; #ifndef DBUG_OFF // This is used for mtr purposes in debug builds Type_aggregator m_type_aggregator_non_commutative_test; #endif bool init(); }; extern Type_handler_data *type_handler_data; #endif /* SQL_TYPE_H_INCLUDED */ server/private/wsrep_var.h000064400000010777151031265040011716 0ustar00/* Copyright (C) 2013-2023 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA. */ #ifndef WSREP_VAR_H #define WSREP_VAR_H #include #ifdef WITH_WSREP #define WSREP_CLUSTER_NAME "my_wsrep_cluster" #define WSREP_NODE_INCOMING_AUTO "AUTO" #define WSREP_START_POSITION_ZERO "00000000-0000-0000-0000-000000000000:-1" #define WSREP_START_POSITION_ZERO_GTID "00000000-0000-0000-0000-000000000000:-1,0-0-0" // MySQL variables funcs #include "sql_priv.h" #include #include class sys_var; class set_var; class THD; int wsrep_init_vars(); void wsrep_set_wsrep_on(THD *thd); void wsrep_free_status_vars(); #define CHECK_ARGS (sys_var *self, THD* thd, set_var *var) #define UPDATE_ARGS (sys_var *self, THD* thd, enum_var_type type) #define DEFAULT_ARGS (THD* thd, enum_var_type var_type) #define INIT_ARGS (const char* opt) extern bool wsrep_causal_reads_update UPDATE_ARGS; extern bool wsrep_on_check CHECK_ARGS; extern bool wsrep_on_update UPDATE_ARGS; extern bool wsrep_sync_wait_update UPDATE_ARGS; extern bool wsrep_start_position_check CHECK_ARGS; extern bool wsrep_start_position_update UPDATE_ARGS; extern bool wsrep_start_position_init INIT_ARGS; extern bool wsrep_provider_check CHECK_ARGS; extern bool wsrep_provider_update UPDATE_ARGS; extern void wsrep_provider_init INIT_ARGS; extern bool wsrep_provider_options_check CHECK_ARGS; extern bool wsrep_provider_options_update UPDATE_ARGS; extern void wsrep_provider_options_init INIT_ARGS; extern bool wsrep_cluster_address_check CHECK_ARGS; extern bool wsrep_cluster_address_update UPDATE_ARGS; extern void wsrep_cluster_address_init INIT_ARGS; extern bool wsrep_cluster_name_check CHECK_ARGS; extern bool wsrep_cluster_name_update UPDATE_ARGS; extern bool wsrep_node_name_check CHECK_ARGS; extern bool wsrep_node_name_update UPDATE_ARGS; extern bool wsrep_node_address_check CHECK_ARGS; extern bool wsrep_node_address_update UPDATE_ARGS; extern void wsrep_node_address_init INIT_ARGS; extern bool wsrep_sst_method_check CHECK_ARGS; extern bool wsrep_sst_method_update UPDATE_ARGS; extern void wsrep_sst_method_init INIT_ARGS; extern bool wsrep_sst_receive_address_check CHECK_ARGS; extern bool wsrep_sst_receive_address_update UPDATE_ARGS; extern bool wsrep_sst_auth_check CHECK_ARGS; extern bool wsrep_sst_auth_update UPDATE_ARGS; extern bool wsrep_sst_donor_check CHECK_ARGS; extern bool wsrep_sst_donor_update UPDATE_ARGS; extern bool wsrep_slave_threads_check CHECK_ARGS; extern bool wsrep_slave_threads_update UPDATE_ARGS; extern bool wsrep_desync_check CHECK_ARGS; extern bool wsrep_desync_update UPDATE_ARGS; extern bool wsrep_trx_fragment_size_check CHECK_ARGS; extern bool wsrep_trx_fragment_size_update UPDATE_ARGS; extern bool wsrep_trx_fragment_unit_update UPDATE_ARGS; extern bool wsrep_max_ws_size_check CHECK_ARGS; extern bool wsrep_max_ws_size_update UPDATE_ARGS; extern bool wsrep_reject_queries_update UPDATE_ARGS; extern bool wsrep_debug_update UPDATE_ARGS; extern bool wsrep_gtid_seq_no_check CHECK_ARGS; extern bool wsrep_gtid_domain_id_update UPDATE_ARGS; extern bool wsrep_mode_check CHECK_ARGS; extern bool wsrep_strict_ddl_update UPDATE_ARGS; extern bool wsrep_replicate_myisam_update UPDATE_ARGS; extern bool wsrep_replicate_myisam_check CHECK_ARGS; extern bool wsrep_forced_binlog_format_check CHECK_ARGS; #else /* WITH_WSREP */ #define wsrep_provider_init(X) #define wsrep_init_vars() (0) #define wsrep_start_position_init(X) #endif /* WITH_WSREP */ #endif /* WSREP_VAR_H */ server/private/transaction.h000064400000002672151031265040012226 0ustar00/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef TRANSACTION_H #define TRANSACTION_H #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include class THD; void trans_track_end_trx(THD *thd); bool trans_begin(THD *thd, uint flags= 0); bool trans_commit(THD *thd); bool trans_commit_implicit(THD *thd); bool trans_rollback(THD *thd); bool trans_rollback_implicit(THD *thd); bool trans_commit_stmt(THD *thd); bool trans_rollback_stmt(THD *thd); bool trans_savepoint(THD *thd, LEX_CSTRING name); bool trans_rollback_to_savepoint(THD *thd, LEX_CSTRING name); bool trans_release_savepoint(THD *thd, LEX_CSTRING name); void trans_reset_one_shot_chistics(THD *thd); #endif /* TRANSACTION_H */ server/private/multi_range_read.h000064400000055213151031265040013201 0ustar00/* Copyright (c) 2009, 2011, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @defgroup DS-MRR declarations @{ */ /** A Disk-Sweep implementation of MRR Interface (DS-MRR for short) This is a "plugin"(*) for storage engines that allows to 1. When doing index scans, read table rows in rowid order; 2. when making many index lookups, do them in key order and don't lookup the same key value multiple times; 3. Do both #1 and #2, when applicable. These changes are expected to speed up query execution for disk-based storage engines running io-bound loads and "big" queries (ie. queries that do joins and enumerate lots of records). (*) - only conceptually. No dynamic loading or binary compatibility of any kind. General scheme of things: SQL Layer code | | | v v v -|---|---|---- handler->multi_range_read_XXX() function calls | | | _____________________________________ / DS-MRR module \ | (order/de-duplicate lookup keys, | | scan indexes in key order, | | order/de-duplicate rowids, | | retrieve full record reads in rowid | | order) | \_____________________________________/ | | | -|---|---|----- handler->read_range_first()/read_range_next(), | | | handler->index_read(), handler->rnd_pos() calls. | | | v v v Storage engine internals Currently DS-MRR is used by MyISAM, InnoDB and Maria storage engines. Potentially it can be used with any table handler that has disk-based data storage and has better performance when reading data in rowid order. */ #include "sql_lifo_buffer.h" class DsMrr_impl; class Mrr_ordered_index_reader; /* A structure with key parameters that's shared among several classes */ class Key_parameters { public: uint key_tuple_length; /* Length of index lookup tuple, in bytes */ key_part_map key_tuple_map; /* keyparts used in index lookup tuples */ /* This is = key_tuple_length if we copy keys to buffer = sizeof(void*) if we're using pointers to materialized keys. */ uint key_size_in_keybuf; /* TRUE <=> don't copy key values, use pointers to them instead. */ bool use_key_pointers; /* TRUE <=> We can get at most one index tuple for a lookup key */ bool index_ranges_unique; }; /** A class to enumerate (record, range_id) pairs that match given key value. @note The idea is that we have a Lifo_buffer which holds (key, range_id) pairs ordered by key value. From the front of the buffer we see (key_val1, range_id1), (key_val1, range_id2) ... (key_val2, range_idN) we take the first elements that have the same key value (key_val1 in the example above), and make lookup into the table. The table will have multiple matches for key_val1: == Table Index == ... key_val1 -> key_val1, index_tuple1 key_val1, index_tuple2 ... key_val1, index_tupleN ... Our goal is to produce all possible combinations, i.e. we need: {(key_val1, index_tuple1), range_id1} {(key_val1, index_tuple1), range_id2} ... ... | {(key_val1, index_tuple1), range_idN}, {(key_val1, index_tuple2), range_id1} {(key_val1, index_tuple2), range_id2} ... ... | {(key_val1, index_tuple2), range_idN}, ... ... ... {(key_val1, index_tupleK), range_idN} */ class Key_value_records_iterator { /* Use this to get table handler, key buffer and other parameters */ Mrr_ordered_index_reader *owner; /* Iterator to get (key, range_id) pairs from */ Lifo_buffer_iterator identical_key_it; /* Last of the identical key values (when we get this pointer from identical_key_it, it will be time to stop). */ uchar *last_identical_key_ptr; /* FALSE <=> we're right after the init() call, the record has been already read with owner->file->index_read_map() call */ bool get_next_row; public: int init(Mrr_ordered_index_reader *owner_arg); int get_next(range_id_t *range_info); void move_to_next_key_value(); }; /* Buffer manager interface. Mrr_reader objects use it to inqure DsMrr_impl to manage buffer space for them. */ typedef struct st_buffer_manager { public: /* Opaque value to be passed as the first argument to all member functions */ void *arg; /* This is called when we've freed more space from the rowid buffer. The callee will get the unused space from the rowid buffer and give it to the key buffer. */ void (*redistribute_buffer_space)(void *arg); /* This is called when both key and rowid buffers are empty, and so it's time to reset them to their original size (They've lost their original size, because we were dynamically growing rowid buffer and shrinking key buffer). */ void (*reset_buffer_sizes)(void *arg); } Buffer_manager; /* Mrr_reader - DS-MRR execution strategy abstraction A reader produces ([index]_record, range_info) pairs, and requires periodic refill operations. - one starts using the reader by calling reader->get_next(), - when a get_next() call returns HA_ERR_END_OF_FILE, one must call refill_buffer() before they can make more get_next() calls. - when refill_buffer() returns HA_ERR_END_OF_FILE, this means the real end of stream and get_next() should not be called anymore. Both functions can return other error codes, these mean unrecoverable errors after which one cannot continue. */ class Mrr_reader { public: virtual int get_next(range_id_t *range_info) = 0; virtual int refill_buffer(bool initial) = 0; virtual ~Mrr_reader() = default; /* just to remove compiler warning */ }; /* A common base for readers that do index scans and produce index tuples */ class Mrr_index_reader : public Mrr_reader { protected: handler *file; /* Handler object to use */ public: virtual int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, void *seq_init_param, uint n_ranges, uint mode, Key_parameters *key_par, Lifo_buffer *key_buffer, Buffer_manager *buf_manager_arg) = 0; /* Get pointer to place where every get_next() call will put rowid */ virtual uchar *get_rowid_ptr() = 0; /* Get the rowid (call this after get_next() call) */ virtual void position(); virtual bool skip_record(range_id_t range_id, uchar *rowid) = 0; virtual void interrupt_read() {} virtual void resume_read() {} }; /* A "bypass" index reader that just does and index scan. The index scan is done by calling default MRR implementation (i.e. handler::multi_range_read_XXX()) functions. */ class Mrr_simple_index_reader : public Mrr_index_reader { public: int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, void *seq_init_param, uint n_ranges, uint mode, Key_parameters *key_par, Lifo_buffer *key_buffer, Buffer_manager *buf_manager_arg) override; int get_next(range_id_t *range_info) override; int refill_buffer(bool initial) override { return initial? 0: HA_ERR_END_OF_FILE; } uchar *get_rowid_ptr() override { return file->ref; } bool skip_record(range_id_t range_id, uchar *rowid) override { return (file->mrr_funcs.skip_record && file->mrr_funcs.skip_record(file->mrr_iter, range_id, rowid)); } }; /* A reader that sorts the key values before it makes the index lookups. */ class Mrr_ordered_index_reader : public Mrr_index_reader { public: int init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, void *seq_init_param, uint n_ranges, uint mode, Key_parameters *key_par, Lifo_buffer *key_buffer, Buffer_manager *buf_manager_arg) override; int get_next(range_id_t *range_info) override; int refill_buffer(bool initial) override; uchar *get_rowid_ptr() override { return file->ref; } bool skip_record(range_id_t range_info, uchar *rowid) override { return (mrr_funcs.skip_record && mrr_funcs.skip_record(mrr_iter, range_info, rowid)); } bool skip_index_tuple(range_id_t range_info) { return (mrr_funcs.skip_index_tuple && mrr_funcs.skip_index_tuple(mrr_iter, range_info)); } bool set_interruption_temp_buffer(uint rowid_length, uint key_len, uint saved_pk_len, uchar **space_start, uchar *space_end); void set_no_interruption_temp_buffer(); void interrupt_read() override; void resume_read() override; void position() override; private: Key_value_records_iterator kv_it; bool scanning_key_val_iter; /* Buffer to store (key, range_id) pairs */ Lifo_buffer *key_buffer; /* This manages key buffer allocation and sizing for us */ Buffer_manager *buf_manager; Key_parameters keypar; /* index scan and lookup tuple parameters */ /* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */ bool is_mrr_assoc; /* Range sequence iteration members */ RANGE_SEQ_IF mrr_funcs; range_seq_t mrr_iter; /* TRUE == reached eof when enumerating ranges */ bool source_exhausted; /* Following members are for interrupt_read()/resume_read(). The idea is that in some cases index scan that is done by this object is interrupted by rnd_pos() calls made by Mrr_ordered_rndpos_reader. The problem is that we're sharing handler->record[0] with that object, and it destroys its contents. We need to save/restore our current - index tuple (for pushed index condition checks) - clustered primary key values (again, for pushed index condition checks) - rowid of the last record we've retrieved (in case this rowid matches multiple ranges and we'll need to return it again) */ bool support_scan_interruptions; /* Space where we save the rowid of the last record we've returned */ uchar *saved_rowid; /* TRUE <=> saved_rowid has the last saved rowid */ bool have_saved_rowid; uchar *saved_key_tuple; /* Saved current key tuple */ uchar *saved_primary_key; /* Saved current primary key tuple */ /* TRUE<=> saved_key_tuple (and saved_primary_key when applicable) have valid values. */ bool read_was_interrupted; static int compare_keys(void *arg, const void *key1, const void *key2); static int compare_keys_reverse(void *arg, const void *key1, const void *key2); friend class Key_value_records_iterator; friend class DsMrr_impl; friend class Mrr_ordered_rndpos_reader; }; /* A reader that gets rowids from an Mrr_index_reader, and then sorts them before getting full records with handler->rndpos() calls. */ class Mrr_ordered_rndpos_reader : public Mrr_reader { public: int init(handler *file, Mrr_index_reader *index_reader, uint mode, Lifo_buffer *buf, Rowid_filter *filter); int get_next(range_id_t *range_info) override; int refill_buffer(bool initial) override; private: handler *file; /* Handler to use */ /* This what we get (rowid, range_info) pairs from */ Mrr_index_reader *index_reader; /* index_reader->get_next() puts rowid here */ uchar *index_rowid; /* TRUE <=> index_reader->refill_buffer() call has returned EOF */ bool index_reader_exhausted; /* TRUE <=> We should call index_reader->refill_buffer(). This happens if 1. we've made index_reader->get_next() call which returned EOF 2. we haven't made any index_reader calls (and our first call should be index_reader->refill_buffer(initial=TRUE) */ bool index_reader_needs_refill; /* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */ bool is_mrr_assoc; /* When reading from ordered rowid buffer: the rowid element of the last buffer element that has rowid identical to this one. */ uchar *last_identical_rowid; /* Buffer to store (rowid, range_id) pairs */ Lifo_buffer *rowid_buffer; /* Rowid filter to be checked against (if any) */ Rowid_filter *rowid_filter; int refill_from_index_reader(); }; /* A primitive "factory" of various Mrr_*_reader classes (the point is to get various kinds of readers without having to allocate them on the heap) */ class Mrr_reader_factory { public: Mrr_ordered_rndpos_reader ordered_rndpos_reader; Mrr_ordered_index_reader ordered_index_reader; Mrr_simple_index_reader simple_index_reader; }; #define DSMRR_IMPL_SORT_KEYS HA_MRR_IMPLEMENTATION_FLAG1 #define DSMRR_IMPL_SORT_ROWIDS HA_MRR_IMPLEMENTATION_FLAG2 /* DS-MRR implementation for one table. Create/use one object of this class for each ha_{myisam/innobase/etc} object. That object will be further referred to as "the handler" DsMrr_impl supports has the following execution strategies: - Bypass DS-MRR, pass all calls to default MRR implementation, which is an MRR-to-non-MRR call converter. - Key-Ordered Retrieval - Rowid-Ordered Retrieval DsMrr_impl will use one of the above strategies, or a combination of them, according to the following diagram: (mrr function calls) | +----------------->-----------------+ | | ___________v______________ _______________v________________ / default: use lookup keys \ / KEY-ORDERED RETRIEVAL: \ | (or ranges) in whatever | | sort lookup keys and then make | | order they are supplied | | index lookups in index order | \__________________________/ \________________________________/ | | | | | +---<---+ | +--------------->-----------|----+ | | | | | | +---------------+ | | ______v___ ______ | _______________v_______________ | / default: read \ | / ROWID-ORDERED RETRIEVAL: \ | | table records | | | Before reading table records, | v | in random order | v | sort their rowids and then | | \_________________/ | | read them in rowid order | | | | \_______________________________/ | | | | | | | | +-->---+ | +----<------+-----------<--------+ | | | v v v (table records and range_ids) The choice of strategy depends on MRR scan properties, table properties (whether we're scanning clustered primary key), and @@optimizer_switch settings. Key-Ordered Retrieval --------------------- The idea is: if MRR scan is essentially a series of lookups on tbl.key=value1 OR tbl.key=value2 OR ... OR tbl.key=valueN then it makes sense to collect and order the set of lookup values, i.e. sort(value1, value2, .. valueN) and then do index lookups in index order. This results in fewer index page fetch operations, and we also can avoid making multiple index lookups for the same value. That is, if value1=valueN we can easily discover that after sorting and make one index lookup for them instead of two. Rowid-Ordered Retrieval ----------------------- If we do a regular index scan or a series of index lookups, we'll be hitting table records at random. For disk-based engines, this is much slower than reading the same records in disk order. We assume that disk ordering of rows is the same as ordering of their rowids (which is provided by handler::cmp_ref()) In order to retrieve records in different order, we must separate index scanning and record fetching, that is, MRR scan uses the following steps: 1. Scan the index (and only index, that is, with HA_EXTRA_KEYREAD on) and fill a buffer with {rowid, range_id} pairs 2. Sort the buffer by rowid value 3. for each {rowid, range_id} pair in the buffer get record by rowid and return the {record, range_id} pair 4. Repeat the above steps until we've exhausted the list of ranges we're scanning. Buffer space management considerations -------------------------------------- With regards to buffer/memory management, MRR interface specifies that - SQL layer provides multi_range_read_init() with buffer of certain size. - MRR implementation may use (i.e. have at its disposal till the end of the MRR scan) all of the buffer, or return the unused end of the buffer to SQL layer. DS-MRR needs buffer in order to accumulate and sort rowids and/or keys. When we need to accumulate/sort only keys (or only rowids), it is fairly trivial. When we need to accumulate/sort both keys and rowids, efficient buffer use gets complicated. We need to: - First, accumulate keys and sort them - Then use the keys (smaller values go first) to obtain rowids. A key is not needed after we've got matching rowids for it. - Make sure that rowids are accumulated at the front of the buffer, so that we can return the end part of the buffer to SQL layer, should there be too few rowid values to occupy the buffer. All of these goals are achieved by using the following scheme: | | We get an empty buffer from SQL layer. | *-| | *----| First, we fill the buffer with keys. Key_buffer | *-------| part grows from end of the buffer space to start | *----------| (In this picture, the buffer is big enough to | *-------------| accomodate all keys and even have some space left) | *=============| We want to do key-ordered index scan, so we sort the keys |-x *===========| Then we use the keys get rowids. Rowids are |----x *========| stored from start of buffer space towards the end. |--------x *=====| The part of the buffer occupied with keys |------------x *===| gradually frees up space for rowids. In this |--------------x *=| picture we run out of keys before we've ran out |----------------x | of buffer space (it can be other way as well). |================x | Then we sort the rowids. | |~~~| The unused part of the buffer is at the end, so we can return it to the SQL layer. |================* Sorted rowids are then used to read table records in disk order */ class DsMrr_impl { public: typedef void (handler::*range_check_toggle_func_t)(bool on); void init(handler *h_arg, TABLE *table_arg) { primary_file= h_arg; table= table_arg; } int dsmrr_init(handler *h_arg, RANGE_SEQ_IF *seq_funcs, void *seq_init_param, uint n_ranges, uint mode, HANDLER_BUFFER *buf); void dsmrr_close(); int dsmrr_next(range_id_t *range_info); ha_rows dsmrr_info(uint keyno, uint n_ranges, uint keys, uint key_parts, uint *bufsz, uint *flags, Cost_estimate *cost); ha_rows dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, uint *flags, Cost_estimate *cost); int dsmrr_explain_info(uint mrr_mode, char *str, size_t size); private: /* Buffer to store (key, range_id) pairs */ Lifo_buffer *key_buffer= nullptr; /* The "owner" handler object (the one that is expected to "own" this object and call its functions). */ handler *primary_file; TABLE *table; /* Always equal to primary_file->table */ /* Secondary handler object. (created when needed, we need it when we need to run both index scan and rnd_pos() scan at the same time) */ handler *secondary_file= nullptr; /* The rowid filter that DS-MRR has "unpushed" from the storage engine. If it's present, DS-MRR will use it. */ Rowid_filter *rowid_filter= nullptr; uint keyno; /* index we're running the scan on */ /* TRUE <=> need range association, buffers hold {rowid, range_id} pairs */ bool is_mrr_assoc; Mrr_reader_factory reader_factory; Mrr_reader *strategy; bool strategy_exhausted; Mrr_index_reader *index_strategy; /* The whole buffer space that we're using */ uchar *full_buf; uchar *full_buf_end; /* When using both rowid and key buffers: the boundary between key and rowid parts of the buffer. This is the "original" value, actual memory ranges used by key and rowid parts may be different because of dynamic space reallocation between them. */ uchar *rowid_buffer_end; /* One of the following two is used for key buffer: forward is used when we only need key buffer, backward is used when we need both key and rowid buffers. */ Forward_lifo_buffer forward_key_buf; Backward_lifo_buffer backward_key_buf; /* Buffer to store (rowid, range_id) pairs, or just rowids if is_mrr_assoc==FALSE */ Forward_lifo_buffer rowid_buffer; bool choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, uint *bufsz, Cost_estimate *cost); bool get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, uint *buffer_size, uint extra_mem_overhead, Cost_estimate *cost); bool check_cpk_scan(THD *thd, TABLE_SHARE *share, uint keyno, uint mrr_flags); bool setup_buffer_sharing(uint key_size_in_keybuf, key_part_map key_tuple_map); /* Buffer_manager and its member functions */ Buffer_manager buf_manager; static void redistribute_buffer_space(void *dsmrr_arg); static void reset_buffer_sizes(void *dsmrr_arg); static void do_nothing(void *dsmrr_arg); Lifo_buffer* get_key_buffer() { return key_buffer; } friend class Key_value_records_iterator; friend class Mrr_ordered_index_reader; friend class Mrr_ordered_rndpos_reader; int setup_two_handlers(); void close_second_handler(); }; /** @} (end of group DS-MRR declarations) */ server/private/my_uctype.h000064400000207630151031265040011720 0ustar00#ifndef MY_UCTYPE_INCLUDED #define MY_UCTYPE_INCLUDED /* Copyright (c) 2006 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Unicode ctype data Generated from UnicodeData-5.0.0d9.txt */ static unsigned char uctype_page00[256]= { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 16, 16, 16, 16, 16, 16, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 16, 16, 16, 16, 16, 16, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 32, 16, 16, 16, 16, 20, 20, 16, 2, 16, 16, 16, 20, 2, 16, 20, 20, 20, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2 }; static unsigned char uctype_page01[256]= { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2 }; static unsigned char uctype_page02[256]= { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 2, 2, 2, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; static unsigned char uctype_page03[256]= { 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 16, 16, 0, 0, 0, 0, 2, 2, 2, 2, 16, 0, 0, 0, 0, 0, 16, 16, 1, 16, 1, 1, 1, 0, 1, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 1, 2, 16, 1, 2, 1, 1, 2, 2, 1, 1, 1 }; static unsigned char uctype_page04[256]= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 16, 18, 18, 18, 18, 0, 18, 18, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 }; static unsigned char uctype_page05[256]= { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 2, 16, 16, 16, 16, 16, 16, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 16, 16, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 16, 18, 16, 18, 18, 16, 18, 18, 16, 18, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page06[256]= { 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 16, 0, 0, 16, 16, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 16, 16, 16, 2, 2, 18, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 2, 18, 18, 18, 18, 18, 18, 18, 32, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18, 16, 18, 18, 18, 18, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 16, 16, 2 }; static unsigned char uctype_page07[256]= { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 32, 2, 18, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 2, 16, 16, 16, 16, 2, 0, 0, 0, 0, 0 }; static unsigned char uctype_page09[256]= { 0, 18, 18, 18, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 2, 18, 18, 18, 18, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 16, 16, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 18, 18, 18, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 18, 2, 18, 18, 18, 18, 18, 18, 18, 0, 0, 18, 18, 0, 0, 18, 18, 18, 2, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 2, 2, 0, 2, 2, 2, 18, 18, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 16, 16, 20, 20, 20, 20, 20, 20, 16, 0, 0, 0, 0, 0 }; static unsigned char uctype_page0A[256]= { 0, 18, 18, 18, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 18, 18, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 18, 18, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 18, 18, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page0B[256]= { 0, 18, 18, 18, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 18, 2, 18, 18, 18, 18, 18, 18, 0, 0, 0, 18, 18, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 0, 0, 0, 0, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 2, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 0, 2, 0, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 18, 18, 18, 18, 18, 0, 0, 0, 18, 18, 18, 0, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 20, 20, 20, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0 }; static unsigned char uctype_page0C[256]= { 0, 18, 18, 18, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 18, 2, 18, 18, 18, 18, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 2, 18, 18, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page0D[256]= { 0, 0, 18, 18, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 0, 0, 18, 18, 18, 0, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 18, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 0, 18, 0, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page0E[256]= { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 2, 2, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 16, 2, 2, 2, 2, 2, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 16, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 2, 2, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 0, 2, 0, 0, 2, 2, 0, 2, 2, 2, 2, 18, 2, 2, 18, 18, 18, 18, 18, 18, 0, 18, 18, 2, 0, 0, 2, 2, 2, 2, 2, 0, 2, 0, 18, 18, 18, 18, 18, 18, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page0F[256]= { 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 18, 18, 16, 16, 16, 16, 16, 16, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16, 18, 16, 18, 16, 18, 16, 16, 16, 16, 18, 18, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 16, 18, 18, 2, 2, 2, 2, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 16, 16, 16, 16, 16, 16, 16, 16, 18, 16, 16, 16, 16, 16, 16, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page10[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 0, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 16, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 2, 0, 0, 0 }; static unsigned char uctype_page11[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page12[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; static unsigned char uctype_page13[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 18, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page14[256]= { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; static unsigned char uctype_page16[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page17[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 18, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 32, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 16, 16, 16, 2, 16, 16, 16, 16, 2, 18, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page18[256]= { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 18, 18, 18, 8, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page19[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 16, 0, 0, 0, 16, 16, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 2, 2, 2, 2, 2, 2, 18, 18, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; static unsigned char uctype_page1A[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 18, 18, 18, 0, 0, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page1B[256]= { 18, 18, 18, 18, 18, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 18, 18, 18, 18, 18, 18, 18, 18, 18, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page1D[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18 }; static unsigned char uctype_page1E[256]= { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page1F[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 2, 2, 1, 1, 1, 1, 1, 16, 2, 16, 16, 16, 2, 2, 2, 0, 2, 2, 1, 1, 1, 1, 1, 16, 16, 16, 2, 2, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 0, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 16, 16, 16, 0, 0, 2, 2, 2, 0, 2, 2, 1, 1, 1, 1, 1, 16, 16, 0 }; static unsigned char uctype_page20[256]= { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 32, 32, 32, 32, 32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 32, 32, 32, 32, 32, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 32, 32, 32, 32, 32, 32, 20, 2, 0, 0, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 16, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 16, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page21[256]= { 16, 16, 1, 16, 16, 16, 16, 1, 16, 16, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 16, 1, 16, 16, 16, 1, 1, 1, 1, 1, 16, 16, 16, 16, 16, 16, 1, 16, 1, 16, 1, 16, 1, 1, 1, 1, 16, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 16, 16, 2, 2, 1, 1, 16, 16, 16, 16, 16, 1, 2, 2, 2, 2, 16, 16, 16, 16, 2, 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; static unsigned char uctype_page23[256]= { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page24[256]= { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 }; static unsigned char uctype_page26[256]= { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page27[256]= { 0, 16, 16, 16, 16, 0, 16, 16, 16, 16, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 16, 0, 16, 16, 16, 16, 0, 0, 0, 16, 0, 16, 16, 16, 16, 16, 16, 16, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; static unsigned char uctype_page2B[256]= { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page2C[256]= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 20, 16, 16 }; static unsigned char uctype_page2D[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page2E[256]= { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_page2F[256]= { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0 }; static unsigned char uctype_page30[256]= { 8, 16, 16, 16, 16, 2, 2, 7, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 7, 7, 7, 7, 7, 7, 7, 7, 7, 18, 18, 18, 18, 18, 18, 16, 2, 2, 2, 2, 2, 16, 16, 7, 7, 7, 2, 2, 16, 16, 16, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 18, 18, 16, 16, 2, 2, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, 2, 2 }; static unsigned char uctype_page31[256]= { 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 16, 16, 20, 20, 20, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; static unsigned char uctype_page32[256]= { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0 }; static unsigned char uctype_page4D[256]= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; static unsigned char uctype_page9F[256]= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_pageA4[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_pageA7[256]= { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 2, 2, 2, 0, 0, 0, 0, 0, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_pageA8[256]= { 2, 2, 18, 2, 2, 2, 18, 2, 2, 2, 2, 18, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 18, 18, 18, 18, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_pageD7[256]= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_pageD8[256]= { 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_pageDB[256]= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32 }; static unsigned char uctype_pageDC[256]= { 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_pageDF[256]= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32 }; static unsigned char uctype_pageE0[256]= { 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_pageF8[256]= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32 }; static unsigned char uctype_pageFA[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char uctype_pageFB[256]= { 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 18, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; static unsigned char uctype_pageFD[256]= { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 0, 0 }; static unsigned char uctype_pageFE[256]= { 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 32 }; static unsigned char uctype_pageFF[256]= { 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 16, 16, 16, 16, 16, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 16, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 16, 16, 0, 0 }; MY_UNI_CTYPE my_uni_ctype[256]={ {0,uctype_page00}, {0,uctype_page01}, {0,uctype_page02}, {0,uctype_page03}, {0,uctype_page04}, {0,uctype_page05}, {0,uctype_page06}, {0,uctype_page07}, {0,NULL}, {0,uctype_page09}, {0,uctype_page0A}, {0,uctype_page0B}, {0,uctype_page0C}, {0,uctype_page0D}, {0,uctype_page0E}, {0,uctype_page0F}, {0,uctype_page10}, {0,uctype_page11}, {0,uctype_page12}, {0,uctype_page13}, {0,uctype_page14}, {2,NULL}, {0,uctype_page16}, {0,uctype_page17}, {0,uctype_page18}, {0,uctype_page19}, {0,uctype_page1A}, {0,uctype_page1B}, {0,NULL}, {0,uctype_page1D}, {0,uctype_page1E}, {0,uctype_page1F}, {0,uctype_page20}, {0,uctype_page21}, {16,NULL}, {0,uctype_page23}, {0,uctype_page24}, {16,NULL}, {0,uctype_page26}, {0,uctype_page27}, {16,NULL}, {16,NULL}, {16,NULL}, {0,uctype_page2B}, {0,uctype_page2C}, {0,uctype_page2D}, {0,uctype_page2E}, {0,uctype_page2F}, {0,uctype_page30}, {0,uctype_page31}, {0,uctype_page32}, {16,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {0,uctype_page4D}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {0,uctype_page9F}, {2,NULL}, {2,NULL}, {2,NULL}, {2,NULL}, {0,uctype_pageA4}, {0,NULL}, {0,NULL}, {0,uctype_pageA7}, {0,uctype_pageA8}, {0,NULL}, {0,NULL}, {0,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {3,NULL}, {0,uctype_pageD7}, {0,uctype_pageD8}, {0,NULL}, {0,NULL}, {0,uctype_pageDB}, {0,uctype_pageDC}, {0,NULL}, {0,NULL}, {0,uctype_pageDF}, {0,uctype_pageE0}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,NULL}, {0,uctype_pageF8}, {2,NULL}, {0,uctype_pageFA}, {0,uctype_pageFB}, {2,NULL}, {0,uctype_pageFD}, {0,uctype_pageFE}, {0,uctype_pageFF} }; #endif /* MY_UCTYPE_INCLUDED */ server/private/myisam.h000064400000042142151031265040011174 0ustar00/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. Copyright (c) 2009, 2013, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file should be included when using myisam_functions */ #ifndef _myisam_h #define _myisam_h #ifdef __cplusplus extern "C" { #endif #include #include #include "keycache.h" #include "my_compare.h" #include #include #include /* Limit max keys according to HA_MAX_POSSIBLE_KEY; See myisamchk.h for details */ #if MAX_INDEXES > HA_MAX_POSSIBLE_KEY #define MI_MAX_KEY HA_MAX_POSSIBLE_KEY /* Max allowed keys */ #else #define MI_MAX_KEY MAX_INDEXES /* Max allowed keys */ #endif #define MI_MAX_POSSIBLE_KEY_BUFF HA_MAX_POSSIBLE_KEY_BUFF /* The following defines can be increased if necessary. But beware the dependency of MI_MAX_POSSIBLE_KEY_BUFF and MI_MAX_KEY_LENGTH. */ #define MI_MAX_KEY_LENGTH 1000 /* Max length in bytes */ #define MI_MAX_KEY_SEG 16 /* Max segments for key */ #define MI_NAME_IEXT ".MYI" #define MI_NAME_DEXT ".MYD" /* Possible values for myisam_block_size (must be power of 2) */ #define MI_KEY_BLOCK_LENGTH 1024 /* default key block length */ #define MI_MIN_KEY_BLOCK_LENGTH 1024 /* Min key block length */ #define MI_MAX_KEY_BLOCK_LENGTH 16384 /* In the following macros '_keyno_' is 0 .. keys-1. If there can be more keys than bits in the key_map, the highest bit is for all upper keys. They cannot be switched individually. This means that clearing of high keys is ignored, setting one high key sets all high keys. */ #define MI_KEYMAP_BITS (8 * SIZEOF_LONG_LONG) #define MI_KEYMAP_HIGH_MASK (1ULL << (MI_KEYMAP_BITS - 1)) #define mi_get_mask_all_keys_active(_keys_) \ (((_keys_) < MI_KEYMAP_BITS) ? \ ((1ULL << (_keys_)) - 1ULL) : \ (~ 0ULL)) #if MI_MAX_KEY > MI_KEYMAP_BITS #define mi_is_key_active(_keymap_,_keyno_) \ (((_keyno_) < MI_KEYMAP_BITS) ? \ MY_TEST((_keymap_) & (1ULL << (_keyno_))) : \ MY_TEST((_keymap_) & MI_KEYMAP_HIGH_MASK)) #define mi_set_key_active(_keymap_,_keyno_) \ (_keymap_)|= (((_keyno_) < MI_KEYMAP_BITS) ? \ (1ULL << (_keyno_)) : \ MI_KEYMAP_HIGH_MASK) #define mi_clear_key_active(_keymap_,_keyno_) \ (_keymap_)&= (((_keyno_) < MI_KEYMAP_BITS) ? \ (~ (1ULL << (_keyno_))) : \ (~ (0ULL)) /*ignore*/ ) #else #define mi_is_key_active(_keymap_,_keyno_) \ MY_TEST((_keymap_) & (1ULL << (_keyno_))) #define mi_set_key_active(_keymap_,_keyno_) \ (_keymap_)|= (1ULL << (_keyno_)) #define mi_clear_key_active(_keymap_,_keyno_) \ (_keymap_)&= (~ (1ULL << (_keyno_))) #endif #define mi_is_any_key_active(_keymap_) \ MY_TEST((_keymap_)) #define mi_is_all_keys_active(_keymap_,_keys_) \ ((_keymap_) == mi_get_mask_all_keys_active(_keys_)) #define mi_set_all_keys_active(_keymap_,_keys_) \ (_keymap_)= mi_get_mask_all_keys_active(_keys_) #define mi_clear_all_keys_active(_keymap_) \ (_keymap_)= 0 #define mi_intersect_keys_active(_to_,_from_) \ (_to_)&= (_from_) #define mi_is_any_intersect_keys_active(_keymap1_,_keys_,_keymap2_) \ ((_keymap1_) & (_keymap2_) & \ mi_get_mask_all_keys_active(_keys_)) #define mi_copy_keys_active(_to_,_maxkeys_,_from_) \ (_to_)= (mi_get_mask_all_keys_active(_maxkeys_) & \ (_from_)) /* Param to/from mi_info */ typedef struct st_mi_isaminfo /* Struct from h_info */ { ha_rows records; /* Records in database */ ha_rows deleted; /* Deleted records in database */ my_off_t recpos; /* Pos for last used record */ my_off_t newrecpos; /* Pos if we write new record */ my_off_t dupp_key_pos; /* Position to record with dupp key */ my_off_t data_file_length, /* Length of data file */ max_data_file_length, index_file_length, max_index_file_length, delete_length; ulong reclength; /* Recordlength */ ulong mean_reclength; /* Mean recordlength (if packed) */ ulonglong auto_increment; ulonglong key_map; /* Which keys are used */ char *data_file_name, *index_file_name; uint keys; /* Number of keys in use */ uint options; /* HA_OPTION_... used */ int errkey, /* With key was dupplicated on err */ sortkey; /* clustered by this key */ File filenr; /* (uniq) filenr for datafile */ time_t create_time; /* When table was created */ time_t check_time; time_t update_time; uint reflength; ulong record_offset; ulong *rec_per_key; /* for sql optimizing */ } MI_ISAMINFO; typedef struct st_mi_create_info { const char *index_file_name, *data_file_name; /* If using symlinks */ ha_rows max_rows; ha_rows reloc_rows; ulonglong auto_increment; ulonglong data_file_length; ulonglong key_file_length; uint old_options; uint16 language; my_bool with_auto_increment; } MI_CREATE_INFO; struct st_myisam_info; /* For reference */ struct st_mi_isam_share; typedef struct st_myisam_info MI_INFO; struct st_mi_s_param; typedef struct st_mi_keydef /* Key definition with open & info */ { struct st_mi_isam_share *share; /* Pointer to base (set in mi_open) */ uint16 keysegs; /* Number of key-segment */ uint16 flag; /* NOSAME, PACK_USED */ uint8 key_alg; /* BTREE, RTREE */ uint16 block_length; /* Length of keyblock (auto) */ uint16 underflow_block_length; /* When to execute underflow */ uint16 keylength; /* Tot length of keyparts (auto) */ uint16 minlength; /* min length of (packed) key (auto) */ uint16 maxlength; /* max length of (packed) key (auto) */ uint16 block_size_index; /* block_size (auto) */ uint32 version; /* For concurrent read/write */ uint32 ftkey_nr; /* full-text index number */ HA_KEYSEG *seg,*end; struct st_mysql_ftparser *parser; /* Fulltext [pre]parser */ int (*bin_search)(struct st_myisam_info *info,struct st_mi_keydef *keyinfo, uchar *page,uchar *key, uint key_len,uint comp_flag,uchar * *ret_pos, uchar *buff, my_bool *was_last_key); uint (*get_key)(struct st_mi_keydef *keyinfo,uint nod_flag,uchar * *page, uchar *key); int (*pack_key)(struct st_mi_keydef *keyinfo,uint nod_flag,uchar *next_key, uchar *org_key, uchar *prev_key, uchar *key, struct st_mi_s_param *s_temp); void (*store_key)(struct st_mi_keydef *keyinfo, uchar *key_pos, struct st_mi_s_param *s_temp); int (*ck_insert)(struct st_myisam_info *inf, uint k_nr, uchar *k, uint klen); int (*ck_delete)(struct st_myisam_info *inf, uint k_nr, uchar *k, uint klen); } MI_KEYDEF; #define MI_UNIQUE_HASH_LENGTH 4 typedef struct st_unique_def /* Segment definition of unique */ { uint16 keysegs; /* Number of key-segment */ uchar key; /* Mapped to which key */ uint8 null_are_equal; HA_KEYSEG *seg,*end; } MI_UNIQUEDEF; typedef struct st_mi_decode_tree /* Decode huff-table */ { uint16 *table; uint quick_table_bits; uchar *intervalls; } MI_DECODE_TREE; struct st_mi_bit_buff; /* Note that null markers should always be first in a row ! When creating a column, one should only specify: type, length, null_bit and null_pos */ typedef struct st_columndef /* column information */ { enum en_fieldtype type; uint16 length; /* length of field */ uint32 offset; /* Offset to position in row */ uint8 null_bit; /* If column may be 0 */ uint16 null_pos; /* position for null marker */ #ifndef NOT_PACKED_DATABASES void (*unpack)(struct st_columndef *rec,struct st_mi_bit_buff *buff, uchar *start,uchar *end); enum en_fieldtype base_type; uint space_length_bits,pack_type; MI_DECODE_TREE *huff_tree; #endif } MI_COLUMNDEF; extern char * myisam_log_filename; /* Name of logfile */ extern ulong myisam_block_size; extern ulong myisam_concurrent_insert; extern my_bool myisam_flush,myisam_delay_key_write,myisam_single_user; extern my_off_t myisam_max_temp_length; extern ulong myisam_data_pointer_size; /* usually used to check if a symlink points into the mysql data home */ /* which is normally forbidden */ extern int (*myisam_test_invalid_symlink)(const char *filename); extern ulonglong myisam_mmap_size, myisam_mmap_used; extern mysql_mutex_t THR_LOCK_myisam_mmap; /* Prototypes for myisam-functions */ extern int mi_close(struct st_myisam_info *file); extern int mi_delete(struct st_myisam_info *file,const uchar *buff); extern struct st_myisam_info *mi_open(const char *name,int mode, uint wait_if_locked); extern int mi_panic(enum ha_panic_function function); extern int mi_rfirst(struct st_myisam_info *file,uchar *buf,int inx); extern int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key, key_part_map keypart_map, enum ha_rkey_function search_flag); extern int mi_rlast(struct st_myisam_info *file,uchar *buf,int inx); extern int mi_rnext(struct st_myisam_info *file,uchar *buf,int inx); extern int mi_rnext_same(struct st_myisam_info *info, uchar *buf); extern int mi_rprev(struct st_myisam_info *file,uchar *buf,int inx); extern int mi_rrnd(struct st_myisam_info *file,uchar *buf, my_off_t pos); extern int mi_scan_init(struct st_myisam_info *file); extern int mi_scan(struct st_myisam_info *file,uchar *buf); extern int mi_rsame(struct st_myisam_info *file,uchar *record,int inx); extern int mi_rsame_with_pos(struct st_myisam_info *file,uchar *record, int inx, my_off_t pos); extern int mi_update(struct st_myisam_info *file,const uchar *old, const uchar *new_record); extern int mi_write(struct st_myisam_info *file,const uchar *buff); extern my_off_t mi_position(struct st_myisam_info *file); extern int mi_status(struct st_myisam_info *info, MI_ISAMINFO *x, uint flag); extern int mi_lock_database(struct st_myisam_info *file,int lock_type); extern int mi_create(const char *name,uint keys,MI_KEYDEF *keydef, uint columns, MI_COLUMNDEF *columndef, uint uniques, MI_UNIQUEDEF *uniquedef, MI_CREATE_INFO *create_info, uint flags); extern int mi_delete_table(const char *name); extern int mi_rename(const char *from, const char *to); extern int mi_extra(struct st_myisam_info *file, enum ha_extra_function function, void *extra_arg); extern int mi_reset(struct st_myisam_info *file); extern ha_rows mi_records_in_range(MI_INFO *info,int inx, const key_range *min_key, const key_range *max_key, page_range *pages); extern int mi_log(int activate_log); extern int mi_is_changed(struct st_myisam_info *info); extern int mi_delete_all_rows(struct st_myisam_info *info); extern ulong _mi_calc_blob_length(uint length , const uchar *pos); extern uint mi_get_pointer_length(ulonglong file_length, uint def); extern int mi_make_backup_of_index(struct st_myisam_info *info, time_t backup_time, myf flags); #define myisam_max_key_length() HA_MAX_KEY_LENGTH #define myisam_max_key_segments() HA_MAX_KEY_SEG #define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for mmap file */ /* this is used to pass to mysql_myisamchk_table */ #define MYISAMCHK_REPAIR 1 /* equivalent to myisamchk -r */ #define MYISAMCHK_VERIFY 2 /* Verify, run repair if failure */ typedef uint mi_bit_type; typedef struct st_sort_key_blocks SORT_KEY_BLOCKS; typedef struct st_sort_ftbuf SORT_FT_BUF; typedef struct st_mi_bit_buff { /* Used for packing of record */ mi_bit_type current_byte; uint bits; uchar *pos, *end, *blob_pos, *blob_end; uint error; } MI_BIT_BUFF; typedef struct st_sort_info { /* sync things */ mysql_mutex_t mutex; mysql_cond_t cond; MI_INFO *info; HA_CHECK *param; uchar *buff; SORT_KEY_BLOCKS *key_block, *key_block_end; SORT_FT_BUF *ft_buf; my_off_t filelength, dupp, buff_length; ha_rows max_records; uint current_key, total_keys; volatile uint got_error; uint threads_running; myf myf_rw; enum data_file_type new_data_file_type; } MI_SORT_INFO; typedef struct st_mi_sort_param { pthread_t thr; IO_CACHE read_cache, tempfile, tempfile_for_exceptions; DYNAMIC_ARRAY buffpek; MI_BIT_BUFF bit_buff; /* For parallel repair of packrec. */ MI_KEYDEF *keyinfo; MI_SORT_INFO *sort_info; HA_KEYSEG *seg; uchar **sort_keys; uchar *rec_buff; void *wordlist, *wordptr; MEM_ROOT wordroot; uchar *record; MY_TMPDIR *tmpdir; /* The next two are used to collect statistics, see update_key_parts for description. */ ulonglong unique[HA_MAX_KEY_SEG+1]; ulonglong notnull[HA_MAX_KEY_SEG+1]; my_off_t pos,max_pos,filepos,start_recpos; uint key, key_length,real_key_length; uint maxbuffers, find_length; ulonglong sortbuff_size; ha_rows keys; my_bool fix_datafile, master; my_bool calc_checksum; /* calculate table checksum */ int (*key_cmp)(void *, const void *, const void *); int (*key_read)(struct st_mi_sort_param *,void *); int (*key_write)(struct st_mi_sort_param *, const void *); void (*lock_in_memory)(HA_CHECK *); int (*write_keys)(struct st_mi_sort_param *, uchar **, ulonglong , struct st_buffpek *, IO_CACHE *); my_off_t (*read_to_buffer)(IO_CACHE *,struct st_buffpek *, uint); int (*write_key)(struct st_mi_sort_param *, IO_CACHE *,uchar *, uint, ulonglong); } MI_SORT_PARAM; /* functions in mi_check */ void myisamchk_init(HA_CHECK *param); int chk_status(HA_CHECK *param, MI_INFO *info); int chk_del(HA_CHECK *param, MI_INFO *info, ulonglong test_flag); int chk_size(HA_CHECK *param, MI_INFO *info); int chk_key(HA_CHECK *param, MI_INFO *info); int chk_data_link(HA_CHECK *param, MI_INFO *info, my_bool extend); int mi_repair(HA_CHECK *param, MI_INFO *info, char * name, int rep_quick); int mi_sort_index(HA_CHECK *param, MI_INFO *info, char * name); int mi_repair_by_sort(HA_CHECK *param, MI_INFO *info, const char * name, int rep_quick); int mi_repair_parallel(HA_CHECK *param, MI_INFO *info, const char * name, int rep_quick); int change_to_newfile(const char * filename, const char * old_ext, const char * new_ext, time_t backup_time, myf myflags); int lock_file(HA_CHECK *param, File file, my_off_t start, int lock_type, const char *filetype, const char *filename); void lock_memory(HA_CHECK *param); void update_auto_increment_key(HA_CHECK *param, MI_INFO *info, my_bool repair); int update_state_info(HA_CHECK *param, MI_INFO *info,uint update); void update_key_parts(MI_KEYDEF *keyinfo, ulong *rec_per_key_part, ulonglong *unique, ulonglong *notnull, ulonglong records); int filecopy(HA_CHECK *param, File to,File from,my_off_t start, my_off_t length, const char *type); int movepoint(MI_INFO *info,uchar *record,my_off_t oldpos, my_off_t newpos, uint prot_key); int write_data_suffix(MI_SORT_INFO *sort_info, my_bool fix_datafile); int test_if_almost_full(MI_INFO *info); int recreate_table(HA_CHECK *param, MI_INFO **org_info, char *filename); void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows); my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, ulonglong key_map, my_bool force); int mi_init_bulk_insert(MI_INFO *info, size_t cache_size, ha_rows rows); void mi_flush_bulk_insert(MI_INFO *info, uint inx); int mi_end_bulk_insert(MI_INFO *info, my_bool abort); int mi_assign_to_key_cache(MI_INFO *info, ulonglong key_map, KEY_CACHE *key_cache); void mi_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache); int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves); int write_data_suffix(MI_SORT_INFO *sort_info, my_bool fix_datafile); int flush_pending_blocks(MI_SORT_PARAM *param); int sort_ft_buf_flush(MI_SORT_PARAM *sort_param); int thr_write_keys(MI_SORT_PARAM *sort_param); int sort_write_record(MI_SORT_PARAM *sort_param); int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ulonglong); my_bool mi_too_big_key_for_sort(MI_KEYDEF *key, ha_rows rows); #ifdef __cplusplus } #endif #endif server/private/item_vers.h000064400000010356151031265040011674 0ustar00#ifndef ITEM_VERS_INCLUDED #define ITEM_VERS_INCLUDED /* Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /* System Versioning items */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif class Item_func_history: public Item_bool_func { public: /* @param a Item_field for row_end system field */ Item_func_history(THD *thd, Item *a): Item_bool_func(thd, a) { DBUG_ASSERT(a->type() == Item::FIELD_ITEM); } bool val_bool() override; bool fix_length_and_dec() override { set_maybe_null(); null_value= 0; decimals= 0; max_length= 1; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("is_history") }; return name; } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_trt_ts: public Item_datetimefunc { TR_table::field_id_t trt_field; public: Item_func_trt_ts(THD *thd, Item* a, TR_table::field_id_t _trt_field); LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING begin_name= {STRING_WITH_LEN("trt_begin_ts") }; static LEX_CSTRING commit_name= {STRING_WITH_LEN("trt_commit_ts") }; return (trt_field == TR_table::FLD_BEGIN_TS) ? begin_name : commit_name; } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } bool fix_length_and_dec() override { fix_attributes_datetime(decimals); return FALSE; } }; class Item_func_trt_id : public Item_longlong_func { TR_table::field_id_t trt_field; bool backwards; longlong get_by_trx_id(ulonglong trx_id); longlong get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards); public: Item_func_trt_id(THD *thd, Item* a, TR_table::field_id_t _trt_field, bool _backwards= false); Item_func_trt_id(THD *thd, Item* a, Item* b, TR_table::field_id_t _trt_field); LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING trx_name= {STRING_WITH_LEN("trt_trx_id") }; static LEX_CSTRING commit_name= {STRING_WITH_LEN("trt_commit_id") }; static LEX_CSTRING iso_name= {STRING_WITH_LEN("trt_iso_level") }; switch (trt_field) { case TR_table::FLD_TRX_ID: return trx_name; case TR_table::FLD_COMMIT_ID: return commit_name; case TR_table::FLD_ISO_LEVEL: return iso_name; default: DBUG_ASSERT(0); } return NULL_clex_str; } bool fix_length_and_dec() override { bool res= Item_int_func::fix_length_and_dec(); max_length= 20; return res; } longlong val_int() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_trt_trx_sees : public Item_bool_func { protected: bool accept_eq; public: Item_func_trt_trx_sees(THD *thd, Item* a, Item* b); LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("trt_trx_sees") }; return name; } bool val_bool() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_trt_trx_sees_eq : public Item_func_trt_trx_sees { public: Item_func_trt_trx_sees_eq(THD *thd, Item* a, Item* b) : Item_func_trt_trx_sees(thd, a, b) { accept_eq= true; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("trt_trx_sees_eq") }; return name; } }; #endif /* ITEM_VERS_INCLUDED */ server/private/rijndael.h000064400000003257151031265040011471 0ustar00#ifndef RIJNDAEL_INCLUDED #define RIJNDAEL_INCLUDED /* Copyright (c) 2002, 2006 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* rijndael-alg-fst.h @version 3.0 (December 2000) Optimised ANSI C code for the Rijndael cipher (now AES) @author Vincent Rijmen @author Antoon Bosselaers @author Paulo Barreto This code is hereby placed in the public domain. Modified by Peter Zaitsev to fit MySQL coding style. */ #define AES_MAXKC (256/32) #define AES_MAXKB (256/8) #define AES_MAXNR 14 int rijndaelKeySetupEnc(uint32 rk[/*4*(Nr + 1)*/], const uint8 cipherKey[], int keyBits); int rijndaelKeySetupDec(uint32 rk[/*4*(Nr + 1)*/], const uint8 cipherKey[], int keyBits); void rijndaelEncrypt(const uint32 rk[/*4*(Nr + 1)*/], int Nr, const uint8 pt[16], uint8 ct[16]); void rijndaelDecrypt(const uint32 rk[/*4*(Nr + 1)*/], int Nr, const uint8 ct[16], uint8 pt[16]); #endif /* RIJNDAEL_INCLUDED */ server/private/sql_schema.h000064400000006347151031265040012023 0ustar00#ifndef SQL_SCHEMA_H_INCLUDED #define SQL_SCHEMA_H_INCLUDED /* Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "mysqld.h" #include "lex_string.h" class Lex_ident_sys; class Create_func; class Schema { LEX_CSTRING m_name; public: Schema(const LEX_CSTRING &name) :m_name(name) { } virtual ~Schema() = default; const LEX_CSTRING &name() const { return m_name; } virtual const Type_handler *map_data_type(THD *thd, const Type_handler *src) const { return src; } /** Find a native function builder, return an error if not found, build an Item otherwise. */ Item *make_item_func_call_native(THD *thd, const Lex_ident_sys &name, List *args) const; /** Find the native function builder associated with a given function name. @param thd The current thread @param name The native function name @return The native function builder associated with the name, or NULL */ virtual Create_func *find_native_function_builder(THD *thd, const LEX_CSTRING &name) const; // Builders for native SQL function with a special syntax in sql_yacc.yy virtual Item *make_item_func_replace(THD *thd, Item *subj, Item *find, Item *replace) const; virtual Item *make_item_func_substr(THD *thd, const Lex_substring_spec_st &spec) const; virtual Item *make_item_func_trim(THD *thd, const Lex_trim_st &spec) const; /* For now we have *hard-coded* compatibility schemas: schema_mariadb, schema_oracle, schema_maxdb. But eventually we'll turn then into real databases on disk. So the code below compares names according to the filesystem case sensitivity, like it is done for regular databases. Note, this is different to information_schema, whose name is always case insensitive. This is intentional! The assymetry will be gone when we'll implement SQL standard regular and delimited identifiers. */ bool eq_name(const LEX_CSTRING &name) const { return !table_alias_charset->strnncoll(m_name.str, m_name.length, name.str, name.length); } static Schema *find_by_name(const LEX_CSTRING &name); static Schema *find_implied(THD *thd); }; extern Schema mariadb_schema; extern const Schema &oracle_schema_ref; #endif // SQL_SCHEMA_H_INCLUDED server/private/item_jsonfunc.h000064400000053764151031265040012554 0ustar00#ifndef ITEM_JSONFUNC_INCLUDED #define ITEM_JSONFUNC_INCLUDED /* Copyright (c) 2016, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* This file defines all JSON functions */ #include #include "item_cmpfunc.h" // Item_bool_func #include "item_strfunc.h" // Item_str_func #include "item_sum.h" #include "sql_type_json.h" class json_path_with_flags { public: json_path_t p; bool constant; bool parsed; json_path_step_t *cur_step; void set_constant_flag(bool s_constant) { constant= s_constant; parsed= FALSE; } }; void report_path_error_ex(const char *ps, json_path_t *p, const char *fname, int n_param, Sql_condition::enum_warning_level lv); void report_json_error_ex(const char *js, json_engine_t *je, const char *fname, int n_param, Sql_condition::enum_warning_level lv); class Json_engine_scan: public json_engine_t { public: Json_engine_scan(CHARSET_INFO *i_cs, const uchar *str, const uchar *end) { json_scan_start(this, i_cs, str, end); } Json_engine_scan(const String &str) :Json_engine_scan(str.charset(), (const uchar *) str.ptr(), (const uchar *) str.end()) { } bool check_and_get_value_scalar(String *res, int *error); bool check_and_get_value_complex(String *res, int *error); }; class Json_path_extractor: public json_path_with_flags { protected: String tmp_js, tmp_path; virtual ~Json_path_extractor() { } virtual bool check_and_get_value(Json_engine_scan *je, String *to, int *error)=0; bool extract(String *to, Item *js, Item *jp, CHARSET_INFO *cs); }; class Item_func_json_valid: public Item_bool_func { protected: String tmp_value; public: Item_func_json_valid(THD *thd, Item *json) : Item_bool_func(thd, json) {} bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_valid") }; return name; } bool fix_length_and_dec() override { if (Item_bool_func::fix_length_and_dec()) return TRUE; set_maybe_null(); return FALSE; } bool set_format_by_check_constraint(Send_field_extended_metadata *to) const override { static const Lex_cstring fmt(STRING_WITH_LEN("json")); return to->set_format_name(fmt); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } enum Functype functype() const override { return JSON_VALID_FUNC; } }; class Item_func_json_exists: public Item_bool_func { protected: json_path_with_flags path; String tmp_js, tmp_path; public: Item_func_json_exists(THD *thd, Item *js, Item *i_path): Item_bool_func(thd, js, i_path) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_exists") }; return name; } bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } bool val_bool() override; }; class Item_json_func: public Item_str_func { public: Item_json_func(THD *thd) :Item_str_func(thd) { } Item_json_func(THD *thd, Item *a) :Item_str_func(thd, a) { } Item_json_func(THD *thd, Item *a, Item *b) :Item_str_func(thd, a, b) { } Item_json_func(THD *thd, List &list) :Item_str_func(thd, list) { } const Type_handler *type_handler() const override { return Type_handler_json_common::json_type_handler(max_length); } }; class Item_func_json_value: public Item_str_func, public Json_path_extractor { public: Item_func_json_value(THD *thd, Item *js, Item *i_path): Item_str_func(thd, js, i_path) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_value") }; return name; } bool fix_length_and_dec() override ; String *val_str(String *to) override { null_value= Json_path_extractor::extract(to, args[0], args[1], collation.collation); return null_value ? NULL : to; } bool check_and_get_value(Json_engine_scan *je, String *res, int *error) override { return je->check_and_get_value_scalar(res, error); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_query: public Item_json_func, public Json_path_extractor { public: Item_func_json_query(THD *thd, Item *js, Item *i_path): Item_json_func(thd, js, i_path) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_query") }; return name; } bool fix_length_and_dec() override; String *val_str(String *to) override { null_value= Json_path_extractor::extract(to, args[0], args[1], collation.collation); return null_value ? NULL : to; } bool check_and_get_value(Json_engine_scan *je, String *res, int *error) override { return je->check_and_get_value_complex(res, error); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_quote: public Item_str_func { protected: String tmp_s; public: Item_func_json_quote(THD *thd, Item *s): Item_str_func(thd, s) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_quote") }; return name; } bool fix_length_and_dec() override; String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_unquote: public Item_str_func { protected: String tmp_s; String *read_json(json_engine_t *je); public: Item_func_json_unquote(THD *thd, Item *s): Item_str_func(thd, s) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_unquote") }; return name; } bool fix_length_and_dec() override; String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_json_str_multipath: public Item_json_func { protected: json_path_with_flags *paths; String *tmp_paths; private: /** Number of paths returned by calling virtual method get_n_paths() and remembered inside fix_fields(). It is used by the virtual destructor ~Item_json_str_multipath() to iterate along allocated memory chunks stored in the array tmp_paths and free every of them. The virtual method get_n_paths() can't be used for this goal from within virtual destructor. We could get rid of the virtual method get_n_paths() and store the number of paths directly in the constructor of classes derived from the class Item_json_str_multipath but presence of the method get_n_paths() allows to check invariant that the number of arguments not changed between sequential runs of the same prepared statement that seems to be useful. */ uint n_paths; public: Item_json_str_multipath(THD *thd, List &list): Item_json_func(thd, list), paths(NULL), tmp_paths(0), n_paths(0) {} virtual ~Item_json_str_multipath(); bool fix_fields(THD *thd, Item **ref) override; virtual uint get_n_paths() const = 0; }; class Item_func_json_extract: public Item_json_str_multipath { protected: String tmp_js; public: String *read_json(String *str, json_value_types *type, char **out_val, int *value_len); Item_func_json_extract(THD *thd, List &list): Item_json_str_multipath(thd, list) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_extract") }; return name; } enum Functype functype() const override { return JSON_EXTRACT_FUNC; } bool fix_length_and_dec() override; String *val_str(String *) override; longlong val_int() override; double val_real() override; my_decimal *val_decimal(my_decimal *) override; uint get_n_paths() const override { return arg_count - 1; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_contains: public Item_bool_func { protected: String tmp_js; json_path_with_flags path; String tmp_path; bool a2_constant, a2_parsed; String tmp_val, *val; public: Item_func_json_contains(THD *thd, List &list): Item_bool_func(thd, list) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_contains") }; return name; } bool fix_length_and_dec() override; bool val_bool() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_contains_path: public Item_bool_func { protected: String tmp_js; json_path_with_flags *paths; String *tmp_paths; bool mode_one; bool ooa_constant, ooa_parsed; bool *p_found; public: Item_func_json_contains_path(THD *thd, List &list): Item_bool_func(thd, list), tmp_paths(0) {} virtual ~Item_func_json_contains_path(); LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_contains_path") }; return name; } bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override; bool val_bool() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_array: public Item_json_func { protected: String tmp_val; ulong result_limit; public: Item_func_json_array(THD *thd): Item_json_func(thd) {} Item_func_json_array(THD *thd, List &list): Item_json_func(thd, list) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_array") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_array_append: public Item_json_str_multipath { protected: String tmp_js; String tmp_val; public: Item_func_json_array_append(THD *thd, List &list): Item_json_str_multipath(thd, list) {} bool fix_length_and_dec() override; String *val_str(String *) override; uint get_n_paths() const override { return arg_count/2; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_array_append") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_array_insert: public Item_func_json_array_append { public: Item_func_json_array_insert(THD *thd, List &list): Item_func_json_array_append(thd, list) {} String *val_str(String *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_array_insert") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_object: public Item_func_json_array { public: Item_func_json_object(THD *thd): Item_func_json_array(thd) {} Item_func_json_object(THD *thd, List &list): Item_func_json_array(thd, list) {} String *val_str(String *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_object") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_merge: public Item_func_json_array { protected: String tmp_js1, tmp_js2; public: Item_func_json_merge(THD *thd, List &list): Item_func_json_array(thd, list) {} String *val_str(String *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_merge_preserve") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_merge_patch: public Item_func_json_merge { public: Item_func_json_merge_patch(THD *thd, List &list): Item_func_json_merge(thd, list) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_merge_patch") }; return name; } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_length: public Item_long_func { bool check_arguments() const override { const LEX_CSTRING name= func_name_cstring(); if (arg_count == 0 || arg_count > 2) { my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str); return true; } return args[0]->check_type_can_return_text(name) || (arg_count > 1 && args[1]->check_type_general_purpose_string(name)); } protected: json_path_with_flags path; String tmp_js; String tmp_path; public: Item_func_json_length(THD *thd, List &list): Item_long_func(thd, list) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_length") }; return name; } bool fix_length_and_dec() override; longlong val_int() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_depth: public Item_long_func { bool check_arguments() const override { return args[0]->check_type_can_return_text(func_name_cstring()); } protected: String tmp_js; public: Item_func_json_depth(THD *thd, Item *js): Item_long_func(thd, js) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_depth") }; return name; } bool fix_length_and_dec() override { max_length= 10; return FALSE; } longlong val_int() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_type: public Item_str_func { protected: String tmp_js; public: Item_func_json_type(THD *thd, Item *js): Item_str_func(thd, js) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_type") }; return name; } bool fix_length_and_dec() override; String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_insert: public Item_json_str_multipath { protected: String tmp_js; String tmp_val; bool mode_insert, mode_replace; public: Item_func_json_insert(bool i_mode, bool r_mode, THD *thd, List &list): Item_json_str_multipath(thd, list), mode_insert(i_mode), mode_replace(r_mode) {} bool fix_length_and_dec() override; String *val_str(String *) override; uint get_n_paths() const override { return arg_count/2; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING json_set= {STRING_WITH_LEN("json_set") }; static LEX_CSTRING json_insert= {STRING_WITH_LEN("json_insert") }; static LEX_CSTRING json_replace= {STRING_WITH_LEN("json_replace") }; return (mode_insert ? (mode_replace ? json_set : json_insert) : json_replace); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_remove: public Item_json_str_multipath { protected: String tmp_js; public: Item_func_json_remove(THD *thd, List &list): Item_json_str_multipath(thd, list) {} bool fix_length_and_dec() override; String *val_str(String *) override; uint get_n_paths() const override { return arg_count - 1; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_remove") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_keys: public Item_str_func { protected: json_path_with_flags path; String tmp_js, tmp_path; public: Item_func_json_keys(THD *thd, List &list): Item_str_func(thd, list) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_keys") }; return name; } bool fix_length_and_dec() override; String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_search: public Item_json_str_multipath { protected: String tmp_js, tmp_path, esc_value; bool mode_one; bool ooa_constant, ooa_parsed; int escape; int n_path_found; json_path_t sav_path; int compare_json_value_wild(json_engine_t *je, const String *cmp_str); public: Item_func_json_search(THD *thd, List &list): Item_json_str_multipath(thd, list) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_search") }; return name; } bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override; String *val_str(String *) override; uint get_n_paths() const override { return arg_count > 4 ? arg_count - 4 : 0; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_format: public Item_json_func { public: enum formats { NONE, COMPACT, LOOSE, DETAILED }; protected: formats fmt; String tmp_js; public: Item_func_json_format(THD *thd, Item *js, formats format): Item_json_func(thd, js), fmt(format) {} Item_func_json_format(THD *thd, List &list): Item_json_func(thd, list), fmt(DETAILED) {} LEX_CSTRING func_name_cstring() const override; bool fix_length_and_dec() override; String *val_str(String *str) override; String *val_json(String *str) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_arrayagg : public Item_func_group_concat { protected: /* Overrides Item_func_group_concat::skip_nulls() NULL-s should be added to the result as JSON null value. */ bool skip_nulls() const override { return false; } String *get_str_from_item(Item *i, String *tmp) override; String *get_str_from_field(Item *i, Field *f, String *tmp, const uchar *key, size_t offset) override; void cut_max_length(String *result, uint old_length, uint max_length) const override; public: String m_tmp_json; /* Used in get_str_from_*.. */ Item_func_json_arrayagg(THD *thd, Name_resolution_context *context_arg, bool is_distinct, List *is_select, const SQL_I_List &is_order, String *is_separator, bool limit_clause, Item *row_limit, Item *offset_limit): Item_func_group_concat(thd, context_arg, is_distinct, is_select, is_order, is_separator, limit_clause, row_limit, offset_limit) { } Item_func_json_arrayagg(THD *thd, Item_func_json_arrayagg *item) : Item_func_group_concat(thd, item) {} const Type_handler *type_handler() const override { return Type_handler_json_common::json_type_handler_sum(this); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_arrayagg(") }; return name; } bool fix_fields(THD *thd, Item **ref) override; enum Sumfunctype sum_func() const override { return JSON_ARRAYAGG_FUNC; } String* val_str(String *str) override; Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_json_objectagg : public Item_sum { String result; public: Item_func_json_objectagg(THD *thd, Item *key, Item *value) : Item_sum(thd, key, value) { quick_group= FALSE; result.append('{'); } Item_func_json_objectagg(THD *thd, Item_func_json_objectagg *item); void cleanup() override; enum Sumfunctype sum_func () const override { return JSON_OBJECTAGG_FUNC;} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_objectagg") }; return name; } const Type_handler *type_handler() const override { return Type_handler_json_common::json_type_handler_sum(this); } void clear() override; bool add() override; void reset_field() override { DBUG_ASSERT(0); } // not used void update_field() override { DBUG_ASSERT(0); } // not used bool fix_fields(THD *,Item **) override; double val_real() override { return 0.0; } longlong val_int() override { return 0; } my_decimal *val_decimal(my_decimal *decimal_value) override { my_decimal_set_zero(decimal_value); return decimal_value; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_string(thd, ltime, fuzzydate); } String* val_str(String* str) override; Item *copy_or_same(THD* thd) override; void no_rows_in_result() override {} Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; extern bool is_json_type(const Item *item); #endif /* ITEM_JSONFUNC_INCLUDED */ server/private/backup.h000064400000003247151031265040011145 0ustar00#ifndef BACKUP_INCLUDED #define BACKUP_INCLUDED /* Copyright (c) 2018, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ enum backup_stages { BACKUP_START, BACKUP_FLUSH, BACKUP_WAIT_FOR_FLUSH, BACKUP_LOCK_COMMIT, BACKUP_END, BACKUP_FINISHED }; extern TYPELIB backup_stage_names; struct backup_log_info { LEX_CSTRING query; LEX_CUSTRING org_table_id; /* Unique id from frm */ LEX_CSTRING org_database, org_table; LEX_CSTRING org_storage_engine_name; LEX_CSTRING new_database, new_table; LEX_CSTRING new_storage_engine_name; LEX_CUSTRING new_table_id; /* Unique id from frm */ bool org_partitioned; bool new_partitioned; }; void backup_init(); bool run_backup_stage(THD *thd, backup_stages stage); bool backup_end(THD *thd); void backup_set_alter_copy_lock(THD *thd, TABLE *altered_table); bool backup_reset_alter_copy_lock(THD *thd); bool backup_lock(THD *thd, TABLE_LIST *table); void backup_unlock(THD *thd); void backup_log_ddl(const backup_log_info *info); #endif /* BACKUP_INCLUDED */ server/private/lock.h000064400000004233151031265040010624 0ustar00/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef LOCK_INCLUDED #define LOCK_INCLUDED #include "thr_lock.h" /* thr_lock_type */ #include "mdl.h" // Forward declarations struct TABLE; struct TABLE_LIST; class THD; typedef struct st_mysql_lock MYSQL_LOCK; MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags); bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags); int mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock); int mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); int mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); int mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag); int mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); bool mysql_lock_abort_for_thread(THD *thd, TABLE *table); MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b); /* Lock based on name */ bool lock_schema_name(THD *thd, const char *db); /* Lock based on stored routine name */ bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type, const char *db, const char *name); /* flags for get_lock_data */ #define GET_LOCK_UNLOCK 0 #define GET_LOCK_STORE_LOCKS 1 #define GET_LOCK_ACTION_MASK 1 #define GET_LOCK_ON_THD (1 << 1) #define GET_LOCK_SKIP_SEQUENCES (1 << 2) MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags); void reset_lock_data(MYSQL_LOCK *sql_lock, bool unlock); #endif /* LOCK_INCLUDED */ server/private/sql_test.h000064400000003065151031265040011534 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_TEST_INCLUDED #define SQL_TEST_INCLUDED #include "mysqld.h" #include "opt_trace_context.h" class JOIN; struct TABLE_LIST; typedef class Item COND; typedef class st_select_lex SELECT_LEX; struct SORT_FIELD; #ifndef DBUG_OFF void print_where(COND *cond,const char *info, enum_query_type query_type); void TEST_filesort(SORT_FIELD *sortorder,uint s_length); void TEST_join(JOIN *join); void print_plan(JOIN* join,uint idx, double record_count, double read_time, double current_read_time, const char *info); void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array); void print_sjm(SJ_MATERIALIZATION_INFO *sjm); void dump_TABLE_LIST_graph(SELECT_LEX *select_lex, TABLE_LIST* tl); #endif void print_keyuse_array_for_trace(THD *thd, DYNAMIC_ARRAY *keyuse_array); void mysql_print_status(); #endif /* SQL_TEST_INCLUDED */ server/private/sql_cmd.h000064400000022037151031265040011320 0ustar00/* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Representation of an SQL command. */ #ifndef SQL_CMD_INCLUDED #define SQL_CMD_INCLUDED /* When a command is added here, be sure it's also added in mysqld.cc in "struct show_var_st status_vars[]= {" ... If the command returns a result set or is not allowed in stored functions or triggers, please also make sure that sp_get_flags_for_command (sp_head.cc) returns proper flags for the added SQLCOM_. */ enum enum_sql_command { SQLCOM_SELECT, SQLCOM_CREATE_TABLE, SQLCOM_CREATE_INDEX, SQLCOM_ALTER_TABLE, SQLCOM_UPDATE, SQLCOM_INSERT, SQLCOM_INSERT_SELECT, SQLCOM_DELETE, SQLCOM_TRUNCATE, SQLCOM_DROP_TABLE, SQLCOM_DROP_INDEX, SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS, SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_STATUS, SQLCOM_SHOW_ENGINE_LOGS, SQLCOM_SHOW_ENGINE_STATUS, SQLCOM_SHOW_ENGINE_MUTEX, SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_BINLOG_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS, SQLCOM_SHOW_TRIGGERS, SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES, SQLCOM_GRANT, SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB, SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS, SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, SQLCOM_BEGIN, SQLCOM_CHANGE_MASTER, SQLCOM_RENAME_TABLE, SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS, SQLCOM_SHOW_OPEN_TABLES, SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI, SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_DO, SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES, SQLCOM_HELP, SQLCOM_CREATE_USER, SQLCOM_DROP_USER, SQLCOM_RENAME_USER, SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM, SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL, SQLCOM_DROP_PROCEDURE, SQLCOM_ALTER_PROCEDURE,SQLCOM_ALTER_FUNCTION, SQLCOM_SHOW_CREATE_PROC, SQLCOM_SHOW_CREATE_FUNC, SQLCOM_SHOW_STATUS_PROC, SQLCOM_SHOW_STATUS_FUNC, SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE, SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW, SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER, SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE, SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER, SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE, SQLCOM_ALTER_TABLESPACE, SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN, SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT, SQLCOM_SHOW_PLUGINS, SQLCOM_SHOW_CONTRIBUTORS, SQLCOM_CREATE_SERVER, SQLCOM_DROP_SERVER, SQLCOM_ALTER_SERVER, SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT, SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS, SQLCOM_SHOW_CREATE_TRIGGER, SQLCOM_ALTER_DB_UPGRADE, SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, SQLCOM_SIGNAL, SQLCOM_RESIGNAL, SQLCOM_SHOW_RELAYLOG_EVENTS, SQLCOM_GET_DIAGNOSTICS, SQLCOM_SLAVE_ALL_START, SQLCOM_SLAVE_ALL_STOP, SQLCOM_SHOW_EXPLAIN, SQLCOM_SHUTDOWN, SQLCOM_CREATE_ROLE, SQLCOM_DROP_ROLE, SQLCOM_GRANT_ROLE, SQLCOM_REVOKE_ROLE, SQLCOM_COMPOUND, SQLCOM_SHOW_GENERIC, SQLCOM_ALTER_USER, SQLCOM_SHOW_CREATE_USER, SQLCOM_EXECUTE_IMMEDIATE, SQLCOM_CREATE_SEQUENCE, SQLCOM_DROP_SEQUENCE, SQLCOM_ALTER_SEQUENCE, SQLCOM_CREATE_PACKAGE, SQLCOM_DROP_PACKAGE, SQLCOM_CREATE_PACKAGE_BODY, SQLCOM_DROP_PACKAGE_BODY, SQLCOM_SHOW_CREATE_PACKAGE, SQLCOM_SHOW_CREATE_PACKAGE_BODY, SQLCOM_SHOW_STATUS_PACKAGE, SQLCOM_SHOW_STATUS_PACKAGE_BODY, SQLCOM_SHOW_PACKAGE_BODY_CODE, SQLCOM_BACKUP, SQLCOM_BACKUP_LOCK, /* When a command is added here, be sure it's also added in mysqld.cc in "struct show_var_st com_status_vars[]= {" ... */ /* This should be the last !!! */ SQLCOM_END }; class Storage_engine_name { protected: LEX_CSTRING m_storage_engine_name; public: Storage_engine_name() { m_storage_engine_name.str= NULL; m_storage_engine_name.length= 0; } Storage_engine_name(const LEX_CSTRING &name) :m_storage_engine_name(name) { } Storage_engine_name(const LEX_STRING &name) { m_storage_engine_name.str= name.str; m_storage_engine_name.length= name.length; } bool resolve_storage_engine_with_error(THD *thd, handlerton **ha, bool tmp_table); bool is_set() { return m_storage_engine_name.str != NULL; } const LEX_CSTRING *name() const { return &m_storage_engine_name; } }; /** @class Sql_cmd - Representation of an SQL command. This class is an interface between the parser and the runtime. The parser builds the appropriate derived classes of Sql_cmd to represent a SQL statement in the parsed tree. The execute() method in the derived classes of Sql_cmd contain the runtime implementation. Note that this interface is used for SQL statements recently implemented, the code for older statements tend to load the LEX structure with more attributes instead. Implement new statements by sub-classing Sql_cmd, as this improves code modularity (see the 'big switch' in dispatch_command()), and decreases the total size of the LEX structure (therefore saving memory in stored programs). The recommended name of a derived class of Sql_cmd is Sql_cmd_. Notice that the Sql_cmd class should not be confused with the Statement class. Statement is a class that is used to manage an SQL command or a set of SQL commands. When the SQL statement text is analyzed, the parser will create one or more Sql_cmd objects to represent the actual SQL commands. */ class Sql_cmd : public Sql_alloc { private: Sql_cmd(const Sql_cmd &); // No copy constructor wanted void operator=(Sql_cmd &); // No assignment operator wanted public: /** @brief Return the command code for this statement */ virtual enum_sql_command sql_command_code() const = 0; /** Execute this SQL statement. @param thd the current thread. @retval false on success. @retval true on error */ virtual bool execute(THD *thd) = 0; virtual Storage_engine_name *option_storage_engine_name() { return NULL; } protected: Sql_cmd() = default; virtual ~Sql_cmd() { /* Sql_cmd objects are allocated in thd->mem_root. In MySQL, the C++ destructor is never called, the underlying MEM_ROOT is simply destroyed instead. Do not rely on the destructor for any cleanup. */ DBUG_ASSERT(FALSE); } }; class Sql_cmd_show_slave_status: public Sql_cmd { protected: bool show_all_slaves_status; public: Sql_cmd_show_slave_status() :show_all_slaves_status(false) {} Sql_cmd_show_slave_status(bool status_all) :show_all_slaves_status(status_all) {} enum_sql_command sql_command_code() const override { return SQLCOM_SHOW_SLAVE_STAT; } bool execute(THD *thd) override; bool is_show_all_slaves_stat() { return show_all_slaves_status; } }; class Sql_cmd_create_table_like: public Sql_cmd, public Storage_engine_name { public: Storage_engine_name *option_storage_engine_name() override { return this; } bool execute(THD *thd) override; }; class Sql_cmd_create_table: public Sql_cmd_create_table_like { public: enum_sql_command sql_command_code() const override { return SQLCOM_CREATE_TABLE; } }; class Sql_cmd_create_sequence: public Sql_cmd_create_table_like { public: enum_sql_command sql_command_code() const override { return SQLCOM_CREATE_SEQUENCE; } }; /** Sql_cmd_call represents the CALL statement. */ class Sql_cmd_call : public Sql_cmd { public: class sp_name *m_name; const class Sp_handler *m_handler; Sql_cmd_call(class sp_name *name, const class Sp_handler *handler) :m_name(name), m_handler(handler) {} virtual ~Sql_cmd_call() = default; /** Execute a CALL statement at runtime. @param thd the current thread. @return false on success. */ bool execute(THD *thd) override; enum_sql_command sql_command_code() const override { return SQLCOM_CALL; } }; #endif // SQL_CMD_INCLUDED server/private/sql_table.h000064400000022614151031265040011645 0ustar00/* Copyright (c) 2006, 2014, Oracle and/or its affiliates. Copyright (c) 2011, 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_TABLE_INCLUDED #define SQL_TABLE_INCLUDED #include // pthread_mutex_t #include "m_string.h" // LEX_CUSTRING class Alter_info; class Alter_table_ctx; class Column_definition; class Create_field; struct TABLE_LIST; class THD; struct TABLE; struct handlerton; class handler; class String; typedef struct st_ha_check_opt HA_CHECK_OPT; struct HA_CREATE_INFO; struct Table_specification_st; typedef struct st_key KEY; typedef struct st_key_cache KEY_CACHE; typedef struct st_lock_param_type ALTER_PARTITION_PARAM_TYPE; typedef struct st_order ORDER; typedef struct st_ddl_log_state DDL_LOG_STATE; enum enum_explain_filename_mode { EXPLAIN_ALL_VERBOSE= 0, EXPLAIN_PARTITIONS_VERBOSE, EXPLAIN_PARTITIONS_AS_COMMENT }; /* depends on errmsg.txt Database `db`, Table `t` ... */ #define EXPLAIN_FILENAME_MAX_EXTRA_LENGTH 63 #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_KEEP_SHARE 4 /* Flags for conversion functions. */ static const uint FN_FROM_IS_TMP= 1 << 0; static const uint FN_TO_IS_TMP= 1 << 1; static const uint FN_IS_TMP= FN_FROM_IS_TMP | FN_TO_IS_TMP; static const uint NO_FRM_RENAME= 1 << 2; static const uint FRM_ONLY= 1 << 3; /** Don't remove table in engine. Remove only .FRM and maybe .PAR files. */ static const uint NO_HA_TABLE= 1 << 4; /** Don't resolve MySQL's fake "foo.sym" symbolic directory names. */ static const uint SKIP_SYMDIR_ACCESS= 1 << 5; /** Don't check foreign key constraints while renaming table */ static const uint NO_FK_CHECKS= 1 << 6; /* Don't delete .par table in quick_rm_table() */ static const uint NO_PAR_TABLE= 1 << 7; uint filename_to_tablename(const char *from, char *to, size_t to_length, bool stay_quiet = false); uint tablename_to_filename(const char *from, char *to, size_t to_length); uint check_n_cut_mysql50_prefix(const char *from, char *to, size_t to_length); bool check_mysql50_prefix(const char *name); uint build_table_filename(char *buff, size_t bufflen, const char *db, const char *table, const char *ext, uint flags); uint build_table_shadow_filename(char *buff, size_t bufflen, ALTER_PARTITION_PARAM_TYPE *lpt); void build_lower_case_table_filename(char *buff, size_t bufflen, const LEX_CSTRING *db, const LEX_CSTRING *table, uint flags); uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen); bool mysql_create_table(THD *thd, TABLE_LIST *create_table, Table_specification_st *create_info, Alter_info *alter_info); bool add_keyword_to_query(THD *thd, String *result, const LEX_CSTRING *keyword, const LEX_CSTRING *add); /* mysql_create_table_no_lock can be called in one of the following mutually exclusive situations: - Just a normal ordinary CREATE TABLE statement that explicitly defines the table structure. - CREATE TABLE ... SELECT. It is special, because only in this case, the list of fields is allowed to have duplicates, as long as one of the duplicates comes from the select list, and the other doesn't. For example in CREATE TABLE t1 (a int(5) NOT NUL) SELECT b+10 as a FROM t2; the list in alter_info->create_list will have two fields `a`. - ALTER TABLE, that creates a temporary table #sql-xxx, which will be later renamed to replace the original table. - ALTER TABLE as above, but which only modifies the frm file, it only creates an frm file for the #sql-xxx, the table in the engine is not created. - Assisted discovery, CREATE TABLE statement without the table structure. These situations are distinguished by the following "create table mode" values, where a CREATE ... SELECT is denoted by any non-negative number (which should be the number of fields in the SELECT ... part), and other cases use constants as defined below. */ #define C_CREATE_SELECT(X) ((X) > 0 ? (X) : 0) #define C_ORDINARY_CREATE 0 #define C_ASSISTED_DISCOVERY -1 #define C_ALTER_TABLE -2 #define C_ALTER_TABLE_FRM_ONLY -3 int mysql_create_table_no_lock(THD *thd, DDL_LOG_STATE *ddl_log_state, DDL_LOG_STATE *ddl_log_state_rm, Table_specification_st *create_info, Alter_info *alter_info, bool *is_trans, int create_table_mode, TABLE_LIST *table); handler *mysql_create_frm_image(THD *thd, HA_CREATE_INFO *create_info, Alter_info *alter_info, int create_table_mode, KEY **key_info, uint *key_count, LEX_CUSTRING *frm); int mysql_discard_or_import_tablespace(THD *thd, TABLE_LIST *table_list, bool discard); bool mysql_prepare_alter_table(THD *thd, TABLE *table, HA_CREATE_INFO *create_info, Alter_info *alter_info, Alter_table_ctx *alter_ctx); bool mysql_trans_prepare_alter_copy_data(THD *thd); bool mysql_trans_commit_alter_copy_data(THD *thd); bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, const LEX_CSTRING *new_name, HA_CREATE_INFO *create_info, TABLE_LIST *table_list, class Recreate_info *recreate_info, Alter_info *alter_info, uint order_num, ORDER *order, bool ignore, bool if_exists); bool mysql_compare_tables(TABLE *table, Alter_info *alter_info, HA_CREATE_INFO *create_info, bool *metadata_equal); bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, class Recreate_info *recreate_info, bool table_copy); bool mysql_create_like_table(THD *thd, TABLE_LIST *table, TABLE_LIST *src_table, Table_specification_st *create_info); bool mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db, const LEX_CSTRING *old_name, const LEX_CSTRING *new_db, const LEX_CSTRING *new_name, LEX_CUSTRING *id, uint flags); bool mysql_backup_table(THD* thd, TABLE_LIST* table_list); bool mysql_restore_table(THD* thd, TABLE_LIST* table_list); template class List; void fill_checksum_table_metadata_fields(THD *thd, List *fields); bool mysql_checksum_table(THD* thd, TABLE_LIST* table_list, HA_CHECK_OPT* check_opt); bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists, bool drop_temporary, bool drop_sequence, bool dont_log_query); int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, const LEX_CSTRING *db, DDL_LOG_STATE *ddl_log_state, bool if_exists, bool drop_temporary, bool drop_view, bool drop_sequence, bool dont_log_query, bool dont_free_locks); bool log_drop_table(THD *thd, const LEX_CSTRING *db_name, const LEX_CSTRING *table_name, const LEX_CSTRING *handler, bool partitioned, const LEX_CUSTRING *id, bool temporary_table); bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db, const LEX_CSTRING *table_name, uint flags, const char *table_path=0); void close_cached_table(THD *thd, TABLE *table); void sp_prepare_create_field(THD *thd, Column_definition *sql_field); bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); int write_bin_log(THD *thd, bool clear_error, char const *query, ulong query_length, bool is_trans= FALSE); int write_bin_log_with_if_exists(THD *thd, bool clear_error, bool is_trans, bool add_if_exists); void promote_first_timestamp_column(List *column_definitions); /* These prototypes where under INNODB_COMPATIBILITY_HOOKS. */ uint explain_filename(THD* thd, const char *from, char *to, uint to_length, enum_explain_filename_mode explain_mode); extern MYSQL_PLUGIN_IMPORT const LEX_CSTRING primary_key_name; bool check_engine(THD *, const char *, const char *, HA_CREATE_INFO *); #endif /* SQL_TABLE_INCLUDED */ server/private/handler.h000064400000611465151031265040011324 0ustar00#ifndef HANDLER_INCLUDED #define HANDLER_INCLUDED /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. Copyright (c) 2009, 2023, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Definitions for parameters to do with handler-routines */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_const.h" #include "sql_basic_types.h" #include "mysqld.h" /* server_id */ #include "sql_plugin.h" /* plugin_ref, st_plugin_int, plugin */ #include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA */ #include "sql_cache.h" #include "structs.h" /* SHOW_COMP_OPTION */ #include "sql_array.h" /* Dynamic_array<> */ #include "mdl.h" #include "vers_string.h" #include "ha_handler_stats.h" #include "sql_analyze_stmt.h" // for Exec_time_tracker #include #include #include #include #include "sql_sequence.h" #include "mem_root_array.h" #include // pair #include /* __attribute__ */ class Alter_info; class Virtual_column_info; class sequence_definition; class Rowid_filter; class Field_string; class Field_varstring; class Field_blob; class Column_definition; // the following is for checking tables #define HA_ADMIN_ALREADY_DONE 1 #define HA_ADMIN_OK 0 #define HA_ADMIN_NOT_IMPLEMENTED -1 #define HA_ADMIN_FAILED -2 #define HA_ADMIN_CORRUPT -3 #define HA_ADMIN_INTERNAL_ERROR -4 #define HA_ADMIN_INVALID -5 #define HA_ADMIN_REJECT -6 #define HA_ADMIN_TRY_ALTER -7 #define HA_ADMIN_WRONG_CHECKSUM -8 #define HA_ADMIN_NOT_BASE_TABLE -9 #define HA_ADMIN_NEEDS_UPGRADE -10 #define HA_ADMIN_NEEDS_ALTER -11 #define HA_ADMIN_NEEDS_CHECK -12 #define HA_ADMIN_COMMIT_ERROR -13 /** Return values for check_if_supported_inplace_alter(). @see check_if_supported_inplace_alter() for description of the individual values. */ enum enum_alter_inplace_result { HA_ALTER_ERROR, HA_ALTER_INPLACE_COPY_NO_LOCK, HA_ALTER_INPLACE_COPY_LOCK, HA_ALTER_INPLACE_NOCOPY_LOCK, HA_ALTER_INPLACE_NOCOPY_NO_LOCK, HA_ALTER_INPLACE_INSTANT, HA_ALTER_INPLACE_NOT_SUPPORTED, HA_ALTER_INPLACE_EXCLUSIVE_LOCK, HA_ALTER_INPLACE_SHARED_LOCK, HA_ALTER_INPLACE_NO_LOCK }; /* Flags for create_partitioning_metadata() */ enum chf_create_flags { CHF_CREATE_FLAG, CHF_DELETE_FLAG, CHF_RENAME_FLAG, CHF_INDEX_FLAG }; /* Bits in table_flags() to show what database can do */ #define HA_NO_TRANSACTIONS (1ULL << 0) /* Doesn't support transactions */ #define HA_PARTIAL_COLUMN_READ (1ULL << 1) /* read may not return all columns */ #define HA_TABLE_SCAN_ON_INDEX (1ULL << 2) /* No separate data/index file */ /* The following should be set if the following is not true when scanning a table with rnd_next() - We will see all rows (including deleted ones) - Row positions are 'table->s->db_record_offset' apart If this flag is not set, filesort will do a position() call for each matched row to be able to find the row later. */ #define HA_REC_NOT_IN_SEQ (1ULL << 3) #define HA_CAN_GEOMETRY (1ULL << 4) /* Reading keys in random order is as fast as reading keys in sort order (Used in records.cc to decide if we should use a record cache and by filesort to decide if we should sort key + data or key + pointer-to-row */ #define HA_FAST_KEY_READ (1ULL << 5) /* Set the following flag if we on delete should force all key to be read and on update read all keys that changes */ #define HA_REQUIRES_KEY_COLUMNS_FOR_DELETE (1ULL << 6) #define HA_NULL_IN_KEY (1ULL << 7) /* One can have keys with NULL */ #define HA_DUPLICATE_POS (1ULL << 8) /* ha_position() gives dup row */ #define HA_NO_BLOBS (1ULL << 9) /* Doesn't support blobs */ #define HA_CAN_INDEX_BLOBS (1ULL << 10) #define HA_AUTO_PART_KEY (1ULL << 11) /* auto-increment in multi-part key */ /* The engine requires every table to have a user-specified PRIMARY KEY. Do not set the flag if the engine can generate a hidden primary key internally. This flag is ignored if a SEQUENCE is created (which, in turn, needs HA_CAN_TABLES_WITHOUT_ROLLBACK flag) */ #define HA_REQUIRE_PRIMARY_KEY (1ULL << 12) #define HA_STATS_RECORDS_IS_EXACT (1ULL << 13) /* stats.records is exact */ /* INSERT_DELAYED only works with handlers that uses MySQL internal table level locks */ #define HA_CAN_INSERT_DELAYED (1ULL << 14) /* If we get the primary key columns for free when we do an index read (usually, it also implies that HA_PRIMARY_KEY_REQUIRED_FOR_POSITION flag is set). */ #define HA_PRIMARY_KEY_IN_READ_INDEX (1ULL << 15) /* If HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is set, it means that to position() uses a primary key given by the record argument. Without primary key, we can't call position(). If not set, the position is returned as the current rows position regardless of what argument is given. */ #define HA_PRIMARY_KEY_REQUIRED_FOR_POSITION (1ULL << 16) #define HA_CAN_RTREEKEYS (1ULL << 17) #define HA_NOT_DELETE_WITH_CACHE (1ULL << 18) /* unused */ /* The following is we need to a primary key to delete (and update) a row. If there is no primary key, all columns needs to be read on update and delete */ #define HA_PRIMARY_KEY_REQUIRED_FOR_DELETE (1ULL << 19) #define HA_NO_PREFIX_CHAR_KEYS (1ULL << 20) #define HA_CAN_FULLTEXT (1ULL << 21) #define HA_CAN_SQL_HANDLER (1ULL << 22) #define HA_NO_AUTO_INCREMENT (1ULL << 23) /* Has automatic checksums and uses the old checksum format */ #define HA_HAS_OLD_CHECKSUM (1ULL << 24) /* Table data are stored in separate files (for lower_case_table_names) */ #define HA_FILE_BASED (1ULL << 26) #define HA_CAN_BIT_FIELD (1ULL << 28) /* supports bit fields */ #define HA_NEED_READ_RANGE_BUFFER (1ULL << 29) /* for read_multi_range */ #define HA_ANY_INDEX_MAY_BE_UNIQUE (1ULL << 30) #define HA_NO_COPY_ON_ALTER (1ULL << 31) #define HA_HAS_RECORDS (1ULL << 32) /* records() gives exact count*/ /* Has it's own method of binlog logging */ #define HA_HAS_OWN_BINLOGGING (1ULL << 33) /* Engine is capable of row-format and statement-format logging, respectively */ #define HA_BINLOG_ROW_CAPABLE (1ULL << 34) #define HA_BINLOG_STMT_CAPABLE (1ULL << 35) /* When a multiple key conflict happens in a REPLACE command mysql expects the conflicts to be reported in the ascending order of key names. For e.g. CREATE TABLE t1 (a INT, UNIQUE (a), b INT NOT NULL, UNIQUE (b), c INT NOT NULL, INDEX(c)); REPLACE INTO t1 VALUES (1,1,1),(2,2,2),(2,1,3); MySQL expects the conflict with 'a' to be reported before the conflict with 'b'. If the underlying storage engine does not report the conflicting keys in ascending order, it causes unexpected errors when the REPLACE command is executed. This flag helps the underlying SE to inform the server that the keys are not ordered. */ #define HA_DUPLICATE_KEY_NOT_IN_ORDER (1ULL << 36) /* Engine supports REPAIR TABLE. Used by CHECK TABLE FOR UPGRADE if an incompatible table is detected. If this flag is set, CHECK TABLE FOR UPGRADE will report ER_TABLE_NEEDS_UPGRADE, otherwise ER_TABLE_NEED_REBUILD. */ #define HA_CAN_REPAIR (1ULL << 37) /* Has automatic checksums and uses the new checksum format */ #define HA_HAS_NEW_CHECKSUM (1ULL << 38) #define HA_CAN_VIRTUAL_COLUMNS (1ULL << 39) #define HA_MRR_CANT_SORT (1ULL << 40) /* All of VARCHAR is stored, including bytes after real varchar data */ #define HA_RECORD_MUST_BE_CLEAN_ON_WRITE (1ULL << 41) /* This storage engine supports condition pushdown */ #define HA_CAN_TABLE_CONDITION_PUSHDOWN (1ULL << 42) /* old name for the same flag */ #define HA_MUST_USE_TABLE_CONDITION_PUSHDOWN HA_CAN_TABLE_CONDITION_PUSHDOWN /** The handler supports read before write removal optimization Read before write removal may be used for storage engines which support write without previous read of the row to be updated. Handler returning this flag must implement start_read_removal() and end_read_removal(). The handler may return "fake" rows constructed from the key of the row asked for. This is used to optimize UPDATE and DELETE by reducing the number of roundtrips between handler and storage engine. Example: UPDATE a=1 WHERE pk IN () mysql_update() { if () start_read_removal() -> handler returns true if read removal supported for this table/query while(read_record("pk=")) -> handler returns fake row with column "pk" set to ha_update_row() -> handler sends write "a=1" for row with "pk=" end_read_removal() -> handler returns the number of rows actually written } @note This optimization in combination with batching may be used to remove even more roundtrips. */ #define HA_READ_BEFORE_WRITE_REMOVAL (1ULL << 43) /* Engine supports extended fulltext API */ #define HA_CAN_FULLTEXT_EXT (1ULL << 44) /* Storage engine supports table export using the FLUSH TABLE FOR EXPORT statement (meaning, after this statement one can copy table files out of the datadir and later "import" (somehow) in another MariaDB instance) */ #define HA_CAN_EXPORT (1ULL << 45) /* Storage engine does not require an exclusive metadata lock on the table during optimize. (TODO and repair?). It can allow other connections to open the table. (it does not necessarily mean that other connections can read or modify the table - this is defined by THR locks and the ::store_lock() method). */ #define HA_CONCURRENT_OPTIMIZE (1ULL << 46) /* If the storage engine support tables that will not roll back on commit In addition the table should not lock rows and support READ and WRITE UNCOMMITTED. This is useful for implementing things like SEQUENCE but can also in the future be useful to do logging that should never roll back. */ #define HA_CAN_TABLES_WITHOUT_ROLLBACK (1ULL << 47) /* Mainly for usage by SEQUENCE engine. Setting this flag means that the table will never roll back and that all operations for this table should stored in the non transactional log space that will always be written, even on rollback. */ #define HA_PERSISTENT_TABLE (1ULL << 48) /* If storage engine uses another engine as a base This flag is also needed if the table tries to open the .frm file as part of drop table. */ #define HA_REUSES_FILE_NAMES (1ULL << 49) /* Set of all binlog flags. Currently only contain the capabilities flags. */ #define HA_BINLOG_FLAGS (HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE) /* The following are used by Spider */ #define HA_CAN_FORCE_BULK_UPDATE (1ULL << 50) #define HA_CAN_FORCE_BULK_DELETE (1ULL << 51) #define HA_CAN_DIRECT_UPDATE_AND_DELETE (1ULL << 52) /* The following is for partition handler */ #define HA_CAN_MULTISTEP_MERGE (1LL << 53) /* calling cmp_ref() on the engine is expensive */ #define HA_SLOW_CMP_REF (1ULL << 54) #define HA_CMP_REF_IS_EXPENSIVE HA_SLOW_CMP_REF /** Some engines are unable to provide an efficient implementation for rnd_pos(). Server will try to avoid it, if possible TODO better to do it with cost estimates, not with an explicit flag */ #define HA_SLOW_RND_POS (1ULL << 55) /* Safe for online backup */ #define HA_CAN_ONLINE_BACKUPS (1ULL << 56) /* Support native hash index */ #define HA_CAN_HASH_KEYS (1ULL << 57) #define HA_CRASH_SAFE (1ULL << 58) /* There is no need to evict the table from the table definition cache having run ANALYZE TABLE on it */ #define HA_ONLINE_ANALYZE (1ULL << 59) /* Rowid's are not comparable. This is set if the rowid is unique to the current open handler, like it is with federated where the rowid is a pointer to a local result set buffer. The effect of having this set is that the optimizer will not consider the following optimizations for the table: ror scans, filtering or duplicate weedout */ #define HA_NON_COMPARABLE_ROWID (1ULL << 60) /* Implements SELECT ... FOR UPDATE SKIP LOCKED */ #define HA_CAN_SKIP_LOCKED (1ULL << 61) #define HA_CHECK_UNIQUE_AFTER_WRITE (1ULL << 62) #define HA_LAST_TABLE_FLAG HA_CHECK_UNIQUE_AFTER_WRITE /* bits in index_flags(index_number) for what you can do with index */ #define HA_READ_NEXT 1 /* TODO really use this flag */ #define HA_READ_PREV 2 /* supports ::index_prev */ #define HA_READ_ORDER 4 /* index_next/prev follow sort order */ #define HA_READ_RANGE 8 /* can find all records in a range */ #define HA_ONLY_WHOLE_INDEX 16 /* Can't use part key searches */ #define HA_KEYREAD_ONLY 64 /* Support HA_EXTRA_KEYREAD */ /* Index scan will not return records in rowid order. Not guaranteed to be set for unordered (e.g. HASH) indexes. */ #define HA_KEY_SCAN_NOT_ROR 128 #define HA_DO_INDEX_COND_PUSHDOWN 256 /* Supports Index Condition Pushdown */ /* Data is clustered on this key. This means that when you read the key you also get the row data without any additional disk reads. */ #define HA_CLUSTERED_INDEX 512 #define HA_DO_RANGE_FILTER_PUSHDOWN 1024 /* bits in alter_table_flags: */ /* These bits are set if different kinds of indexes can be created or dropped in-place without re-creating the table using a temporary table. NO_READ_WRITE indicates that the handler needs concurrent reads and writes of table data to be blocked. Partitioning needs both ADD and DROP to be supported by its underlying handlers, due to error handling, see bug#57778. */ #define HA_INPLACE_ADD_INDEX_NO_READ_WRITE (1UL << 0) #define HA_INPLACE_DROP_INDEX_NO_READ_WRITE (1UL << 1) #define HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE (1UL << 2) #define HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE (1UL << 3) #define HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE (1UL << 4) #define HA_INPLACE_DROP_PK_INDEX_NO_READ_WRITE (1UL << 5) /* These are set if different kinds of indexes can be created or dropped in-place while still allowing concurrent reads (but not writes) of table data. If a handler is capable of one or more of these, it should also set the corresponding *_NO_READ_WRITE bit(s). */ #define HA_INPLACE_ADD_INDEX_NO_WRITE (1UL << 6) #define HA_INPLACE_DROP_INDEX_NO_WRITE (1UL << 7) #define HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE (1UL << 8) #define HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE (1UL << 9) #define HA_INPLACE_ADD_PK_INDEX_NO_WRITE (1UL << 10) #define HA_INPLACE_DROP_PK_INDEX_NO_WRITE (1UL << 11) /* HA_PARTITION_FUNCTION_SUPPORTED indicates that the function is supported at all. HA_FAST_CHANGE_PARTITION means that optimised variants of the changes exists but they are not necessarily done online. HA_ONLINE_DOUBLE_WRITE means that the handler supports writing to both the new partition and to the old partitions when updating through the old partitioning schema while performing a change of the partitioning. This means that we can support updating of the table while performing the copy phase of the change. For no lock at all also a double write from new to old must exist and this is not required when this flag is set. This is actually removed even before it was introduced the first time. The new idea is that handlers will handle the lock level already in store_lock for ALTER TABLE partitions. HA_PARTITION_ONE_PHASE is a flag that can be set by handlers that take care of changing the partitions online and in one phase. Thus all phases needed to handle the change are implemented inside the storage engine. The storage engine must also support auto-discovery since the frm file is changed as part of the change and this change must be controlled by the storage engine. A typical engine to support this is NDB (through WL #2498). */ #define HA_PARTITION_FUNCTION_SUPPORTED (1UL << 12) #define HA_FAST_CHANGE_PARTITION (1UL << 13) #define HA_PARTITION_ONE_PHASE (1UL << 14) /* Note: the following includes binlog and closing 0. TODO remove the limit, use dynarrays */ #define MAX_HA 64 /* Use this instead of 0 as the initial value for the slot number of handlerton, so that we can distinguish uninitialized slot number from slot 0. */ #define HA_SLOT_UNDEF ((uint)-1) /* Parameters for open() (in register form->filestat) HA_GET_INFO does an implicit HA_ABORT_IF_LOCKED */ #define HA_OPEN_KEYFILE 1U #define HA_READ_ONLY 16U /* File opened as readonly */ /* Try readonly if can't open with read and write */ #define HA_TRY_READ_ONLY 32U /* Some key definitions */ #define HA_KEY_NULL_LENGTH 1 #define HA_KEY_BLOB_LENGTH 2 /* Maximum length of any index lookup key, in bytes */ #define MAX_KEY_LENGTH (MAX_DATA_LENGTH_FOR_KEY \ +(MAX_REF_PARTS \ *(HA_KEY_NULL_LENGTH + HA_KEY_BLOB_LENGTH))) #define HA_LEX_CREATE_TMP_TABLE 1U #define HA_CREATE_TMP_ALTER 8U #define HA_LEX_CREATE_SEQUENCE 16U #define HA_VERSIONED_TABLE 32U #define HA_SKIP_KEY_SORT 64U /* A temporary table that can be used by different threads, eg. replication threads. This flag ensure that memory is not allocated with THREAD_SPECIFIC, as we do for other temporary tables. */ #define HA_LEX_CREATE_GLOBAL_TMP_TABLE 128U #define HA_MAX_REC_LENGTH 65535 /* Table caching type */ #define HA_CACHE_TBL_NONTRANSACT 0 #define HA_CACHE_TBL_NOCACHE 1U #define HA_CACHE_TBL_ASKTRANSACT 2U #define HA_CACHE_TBL_TRANSACT 4U /** Options for the START TRANSACTION statement. Note that READ ONLY and READ WRITE are logically mutually exclusive. This is enforced by the parser and depended upon by trans_begin(). We need two flags instead of one in order to differentiate between situation when no READ WRITE/ONLY clause were given and thus transaction is implicitly READ WRITE and the case when READ WRITE clause was used explicitly. */ // WITH CONSISTENT SNAPSHOT option static const uint MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT = 1; // READ ONLY option static const uint MYSQL_START_TRANS_OPT_READ_ONLY = 2; // READ WRITE option static const uint MYSQL_START_TRANS_OPT_READ_WRITE = 4; /* Flags for method is_fatal_error */ #define HA_CHECK_DUP_KEY 1U #define HA_CHECK_DUP_UNIQUE 2U #define HA_CHECK_FK_ERROR 4U #define HA_CHECK_DUP (HA_CHECK_DUP_KEY + HA_CHECK_DUP_UNIQUE) #define HA_CHECK_ALL (~0U) /* Options for info_push() */ #define INFO_KIND_UPDATE_FIELDS 101 #define INFO_KIND_UPDATE_VALUES 102 #define INFO_KIND_FORCE_LIMIT_BEGIN 103 #define INFO_KIND_FORCE_LIMIT_END 104 enum legacy_db_type { /* note these numerical values are fixed and can *not* be changed */ DB_TYPE_UNKNOWN=0, DB_TYPE_HEAP=6, DB_TYPE_MYISAM=9, DB_TYPE_MRG_MYISAM=10, DB_TYPE_INNODB=12, DB_TYPE_EXAMPLE_DB=15, DB_TYPE_ARCHIVE_DB=16, DB_TYPE_CSV_DB=17, DB_TYPE_FEDERATED_DB=18, DB_TYPE_BLACKHOLE_DB=19, DB_TYPE_PARTITION_DB=20, DB_TYPE_BINLOG=21, DB_TYPE_PBXT=23, DB_TYPE_PERFORMANCE_SCHEMA=28, DB_TYPE_S3=41, DB_TYPE_ARIA=42, DB_TYPE_TOKUDB=43, /* disabled in MariaDB Server 10.5, removed in 10.6 */ DB_TYPE_SEQUENCE=44, DB_TYPE_FIRST_DYNAMIC=45, DB_TYPE_DEFAULT=127 // Must be last }; /* Better name for DB_TYPE_UNKNOWN. Should be used for engines that do not have a hard-coded type value here. */ #define DB_TYPE_AUTOASSIGN DB_TYPE_UNKNOWN enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED, ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED, ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT, ROW_TYPE_PAGE }; /* not part of the enum, so that it shouldn't be in switch(row_type) */ #define ROW_TYPE_MAX ((uint)ROW_TYPE_PAGE + 1) /* Specifies data storage format for individual columns */ enum column_format_type { COLUMN_FORMAT_TYPE_DEFAULT= 0, /* Not specified (use engine default) */ COLUMN_FORMAT_TYPE_FIXED= 1, /* FIXED format */ COLUMN_FORMAT_TYPE_DYNAMIC= 2 /* DYNAMIC format */ }; enum enum_binlog_func { BFN_RESET_LOGS= 1, BFN_RESET_SLAVE= 2, BFN_BINLOG_WAIT= 3, BFN_BINLOG_END= 4, BFN_BINLOG_PURGE_FILE= 5 }; enum enum_binlog_command { LOGCOM_CREATE_TABLE, LOGCOM_ALTER_TABLE, LOGCOM_RENAME_TABLE, LOGCOM_DROP_TABLE, LOGCOM_CREATE_DB, LOGCOM_ALTER_DB, LOGCOM_DROP_DB }; /* struct to hold information about the table that should be created */ /* Bits in used_fields */ #define HA_CREATE_USED_AUTO (1UL << 0) #define HA_CREATE_USED_RAID (1UL << 1) //RAID is no longer available #define HA_CREATE_USED_UNION (1UL << 2) #define HA_CREATE_USED_INSERT_METHOD (1UL << 3) #define HA_CREATE_USED_MIN_ROWS (1UL << 4) #define HA_CREATE_USED_MAX_ROWS (1UL << 5) #define HA_CREATE_USED_AVG_ROW_LENGTH (1UL << 6) #define HA_CREATE_USED_PACK_KEYS (1UL << 7) #define HA_CREATE_USED_CHARSET (1UL << 8) #define HA_CREATE_USED_DEFAULT_CHARSET (1UL << 9) #define HA_CREATE_USED_DATADIR (1UL << 10) #define HA_CREATE_USED_INDEXDIR (1UL << 11) #define HA_CREATE_USED_ENGINE (1UL << 12) #define HA_CREATE_USED_CHECKSUM (1UL << 13) #define HA_CREATE_USED_DELAY_KEY_WRITE (1UL << 14) #define HA_CREATE_USED_ROW_FORMAT (1UL << 15) #define HA_CREATE_USED_COMMENT (1UL << 16) #define HA_CREATE_USED_PASSWORD (1UL << 17) #define HA_CREATE_USED_CONNECTION (1UL << 18) #define HA_CREATE_USED_KEY_BLOCK_SIZE (1UL << 19) /* The following two are used by Maria engine: */ #define HA_CREATE_USED_TRANSACTIONAL (1UL << 20) #define HA_CREATE_USED_PAGE_CHECKSUM (1UL << 21) /** This is set whenever STATS_PERSISTENT=0|1|default has been specified in CREATE/ALTER TABLE. See also HA_OPTION_STATS_PERSISTENT in include/my_base.h. It is possible to distinguish whether STATS_PERSISTENT=default has been specified or no STATS_PERSISTENT= is given at all. */ #define HA_CREATE_USED_STATS_PERSISTENT (1UL << 22) /** This is set whenever STATS_AUTO_RECALC=0|1|default has been specified in CREATE/ALTER TABLE. See enum_stats_auto_recalc. It is possible to distinguish whether STATS_AUTO_RECALC=default has been specified or no STATS_AUTO_RECALC= is given at all. */ #define HA_CREATE_USED_STATS_AUTO_RECALC (1UL << 23) /** This is set whenever STATS_SAMPLE_PAGES=N|default has been specified in CREATE/ALTER TABLE. It is possible to distinguish whether STATS_SAMPLE_PAGES=default has been specified or no STATS_SAMPLE_PAGES= is given at all. */ #define HA_CREATE_USED_STATS_SAMPLE_PAGES (1UL << 24) /* Create a sequence */ #define HA_CREATE_USED_SEQUENCE (1UL << 25) /* Tell binlog_show_create_table to print all engine options */ #define HA_CREATE_PRINT_ALL_OPTIONS (1UL << 26) typedef ulonglong alter_table_operations; typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*); /* These flags are set by the parser and describes the type of operation(s) specified by the ALTER TABLE statement. */ // Set by parser for ADD [COLUMN] #define ALTER_PARSER_ADD_COLUMN (1ULL << 0) // Set by parser for DROP [COLUMN] #define ALTER_PARSER_DROP_COLUMN (1ULL << 1) // Set for CHANGE [COLUMN] | MODIFY [CHANGE] & mysql_recreate_table #define ALTER_CHANGE_COLUMN (1ULL << 2) // Set for ADD INDEX | ADD KEY | ADD PRIMARY KEY | ADD UNIQUE KEY | // ADD UNIQUE INDEX | ALTER ADD [COLUMN] #define ALTER_ADD_INDEX (1ULL << 3) // Set for DROP PRIMARY KEY | DROP FOREIGN KEY | DROP KEY | DROP INDEX #define ALTER_DROP_INDEX (1ULL << 4) // Set for RENAME [TO] #define ALTER_RENAME (1ULL << 5) // Set for ORDER BY #define ALTER_ORDER (1ULL << 6) // Set for table_options, like table comment #define ALTER_OPTIONS (1ULL << 7) // Set for ALTER [COLUMN] ... SET DEFAULT ... | DROP DEFAULT #define ALTER_CHANGE_COLUMN_DEFAULT (1ULL << 8) // Set for DISABLE KEYS | ENABLE KEYS #define ALTER_KEYS_ONOFF (1ULL << 9) // Set for FORCE, ENGINE(same engine), by mysql_recreate_table() #define ALTER_RECREATE (1ULL << 10) // Set for CONVERT TO #define ALTER_CONVERT_TO (1ULL << 11) // Set for DROP ... ADD some_index #define ALTER_RENAME_INDEX (1ULL << 12) // Set for ADD FOREIGN KEY #define ALTER_ADD_FOREIGN_KEY (1ULL << 21) // Set for DROP FOREIGN KEY #define ALTER_DROP_FOREIGN_KEY (1ULL << 22) #define ALTER_CHANGE_INDEX_COMMENT (1ULL << 23) // Set for ADD [COLUMN] FIRST | AFTER #define ALTER_COLUMN_ORDER (1ULL << 25) #define ALTER_ADD_CHECK_CONSTRAINT (1ULL << 27) #define ALTER_DROP_CHECK_CONSTRAINT (1ULL << 28) #define ALTER_RENAME_COLUMN (1ULL << 29) #define ALTER_COLUMN_UNVERSIONED (1ULL << 30) #define ALTER_ADD_SYSTEM_VERSIONING (1ULL << 31) #define ALTER_DROP_SYSTEM_VERSIONING (1ULL << 32) #define ALTER_ADD_PERIOD (1ULL << 33) #define ALTER_DROP_PERIOD (1ULL << 34) /* Following defines are used by ALTER_INPLACE_TABLE They do describe in more detail the type operation(s) to be executed by the storage engine. For example, which type of type of index to be added/dropped. These are set by fill_alter_inplace_info(). */ #define ALTER_RECREATE_TABLE ALTER_RECREATE #define ALTER_CHANGE_CREATE_OPTION ALTER_OPTIONS #define ALTER_ADD_COLUMN (ALTER_ADD_VIRTUAL_COLUMN | \ ALTER_ADD_STORED_BASE_COLUMN | \ ALTER_ADD_STORED_GENERATED_COLUMN) #define ALTER_DROP_COLUMN (ALTER_DROP_VIRTUAL_COLUMN | \ ALTER_DROP_STORED_COLUMN) #define ALTER_COLUMN_DEFAULT ALTER_CHANGE_COLUMN_DEFAULT // Add non-unique, non-primary index #define ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX (1ULL << 35) // Drop non-unique, non-primary index #define ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX (1ULL << 36) // Add unique, non-primary index #define ALTER_ADD_UNIQUE_INDEX (1ULL << 37) // Drop unique, non-primary index #define ALTER_DROP_UNIQUE_INDEX (1ULL << 38) // Add primary index #define ALTER_ADD_PK_INDEX (1ULL << 39) // Drop primary index #define ALTER_DROP_PK_INDEX (1ULL << 40) // Virtual generated column #define ALTER_ADD_VIRTUAL_COLUMN (1ULL << 41) // Stored base (non-generated) column #define ALTER_ADD_STORED_BASE_COLUMN (1ULL << 42) // Stored generated column #define ALTER_ADD_STORED_GENERATED_COLUMN (1ULL << 43) // Drop column #define ALTER_DROP_VIRTUAL_COLUMN (1ULL << 44) #define ALTER_DROP_STORED_COLUMN (1ULL << 45) // Rename column (verified; ALTER_RENAME_COLUMN may use original name) #define ALTER_COLUMN_NAME (1ULL << 46) // Change column datatype #define ALTER_VIRTUAL_COLUMN_TYPE (1ULL << 47) #define ALTER_STORED_COLUMN_TYPE (1ULL << 48) // Engine can handle type change by itself in ALGORITHM=INPLACE #define ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE (1ULL << 49) // Reorder column #define ALTER_STORED_COLUMN_ORDER (1ULL << 50) // Reorder column #define ALTER_VIRTUAL_COLUMN_ORDER (1ULL << 51) // Change column from NOT NULL to NULL #define ALTER_COLUMN_NULLABLE (1ULL << 52) // Change column from NULL to NOT NULL #define ALTER_COLUMN_NOT_NULLABLE (1ULL << 53) // Change column generation expression #define ALTER_VIRTUAL_GCOL_EXPR (1ULL << 54) #define ALTER_STORED_GCOL_EXPR (1ULL << 55) // column's engine options changed, something in field->option_struct #define ALTER_COLUMN_OPTION (1ULL << 56) // MySQL alias for the same thing: #define ALTER_COLUMN_STORAGE_TYPE ALTER_COLUMN_OPTION // Change the column format of column #define ALTER_COLUMN_COLUMN_FORMAT (1ULL << 57) /** Changes in generated columns that affect storage, for example, when a vcol type or expression changes and this vcol is indexed or used in a partitioning expression */ #define ALTER_COLUMN_VCOL (1ULL << 58) /** ALTER TABLE for a partitioned table. The engine needs to commit online alter of all partitions atomically (using group_commit_ctx) */ #define ALTER_PARTITIONED (1ULL << 59) /** Change in index length such that it doesn't require index rebuild. */ #define ALTER_COLUMN_INDEX_LENGTH (1ULL << 60) /** Indicate that index order might have been changed. Disables inplace algorithm by default (not for InnoDB). */ #define ALTER_INDEX_ORDER (1ULL << 61) /** Means that the ignorability of an index is changed. */ #define ALTER_INDEX_IGNORABILITY (1ULL << 62) /* Flags set in partition_flags when altering partitions */ // Set for ADD PARTITION #define ALTER_PARTITION_ADD (1ULL << 1) // Set for DROP PARTITION #define ALTER_PARTITION_DROP (1ULL << 2) // Set for COALESCE PARTITION #define ALTER_PARTITION_COALESCE (1ULL << 3) // Set for REORGANIZE PARTITION ... INTO #define ALTER_PARTITION_REORGANIZE (1ULL << 4) // Set for partition_options #define ALTER_PARTITION_INFO (1ULL << 5) // Set for LOAD INDEX INTO CACHE ... PARTITION // Set for CACHE INDEX ... PARTITION #define ALTER_PARTITION_ADMIN (1ULL << 6) // Set for REBUILD PARTITION #define ALTER_PARTITION_REBUILD (1ULL << 7) // Set for partitioning operations specifying ALL keyword #define ALTER_PARTITION_ALL (1ULL << 8) // Set for REMOVE PARTITIONING #define ALTER_PARTITION_REMOVE (1ULL << 9) // Set for EXCHANGE PARITION #define ALTER_PARTITION_EXCHANGE (1ULL << 10) // Set by Sql_cmd_alter_table_truncate_partition::execute() #define ALTER_PARTITION_TRUNCATE (1ULL << 11) // Set for REORGANIZE PARTITION #define ALTER_PARTITION_TABLE_REORG (1ULL << 12) /* This is master database for most of system tables. However there can be other databases which can hold system tables. Respective storage engines define their own system database names. */ extern const char *mysqld_system_database; /* Structure to hold list of system_database.system_table. This is used at both mysqld and storage engine layer. */ struct st_system_tablename { const char *db; const char *tablename; }; typedef ulonglong my_xid; // this line is the same as in log_event.h #define MYSQL_XID_PREFIX "MySQLXid" #define MYSQL_XID_PREFIX_LEN 8 // must be a multiple of 8 #define MYSQL_XID_OFFSET (MYSQL_XID_PREFIX_LEN+sizeof(server_id)) #define MYSQL_XID_GTRID_LEN (MYSQL_XID_OFFSET+sizeof(my_xid)) #define XIDDATASIZE MYSQL_XIDDATASIZE #define MAXGTRIDSIZE 64 #define MAXBQUALSIZE 64 #define COMPATIBLE_DATA_YES 0 #define COMPATIBLE_DATA_NO 1 /** struct xid_t is binary compatible with the XID structure as in the X/Open CAE Specification, Distributed Transaction Processing: The XA Specification, X/Open Company Ltd., 1991. http://www.opengroup.org/bookstore/catalog/c193.htm @see MYSQL_XID in mysql/plugin.h */ struct xid_t { long formatID; long gtrid_length; long bqual_length; char data[XIDDATASIZE]; // not \0-terminated ! xid_t() = default; /* Remove gcc warning */ bool eq(struct xid_t *xid) const { return !xid->is_null() && eq(xid->gtrid_length, xid->bqual_length, xid->data); } bool eq(long g, long b, const char *d) const { return !is_null() && g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); } void set(struct xid_t *xid) { memcpy(this, xid, xid->length()); } void set(long f, const char *g, long gl, const char *b, long bl) { formatID= f; if ((gtrid_length= gl)) memcpy(data, g, gl); if ((bqual_length= bl)) memcpy(data+gl, b, bl); } // Populate server_id if it's specified, otherwise use the current server_id void set(ulonglong xid, decltype(::server_id) trx_server_id= server_id) { my_xid tmp; formatID= 1; set(MYSQL_XID_PREFIX_LEN, 0, MYSQL_XID_PREFIX); memcpy(data+MYSQL_XID_PREFIX_LEN, &trx_server_id, sizeof(trx_server_id)); tmp= xid; memcpy(data+MYSQL_XID_OFFSET, &tmp, sizeof(tmp)); gtrid_length=MYSQL_XID_GTRID_LEN; } void set(long g, long b, const char *d) { formatID= 1; gtrid_length= g; bqual_length= b; memcpy(data, d, g+b); } bool is_null() const { return formatID == -1; } void null() { formatID= -1; } my_xid quick_get_my_xid() { my_xid tmp; memcpy(&tmp, data+MYSQL_XID_OFFSET, sizeof(tmp)); return tmp; } my_xid get_my_xid() { return gtrid_length == MYSQL_XID_GTRID_LEN && bqual_length == 0 && !memcmp(data, MYSQL_XID_PREFIX, MYSQL_XID_PREFIX_LEN) ? quick_get_my_xid() : 0; } decltype(::server_id) get_trx_server_id() { decltype(::server_id) trx_server_id; memcpy(&trx_server_id, data+MYSQL_XID_PREFIX_LEN, sizeof(trx_server_id)); return trx_server_id; } uint length() { return static_cast(sizeof(formatID)) + key_length(); } uchar *key() const { return (uchar *)>rid_length; } uint key_length() const { return static_cast(sizeof(gtrid_length)+sizeof(bqual_length)+ gtrid_length+bqual_length); } }; typedef struct xid_t XID; /* Enumerates a sequence in the order of their creation that is in the top-down order of the index file. Ranges from zero through MAX_binlog_id. Not confuse the value with the binlog file numerical suffix, neither with the binlog file line in the binlog index file. */ typedef uint Binlog_file_id; const Binlog_file_id MAX_binlog_id= UINT_MAX; const my_off_t MAX_off_t = (~(my_off_t) 0); /* Compound binlog-id and byte offset of transaction's first event in a sequence (e.g the recovery sequence) of binlog files. Binlog_offset(0,0) is the minimum value to mean the first byte of the first binlog file. */ typedef std::pair Binlog_offset; /* binlog-based recovery transaction descriptor */ struct xid_recovery_member { my_xid xid; uint in_engine_prepare; // number of engines that have xid prepared bool decided_to_commit; /* Semisync recovery binlog offset. It's initialized with the maximum unreachable offset. The max value will remain for any transaction not found in binlog to yield its rollback decision as it's guaranteed to be within a truncated tail part of the binlog. */ Binlog_offset binlog_coord; XID *full_xid; // needed by wsrep or past it recovery decltype(::server_id) server_id; // server id of orginal server xid_recovery_member(my_xid xid_arg, uint prepare_arg, bool decided_arg, XID *full_xid_arg, decltype(::server_id) server_id_arg) : xid(xid_arg), in_engine_prepare(prepare_arg), decided_to_commit(decided_arg), binlog_coord(Binlog_offset(MAX_binlog_id, MAX_off_t)), full_xid(full_xid_arg), server_id(server_id_arg) {}; }; /* for recover() handlerton call */ #define MIN_XID_LIST_SIZE 128 #define MAX_XID_LIST_SIZE (1024*128) /* These structures are used to pass information from a set of SQL commands on add/drop/change tablespace definitions to the proper hton. */ #define UNDEF_NODEGROUP 65535 enum ts_command_type { TS_CMD_NOT_DEFINED = -1, CREATE_TABLESPACE = 0, ALTER_TABLESPACE = 1, CREATE_LOGFILE_GROUP = 2, ALTER_LOGFILE_GROUP = 3, DROP_TABLESPACE = 4, DROP_LOGFILE_GROUP = 5, CHANGE_FILE_TABLESPACE = 6, ALTER_ACCESS_MODE_TABLESPACE = 7 }; enum ts_alter_tablespace_type { TS_ALTER_TABLESPACE_TYPE_NOT_DEFINED = -1, ALTER_TABLESPACE_ADD_FILE = 1, ALTER_TABLESPACE_DROP_FILE = 2 }; enum tablespace_access_mode { TS_NOT_DEFINED= -1, TS_READ_ONLY = 0, TS_READ_WRITE = 1, TS_NOT_ACCESSIBLE = 2 }; /* Statistics about batch operations like bulk_insert */ struct ha_copy_info { ha_rows records; /* Used to check if rest of variables can be used */ ha_rows touched; ha_rows copied; ha_rows deleted; ha_rows updated; }; struct handlerton; class st_alter_tablespace : public Sql_alloc { public: const char *tablespace_name; const char *logfile_group_name; enum ts_command_type ts_cmd_type; enum ts_alter_tablespace_type ts_alter_tablespace_type; const char *data_file_name; const char *undo_file_name; const char *redo_file_name; ulonglong extent_size; ulonglong undo_buffer_size; ulonglong redo_buffer_size; ulonglong initial_size; ulonglong autoextend_size; ulonglong max_size; uint nodegroup_id; handlerton *storage_engine; bool wait_until_completed; const char *ts_comment; enum tablespace_access_mode ts_access_mode; st_alter_tablespace() { tablespace_name= NULL; logfile_group_name= "DEFAULT_LG"; //Default log file group ts_cmd_type= TS_CMD_NOT_DEFINED; data_file_name= NULL; undo_file_name= NULL; redo_file_name= NULL; extent_size= 1024*1024; //Default 1 MByte undo_buffer_size= 8*1024*1024; //Default 8 MByte redo_buffer_size= 8*1024*1024; //Default 8 MByte initial_size= 128*1024*1024; //Default 128 MByte autoextend_size= 0; //No autoextension as default max_size= 0; //Max size == initial size => no extension storage_engine= NULL; nodegroup_id= UNDEF_NODEGROUP; wait_until_completed= TRUE; ts_comment= NULL; ts_access_mode= TS_NOT_DEFINED; } }; /* The handler for a table type. Will be included in the TABLE structure */ struct TABLE; /* Make sure that the order of schema_tables and enum_schema_tables are the same. */ enum enum_schema_tables { SCH_ALL_PLUGINS, SCH_APPLICABLE_ROLES, SCH_CHARSETS, SCH_CHECK_CONSTRAINTS, SCH_COLLATIONS, SCH_COLLATION_CHARACTER_SET_APPLICABILITY, SCH_COLUMNS, SCH_COLUMN_PRIVILEGES, SCH_ENABLED_ROLES, SCH_ENGINES, SCH_EVENTS, SCH_EXPLAIN, SCH_FILES, SCH_GLOBAL_STATUS, SCH_GLOBAL_VARIABLES, SCH_KEYWORDS, SCH_KEY_CACHES, SCH_KEY_COLUMN_USAGE, SCH_OPEN_TABLES, SCH_OPT_TRACE, SCH_PARAMETERS, SCH_PARTITIONS, SCH_PLUGINS, SCH_PROCESSLIST, SCH_PROFILES, SCH_REFERENTIAL_CONSTRAINTS, SCH_PROCEDURES, SCH_SCHEMATA, SCH_SCHEMA_PRIVILEGES, SCH_SESSION_STATUS, SCH_SESSION_VARIABLES, SCH_STATISTICS, SCH_SQL_FUNCTIONS, SCH_SYSTEM_VARIABLES, SCH_TABLES, SCH_TABLESPACES, SCH_TABLE_CONSTRAINTS, SCH_TABLE_NAMES, SCH_TABLE_PRIVILEGES, SCH_TRIGGERS, SCH_USER_PRIVILEGES, SCH_VIEWS }; struct TABLE_SHARE; struct HA_CREATE_INFO; struct st_foreign_key_info; typedef struct st_foreign_key_info FOREIGN_KEY_INFO; typedef bool (stat_print_fn)(THD *thd, const char *type, size_t type_len, const char *file, size_t file_len, const char *status, size_t status_len); enum ha_stat_type { HA_ENGINE_STATUS, HA_ENGINE_LOGS, HA_ENGINE_MUTEX }; extern MYSQL_PLUGIN_IMPORT st_plugin_int *hton2plugin[MAX_HA]; #define view_pseudo_hton ((handlerton *)1) /* Definitions for engine-specific table/field/index options in the CREATE TABLE. Options are declared with HA_*OPTION_* macros (HA_TOPTION_NUMBER, HA_FOPTION_ENUM, HA_IOPTION_STRING, etc). Every macros takes the option name, and the name of the underlying field of the appropriate C structure. The "appropriate C structure" is ha_table_option_struct for table level options, ha_field_option_struct for field level options, ha_index_option_struct for key level options. The engine either defines a structure of this name, or uses #define's to map these "appropriate" names to the actual structure type name. ULL options use a ulonglong as the backing store. HA_*OPTION_NUMBER() takes the option name, the structure field name, the default value for the option, min, max, and blk_siz values. STRING options use a char* as a backing store. HA_*OPTION_STRING takes the option name and the structure field name. The default value will be 0. ENUM options use a uint as a backing store (not enum!!!). HA_*OPTION_ENUM takes the option name, the structure field name, the default value for the option as a number, and a string with the permitted values for this enum - one string with comma separated values, for example: "gzip,bzip2,lzma" BOOL options use a bool as a backing store. HA_*OPTION_BOOL takes the option name, the structure field name, and the default value for the option. From the SQL, BOOL options accept YES/NO, ON/OFF, and 1/0. The name of the option is limited to 255 bytes, the value (for string options) - to the 32767 bytes. See ha_example.cc for an example. */ struct ha_table_option_struct; struct ha_field_option_struct; struct ha_index_option_struct; enum ha_option_type { HA_OPTION_TYPE_ULL, /* unsigned long long */ HA_OPTION_TYPE_STRING, /* char * */ HA_OPTION_TYPE_ENUM, /* uint */ HA_OPTION_TYPE_BOOL, /* bool */ HA_OPTION_TYPE_SYSVAR};/* type of the sysval */ #define HA_xOPTION_NUMBER(name, struc, field, def, min, max, blk_siz) \ { HA_OPTION_TYPE_ULL, name, sizeof(name)-1, \ offsetof(struc, field), def, min, max, blk_siz, 0, 0 } #define HA_xOPTION_STRING(name, struc, field) \ { HA_OPTION_TYPE_STRING, name, sizeof(name)-1, \ offsetof(struc, field), 0, 0, 0, 0, 0, 0} #define HA_xOPTION_ENUM(name, struc, field, values, def) \ { HA_OPTION_TYPE_ENUM, name, sizeof(name)-1, \ offsetof(struc, field), def, 0, \ sizeof(values)-1, 0, values, 0 } #define HA_xOPTION_BOOL(name, struc, field, def) \ { HA_OPTION_TYPE_BOOL, name, sizeof(name)-1, \ offsetof(struc, field), def, 0, 1, 0, 0, 0 } #define HA_xOPTION_SYSVAR(name, struc, field, sysvar) \ { HA_OPTION_TYPE_SYSVAR, name, sizeof(name)-1, \ offsetof(struc, field), 0, 0, 0, 0, 0, MYSQL_SYSVAR(sysvar) } #define HA_xOPTION_END { HA_OPTION_TYPE_ULL, 0, 0, 0, 0, 0, 0, 0, 0, 0 } #define HA_TOPTION_NUMBER(name, field, def, min, max, blk_siz) \ HA_xOPTION_NUMBER(name, ha_table_option_struct, field, def, min, max, blk_siz) #define HA_TOPTION_STRING(name, field) \ HA_xOPTION_STRING(name, ha_table_option_struct, field) #define HA_TOPTION_ENUM(name, field, values, def) \ HA_xOPTION_ENUM(name, ha_table_option_struct, field, values, def) #define HA_TOPTION_BOOL(name, field, def) \ HA_xOPTION_BOOL(name, ha_table_option_struct, field, def) #define HA_TOPTION_SYSVAR(name, field, sysvar) \ HA_xOPTION_SYSVAR(name, ha_table_option_struct, field, sysvar) #define HA_TOPTION_END HA_xOPTION_END #define HA_FOPTION_NUMBER(name, field, def, min, max, blk_siz) \ HA_xOPTION_NUMBER(name, ha_field_option_struct, field, def, min, max, blk_siz) #define HA_FOPTION_STRING(name, field) \ HA_xOPTION_STRING(name, ha_field_option_struct, field) #define HA_FOPTION_ENUM(name, field, values, def) \ HA_xOPTION_ENUM(name, ha_field_option_struct, field, values, def) #define HA_FOPTION_BOOL(name, field, def) \ HA_xOPTION_BOOL(name, ha_field_option_struct, field, def) #define HA_FOPTION_SYSVAR(name, field, sysvar) \ HA_xOPTION_SYSVAR(name, ha_field_option_struct, field, sysvar) #define HA_FOPTION_END HA_xOPTION_END #define HA_IOPTION_NUMBER(name, field, def, min, max, blk_siz) \ HA_xOPTION_NUMBER(name, ha_index_option_struct, field, def, min, max, blk_siz) #define HA_IOPTION_STRING(name, field) \ HA_xOPTION_STRING(name, ha_index_option_struct, field) #define HA_IOPTION_ENUM(name, field, values, def) \ HA_xOPTION_ENUM(name, ha_index_option_struct, field, values, def) #define HA_IOPTION_BOOL(name, field, def) \ HA_xOPTION_BOOL(name, ha_index_option_struct, field, def) #define HA_IOPTION_SYSVAR(name, field, sysvar) \ HA_xOPTION_SYSVAR(name, ha_index_option_struct, field, sysvar) #define HA_IOPTION_END HA_xOPTION_END typedef struct st_ha_create_table_option { enum ha_option_type type; const char *name; size_t name_length; ptrdiff_t offset; ulonglong def_value; ulonglong min_value, max_value, block_size; const char *values; struct st_mysql_sys_var *var; } ha_create_table_option; class handler; class group_by_handler; class derived_handler; class select_handler; struct Query; typedef class st_select_lex SELECT_LEX; typedef struct st_order ORDER; /* handlerton is a singleton structure - one instance per storage engine - to provide access to storage engine functionality that works on the "global" level (unlike handler class that works on a per-table basis) usually handlerton instance is defined statically in ha_xxx.cc as static handlerton { ... } xxx_hton; savepoint_*, prepare, recover, and *_by_xid pointers can be 0. */ struct handlerton { /* Historical number used for frm file to determine the correct storage engine. This is going away and new engines will just use "name" for this. */ enum legacy_db_type db_type; /* each storage engine has it's own memory area (actually a pointer) in the thd, for storing per-connection information. It is accessed as thd->ha_data[xxx_hton.slot] slot number is initialized by MySQL after xxx_init() is called. */ uint slot; /* to store per-savepoint data storage engine is provided with an area of a requested size (0 is ok here). savepoint_offset must be initialized statically to the size of the needed memory to store per-savepoint information. After xxx_init it is changed to be an offset to savepoint storage area and need not be used by storage engine. see binlog_hton and binlog_savepoint_set/rollback for an example. */ uint savepoint_offset; /* handlerton methods: close_connection is only called if thd->ha_data[xxx_hton.slot] is non-zero, so even if you don't need this storage area - set it to something, so that MySQL would know this storage engine was accessed in this connection */ int (*close_connection)(handlerton *hton, THD *thd); /* Tell handler that query has been killed. */ void (*kill_query)(handlerton *hton, THD *thd, enum thd_kill_levels level); /* sv points to an uninitialized storage area of requested size (see savepoint_offset description) */ int (*savepoint_set)(handlerton *hton, THD *thd, void *sv); /* sv points to a storage area, that was earlier passed to the savepoint_set call */ int (*savepoint_rollback)(handlerton *hton, THD *thd, void *sv); /** Check if storage engine allows to release metadata locks which were acquired after the savepoint if rollback to savepoint is done. @return true - If it is safe to release MDL locks. false - If it is not. */ bool (*savepoint_rollback_can_release_mdl)(handlerton *hton, THD *thd); int (*savepoint_release)(handlerton *hton, THD *thd, void *sv); /* 'all' is true if it's a real commit, that makes persistent changes 'all' is false if it's not in fact a commit but an end of the statement that is part of the transaction. NOTE 'all' is also false in auto-commit mode where 'end of statement' and 'real commit' mean the same event. */ int (*commit)(handlerton *hton, THD *thd, bool all); /* The commit_ordered() method is called prior to the commit() method, after the transaction manager has decided to commit (not rollback) the transaction. Unlike commit(), commit_ordered() is called only when the full transaction is committed, not for each commit of statement transaction in a multi-statement transaction. Not that like prepare(), commit_ordered() is only called when 2-phase commit takes place. Ie. when no binary log and only a single engine participates in a transaction, one commit() is called, no commit_ordered(). So engines must be prepared for this. The calls to commit_ordered() in multiple parallel transactions is guaranteed to happen in the same order in every participating handler. This can be used to ensure the same commit order among multiple handlers (eg. in table handler and binlog). So if transaction T1 calls into commit_ordered() of handler A before T2, then T1 will also call commit_ordered() of handler B before T2. Engines that implement this method should during this call make the transaction visible to other transactions, thereby making the order of transaction commits be defined by the order of commit_ordered() calls. The intention is that commit_ordered() should do the minimal amount of work that needs to happen in consistent commit order among handlers. To preserve ordering, calls need to be serialised on a global mutex, so doing any time-consuming or blocking operations in commit_ordered() will limit scalability. Handlers can rely on commit_ordered() calls to be serialised (no two calls can run in parallel, so no extra locking on the handler part is required to ensure this). Note that commit_ordered() can be called from a different thread than the one handling the transaction! So it can not do anything that depends on thread local storage, in particular it can not call my_error() and friends (instead it can store the error code and delay the call of my_error() to the commit() method). Similarly, since commit_ordered() returns void, any return error code must be saved and returned from the commit() method instead. The commit_ordered method is optional, and can be left unset if not needed in a particular handler (then there will be no ordering guarantees wrt. other engines and binary log). */ void (*commit_ordered)(handlerton *hton, THD *thd, bool all); int (*rollback)(handlerton *hton, THD *thd, bool all); int (*prepare)(handlerton *hton, THD *thd, bool all); /* The prepare_ordered method is optional. If set, it will be called after successful prepare() in all handlers participating in 2-phase commit. Like commit_ordered(), it is called only when the full transaction is committed, not for each commit of statement transaction. The calls to prepare_ordered() among multiple parallel transactions are ordered consistently with calls to commit_ordered(). This means that calls to prepare_ordered() effectively define the commit order, and that each handler will see the same sequence of transactions calling into prepare_ordered() and commit_ordered(). Thus, prepare_ordered() can be used to define commit order for handlers that need to do this in the prepare step (like binlog). It can also be used to release transaction's locks early in an order consistent with the order transactions will be eventually committed. Like commit_ordered(), prepare_ordered() calls are serialised to maintain ordering, so the intention is that they should execute fast, with only the minimal amount of work needed to define commit order. Handlers can rely on this serialisation, and do not need to do any extra locking to avoid two prepare_ordered() calls running in parallel. Like commit_ordered(), prepare_ordered() is not guaranteed to be called in the context of the thread handling the rest of the transaction. So it cannot invoke code that relies on thread local storage, in particular it cannot call my_error(). prepare_ordered() cannot cause a rollback by returning an error, all possible errors must be handled in prepare() (the prepare_ordered() method returns void). In case of some fatal error, a record of the error must be made internally by the engine and returned from commit() later. Note that for user-level XA SQL commands, no consistent ordering among prepare_ordered() and commit_ordered() is guaranteed (as that would require blocking all other commits for an indefinite time). When 2-phase commit is not used (eg. only one engine (and no binlog) in transaction), neither prepare() nor prepare_ordered() is called. */ void (*prepare_ordered)(handlerton *hton, THD *thd, bool all); int (*recover)(handlerton *hton, XID *xid_list, uint len); int (*commit_by_xid)(handlerton *hton, XID *xid); int (*rollback_by_xid)(handlerton *hton, XID *xid); /* The commit_checkpoint_request() handlerton method is used to checkpoint the XA recovery process for storage engines that support two-phase commit. The method is optional - an engine that does not implemented is expected to work the traditional way, where every commit() durably flushes the transaction to disk in the engine before completion, so XA recovery will no longer be needed for that transaction. An engine that does implement commit_checkpoint_request() is also expected to implement commit_ordered(), so that ordering of commits is consistent between 2pc participants. Such engine is no longer required to durably flush to disk transactions in commit(), provided that the transaction has been successfully prepare()d and commit_ordered(); thus potentionally saving one fsync() call. (Engine must still durably flush to disk in commit() when no prepare()/commit_ordered() steps took place, at least if durable commits are wanted; this happens eg. if binlog is disabled). The TC will periodically (eg. once per binlog rotation) call commit_checkpoint_request(). When this happens, the engine must arrange for all transaction that have completed commit_ordered() to be durably flushed to disk (this does not include transactions that might be in the middle of executing commit_ordered()). When such flush has completed, the engine must call commit_checkpoint_notify_ha(), passing back the opaque "cookie". The flush and call of commit_checkpoint_notify_ha() need not happen immediately - it can be scheduled and performed asynchronously (ie. as part of next prepare(), or sync every second, or whatever), but should not be postponed indefinitely. It is however also permissible to do it immediately, before returning from commit_checkpoint_request(). When commit_checkpoint_notify_ha() is called, the TC will know that the transactions are durably committed, and thus no longer require XA recovery. It uses that to reduce the work needed for any subsequent XA recovery process. */ void (*commit_checkpoint_request)(void *cookie); /* "Disable or enable checkpointing internal to the storage engine. This is used for FLUSH TABLES WITH READ LOCK AND DISABLE CHECKPOINT to ensure that the engine will never start any recovery from a time between FLUSH TABLES ... ; UNLOCK TABLES. While checkpointing is disabled, the engine should pause any background write activity (such as tablespace checkpointing) that require consistency between different files (such as transaction log and tablespace files) for crash recovery to succeed. The idea is to use this to make safe multi-volume LVM snapshot backups. */ int (*checkpoint_state)(handlerton *hton, bool disabled); void *(*create_cursor_read_view)(handlerton *hton, THD *thd); void (*set_cursor_read_view)(handlerton *hton, THD *thd, void *read_view); void (*close_cursor_read_view)(handlerton *hton, THD *thd, void *read_view); handler *(*create)(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); void (*drop_database)(handlerton *hton, char* path); /* return 0 if dropped successfully, -1 if nothing was done by design (as in e.g. blackhole) an error code (e.g. HA_ERR_NO_SUCH_TABLE) otherwise */ int (*drop_table)(handlerton *hton, const char* path); int (*panic)(handlerton *hton, enum ha_panic_function flag); int (*start_consistent_snapshot)(handlerton *hton, THD *thd); bool (*flush_logs)(handlerton *hton); bool (*show_status)(handlerton *hton, THD *thd, stat_print_fn *print, enum ha_stat_type stat); uint (*partition_flags)(); alter_table_operations (*alter_table_flags)(alter_table_operations flags); int (*alter_tablespace)(handlerton *hton, THD *thd, st_alter_tablespace *ts_info); int (*fill_is_table)(handlerton *hton, THD *thd, TABLE_LIST *tables, class Item *cond, enum enum_schema_tables); uint32 flags; /* global handler flags */ /* Those handlerton functions below are properly initialized at handler init. */ int (*binlog_func)(handlerton *hton, THD *thd, enum_binlog_func fn, void *arg); void (*binlog_log_query)(handlerton *hton, THD *thd, enum_binlog_command binlog_command, const char *query, uint query_length, const char *db, const char *table_name); void (*abort_transaction)(handlerton *hton, THD *bf_thd, THD *victim_thd, my_bool signal) __attribute__((nonnull)); int (*set_checkpoint)(handlerton *hton, const XID *xid); int (*get_checkpoint)(handlerton *hton, XID* xid); /** Check if the version of the table matches the version in the .frm file. This is mainly used to verify in recovery to check if an inplace ALTER TABLE succeded. Storage engines that does not support inplace alter table does not have to implement this function. @param hton handlerton @param path Path for table @param version The unique id that is stored in the .frm file for CREATE and updated for each ALTER TABLE (but not for simple renames). This is the ID used for the final table. @param create_id The value returned from handler->table_version() for the original table (before ALTER TABLE). @retval 0 If id matches or table is newer than create_id (depending on what version check the engine supports. This means that The (inplace) alter table did succeed. @retval # > 0 Alter table did not succeed. Related to handler::discover_check_version(). */ int (*check_version)(handlerton *hton, const char *path, const LEX_CUSTRING *version, ulonglong create_id); /* Called for all storage handlers after ddl recovery is done */ int (*signal_ddl_recovery_done)(handlerton *hton); /* Optional clauses in the CREATE/ALTER TABLE */ ha_create_table_option *table_options; // table level options ha_create_table_option *field_options; // these are specified per field ha_create_table_option *index_options; // these are specified per index /** The list of extensions of files created for a single table in the database directory (datadir/db_name/). Used by open_table_error(), by the default rename_table and delete_table handler methods, and by the default discovery implementation. For engines that have more than one file name extensions (separate metadata, index, and/or data files), the order of elements is relevant. First element of engine file name extensions array should be metadata file extention. This is implied by the open_table_error() and the default discovery implementation. Second element - data file extension. This is implied assumed by REPAIR TABLE ... USE_FRM implementation. */ const char **tablefile_extensions; // by default - empty list /********************************************************************** Functions to intercept queries **********************************************************************/ /* Create and return a group_by_handler, if the storage engine can execute the summary / group by query. If the storage engine can't do that, return NULL. The server guaranteeds that all tables in the list belong to this storage engine. */ group_by_handler *(*create_group_by)(THD *thd, Query *query); /* Create and return a derived_handler if the storage engine can execute the derived table 'derived', otherwise return NULL. In a general case 'derived' may contain tables not from the engine. If the engine cannot handle or does not want to handle such pushed derived the function create_group_by has to return NULL. */ derived_handler *(*create_derived)(THD *thd, TABLE_LIST *derived); /* Create and return a select_handler if the storage engine can execute the select statement 'select, otherwise return NULL */ select_handler *(*create_select) (THD *thd, SELECT_LEX *select); /********************************************************************* Table discovery API. It allows the server to "discover" tables that exist in the storage engine, without user issuing an explicit CREATE TABLE statement. **********************************************************************/ /* This method is required for any engine that supports automatic table discovery, there is no default implementation. Given a TABLE_SHARE discover_table() fills it in with a correct table structure using one of the TABLE_SHARE::init_from_* methods. Returns HA_ERR_NO_SUCH_TABLE if the table did not exist in the engine, zero if the table was discovered successfully, or any other HA_ERR_* error code as appropriate if the table existed, but the discovery failed. */ int (*discover_table)(handlerton *hton, THD* thd, TABLE_SHARE *share); /* The discover_table_names method tells the server about all tables in the specified database that the engine knows about. Tables (or file names of tables) are added to the provided discovered_list collector object using add_table() or add_file() methods. */ class discovered_list { public: virtual bool add_table(const char *tname, size_t tlen) = 0; virtual bool add_file(const char *fname) = 0; protected: virtual ~discovered_list() = default; }; /* By default (if not implemented by the engine, but the discover_table() is implemented) it will perform a file-based discovery: - if tablefile_extensions[0] is not null, this will discovers all tables with the tablefile_extensions[0] extension. Returns 0 on success and 1 on error. */ int (*discover_table_names)(handlerton *hton, LEX_CSTRING *db, MY_DIR *dir, discovered_list *result); /* This is a method that allows to server to check if a table exists without an overhead of the complete discovery. By default (if not implemented by the engine, but the discovery_table() is implemented) it will try to perform a file-based discovery: - if tablefile_extensions[0] is not null this will look for a file name with the tablefile_extensions[0] extension. - if tablefile_extensions[0] is null, this will resort to discover_table(). Note that resorting to discover_table() is slow and the engine should probably implement its own discover_table_existence() method, if its tablefile_extensions[0] is null. Returns 1 if the table exists and 0 if it does not. */ int (*discover_table_existence)(handlerton *hton, const char *db, const char *table_name); /* This is the assisted table discovery method. Unlike the fully automatic discovery as above, here a user is expected to issue an explicit CREATE TABLE with the appropriate table attributes to "assist" the discovery of a table. But this "discovering" CREATE TABLE statement will not specify the table structure - the engine discovers it using this method. For example, FederatedX uses it in CREATE TABLE t1 ENGINE=FEDERATED CONNECTION="mysql://foo/bar/t1"; Given a TABLE_SHARE discover_table_structure() fills it in with a correct table structure using one of the TABLE_SHARE::init_from_* methods. Assisted discovery works independently from the automatic discover. An engine is allowed to support only assisted discovery and not support automatic one. Or vice versa. */ int (*discover_table_structure)(handlerton *hton, THD* thd, TABLE_SHARE *share, HA_CREATE_INFO *info); /* Notify the storage engine that the definition of the table (and the .frm file) has changed. Returns 0 if ok. */ int (*notify_tabledef_changed)(handlerton *hton, LEX_CSTRING *db, LEX_CSTRING *table_name, LEX_CUSTRING *frm, LEX_CUSTRING *org_tabledef_version, handler *file); /* System Versioning */ /** Determine if system-versioned data was modified by the transaction. @param[in,out] thd current session @param[out] trx_id transaction start ID @return transaction commit ID @retval 0 if no system-versioned data was affected by the transaction */ ulonglong (*prepare_commit_versioned)(THD *thd, ulonglong *trx_id); /** Disable or enable the internal writes of a storage engine */ void (*disable_internal_writes)(bool disable); /* backup */ void (*prepare_for_backup)(void); void (*end_backup)(void); /* Server shutdown early notification.*/ void (*pre_shutdown)(void); /* Inform handler that partitioning engine has changed the .frm and the .par files */ int (*create_partitioning_metadata)(const char *path, const char *old_path, chf_create_flags action_flag); }; extern const char *hton_no_exts[]; static inline LEX_CSTRING *hton_name(const handlerton *hton) { return &(hton2plugin[hton->slot]->name); } static inline handlerton *plugin_hton(plugin_ref plugin) { return plugin_data(plugin, handlerton *); } static inline sys_var *find_hton_sysvar(handlerton *hton, st_mysql_sys_var *var) { return find_plugin_sysvar(hton2plugin[hton->slot], var); } handlerton *ha_default_handlerton(THD *thd); handlerton *ha_default_tmp_handlerton(THD *thd); /* Possible flags of a handlerton (there can be 32 of them) */ #define HTON_NO_FLAGS 0 #define HTON_CLOSE_CURSORS_AT_COMMIT (1 << 0) #define HTON_ALTER_NOT_SUPPORTED (1 << 1) //Engine does not support alter #define HTON_CAN_RECREATE (1 << 2) //Delete all is used for truncate #define HTON_HIDDEN (1 << 3) //Engine does not appear in lists #define HTON_NOT_USER_SELECTABLE (1 << 5) #define HTON_TEMPORARY_NOT_SUPPORTED (1 << 6) //Having temporary tables not supported #define HTON_SUPPORT_LOG_TABLES (1 << 7) //Engine supports log tables #define HTON_NO_PARTITION (1 << 8) //Not partition of these tables /* This flag should be set when deciding that the engine does not allow row based binary logging (RBL) optimizations. Currently, setting this flag, means that table's read/write_set will be left untouched when logging changes to tables in this engine. In practice this means that the server will not mess around with table->write_set and/or table->read_set when using RBL and deciding whether to log full or minimal rows. It's valuable for instance for virtual tables, eg: Performance Schema which have no meaning for replication. */ #define HTON_NO_BINLOG_ROW_OPT (1 << 9) #define HTON_SUPPORTS_EXTENDED_KEYS (1 <<10) //supports extended keys #define HTON_NATIVE_SYS_VERSIONING (1 << 11) //Engine supports System Versioning // MySQL compatibility. Unused. #define HTON_SUPPORTS_FOREIGN_KEYS (1 << 0) //Foreign key constraint supported. #define HTON_CAN_MERGE (1 <<11) //Merge type table // Engine needs to access the main connect string in partitions #define HTON_CAN_READ_CONNECT_STRING_IN_PARTITION (1 <<12) /* can be replicated by wsrep replication provider plugin */ #define HTON_WSREP_REPLICATION (1 << 13) /* Set this on the *slave* that's connected to a shared with a master storage. The slave will ignore any CREATE TABLE, DROP or updates for this engine. */ #define HTON_IGNORE_UPDATES (1 << 14) /* Set this on the *master* that's connected to a shared with a slave storage. The table may not exists on the slave. The effects of having this flag are: - ALTER TABLE that changes engine from this table to another engine will be replicated as CREATE + INSERT - CREATE ... LIKE shared_table will be replicated as a full CREATE TABLE - ALTER TABLE for this engine will have "IF EXISTS" added. - RENAME TABLE for this engine will have "IF EXISTS" added. - DROP TABLE for this engine will have "IF EXISTS" added. */ #define HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE (1 << 15) /* True if handler cannot rollback transactions. If not true, the transaction will be put in the transactional binlog cache. For some engines, like Aria, the rollback can happen in case of crash, but not trough a handler rollback call. */ #define HTON_NO_ROLLBACK (1 << 16) /* This storage engine can support both transactional and non transactional tables */ #define HTON_TRANSACTIONAL_AND_NON_TRANSACTIONAL (1 << 17) /* Table requires and close and reopen after truncate If the handler has HTON_CAN_RECREATE, this flag is not used */ #define HTON_REQUIRES_CLOSE_AFTER_TRUNCATE (1 << 18) /* Truncate requires that all other handlers are closed */ #define HTON_TRUNCATE_REQUIRES_EXCLUSIVE_USE (1 << 19) /* Used by mysql_inplace_alter_table() to decide if we should call hton->notify_tabledef_changed() before commit (MyRocks) or after (InnoDB). */ #define HTON_REQUIRES_NOTIFY_TABLEDEF_CHANGED_AFTER_COMMIT (1 << 20) class Ha_trx_info; struct THD_TRANS { /* true is not all entries in the ht[] support 2pc */ bool no_2pc; /* storage engines that registered in this transaction */ Ha_trx_info *ha_list; /* The purpose of this flag is to keep track of non-transactional tables that were modified in scope of: - transaction, when the variable is a member of THD::transaction.all - top-level statement or sub-statement, when the variable is a member of THD::transaction.stmt This member has the following life cycle: * stmt.modified_non_trans_table is used to keep track of modified non-transactional tables of top-level statements. At the end of the previous statement and at the beginning of the session, it is reset to FALSE. If such functions as mysql_insert, mysql_update, mysql_delete etc modify a non-transactional table, they set this flag to TRUE. At the end of the statement, the value of stmt.modified_non_trans_table is merged with all.modified_non_trans_table and gets reset. * all.modified_non_trans_table is reset at the end of transaction * Since we do not have a dedicated context for execution of a sub-statement, to keep track of non-transactional changes in a sub-statement, we re-use stmt.modified_non_trans_table. At entrance into a sub-statement, a copy of the value of stmt.modified_non_trans_table (containing the changes of the outer statement) is saved on stack. Then stmt.modified_non_trans_table is reset to FALSE and the substatement is executed. Then the new value is merged with the saved value. */ bool modified_non_trans_table; void reset() { no_2pc= FALSE; modified_non_trans_table= FALSE; m_unsafe_rollback_flags= 0; } bool is_empty() const { return ha_list == NULL; } THD_TRANS() = default; /* Remove gcc warning */ unsigned int m_unsafe_rollback_flags; /* Define the type of statements which cannot be rolled back safely. Each type occupies one bit in m_unsafe_rollback_flags. MODIFIED_NON_TRANS_TABLE is limited to mark only the temporary non-transactional table *when* it's cached along with the transactional events; the regular table is covered by the "namesake" bool var. */ enum unsafe_statement_types { MODIFIED_NON_TRANS_TABLE= 1, CREATED_TEMP_TABLE= 2, DROPPED_TEMP_TABLE= 4, DID_WAIT= 8, DID_DDL= 0x10, EXECUTED_TABLE_ADMIN_CMD= 0x20 }; void mark_modified_non_trans_temp_table() { m_unsafe_rollback_flags|= MODIFIED_NON_TRANS_TABLE; } bool has_modified_non_trans_temp_table() const { return (m_unsafe_rollback_flags & MODIFIED_NON_TRANS_TABLE) != 0; } void mark_executed_table_admin_cmd() { DBUG_PRINT("debug", ("mark_executed_table_admin_cmd")); m_unsafe_rollback_flags|= EXECUTED_TABLE_ADMIN_CMD; } bool trans_executed_admin_cmd() { return (m_unsafe_rollback_flags & EXECUTED_TABLE_ADMIN_CMD) != 0; } void mark_created_temp_table() { DBUG_PRINT("debug", ("mark_created_temp_table")); m_unsafe_rollback_flags|= CREATED_TEMP_TABLE; } void mark_dropped_temp_table() { DBUG_PRINT("debug", ("mark_dropped_temp_table")); m_unsafe_rollback_flags|= DROPPED_TEMP_TABLE; } bool has_created_dropped_temp_table() const { return (m_unsafe_rollback_flags & (CREATED_TEMP_TABLE|DROPPED_TEMP_TABLE)) != 0; } void mark_trans_did_wait() { m_unsafe_rollback_flags|= DID_WAIT; } bool trans_did_wait() const { return (m_unsafe_rollback_flags & DID_WAIT) != 0; } bool is_trx_read_write() const; void mark_trans_did_ddl() { m_unsafe_rollback_flags|= DID_DDL; } bool trans_did_ddl() const { return (m_unsafe_rollback_flags & DID_DDL) != 0; } }; /** Either statement transaction or normal transaction - related thread-specific storage engine data. If a storage engine participates in a statement/transaction, an instance of this class is present in thd->transaction.{stmt|all}.ha_list. The addition to {stmt|all}.ha_list is made by trans_register_ha(). When it's time to commit or rollback, each element of ha_list is used to access storage engine's prepare()/commit()/rollback() methods, and also to evaluate if a full two phase commit is necessary. @sa General description of transaction handling in handler.cc. */ class Ha_trx_info { public: /** Register this storage engine in the given transaction context. */ void register_ha(THD_TRANS *trans, handlerton *ht_arg) { DBUG_ASSERT(m_flags == 0); DBUG_ASSERT(m_ht == NULL); DBUG_ASSERT(m_next == NULL); m_ht= ht_arg; m_flags= (int) TRX_READ_ONLY; /* Assume read-only at start. */ m_next= trans->ha_list; trans->ha_list= this; } /** Clear, prepare for reuse. */ void reset() { m_next= NULL; m_ht= NULL; m_flags= 0; } Ha_trx_info() { reset(); } void set_trx_read_write() { DBUG_ASSERT(is_started()); m_flags|= (int) TRX_READ_WRITE; } bool is_trx_read_write() const { DBUG_ASSERT(is_started()); return m_flags & (int) TRX_READ_WRITE; } void set_trx_no_rollback() { DBUG_ASSERT(is_started()); m_flags|= (int) TRX_NO_ROLLBACK; } bool is_trx_no_rollback() const { DBUG_ASSERT(is_started()); return m_flags & (int) TRX_NO_ROLLBACK; } bool is_started() const { return m_ht != NULL; } /** Mark this transaction read-write if the argument is read-write. */ void coalesce_trx_with(const Ha_trx_info *stmt_trx) { /* Must be called only after the transaction has been started. Can be called many times, e.g. when we have many read-write statements in a transaction. */ DBUG_ASSERT(is_started()); if (stmt_trx->is_trx_read_write()) set_trx_read_write(); } Ha_trx_info *next() const { DBUG_ASSERT(is_started()); return m_next; } handlerton *ht() const { DBUG_ASSERT(is_started()); return m_ht; } private: enum { TRX_READ_ONLY= 0, TRX_READ_WRITE= 1, TRX_NO_ROLLBACK= 2 }; /** Auxiliary, used for ha_list management */ Ha_trx_info *m_next; /** Although a given Ha_trx_info instance is currently always used for the same storage engine, 'ht' is not-NULL only when the corresponding storage is a part of a transaction. */ handlerton *m_ht; /** Transaction flags related to this engine. Not-null only if this instance is a part of transaction. May assume a combination of enum values above. */ uchar m_flags; }; inline bool THD_TRANS::is_trx_read_write() const { Ha_trx_info *ha_info; for (ha_info= ha_list; ha_info; ha_info= ha_info->next()) if (ha_info->is_trx_read_write()) return TRUE; return FALSE; } enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED, ISO_REPEATABLE_READ, ISO_SERIALIZABLE}; typedef struct { ulonglong data_file_length; ulonglong max_data_file_length; ulonglong index_file_length; ulonglong max_index_file_length; ulonglong delete_length; ha_rows records; ulong mean_rec_length; time_t create_time; time_t check_time; time_t update_time; ulonglong check_sum; bool check_sum_null; } PARTITION_STATS; #define UNDEF_NODEGROUP 65535 class Item; struct st_table_log_memory_entry; class partition_info; struct st_partition_iter; enum ha_choice { HA_CHOICE_UNDEF, HA_CHOICE_NO, HA_CHOICE_YES, HA_CHOICE_MAX }; enum enum_stats_auto_recalc { HA_STATS_AUTO_RECALC_DEFAULT= 0, HA_STATS_AUTO_RECALC_ON, HA_STATS_AUTO_RECALC_OFF }; /** A helper struct for schema DDL statements: CREATE SCHEMA [IF NOT EXISTS] name [ schema_specification... ] ALTER SCHEMA name [ schema_specification... ] It stores the "schema_specification" part of the CREATE/ALTER statements and is passed to mysql_create_db() and mysql_alter_db(). Currently consists of the schema default character set, collation and schema_comment. */ struct Schema_specification_st { CHARSET_INFO *default_table_charset; LEX_CSTRING *schema_comment; void init() { bzero(this, sizeof(*this)); } }; class Create_field; struct Table_period_info: Sql_alloc { Table_period_info() : create_if_not_exists(false), constr(NULL), unique_keys(0) {} Table_period_info(const char *name_arg, size_t size) : name(name_arg, size), create_if_not_exists(false), constr(NULL), unique_keys(0){} Lex_ident name; struct start_end_t { start_end_t() = default; start_end_t(const LEX_CSTRING& _start, const LEX_CSTRING& _end) : start(_start), end(_end) {} Lex_ident start; Lex_ident end; }; start_end_t period; bool create_if_not_exists; Virtual_column_info *constr; uint unique_keys; bool is_set() const { DBUG_ASSERT(bool(period.start) == bool(period.end)); return period.start; } void set_period(const Lex_ident& start, const Lex_ident& end) { period.start= start; period.end= end; } bool check_field(const Create_field* f, const Lex_ident& f_name) const; }; struct Vers_parse_info: public Table_period_info { Vers_parse_info() : Table_period_info(STRING_WITH_LEN("SYSTEM_TIME")), versioned_fields(false), unversioned_fields(false), can_native(-1) {} Table_period_info::start_end_t as_row; protected: friend struct Table_scope_and_contents_source_st; void set_start(const LEX_CSTRING field_name) { as_row.start= field_name; period.start= field_name; } void set_end(const LEX_CSTRING field_name) { as_row.end= field_name; period.end= field_name; } bool is_start(const char *name) const; bool is_end(const char *name) const; bool is_start(const Create_field &f) const; bool is_end(const Create_field &f) const; bool fix_implicit(THD *thd, Alter_info *alter_info); operator bool() const { return as_row.start || as_row.end || period.start || period.end; } bool need_check(const Alter_info *alter_info) const; bool check_conditions(const Lex_table_name &table_name, const Lex_table_name &db) const; bool create_sys_field(THD *thd, const char *field_name, Alter_info *alter_info, int flags); public: static const Lex_ident default_start; static const Lex_ident default_end; bool fix_alter_info(THD *thd, Alter_info *alter_info, HA_CREATE_INFO *create_info, TABLE *table); bool fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_info, TABLE_LIST &src_table, TABLE_LIST &table); bool check_sys_fields(const Lex_table_name &table_name, const Lex_table_name &db, Alter_info *alter_info) const; /** At least one field was specified 'WITH/WITHOUT SYSTEM VERSIONING'. Useful for error handling. */ bool versioned_fields : 1; bool unversioned_fields : 1; int can_native; }; /** A helper struct for table DDL statements, e.g.: CREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name table_contents_source; Represents a combinations of: 1. The scope, i.e. TEMPORARY or not TEMPORARY 2. The "table_contents_source" part of the table DDL statements, which can be initialized from either of these: - table_element_list ... // Explicit definition (column and key list) - LIKE another_table_name ... // Copy structure from another table - [AS] SELECT ... // Copy structure from a subquery */ struct Table_scope_and_contents_source_pod_st // For trivial members { CHARSET_INFO *alter_table_convert_to_charset; LEX_CUSTRING tabledef_version; LEX_CUSTRING org_tabledef_version; /* version of dropped table */ LEX_CSTRING connect_string; LEX_CSTRING comment; LEX_CSTRING alias; LEX_CSTRING org_storage_engine_name, new_storage_engine_name; const char *password, *tablespace; const char *data_file_name, *index_file_name; ulonglong max_rows,min_rows; ulonglong auto_increment_value; ulong table_options; ///< HA_OPTION_ values ulong avg_row_length; ulong used_fields; ulong key_block_size; ulong expression_length; ulong field_check_constraints; /* number of pages to sample during stats estimation, if used, otherwise 0. */ uint stats_sample_pages; uint null_bits; /* NULL bits at start of record */ uint options; /* OR of HA_CREATE_ options */ uint merge_insert_method; uint extra_size; /* length of extra data segment */ handlerton *db_type; /** Row type of the table definition. Defaults to ROW_TYPE_DEFAULT for all non-ALTER statements. For ALTER TABLE defaults to ROW_TYPE_NOT_USED (means "keep the current"). Can be changed either explicitly by the parser. If nothing specified inherits the value of the original table (if present). */ enum row_type row_type; enum ha_choice transactional; enum ha_storage_media storage_media; ///< DEFAULT, DISK or MEMORY enum ha_choice page_checksum; ///< If we have page_checksums engine_option_value *option_list; ///< list of table create options enum_stats_auto_recalc stats_auto_recalc; bool varchar; ///< 1 if table has a VARCHAR bool sequence; // If SEQUENCE=1 was used List *check_constraint_list; /* the following three are only for ALTER TABLE, check_if_incompatible_data() */ ha_table_option_struct *option_struct; ///< structure with parsed table options ha_field_option_struct **fields_option_struct; ///< array of field option structures ha_index_option_struct **indexes_option_struct; ///< array of index option structures /* The following is used to remember the old state for CREATE OR REPLACE */ TABLE *table; TABLE_LIST *pos_in_locked_tables; TABLE_LIST *merge_list; MDL_ticket *mdl_ticket; bool table_was_deleted; sequence_definition *seq_create_info; void init() { bzero(this, sizeof(*this)); } bool tmp_table() const { return options & HA_LEX_CREATE_TMP_TABLE; } void use_default_db_type(THD *thd) { db_type= tmp_table() ? ha_default_tmp_handlerton(thd) : ha_default_handlerton(thd); } bool versioned() const { return options & HA_VERSIONED_TABLE; } }; struct Table_scope_and_contents_source_st: public Table_scope_and_contents_source_pod_st { Vers_parse_info vers_info; Table_period_info period_info; void init() { Table_scope_and_contents_source_pod_st::init(); vers_info= {}; period_info= {}; } bool fix_create_fields(THD *thd, Alter_info *alter_info, const TABLE_LIST &create_table); bool fix_period_fields(THD *thd, Alter_info *alter_info); bool check_fields(THD *thd, Alter_info *alter_info, const Lex_table_name &table_name, const Lex_table_name &db, int select_count= 0); bool check_period_fields(THD *thd, Alter_info *alter_info); void vers_check_native(); bool vers_fix_system_fields(THD *thd, Alter_info *alter_info, const TABLE_LIST &create_table); bool vers_check_system_fields(THD *thd, Alter_info *alter_info, const Lex_table_name &table_name, const Lex_table_name &db, int select_count= 0); }; /** This struct is passed to handler table routines, e.g. ha_create(). It does not include the "OR REPLACE" and "IF NOT EXISTS" parts, as these parts are handled on the SQL level and are not needed on the handler level. */ struct HA_CREATE_INFO: public Table_scope_and_contents_source_st, public Schema_specification_st { /* TODO: remove after MDEV-20865 */ Alter_info *alter_info; void init() { Table_scope_and_contents_source_st::init(); Schema_specification_st::init(); alter_info= NULL; } bool check_conflicting_charset_declarations(CHARSET_INFO *cs); bool add_table_option_default_charset(CHARSET_INFO *cs) { // cs can be NULL, e.g.: CREATE TABLE t1 (..) CHARACTER SET DEFAULT; if (check_conflicting_charset_declarations(cs)) return true; default_table_charset= cs; used_fields|= HA_CREATE_USED_DEFAULT_CHARSET; return false; } bool add_alter_list_item_convert_to_charset(CHARSET_INFO *cs) { /* cs cannot be NULL, as sql_yacc.yy translates CONVERT TO CHARACTER SET DEFAULT to CONVERT TO CHARACTER SET TODO: Shouldn't we postpone resolution of DEFAULT until the character set of the table owner database is loaded from its db.opt? */ DBUG_ASSERT(cs); if (check_conflicting_charset_declarations(cs)) return true; alter_table_convert_to_charset= default_table_charset= cs; used_fields|= (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET); return false; } ulong table_options_with_row_type() { if (row_type == ROW_TYPE_DYNAMIC || row_type == ROW_TYPE_PAGE) return table_options | HA_OPTION_PACK_RECORD; else return table_options; } }; /** This struct is passed to mysql_create_table() and similar creation functions, as well as to show_create_table(). */ struct Table_specification_st: public HA_CREATE_INFO, public DDL_options_st { // Deep initialization void init() { HA_CREATE_INFO::init(); DDL_options_st::init(); } void init(DDL_options_st::Options options_arg) { HA_CREATE_INFO::init(); DDL_options_st::init(options_arg); } /* Quick initialization, for parser. Most of the HA_CREATE_INFO is left uninitialized. It gets fully initialized in sql_yacc.yy, only when the parser scans a related keyword (e.g. CREATE, ALTER). */ void lex_start() { HA_CREATE_INFO::options= 0; DDL_options_st::init(); } }; /** Structure describing changes to an index to be caused by ALTER TABLE. */ struct KEY_PAIR { /** Pointer to KEY object describing old version of index in TABLE::key_info array for TABLE instance representing old version of table. */ KEY *old_key; /** Pointer to KEY object describing new version of index in Alter_inplace_info::key_info_buffer array. */ KEY *new_key; }; /** In-place alter handler context. This is a superclass intended to be subclassed by individual handlers in order to store handler unique context between in-place alter API calls. The handler is responsible for creating the object. This can be done as early as during check_if_supported_inplace_alter(). The SQL layer is responsible for destroying the object. The class extends Sql_alloc so the memory will be mem root allocated. @see Alter_inplace_info */ class inplace_alter_handler_ctx : public Sql_alloc { public: inplace_alter_handler_ctx() = default; virtual ~inplace_alter_handler_ctx() = default; virtual void set_shared_data(const inplace_alter_handler_ctx& ctx) {} }; /** Class describing changes to be done by ALTER TABLE. Instance of this class is passed to storage engine in order to determine if this ALTER TABLE can be done using in-place algorithm. It is also used for executing the ALTER TABLE using in-place algorithm. */ class Alter_inplace_info { public: /** Create options (like MAX_ROWS) for the new version of table. @note The referenced instance of HA_CREATE_INFO object was already used to create new .FRM file for table being altered. So it has been processed by mysql_prepare_create_table() already. For example, this means that it has HA_OPTION_PACK_RECORD flag in HA_CREATE_INFO::table_options member correctly set. */ HA_CREATE_INFO *create_info; /** Alter options, fields and keys for the new version of table. @note The referenced instance of Alter_info object was already used to create new .FRM file for table being altered. So it has been processed by mysql_prepare_create_table() already. In particular, this means that in Create_field objects for fields which were present in some form in the old version of table, Create_field::field member points to corresponding Field instance for old version of table. */ Alter_info *alter_info; /** Array of KEYs for new version of table - including KEYs to be added. @note Currently this array is produced as result of mysql_prepare_create_table() call. This means that it follows different convention for KEY_PART_INFO::fieldnr values than objects in TABLE::key_info array. @todo This is mainly due to the fact that we need to keep compatibility with removed handler::add_index() call. We plan to switch to TABLE::key_info numbering later. KEYs are sorted - see sort_keys(). */ KEY *key_info_buffer; /** Size of key_info_buffer array. */ uint key_count; /** Size of index_drop_buffer array. */ uint index_drop_count= 0; /** Array of pointers to KEYs to be dropped belonging to the TABLE instance for the old version of the table. */ KEY **index_drop_buffer= nullptr; /** Size of index_add_buffer array. */ uint index_add_count= 0; /** Array of indexes into key_info_buffer for KEYs to be added, sorted in increasing order. */ uint *index_add_buffer= nullptr; KEY_PAIR *index_altered_ignorability_buffer= nullptr; /** Size of index_altered_ignorability_buffer array. */ uint index_altered_ignorability_count= 0; /** Old and new index names. Used for index rename. */ struct Rename_key_pair { Rename_key_pair(const KEY *old_key, const KEY *new_key) : old_key(old_key), new_key(new_key) { } const KEY *old_key; const KEY *new_key; }; /** Vector of key pairs from DROP/ADD index which can be renamed. */ typedef Mem_root_array Rename_keys_vector; /** A list of indexes which should be renamed. Index definitions stays the same. */ Rename_keys_vector rename_keys; /** Context information to allow handlers to keep context between in-place alter API calls. @see inplace_alter_handler_ctx for information about object lifecycle. */ inplace_alter_handler_ctx *handler_ctx= nullptr; /** If the table uses several handlers, like ha_partition uses one handler per partition, this contains a Null terminated array of ctx pointers that should all be committed together. Or NULL if only handler_ctx should be committed. Set to NULL if the low level handler::commit_inplace_alter_table uses it, to signal to the main handler that everything was committed as atomically. @see inplace_alter_handler_ctx for information about object lifecycle. */ inplace_alter_handler_ctx **group_commit_ctx= nullptr; /** Flags describing in detail which operations the storage engine is to execute. Flags are defined in sql_alter.h */ alter_table_operations handler_flags= 0; /* Alter operations involving parititons are strored here */ ulong partition_flags; /** Partition_info taking into account the partition changes to be performed. Contains all partitions which are present in the old version of the table with partitions to be dropped or changed marked as such + all partitions to be added in the new version of table marked as such. */ partition_info * const modified_part_info; /** true for ALTER IGNORE TABLE ... */ const bool ignore; /** true for online operation (LOCK=NONE) */ bool online= false; /** When ha_commit_inplace_alter_table() is called the the engine can set this to a function to be called after the ddl log is committed. */ typedef void (inplace_alter_table_commit_callback)(void *); inplace_alter_table_commit_callback *inplace_alter_table_committed= nullptr; /* This will be used as the argument to the above function when called */ void *inplace_alter_table_committed_argument= nullptr; /** which ALGORITHM and LOCK are supported by the storage engine */ enum_alter_inplace_result inplace_supported; /** Can be set by handler to describe why a given operation cannot be done in-place (HA_ALTER_INPLACE_NOT_SUPPORTED) or why it cannot be done online (HA_ALTER_INPLACE_NO_LOCK or HA_ALTER_INPLACE_COPY_NO_LOCK) If set, it will be used with ER_ALTER_OPERATION_NOT_SUPPORTED_REASON if results from handler::check_if_supported_inplace_alter() doesn't match requirements set by user. If not set, the more generic ER_ALTER_OPERATION_NOT_SUPPORTED will be used. Please set to a properly localized string, for example using my_get_err_msg(), so that the error message as a whole is localized. */ const char *unsupported_reason= nullptr; /** true when InnoDB should abort the alter when table is not empty */ const bool error_if_not_empty; /** True when DDL should avoid downgrading the MDL */ bool mdl_exclusive_after_prepare= false; Alter_inplace_info(HA_CREATE_INFO *create_info_arg, Alter_info *alter_info_arg, KEY *key_info_arg, uint key_count_arg, partition_info *modified_part_info_arg, bool ignore_arg, bool error_non_empty); ~Alter_inplace_info() { delete handler_ctx; } /** Used after check_if_supported_inplace_alter() to report error if the result does not match the LOCK/ALGORITHM requirements set by the user. @param not_supported Part of statement that was not supported. @param try_instead Suggestion as to what the user should replace not_supported with. */ void report_unsupported_error(const char *not_supported, const char *try_instead) const; void add_altered_index_ignorability(KEY *old_key, KEY *new_key) { KEY_PAIR *key_pair= index_altered_ignorability_buffer + index_altered_ignorability_count++; key_pair->old_key= old_key; key_pair->new_key= new_key; DBUG_PRINT("info", ("index had ignorability altered: %i to %i", old_key->is_ignored, new_key->is_ignored)); } }; typedef struct st_key_create_information { enum ha_key_alg algorithm; ulong block_size; uint flags; /* HA_USE.. flags */ LEX_CSTRING parser_name; LEX_CSTRING comment; bool is_ignored; } KEY_CREATE_INFO; /* Class for maintaining hooks used inside operations on tables such as: create table functions, delete table functions, and alter table functions. Class is using the Template Method pattern to separate the public usage interface from the private inheritance interface. This imposes no overhead, since the public non-virtual function is small enough to be inlined. The hooks are usually used for functions that does several things, e.g., create_table_from_items(), which both create a table and lock it. */ class TABLEOP_HOOKS { public: TABLEOP_HOOKS() = default; virtual ~TABLEOP_HOOKS() = default; inline void prelock(TABLE **tables, uint count) { do_prelock(tables, count); } inline int postlock(TABLE **tables, uint count) { return do_postlock(tables, count); } private: /* Function primitive that is called prior to locking tables */ virtual void do_prelock(TABLE **tables, uint count) { /* Default is to do nothing */ } /** Primitive called after tables are locked. If an error is returned, the tables will be unlocked and error handling start. @return Error code or zero. */ virtual int do_postlock(TABLE **tables, uint count) { return 0; /* Default is to do nothing */ } }; typedef struct st_savepoint SAVEPOINT; extern ulong savepoint_alloc_size; extern KEY_CREATE_INFO default_key_create_info; /* Forward declaration for condition pushdown to storage engine */ typedef class Item COND; typedef struct st_ha_check_opt { st_ha_check_opt() = default; /* Remove gcc warning */ uint flags; /* isam layer flags (e.g. for myisamchk) */ uint sql_flags; /* sql layer flags - for something myisamchk cannot do */ uint handler_flags; /* Reserved for handler usage */ time_t start_time; /* When check/repair starts */ KEY_CACHE *key_cache; /* new key cache when changing key cache */ void init(); } HA_CHECK_OPT; /******************************************************************************** * MRR ********************************************************************************/ typedef void *range_seq_t; typedef struct st_range_seq_if { /* Get key information SYNOPSIS get_key_info() init_params The seq_init_param parameter length OUT length of the keys in this range sequence map OUT key_part_map of the keys in this range sequence DESCRIPTION This function is set only when using HA_MRR_FIXED_KEY mode. In that mode, all ranges are single-point equality ranges that use the same set of key parts. This function allows the MRR implementation to get the length of a key, and which keyparts it uses. */ void (*get_key_info)(void *init_params, uint *length, key_part_map *map); /* Initialize the traversal of range sequence SYNOPSIS init() init_params The seq_init_param parameter n_ranges The number of ranges obtained flags A combination of HA_MRR_SINGLE_POINT, HA_MRR_FIXED_KEY RETURN An opaque value to be used as RANGE_SEQ_IF::next() parameter */ range_seq_t (*init)(void *init_params, uint n_ranges, uint flags); /* Get the next range in the range sequence SYNOPSIS next() seq The value returned by RANGE_SEQ_IF::init() range OUT Information about the next range RETURN FALSE - Ok, the range structure filled with info about the next range TRUE - No more ranges */ bool (*next) (range_seq_t seq, KEY_MULTI_RANGE *range); /* Check whether range_info orders to skip the next record SYNOPSIS skip_record() seq The value returned by RANGE_SEQ_IF::init() range_info Information about the next range (Ignored if MRR_NO_ASSOCIATION is set) rowid Rowid of the record to be checked (ignored if set to 0) RETURN 1 - Record with this range_info and/or this rowid shall be filtered out from the stream of records returned by multi_range_read_next() 0 - The record shall be left in the stream */ bool (*skip_record) (range_seq_t seq, range_id_t range_info, uchar *rowid); /* Check if the record combination matches the index condition SYNOPSIS skip_index_tuple() seq The value returned by RANGE_SEQ_IF::init() range_info Information about the next range RETURN 0 - The record combination satisfies the index condition 1 - Otherwise */ bool (*skip_index_tuple) (range_seq_t seq, range_id_t range_info); } RANGE_SEQ_IF; typedef bool (*SKIP_INDEX_TUPLE_FUNC) (range_seq_t seq, range_id_t range_info); class Cost_estimate { public: double io_count; /* number of I/O to fetch records */ double avg_io_cost; /* cost of an average I/O oper. to fetch records */ double idx_io_count; /* number of I/O to read keys */ double idx_avg_io_cost; /* cost of an average I/O oper. to fetch records */ double cpu_cost; /* total cost of operations in CPU */ double idx_cpu_cost; /* cost of operations in CPU for index */ double import_cost; /* cost of remote operations */ double mem_cost; /* cost of used memory */ static constexpr double IO_COEFF= 1; static constexpr double CPU_COEFF= 1; static constexpr double MEM_COEFF= 1; static constexpr double IMPORT_COEFF= 1; Cost_estimate() { reset(); } double total_cost() const { return IO_COEFF*io_count*avg_io_cost + IO_COEFF*idx_io_count*idx_avg_io_cost + CPU_COEFF*(cpu_cost + idx_cpu_cost) + MEM_COEFF*mem_cost + IMPORT_COEFF*import_cost; } double index_only_cost() { return IO_COEFF*idx_io_count*idx_avg_io_cost + CPU_COEFF*idx_cpu_cost; } /** Whether or not all costs in the object are zero @return true if all costs are zero, false otherwise */ bool is_zero() const { return io_count == 0.0 && idx_io_count == 0.0 && cpu_cost == 0.0 && import_cost == 0.0 && mem_cost == 0.0; } void reset() { avg_io_cost= 1.0; idx_avg_io_cost= 1.0; io_count= idx_io_count= cpu_cost= idx_cpu_cost= mem_cost= import_cost= 0.0; } void multiply(double m) { io_count *= m; cpu_cost *= m; idx_io_count *= m; idx_cpu_cost *= m; import_cost *= m; /* Don't multiply mem_cost */ } void add(const Cost_estimate* cost) { if (cost->io_count != 0.0) { double io_count_sum= io_count + cost->io_count; avg_io_cost= (io_count * avg_io_cost + cost->io_count * cost->avg_io_cost) /io_count_sum; io_count= io_count_sum; } if (cost->idx_io_count != 0.0) { double idx_io_count_sum= idx_io_count + cost->idx_io_count; idx_avg_io_cost= (idx_io_count * idx_avg_io_cost + cost->idx_io_count * cost->idx_avg_io_cost) /idx_io_count_sum; idx_io_count= idx_io_count_sum; } cpu_cost += cost->cpu_cost; idx_cpu_cost += cost->idx_cpu_cost; import_cost += cost->import_cost; } void add_io(double add_io_cnt, double add_avg_cost) { /* In edge cases add_io_cnt may be zero */ if (add_io_cnt > 0) { double io_count_sum= io_count + add_io_cnt; avg_io_cost= (io_count * avg_io_cost + add_io_cnt * add_avg_cost) / io_count_sum; io_count= io_count_sum; } } /// Add to CPU cost void add_cpu(double add_cpu_cost) { cpu_cost+= add_cpu_cost; } /// Add to import cost void add_import(double add_import_cost) { import_cost+= add_import_cost; } /// Add to memory cost void add_mem(double add_mem_cost) { mem_cost+= add_mem_cost; } /* To be used when we go from old single value-based cost calculations to the new Cost_estimate-based. */ void convert_from_cost(double cost) { reset(); io_count= cost; } }; void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted, Cost_estimate *cost); /* Indicates that all scanned ranges will be singlepoint (aka equality) ranges. The ranges may not use the full key but all of them will use the same number of key parts. */ #define HA_MRR_SINGLE_POINT 1U #define HA_MRR_FIXED_KEY 2U /* Indicates that RANGE_SEQ_IF::next(&range) doesn't need to fill in the 'range' parameter. */ #define HA_MRR_NO_ASSOCIATION 4U /* The MRR user will provide ranges in key order, and MRR implementation must return rows in key order. */ #define HA_MRR_SORTED 8U /* MRR implementation doesn't have to retrieve full records */ #define HA_MRR_INDEX_ONLY 16U /* The passed memory buffer is of maximum possible size, the caller can't assume larger buffer. */ #define HA_MRR_LIMITS 32U /* Flag set <=> default MRR implementation is used (The choice is made by **_info[_const]() function which may set this flag. SQL layer remembers the flag value and then passes it to multi_read_range_init(). */ #define HA_MRR_USE_DEFAULT_IMPL 64U /* Used only as parameter to multi_range_read_info(): Flag set <=> the caller guarantees that the bounds of the scanned ranges will not have NULL values. */ #define HA_MRR_NO_NULL_ENDPOINTS 128U /* The MRR user has materialized range keys somewhere in the user's buffer. This can be used for optimization of the procedure that sorts these keys since in this case key values don't have to be copied into the MRR buffer. In other words, it is guaranteed that after RANGE_SEQ_IF::next() call the pointer in range->start_key.key will point to a key value that will remain there until the end of the MRR scan. */ #define HA_MRR_MATERIALIZED_KEYS 256U /* The following bits are reserved for use by MRR implementation. The intended use scenario: * sql layer calls handler->multi_range_read_info[_const]() - MRR implementation figures out what kind of scan it will perform, saves the result in *mrr_mode parameter. * sql layer remembers what was returned in *mrr_mode * the optimizer picks the query plan (which may or may not include the MRR scan that was estimated by the multi_range_read_info[_const] call) * if the query is an EXPLAIN statement, sql layer will call handler->multi_range_read_explain_info(mrr_mode) to get a text description of the picked MRR scan; the description will be a part of EXPLAIN output. */ #define HA_MRR_IMPLEMENTATION_FLAG1 512U #define HA_MRR_IMPLEMENTATION_FLAG2 1024U #define HA_MRR_IMPLEMENTATION_FLAG3 2048U #define HA_MRR_IMPLEMENTATION_FLAG4 4096U #define HA_MRR_IMPLEMENTATION_FLAG5 8192U #define HA_MRR_IMPLEMENTATION_FLAG6 16384U #define HA_MRR_IMPLEMENTATION_FLAGS \ (512U | 1024U | 2048U | 4096U | 8192U | 16384U) /* This is a buffer area that the handler can use to store rows. 'end_of_used_area' should be kept updated after calls to read-functions so that other parts of the code can use the remaining area (until next read calls is issued). */ typedef struct st_handler_buffer { /* const? */uchar *buffer; /* Buffer one can start using */ /* const? */uchar *buffer_end; /* End of buffer */ uchar *end_of_used_area; /* End of area that was used by handler */ } HANDLER_BUFFER; typedef struct system_status_var SSV; class ha_statistics { public: ulonglong data_file_length; /* Length off data file */ ulonglong max_data_file_length; /* Length off data file */ ulonglong index_file_length; ulonglong max_index_file_length; ulonglong delete_length; /* Free bytes */ ulonglong auto_increment_value; /* The number of records in the table. 0 - means the table has exactly 0 rows other - if (table_flags() & HA_STATS_RECORDS_IS_EXACT) the value is the exact number of records in the table else it is an estimate */ ha_rows records; ha_rows deleted; /* Deleted records */ ulong mean_rec_length; /* physical reclength */ time_t create_time; /* When table was created */ time_t check_time; time_t update_time; uint block_size; /* index block size */ ha_checksum checksum; bool checksum_null; /* number of buffer bytes that native mrr implementation needs, */ uint mrr_length_per_rec; ha_statistics(): data_file_length(0), max_data_file_length(0), index_file_length(0), max_index_file_length(0), delete_length(0), auto_increment_value(0), records(0), deleted(0), mean_rec_length(0), create_time(0), check_time(0), update_time(0), block_size(8192), checksum(0), checksum_null(FALSE), mrr_length_per_rec(0) {} }; extern "C" check_result_t handler_index_cond_check(void* h_arg); extern "C" check_result_t handler_rowid_filter_check(void* h_arg); extern "C" int handler_rowid_filter_is_active(void* h_arg); uint calculate_key_len(TABLE *, uint, const uchar *, key_part_map); /* bitmap with first N+1 bits set (keypart_map for a key prefix of [0..N] keyparts) */ inline key_part_map make_keypart_map(uint N) { return ((key_part_map)2 << (N)) - 1; } /* bitmap with first N bits set (keypart_map for a key prefix of [0..N-1] keyparts) */ inline key_part_map make_prev_keypart_map(uint N) { return ((key_part_map)1 << (N)) - 1; } /** Base class to be used by handlers different shares */ class Handler_share { public: Handler_share() = default; virtual ~Handler_share() = default; }; enum class Compare_keys : uint32_t { Equal= 0, EqualButKeyPartLength, EqualButComment, NotEqual }; /** The handler class is the interface for dynamically loadable storage engines. Do not add ifdefs and take care when adding or changing virtual functions to avoid vtable confusion Functions in this class accept and return table columns data. Two data representation formats are used: 1. TableRecordFormat - Used to pass [partial] table records to/from storage engine 2. KeyTupleFormat - used to pass index search tuples (aka "keys") to storage engine. See opt_range.cc for description of this format. TableRecordFormat ================= [Warning: this description is work in progress and may be incomplete] The table record is stored in a fixed-size buffer: record: null_bytes, column1_data, column2_data, ... The offsets of the parts of the buffer are also fixed: every column has an offset to its column{i}_data, and if it is nullable it also has its own bit in null_bytes. The record buffer only includes data about columns that are marked in the relevant column set (table->read_set and/or table->write_set, depending on the situation). It could be that it is required that null bits of non-present columns are set to 1 VARIOUS EXCEPTIONS AND SPECIAL CASES If the table has no nullable columns, then null_bytes is still present, its length is one byte which must be set to 0xFF at all times. If the table has columns of type BIT, then certain bits from those columns may be stored in null_bytes as well. Grep around for Field_bit for details. For blob columns (see Field_blob), the record buffer stores length of the data, following by memory pointer to the blob data. The pointer is owned by the storage engine and is valid until the next operation. If a blob column has NULL value, then its length and blob data pointer must be set to 0. */ class handler :public Sql_alloc { public: typedef ulonglong Table_flags; protected: TABLE_SHARE *table_share; /* The table definition */ TABLE *table; /* The current open table */ Table_flags cached_table_flags; /* Set on init() and open() */ ha_rows estimation_rows_to_insert; handler *lookup_handler; /* Statistics for the query. Updated if handler_stats.active is set */ ha_handler_stats active_handler_stats; void set_handler_stats(); public: handlerton *ht; /* storage engine of this handler */ uchar *ref; /* Pointer to current row */ uchar *dup_ref; /* Pointer to duplicate row */ uchar *lookup_buffer; /* General statistics for the table like number of row, file sizes etc */ ha_statistics stats; /* Collect query stats here if pointer is != NULL. This is a pointer because if we do a clone of the handler, we want to use the original handler for collecting statistics. */ ha_handler_stats *handler_stats; /** MultiRangeRead-related members: */ range_seq_t mrr_iter; /* Iterator to traverse the range sequence */ RANGE_SEQ_IF mrr_funcs; /* Range sequence traversal functions */ HANDLER_BUFFER *multi_range_buffer; /* MRR buffer info */ uint ranges_in_seq; /* Total number of ranges in the traversed sequence */ /** Current range (the one we're now returning rows from) */ KEY_MULTI_RANGE mrr_cur_range; /** The following are for read_range() */ key_range save_end_range, *end_range; KEY_PART_INFO *range_key_part; int key_compare_result_on_equal; /* TRUE <=> source MRR ranges and the output are ordered */ bool mrr_is_output_sorted; /** TRUE <=> we're currently traversing a range in mrr_cur_range. */ bool mrr_have_range; bool eq_range; bool internal_tmp_table; /* If internal tmp table */ bool implicit_emptied; /* Can be !=0 only if HEAP */ bool mark_trx_read_write_done; /* mark_trx_read_write was called */ bool check_table_binlog_row_based_done; /* check_table_binlog.. was called */ bool check_table_binlog_row_based_result; /* cached check_table_binlog... */ /* TRUE <=> the engine guarantees that returned records are within the range being scanned. */ bool in_range_check_pushed_down; uint lookup_errkey; uint errkey; /* Last dup key */ uint key_used_on_scan; uint active_index, keyread; /** Length of ref (1-8 or the clustered key length) */ uint ref_length; FT_INFO *ft_handler; enum init_stat { NONE=0, INDEX, RND }; init_stat inited, pre_inited; const COND *pushed_cond; /** next_insert_id is the next value which should be inserted into the auto_increment column: in a inserting-multi-row statement (like INSERT SELECT), for the first row where the autoinc value is not specified by the statement, get_auto_increment() called and asked to generate a value, next_insert_id is set to the next value, then for all other rows next_insert_id is used (and increased each time) without calling get_auto_increment(). */ ulonglong next_insert_id; /** insert id for the current row (*autogenerated*; if not autogenerated, it's 0). At first successful insertion, this variable is stored into THD::first_successful_insert_id_in_cur_stmt. */ ulonglong insert_id_for_cur_row; /** Interval returned by get_auto_increment() and being consumed by the inserter. */ /* Statistics variables */ ulonglong rows_read; ulonglong rows_tmp_read; ulonglong rows_changed; /* One bigger than needed to avoid to test if key == MAX_KEY */ ulonglong index_rows_read[MAX_KEY+1]; ha_copy_info copy_info; private: /* ANALYZE time tracker, if present */ Exec_time_tracker *tracker; public: void set_time_tracker(Exec_time_tracker *tracker_arg) { tracker=tracker_arg;} Exec_time_tracker *get_time_tracker() { return tracker; } Item *pushed_idx_cond; uint pushed_idx_cond_keyno; /* The index which the above condition is for */ /* Rowid filter pushed into the engine */ Rowid_filter *pushed_rowid_filter; /* true when the pushed rowid filter has been already filled */ bool rowid_filter_is_active; /* Used for disabling/enabling pushed_rowid_filter */ Rowid_filter *save_pushed_rowid_filter; bool save_rowid_filter_is_active; Discrete_interval auto_inc_interval_for_cur_row; /** Number of reserved auto-increment intervals. Serves as a heuristic when we have no estimation of how many records the statement will insert: the more intervals we have reserved, the bigger the next one. Reset in handler::ha_release_auto_increment(). */ uint auto_inc_intervals_count; /** Instrumented table associated with this handler. This member should be set to NULL when no instrumentation is in place, so that linking an instrumented/non instrumented server/plugin works. For example: - the server is compiled with the instrumentation. The server expects either NULL or valid pointers in m_psi. - an engine plugin is compiled without instrumentation. The plugin can not leave this pointer uninitialized, or can not leave a trash value on purpose in this pointer, as this would crash the server. */ PSI_table *m_psi; private: /** Internal state of the batch instrumentation. */ enum batch_mode_t { /** Batch mode not used. */ PSI_BATCH_MODE_NONE, /** Batch mode used, before first table io. */ PSI_BATCH_MODE_STARTING, /** Batch mode used, after first table io. */ PSI_BATCH_MODE_STARTED }; /** Batch mode state. @sa start_psi_batch_mode. @sa end_psi_batch_mode. */ batch_mode_t m_psi_batch_mode; /** The number of rows in the batch. @sa start_psi_batch_mode. @sa end_psi_batch_mode. */ ulonglong m_psi_numrows; /** The current event in a batch. @sa start_psi_batch_mode. @sa end_psi_batch_mode. */ PSI_table_locker *m_psi_locker; /** Storage for the event in a batch. @sa start_psi_batch_mode. @sa end_psi_batch_mode. */ PSI_table_locker_state m_psi_locker_state; public: virtual void unbind_psi(); virtual void rebind_psi(); /* Return error if definition doesn't match for already opened table */ virtual int discover_check_version() { return 0; } /** Put the handler in 'batch' mode when collecting table io instrumented events. When operating in batch mode: - a single start event is generated in the performance schema. - all table io performed between @c start_psi_batch_mode and @c end_psi_batch_mode is not instrumented: the number of rows affected is counted instead in @c m_psi_numrows. - a single end event is generated in the performance schema when the batch mode ends with @c end_psi_batch_mode. */ void start_psi_batch_mode(); /** End a batch started with @c start_psi_batch_mode. */ void end_psi_batch_mode(); /* If we have row logging enabled for this table */ bool row_logging, row_logging_init; /* If the row logging should be done in transaction cache */ bool row_logging_has_trans; private: /** The lock type set by when calling::ha_external_lock(). This is propagated down to the storage engine. The reason for also storing it here, is that when doing MRR we need to create/clone a second handler object. This cloned handler object needs to know about the lock_type used. */ int m_lock_type; /** Pointer where to store/retrieve the Handler_share pointer. For non partitioned handlers this is &TABLE_SHARE::ha_share. */ Handler_share **ha_share; public: handler(handlerton *ht_arg, TABLE_SHARE *share_arg) :table_share(share_arg), table(0), estimation_rows_to_insert(0), lookup_handler(this), ht(ht_arg), ref(0), lookup_buffer(NULL), handler_stats(NULL), end_range(NULL), implicit_emptied(0), mark_trx_read_write_done(0), check_table_binlog_row_based_done(0), check_table_binlog_row_based_result(0), in_range_check_pushed_down(FALSE), lookup_errkey(-1), errkey(-1), key_used_on_scan(MAX_KEY), active_index(MAX_KEY), keyread(MAX_KEY), ref_length(sizeof(my_off_t)), ft_handler(0), inited(NONE), pre_inited(NONE), pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0), tracker(NULL), pushed_idx_cond(NULL), pushed_idx_cond_keyno(MAX_KEY), pushed_rowid_filter(NULL), rowid_filter_is_active(0), save_pushed_rowid_filter(NULL), save_rowid_filter_is_active(false), auto_inc_intervals_count(0), m_psi(NULL), m_psi_batch_mode(PSI_BATCH_MODE_NONE), m_psi_numrows(0), m_psi_locker(NULL), row_logging(0), row_logging_init(0), m_lock_type(F_UNLCK), ha_share(NULL) { DBUG_PRINT("info", ("handler created F_UNLCK %d F_RDLCK %d F_WRLCK %d", F_UNLCK, F_RDLCK, F_WRLCK)); reset_statistics(); } virtual ~handler(void) { DBUG_ASSERT(m_lock_type == F_UNLCK); DBUG_ASSERT(inited == NONE); } /* To check if table has been properely opened */ bool is_open() { return ref != 0; } virtual handler *clone(const char *name, MEM_ROOT *mem_root); /** This is called after create to allow us to set up cached variables */ void init() { cached_table_flags= table_flags(); } /* ha_ methods: public wrappers for private virtual API */ int ha_open(TABLE *table, const char *name, int mode, uint test_if_locked, MEM_ROOT *mem_root= 0, List *partitions_to_open=NULL); int ha_index_init(uint idx, bool sorted) { DBUG_EXECUTE_IF("ha_index_init_fail", return HA_ERR_TABLE_DEF_CHANGED;); int result; DBUG_ENTER("ha_index_init"); DBUG_ASSERT(inited==NONE); if (!(result= index_init(idx, sorted))) { inited= INDEX; active_index= idx; end_range= NULL; } DBUG_RETURN(result); } int ha_index_end() { DBUG_ENTER("ha_index_end"); DBUG_ASSERT(inited==INDEX); inited= NONE; active_index= MAX_KEY; end_range= NULL; DBUG_RETURN(index_end()); } /* This is called after index_init() if we need to do a index scan */ virtual int prepare_index_scan() { return 0; } virtual int prepare_index_key_scan_map(const uchar * key, key_part_map keypart_map) { uint key_len= calculate_key_len(table, active_index, key, keypart_map); return prepare_index_key_scan(key, key_len); } virtual int prepare_index_key_scan( const uchar * key, uint key_len ) { return 0; } virtual int prepare_range_scan(const key_range *start_key, const key_range *end_key) { return 0; } int ha_rnd_init(bool scan) __attribute__ ((warn_unused_result)) { DBUG_EXECUTE_IF("ha_rnd_init_fail", return HA_ERR_TABLE_DEF_CHANGED;); int result; DBUG_ENTER("ha_rnd_init"); DBUG_ASSERT(inited==NONE || (inited==RND && scan)); inited= (result= rnd_init(scan)) ? NONE: RND; end_range= NULL; DBUG_RETURN(result); } int ha_rnd_end() { DBUG_ENTER("ha_rnd_end"); DBUG_ASSERT(inited==RND); inited=NONE; end_range= NULL; DBUG_RETURN(rnd_end()); } int ha_rnd_init_with_error(bool scan) __attribute__ ((warn_unused_result)); int ha_reset(); /* this is necessary in many places, e.g. in HANDLER command */ int ha_index_or_rnd_end() { return inited == INDEX ? ha_index_end() : inited == RND ? ha_rnd_end() : 0; } /** The cached_table_flags is set at ha_open and ha_external_lock */ Table_flags ha_table_flags() const { DBUG_ASSERT(cached_table_flags < (HA_LAST_TABLE_FLAG << 1)); return cached_table_flags; } /** These functions represent the public interface to *users* of the handler class, hence they are *not* virtual. For the inheritance interface, see the (private) functions write_row(), update_row(), and delete_row() below. */ int ha_external_lock(THD *thd, int lock_type); int ha_external_unlock(THD *thd) { return ha_external_lock(thd, F_UNLCK); } int ha_write_row(const uchar * buf); int ha_update_row(const uchar * old_data, const uchar * new_data); int ha_delete_row(const uchar * buf); void ha_release_auto_increment(); bool keyread_enabled() { return keyread < MAX_KEY; } int ha_start_keyread(uint idx) { int res= keyread_enabled() ? 0 : extra_opt(HA_EXTRA_KEYREAD, idx); keyread= idx; return res; } int ha_end_keyread() { if (!keyread_enabled()) return 0; keyread= MAX_KEY; return extra(HA_EXTRA_NO_KEYREAD); } int check_collation_compatibility(); int check_long_hash_compatibility() const; int ha_check_for_upgrade(HA_CHECK_OPT *check_opt); /** to be actually called to get 'check()' functionality*/ int ha_check(THD *thd, HA_CHECK_OPT *check_opt); int ha_repair(THD* thd, HA_CHECK_OPT* check_opt); void ha_start_bulk_insert(ha_rows rows, uint flags= 0) { DBUG_ENTER("handler::ha_start_bulk_insert"); estimation_rows_to_insert= rows; bzero(©_info,sizeof(copy_info)); start_bulk_insert(rows, flags); DBUG_VOID_RETURN; } int ha_end_bulk_insert(); int ha_bulk_update_row(const uchar *old_data, const uchar *new_data, ha_rows *dup_key_found); int ha_delete_all_rows(); int ha_truncate(); int ha_reset_auto_increment(ulonglong value); int ha_optimize(THD* thd, HA_CHECK_OPT* check_opt); int ha_analyze(THD* thd, HA_CHECK_OPT* check_opt); bool ha_check_and_repair(THD *thd); int ha_disable_indexes(key_map map, bool persist); int ha_enable_indexes(key_map map, bool persist); int ha_discard_or_import_tablespace(my_bool discard); int ha_rename_table(const char *from, const char *to); int ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info); int ha_create_partitioning_metadata(const char *name, const char *old_name, chf_create_flags action_flag); int ha_change_partitions(HA_CREATE_INFO *create_info, const char *path, ulonglong * const copied, ulonglong * const deleted, const uchar *pack_frm_data, size_t pack_frm_len); int ha_drop_partitions(const char *path); int ha_rename_partitions(const char *path); void adjust_next_insert_id_after_explicit_value(ulonglong nr); int update_auto_increment(); virtual void print_error(int error, myf errflag); virtual bool get_error_message(int error, String *buf); uint get_dup_key(int error); bool has_dup_ref() const; /** Retrieves the names of the table and the key for which there was a duplicate entry in the case of HA_ERR_FOREIGN_DUPLICATE_KEY. If any of the table or key name is not available this method will return false and will not change any of child_table_name or child_key_name. @param child_table_name[out] Table name @param child_table_name_len[in] Table name buffer size @param child_key_name[out] Key name @param child_key_name_len[in] Key name buffer size @retval true table and key names were available and were written into the corresponding out parameters. @retval false table and key names were not available, the out parameters were not touched. */ virtual bool get_foreign_dup_key(char *child_table_name, uint child_table_name_len, char *child_key_name, uint child_key_name_len) { DBUG_ASSERT(false); return(false); } void reset_statistics() { rows_read= rows_changed= rows_tmp_read= 0; bzero(index_rows_read, sizeof(index_rows_read)); bzero(©_info, sizeof(copy_info)); } virtual void reset_copy_info() {} void ha_reset_copy_info() { bzero(©_info, sizeof(copy_info)); reset_copy_info(); } virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share) { table= table_arg; table_share= share; reset_statistics(); } virtual double scan_time() { return ((ulonglong2double(stats.data_file_length) / stats.block_size + 2) * avg_io_cost()); } virtual double key_scan_time(uint index) { return keyread_time(index, 1, records()); } virtual double avg_io_cost() { return 1.0; } /** The cost of reading a set of ranges from the table using an index to access it. @param index The index number. @param ranges The number of ranges to be read. If 0, it means that we calculate separately the cost of reading the key. @param rows Total number of rows to be read. This method can be used to calculate the total cost of scanning a table using an index by calling it using read_time(index, 1, table_size). */ virtual double read_time(uint index, uint ranges, ha_rows rows) { return rows2double(ranges+rows); } /** Calculate cost of 'keyread' scan for given index and number of records. @param index index to read @param ranges #of ranges to read @param rows #of records to read */ virtual double keyread_time(uint index, uint ranges, ha_rows rows); virtual const key_map *keys_to_use_for_scanning() { return &key_map_empty; } /* True if changes to the table is persistent (if there are no rollback) This is used to decide: - If the table is stored in the transaction or non transactional binary log - How things are tracked in trx and in add_changed_table(). - If we can combine several statements under one commit in the binary log. */ bool has_transactions() const { return ((ha_table_flags() & (HA_NO_TRANSACTIONS | HA_PERSISTENT_TABLE)) == 0); } /* True if table has both transactions and rollback. This is used to decide if we should write the changes to the binary log. If this is true, we don't have to write failed statements to the log as they can be rolled back. */ bool has_transactions_and_rollback() const { return has_transactions() && has_rollback(); } /* True if the underlaying table support transactions and rollback */ bool has_transaction_manager() const { return ((ha_table_flags() & HA_NO_TRANSACTIONS) == 0 && has_rollback()); } /* True if the underlaying table support TRANSACTIONAL table option */ bool has_transactional_option() const { extern handlerton *maria_hton; return partition_ht() == maria_hton || has_transaction_manager(); } /* True if table has rollback. Used to check if an update on the table can be killed fast. */ bool has_rollback() const { return ((ht->flags & HTON_NO_ROLLBACK) == 0); } /** This method is used to analyse the error to see whether the error is ignorable or not, certain handlers can have more error that are ignorable than others. E.g. the partition handler can get inserts into a range where there is no partition and this is an ignorable error. HA_ERR_FOUND_DUP_UNIQUE is a special case in MyISAM that means the same thing as HA_ERR_FOUND_DUP_KEY but can in some cases lead to a slightly different error message. */ virtual bool is_fatal_error(int error, uint flags) { if (!error || ((flags & HA_CHECK_DUP_KEY) && (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE)) || error == HA_ERR_AUTOINC_ERANGE || ((flags & HA_CHECK_FK_ERROR) && (error == HA_ERR_ROW_IS_REFERENCED || error == HA_ERR_NO_REFERENCED_ROW))) return FALSE; return TRUE; } /** Number of rows in table. It will only be called if (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0 */ virtual int pre_records() { return 0; } virtual ha_rows records() { return stats.records; } /** Return upper bound of current number of records in the table (max. of how many records one will retrieve when doing a full table scan) If upper bound is not known, HA_POS_ERROR should be returned as a max possible upper bound. */ virtual ha_rows estimate_rows_upper_bound() { return stats.records+EXTRA_RECORDS; } /** Get the row type from the storage engine. If this method returns ROW_TYPE_NOT_USED, the information in HA_CREATE_INFO should be used. */ virtual enum row_type get_row_type() const { return ROW_TYPE_NOT_USED; } virtual const char *index_type(uint key_number) { DBUG_ASSERT(0); return "";} /** Signal that the table->read_set and table->write_set table maps changed The handler is allowed to set additional bits in the above map in this call. Normally the handler should ignore all calls until we have done a ha_rnd_init() or ha_index_init(), write_row(), update_row or delete_row() as there may be several calls to this routine. */ virtual void column_bitmaps_signal(); /* We have to check for inited as some engines, like innodb, sets active_index during table scan. */ uint get_index(void) const { return inited == INDEX ? active_index : MAX_KEY; } int ha_close(void); /** @retval 0 Bulk update used by handler @retval 1 Bulk update not used, normal operation used */ virtual bool start_bulk_update() { return 1; } /** @retval 0 Bulk delete used by handler @retval 1 Bulk delete not used, normal operation used */ virtual bool start_bulk_delete() { return 1; } /** After this call all outstanding updates must be performed. The number of duplicate key errors are reported in the duplicate key parameter. It is allowed to continue to the batched update after this call, the handler has to wait until end_bulk_update with changing state. @param dup_key_found Number of duplicate keys found @retval 0 Success @retval >0 Error code */ virtual int exec_bulk_update(ha_rows *dup_key_found) { DBUG_ASSERT(FALSE); return HA_ERR_WRONG_COMMAND; } /** Perform any needed clean-up, no outstanding updates are there at the moment. */ virtual int end_bulk_update() { return 0; } /** Execute all outstanding deletes and close down the bulk delete. @retval 0 Success @retval >0 Error code */ virtual int end_bulk_delete() { DBUG_ASSERT(FALSE); return HA_ERR_WRONG_COMMAND; } virtual int pre_index_read_map(const uchar *key, key_part_map keypart_map, enum ha_rkey_function find_flag, bool use_parallel) { return 0; } virtual int pre_index_first(bool use_parallel) { return 0; } virtual int pre_index_last(bool use_parallel) { return 0; } virtual int pre_index_read_last_map(const uchar *key, key_part_map keypart_map, bool use_parallel) { return 0; } /* virtual int pre_read_multi_range_first(KEY_MULTI_RANGE **found_range_p, KEY_MULTI_RANGE *ranges, uint range_count, bool sorted, HANDLER_BUFFER *buffer, bool use_parallel); */ virtual int pre_multi_range_read_next(bool use_parallel) { return 0; } virtual int pre_read_range_first(const key_range *start_key, const key_range *end_key, bool eq_range, bool sorted, bool use_parallel) { return 0; } virtual int pre_ft_read(bool use_parallel) { return 0; } virtual int pre_rnd_next(bool use_parallel) { return 0; } int ha_pre_rnd_init(bool scan) { int result; DBUG_ENTER("ha_pre_rnd_init"); DBUG_ASSERT(pre_inited==NONE || (pre_inited==RND && scan)); pre_inited= (result= pre_rnd_init(scan)) ? NONE: RND; DBUG_RETURN(result); } int ha_pre_rnd_end() { DBUG_ENTER("ha_pre_rnd_end"); DBUG_ASSERT(pre_inited==RND); pre_inited=NONE; DBUG_RETURN(pre_rnd_end()); } virtual int pre_rnd_init(bool scan) { return 0; } virtual int pre_rnd_end() { return 0; } virtual int pre_index_init(uint idx, bool sorted) { return 0; } virtual int pre_index_end() { return 0; } int ha_pre_index_init(uint idx, bool sorted) { int result; DBUG_ENTER("ha_pre_index_init"); DBUG_ASSERT(pre_inited==NONE); if (!(result= pre_index_init(idx, sorted))) pre_inited=INDEX; DBUG_RETURN(result); } int ha_pre_index_end() { DBUG_ENTER("ha_pre_index_end"); DBUG_ASSERT(pre_inited==INDEX); pre_inited=NONE; DBUG_RETURN(pre_index_end()); } int ha_pre_index_or_rnd_end() { return (pre_inited == INDEX ? ha_pre_index_end() : pre_inited == RND ? ha_pre_rnd_end() : 0 ); } virtual bool vers_can_native(THD *thd) { return ht->flags & HTON_NATIVE_SYS_VERSIONING; } /** @brief Positions an index cursor to the index specified in the handle. Fetches the row if available. If the key value is null, begin at the first key of the index. */ protected: virtual int index_read_map(uchar * buf, const uchar * key, key_part_map keypart_map, enum ha_rkey_function find_flag) { uint key_len= calculate_key_len(table, active_index, key, keypart_map); return index_read(buf, key, key_len, find_flag); } /** @brief Positions an index cursor to the index specified in the handle. Fetches the row if available. If the key value is null, begin at the first key of the index. */ virtual int index_read_idx_map(uchar * buf, uint index, const uchar * key, key_part_map keypart_map, enum ha_rkey_function find_flag); virtual int index_next(uchar * buf) { return HA_ERR_WRONG_COMMAND; } virtual int index_prev(uchar * buf) { return HA_ERR_WRONG_COMMAND; } virtual int index_first(uchar * buf) { return HA_ERR_WRONG_COMMAND; } virtual int index_last(uchar * buf) { return HA_ERR_WRONG_COMMAND; } virtual int index_next_same(uchar *buf, const uchar *key, uint keylen); /** @brief The following functions works like index_read, but it find the last row with the current key value or prefix. @returns @see index_read_map(). */ virtual int index_read_last_map(uchar * buf, const uchar * key, key_part_map keypart_map) { uint key_len= calculate_key_len(table, active_index, key, keypart_map); return index_read_last(buf, key, key_len); } virtual int close(void)=0; inline void update_rows_read() { if (likely(!internal_tmp_table)) rows_read++; else rows_tmp_read++; } inline void update_index_statistics() { index_rows_read[active_index]++; update_rows_read(); } public: int ha_index_read_map(uchar * buf, const uchar * key, key_part_map keypart_map, enum ha_rkey_function find_flag); int ha_index_read_idx_map(uchar * buf, uint index, const uchar * key, key_part_map keypart_map, enum ha_rkey_function find_flag); int ha_index_next(uchar * buf); int ha_index_prev(uchar * buf); int ha_index_first(uchar * buf); int ha_index_last(uchar * buf); int ha_index_next_same(uchar *buf, const uchar *key, uint keylen); /* TODO: should we make for those functions non-virtual ha_func_name wrappers, too? */ virtual ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, uint *mrr_mode, Cost_estimate *cost); virtual ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, uint key_parts, uint *bufsz, uint *mrr_mode, Cost_estimate *cost); virtual int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint mrr_mode, HANDLER_BUFFER *buf); virtual int multi_range_read_next(range_id_t *range_info); /* Return string representation of the MRR plan. This is intended to be used for EXPLAIN, via the following scenario: 1. SQL layer calls handler->multi_range_read_info(). 1.1. Storage engine figures out whether it will use some non-default MRR strategy, sets appropritate bits in *mrr_mode, and returns control to SQL layer 2. SQL layer remembers the returned mrr_mode 3. SQL layer compares various options and choses the final query plan. As a part of that, it makes a choice of whether to use the MRR strategy picked in 1.1 4. EXPLAIN code converts the query plan to its text representation. If MRR strategy is part of the plan, it calls multi_range_read_explain_info(mrr_mode) to get a text representation of the picked MRR strategy. @param mrr_mode Mode which was returned by multi_range_read_info[_const] @param str INOUT string to be printed for EXPLAIN @param str_end End of the string buffer. The function is free to put the string into [str..str_end] memory range. */ virtual int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size) { return 0; } virtual int read_range_first(const key_range *start_key, const key_range *end_key, bool eq_range, bool sorted); virtual int read_range_next(); void set_end_range(const key_range *end_key); int compare_key(key_range *range); int compare_key2(key_range *range) const; virtual int ft_init() { return HA_ERR_WRONG_COMMAND; } virtual int pre_ft_init() { return HA_ERR_WRONG_COMMAND; } virtual void ft_end() {} virtual int pre_ft_end() { return 0; } virtual FT_INFO *ft_init_ext(uint flags, uint inx,String *key) { return NULL; } public: virtual int ft_read(uchar *buf) { return HA_ERR_WRONG_COMMAND; } virtual int rnd_next(uchar *buf)=0; virtual int rnd_pos(uchar * buf, uchar *pos)=0; /** This function only works for handlers having HA_PRIMARY_KEY_REQUIRED_FOR_POSITION set. It will return the row with the PK given in the record argument. */ virtual int rnd_pos_by_record(uchar *record) { int error; DBUG_ASSERT(table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION); error = ha_rnd_init(false); if (error != 0) return error; position(record); error = ha_rnd_pos(record, ref); ha_rnd_end(); return error; } virtual int read_first_row(uchar *buf, uint primary_key); public: /* Same as above, but with statistics */ inline int ha_ft_read(uchar *buf); inline void ha_ft_end() { ft_end(); ft_handler=NULL; } int ha_rnd_next(uchar *buf); int ha_rnd_pos(uchar *buf, uchar *pos); inline int ha_rnd_pos_by_record(uchar *buf); inline int ha_read_first_row(uchar *buf, uint primary_key); /** The following 2 function is only needed for tables that may be internal temporary tables during joins. */ virtual int remember_rnd_pos() { return HA_ERR_WRONG_COMMAND; } virtual int restart_rnd_next(uchar *buf) { return HA_ERR_WRONG_COMMAND; } virtual ha_rows records_in_range(uint inx, const key_range *min_key, const key_range *max_key, page_range *res) { return (ha_rows) 10; } /* If HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is set, then it sets ref (reference to the row, aka position, with the primary key given in the record). Otherwise it set ref to the current row. */ virtual void position(const uchar *record)=0; virtual int info(uint)=0; // see my_base.h for full description virtual void get_dynamic_partition_info(PARTITION_STATS *stat_info, uint part_id); virtual void set_partitions_to_open(List *partition_names) {} virtual bool check_if_updates_are_ignored(const char *op) const; virtual int change_partitions_to_open(List *partition_names) { return 0; } virtual int extra(enum ha_extra_function operation) { return 0; } virtual int extra_opt(enum ha_extra_function operation, ulong arg) { return extra(operation); } /* Table version id for the the table. This should change for each sucessfull ALTER TABLE. This is used by the handlerton->check_version() to ask the engine if the table definition has been updated. Storage engines that does not support inplace alter table does not have to support this call. */ virtual ulonglong table_version() const { return 0; } /** In an UPDATE or DELETE, if the row under the cursor was locked by another transaction, and the engine used an optimistic read of the last committed row value under the cursor, then the engine returns 1 from this function. MySQL must NOT try to update this optimistic value. If the optimistic value does not match the WHERE condition, MySQL can decide to skip over this row. Currently only works for InnoDB. This can be used to avoid unnecessary lock waits. If this method returns nonzero, it will also signal the storage engine that the next read will be a locking re-read of the row. */ bool ha_was_semi_consistent_read(); virtual bool was_semi_consistent_read() { return 0; } /** Tell the engine whether it should avoid unnecessary lock waits. If yes, in an UPDATE or DELETE, if the row under the cursor was locked by another transaction, the engine may try an optimistic read of the last committed row value under the cursor. */ virtual void try_semi_consistent_read(bool) {} virtual void unlock_row() {} virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;} virtual bool need_info_for_auto_inc() { return 0; } virtual bool can_use_for_auto_inc_init() { return 1; } virtual void get_auto_increment(ulonglong offset, ulonglong increment, ulonglong nb_desired_values, ulonglong *first_value, ulonglong *nb_reserved_values); void set_next_insert_id(ulonglong id) { DBUG_PRINT("info",("auto_increment: next value %lu", (ulong)id)); next_insert_id= id; } virtual void restore_auto_increment(ulonglong prev_insert_id) { /* Insertion of a row failed, re-use the lastly generated auto_increment id, for the next row. This is achieved by resetting next_insert_id to what it was before the failed insertion (that old value is provided by the caller). If that value was 0, it was the first row of the INSERT; then if insert_id_for_cur_row contains 0 it means no id was generated for this first row, so no id was generated since the INSERT started, so we should set next_insert_id to 0; if insert_id_for_cur_row is not 0, it is the generated id of the first and failed row, so we use it. */ next_insert_id= (prev_insert_id > 0) ? prev_insert_id : insert_id_for_cur_row; } virtual void update_create_info(HA_CREATE_INFO *create_info) {} int check_old_types(); virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; } virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; } /* end of the list of admin commands */ virtual int indexes_are_disabled(void) {return 0;} virtual void append_create_info(String *packet) {} /** If index == MAX_KEY then a check for table is made and if index < MAX_KEY then a check is made if the table has foreign keys and if a foreign key uses this index (and thus the index cannot be dropped). @param index Index to check if foreign key uses it @retval TRUE Foreign key defined on table or index @retval FALSE No foreign key defined */ virtual bool is_fk_defined_on_table_or_index(uint index) { return FALSE; } virtual char* get_foreign_key_create_info() { return(NULL);} /* gets foreign key create string from InnoDB */ /** Used in ALTER TABLE to check if changing storage engine is allowed. @note Called without holding thr_lock.c lock. @retval true Changing storage engine is allowed. @retval false Changing storage engine not allowed. */ virtual bool can_switch_engines() { return true; } virtual int can_continue_handler_scan() { return 0; } /** Get the list of foreign keys in this table. @remark Returns the set of foreign keys where this table is the dependent or child table. @param thd The thread handle. @param f_key_list[out] The list of foreign keys. @return The handler error code or zero for success. */ virtual int get_foreign_key_list(THD *thd, List *f_key_list) { return 0; } /** Get the list of foreign keys referencing this table. @remark Returns the set of foreign keys where this table is the referenced or parent table. @param thd The thread handle. @param f_key_list[out] The list of foreign keys. @return The handler error code or zero for success. */ virtual int get_parent_foreign_key_list(THD *thd, List *f_key_list) { return 0; } virtual bool referenced_by_foreign_key() const noexcept { return false;} virtual void init_table_handle_for_HANDLER() { return; } /* prepare InnoDB for HANDLER */ virtual void free_foreign_key_create_info(char* str) {} /** The following can be called without an open handler */ virtual const char *table_type() const { return hton_name(ht)->str; } /* The following is same as table_table(), except for partition engine */ virtual const char *real_table_type() const { return hton_name(ht)->str; } const char **bas_ext() const { return ht->tablefile_extensions; } virtual int get_default_no_partitions(HA_CREATE_INFO *create_info) { return 1;} virtual void set_auto_partitions(partition_info *part_info) { return; } virtual bool get_no_parts(const char *name, uint *no_parts) { *no_parts= 0; return 0; } virtual void set_part_info(partition_info *part_info) {return;} virtual void return_record_by_parent() { return; } /* Information about index. Both index and part starts from 0 */ virtual ulong index_flags(uint idx, uint part, bool all_parts) const =0; uint max_record_length() const { return MY_MIN(HA_MAX_REC_LENGTH, max_supported_record_length()); } uint max_keys() const { return MY_MIN(MAX_KEY, max_supported_keys()); } uint max_key_parts() const { return MY_MIN(MAX_REF_PARTS, max_supported_key_parts()); } uint max_key_length() const { return MY_MIN(MAX_DATA_LENGTH_FOR_KEY, max_supported_key_length()); } uint max_key_part_length() const { return MY_MIN(MAX_DATA_LENGTH_FOR_KEY, max_supported_key_part_length()); } virtual uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; } virtual uint max_supported_keys() const { return 0; } virtual uint max_supported_key_parts() const { return MAX_REF_PARTS; } virtual uint max_supported_key_length() const { return MAX_DATA_LENGTH_FOR_KEY; } virtual uint max_supported_key_part_length() const { return 255; } virtual uint min_record_length(uint options) const { return 1; } virtual int pre_calculate_checksum() { return 0; } virtual int calculate_checksum(); virtual bool is_crashed() const { return 0; } virtual bool auto_repair(int error) const { return 0; } void update_global_table_stats(); void update_global_index_stats(); /** @note lock_count() can return > 1 if the table is MERGE or partitioned. */ virtual uint lock_count(void) const { return 1; } /** Is not invoked for non-transactional temporary tables. @note store_lock() can return more than one lock if the table is MERGE or partitioned. @note that one can NOT rely on table->in_use in store_lock(). It may refer to a different thread if called from mysql_lock_abort_for_thread(). @note If the table is MERGE, store_lock() can return less locks than lock_count() claimed. This can happen when the MERGE children are not attached when this is called from another thread. */ virtual THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type)=0; /** Type of table for caching query */ virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; } /** @brief Register a named table with a call back function to the query cache. @param thd The thread handle @param table_key A pointer to the table name in the table cache @param key_length The length of the table name @param[out] engine_callback The pointer to the storage engine call back function @param[out] engine_data Storage engine specific data which could be anything This method offers the storage engine, the possibility to store a reference to a table name which is going to be used with query cache. The method is called each time a statement is written to the cache and can be used to verify if a specific statement is cacheable. It also offers the possibility to register a generic (but static) call back function which is called each time a statement is matched against the query cache. @note If engine_data supplied with this function is different from engine_data supplied with the callback function, and the callback returns FALSE, a table invalidation on the current table will occur. @return Upon success the engine_callback will point to the storage engine call back function, if any, and engine_data will point to any storage engine data used in the specific implementation. @retval TRUE Success @retval FALSE The specified table or current statement should not be cached */ virtual my_bool register_query_cache_table(THD *thd, const char *table_key, uint key_length, qc_engine_callback *callback, ulonglong *engine_data) { *callback= 0; return TRUE; } /* Count tables invisible from all tables list on which current one built (like myisammrg and partitioned tables) tables_type mask for the tables should be added herdde returns number of such tables */ virtual uint count_query_cache_dependant_tables(uint8 *tables_type __attribute__((unused))) { return 0; } /* register tables invisible from all tables list on which current one built (like myisammrg and partitioned tables). @note they should be counted by method above cache Query cache pointer block Query cache block to write the table n Number of the table @retval FALSE - OK @retval TRUE - Error */ virtual my_bool register_query_cache_dependant_tables(THD *thd __attribute__((unused)), Query_cache *cache __attribute__((unused)), Query_cache_block_table **block __attribute__((unused)), uint *n __attribute__((unused))) { return FALSE; } /* Check if the key is a clustering key - Data is stored together with the primary key (no secondary lookup needed to find the row data). The optimizer uses this to find out the cost of fetching data. Note that in many cases a clustered key is also a reference key. This means that: - The key is part of each secondary key and is used to find the row data in the primary index when reading trough secondary indexes. - When doing a HA_KEYREAD_ONLY we get also all the primary key parts into the row. This is critical property used by index_merge. All the above is usually true for engines that store the row data in the primary key index (e.g. in a b-tree), and use the key key value as a position(). InnoDB is an example of such an engine. For a clustered (primary) key, the following should also hold: index_flags() should contain HA_CLUSTERED_INDEX table_flags() should contain HA_TABLE_SCAN_ON_INDEX For a reference key the following should also hold: table_flags() should contain HA_PRIMARY_KEY_IS_READ_INDEX. @retval TRUE yes @retval FALSE No. */ /* The following code is for primary keys */ bool pk_is_clustering_key(uint index) const { /* We have to check for MAX_INDEX as table->s->primary_key can be MAX_KEY in the case where there is no primary key. */ return index != MAX_KEY && is_clustering_key(index); } /* Same as before but for other keys, in which case we can skip the check */ bool is_clustering_key(uint index) const { DBUG_ASSERT(index != MAX_KEY); return (index_flags(index, 0, 1) & HA_CLUSTERED_INDEX); } virtual int cmp_ref(const uchar *ref1, const uchar *ref2) { return memcmp(ref1, ref2, ref_length); } /* Condition pushdown to storage engines */ /** Push condition down to the table handler. @param cond Condition to be pushed. The condition tree must not be modified by the by the caller. @return The 'remainder' condition that caller must use to filter out records. NULL means the handler will not return rows that do not match the passed condition. @note The pushed conditions form a stack (from which one can remove the last pushed condition using cond_pop). The table handler filters out rows using (pushed_cond1 AND pushed_cond2 AND ... AND pushed_condN) or less restrictive condition, depending on handler's capabilities. handler->ha_reset() call empties the condition stack. Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the condition stack. */ virtual const COND *cond_push(const COND *cond) { return cond; }; /** Pop the top condition from the condition stack of the handler instance. Pops the top if condition stack, if stack is not empty. */ virtual void cond_pop() { return; }; /** Push metadata for the current operation down to the table handler. */ virtual int info_push(uint info_type, void *info) { return 0; }; /** Push down an index condition to the handler. The server will use this method to push down a condition it wants the handler to evaluate when retrieving records using a specified index. The pushed index condition will only refer to fields from this handler that is contained in the index (but it may also refer to fields in other handlers). Before the handler evaluates the condition it must read the content of the index entry into the record buffer. The handler is free to decide if and how much of the condition it will take responsibility for evaluating. Based on this evaluation it should return the part of the condition it will not evaluate. If it decides to evaluate the entire condition it should return NULL. If it decides not to evaluate any part of the condition it should return a pointer to the same condition as given as argument. @param keyno the index number to evaluate the condition on @param idx_cond the condition to be evaluated by the handler @return The part of the pushed condition that the handler decides not to evaluate */ virtual Item *idx_cond_push(uint keyno, Item* idx_cond) { return idx_cond; } /** Reset information about pushed index conditions */ virtual void cancel_pushed_idx_cond() { pushed_idx_cond= NULL; pushed_idx_cond_keyno= MAX_KEY; in_range_check_pushed_down= false; } virtual void cancel_pushed_rowid_filter() { pushed_rowid_filter= NULL; rowid_filter_is_active= false; } virtual void disable_pushed_rowid_filter() { DBUG_ASSERT(pushed_rowid_filter != NULL && save_pushed_rowid_filter == NULL); save_pushed_rowid_filter= pushed_rowid_filter; if (rowid_filter_is_active) save_rowid_filter_is_active= rowid_filter_is_active; pushed_rowid_filter= NULL; rowid_filter_is_active= false; } virtual void enable_pushed_rowid_filter() { DBUG_ASSERT(save_pushed_rowid_filter != NULL && pushed_rowid_filter == NULL); pushed_rowid_filter= save_pushed_rowid_filter; if (save_rowid_filter_is_active) rowid_filter_is_active= true; save_pushed_rowid_filter= NULL; } virtual bool rowid_filter_push(Rowid_filter *rowid_filter) { return true; } /* Needed for partition / spider */ virtual TABLE_LIST *get_next_global_for_child() { return NULL; } /** Part of old, deprecated in-place ALTER API. */ virtual bool check_if_incompatible_data(HA_CREATE_INFO *create_info, uint table_changes) { return COMPATIBLE_DATA_NO; } /* On-line/in-place ALTER TABLE interface. */ /* Here is an outline of on-line/in-place ALTER TABLE execution through this interface. Phase 1 : Initialization ======================== During this phase we determine which algorithm should be used for execution of ALTER TABLE and what level concurrency it will require. *) This phase starts by opening the table and preparing description of the new version of the table. *) Then we check if it is impossible even in theory to carry out this ALTER TABLE using the in-place algorithm. For example, because we need to change storage engine or the user has explicitly requested usage of the "copy" algorithm. *) If in-place ALTER TABLE is theoretically possible, we continue by compiling differences between old and new versions of the table in the form of HA_ALTER_FLAGS bitmap. We also build a few auxiliary structures describing requested changes and store all these data in the Alter_inplace_info object. *) Then the handler::check_if_supported_inplace_alter() method is called in order to find if the storage engine can carry out changes requested by this ALTER TABLE using the in-place algorithm. To determine this, the engine can rely on data in HA_ALTER_FLAGS/Alter_inplace_info passed to it as well as on its own checks. If the in-place algorithm can be used for this ALTER TABLE, the level of required concurrency for its execution is also returned. If any errors occur during the handler call, ALTER TABLE is aborted and no further handler functions are called. *) Locking requirements of the in-place algorithm are compared to any concurrency requirements specified by user. If there is a conflict between them, we either switch to the copy algorithm or emit an error. Phase 2 : Execution =================== In this phase the operations are executed. *) As the first step, we acquire a lock corresponding to the concurrency level which was returned by handler::check_if_supported_inplace_alter() and requested by the user. This lock is held for most of the duration of in-place ALTER (if HA_ALTER_INPLACE_COPY_LOCK or HA_ALTER_INPLACE_COPY_NO_LOCK were returned we acquire an exclusive lock for duration of the next step only). *) After that we call handler::ha_prepare_inplace_alter_table() to give the storage engine a chance to update its internal structures with a higher lock level than the one that will be used for the main step of algorithm. After that we downgrade the lock if it is necessary. *) After that, the main step of this phase and algorithm is executed. We call the handler::ha_inplace_alter_table() method, which carries out the changes requested by ALTER TABLE but does not makes them visible to other connections yet. *) We ensure that no other connection uses the table by upgrading our lock on it to exclusive. *) a) If the previous step succeeds, handler::ha_commit_inplace_alter_table() is called to allow the storage engine to do any final updates to its structures, to make all earlier changes durable and visible to other connections. b) If we have failed to upgrade lock or any errors have occurred during the handler functions calls (including commit), we call handler::ha_commit_inplace_alter_table() to rollback all changes which were done during previous steps. Phase 3 : Final =============== In this phase we: *) Update SQL-layer data-dictionary by installing .FRM file for the new version of the table. *) Inform the storage engine about this change by calling the hton::notify_table_changed() *) Destroy the Alter_inplace_info and handler_ctx objects. */ /** Check if a storage engine supports a particular alter table in-place @param altered_table TABLE object for new version of table. @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data used during in-place alter. @retval HA_ALTER_ERROR Unexpected error. @retval HA_ALTER_INPLACE_NOT_SUPPORTED Not supported, must use copy. @retval HA_ALTER_INPLACE_EXCLUSIVE_LOCK Supported, but requires X lock. @retval HA_ALTER_INPLACE_COPY_LOCK Supported, but requires SNW lock during main phase. Prepare phase requires X lock. @retval HA_ALTER_INPLACE_SHARED_LOCK Supported, but requires SNW lock. @retval HA_ALTER_INPLACE_COPY_NO_LOCK Supported, concurrent reads/writes allowed. However, prepare phase requires X lock. @retval HA_ALTER_INPLACE_NO_LOCK Supported, concurrent reads/writes allowed. @note The default implementation uses the old in-place ALTER API to determine if the storage engine supports in-place ALTER or not. @note Called without holding thr_lock.c lock. */ virtual enum_alter_inplace_result check_if_supported_inplace_alter(TABLE *altered_table, Alter_inplace_info *ha_alter_info); /** Public functions wrapping the actual handler call. @see prepare_inplace_alter_table() */ bool ha_prepare_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info); /** Public function wrapping the actual handler call. @see inplace_alter_table() */ bool ha_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info) { return inplace_alter_table(altered_table, ha_alter_info); } /** Public function wrapping the actual handler call. Allows us to enforce asserts regardless of handler implementation. @see commit_inplace_alter_table() */ bool ha_commit_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info, bool commit); protected: /** Allows the storage engine to update internal structures with concurrent writes blocked. If check_if_supported_inplace_alter() returns HA_ALTER_INPLACE_COPY_NO_LOCK or HA_ALTER_INPLACE_COPY_LOCK, this function is called with exclusive lock otherwise the same level of locking as for inplace_alter_table() will be used. @note Storage engines are responsible for reporting any errors by calling my_error()/print_error() @note If this function reports error, commit_inplace_alter_table() will be called with commit= false. @note For partitioning, failing to prepare one partition, means that commit_inplace_alter_table() will be called to roll back changes for all partitions. This means that commit_inplace_alter_table() might be called without prepare_inplace_alter_table() having been called first for a given partition. @param altered_table TABLE object for new version of table. @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data used during in-place alter. @retval true Error @retval false Success */ virtual bool prepare_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info) { return false; } /** Alter the table structure in-place with operations specified using HA_ALTER_FLAGS and Alter_inplace_info. The level of concurrency allowed during this operation depends on the return value from check_if_supported_inplace_alter(). @note Storage engines are responsible for reporting any errors by calling my_error()/print_error() @note If this function reports error, commit_inplace_alter_table() will be called with commit= false. @param altered_table TABLE object for new version of table. @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data used during in-place alter. @retval true Error @retval false Success */ virtual bool inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info) { return false; } /** Commit or rollback the changes made during prepare_inplace_alter_table() and inplace_alter_table() inside the storage engine. Note that in case of rollback the allowed level of concurrency during this operation will be the same as for inplace_alter_table() and thus might be higher than during prepare_inplace_alter_table(). (For example, concurrent writes were blocked during prepare, but might not be during rollback). @note Storage engines are responsible for reporting any errors by calling my_error()/print_error() @note If this function with commit= true reports error, it will be called again with commit= false. @note In case of partitioning, this function might be called for rollback without prepare_inplace_alter_table() having been called first. Also partitioned tables sets ha_alter_info->group_commit_ctx to a NULL terminated array of the partitions handlers and if all of them are committed as one, then group_commit_ctx should be set to NULL to indicate to the partitioning handler that all partitions handlers are committed. @see prepare_inplace_alter_table(). @param altered_table TABLE object for new version of table. @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data used during in-place alter. @param commit True => Commit, False => Rollback. @retval true Error @retval false Success */ virtual bool commit_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info, bool commit) { /* Nothing to commit/rollback, mark all handlers committed! */ ha_alter_info->group_commit_ctx= NULL; return false; } public: /* End of On-line/in-place ALTER TABLE interface. */ /** use_hidden_primary_key() is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key */ virtual void use_hidden_primary_key(); virtual alter_table_operations alter_table_flags(alter_table_operations flags) { if (ht->alter_table_flags) return ht->alter_table_flags(flags); return 0; } virtual LEX_CSTRING *engine_name(); TABLE* get_table() { return table; } TABLE_SHARE* get_table_share() { return table_share; } protected: /* Service methods for use by storage engines. */ THD *ha_thd(void) const; /** Acquire the instrumented table information from a table share. @return an instrumented table share, or NULL. */ PSI_table_share *ha_table_share_psi() const; /** Default rename_table() and delete_table() rename/delete files with a given name and extensions from bas_ext(). These methods can be overridden, but their default implementation provide useful functionality. */ virtual int rename_table(const char *from, const char *to); public: /** Delete a table in the engine. Called for base as well as temporary tables. */ virtual int delete_table(const char *name); bool check_table_binlog_row_based(); bool prepare_for_row_logging(); int prepare_for_insert(bool do_create); int binlog_log_row(TABLE *table, const uchar *before_record, const uchar *after_record, Log_func *log_func); inline void clear_cached_table_binlog_row_based_flag() { check_table_binlog_row_based_done= 0; } virtual void handler_stats_updated() {} inline void ha_handler_stats_reset() { handler_stats= &active_handler_stats; active_handler_stats.reset(); active_handler_stats.active= 1; handler_stats_updated(); } inline void ha_handler_stats_disable() { if (handler_stats) { handler_stats= 0; active_handler_stats.active= 0; handler_stats_updated(); } } private: /* Cache result to avoid extra calls */ inline void mark_trx_read_write() { if (unlikely(!mark_trx_read_write_done)) { mark_trx_read_write_done= 1; mark_trx_read_write_internal(); } } private: void mark_trx_read_write_internal(); bool check_table_binlog_row_based_internal(); int create_lookup_handler(); void alloc_lookup_buffer(); int check_duplicate_long_entry_key(const uchar *new_rec, uint key_no); /** PRIMARY KEY/UNIQUE WITHOUT OVERLAPS check */ int ha_check_overlaps(const uchar *old_data, const uchar* new_data); int ha_check_long_uniques(const uchar *old_rec, const uchar *new_rec); int ha_check_inserver_constraints(const uchar *old_data, const uchar* new_data); protected: /* These are intended to be used only by handler::ha_xxxx() functions However, engines that implement read_range_XXX() (like MariaRocks) or embed other engines (like ha_partition) may need to call these also */ inline void increment_statistics(ulong SSV::*offset) const; inline void decrement_statistics(ulong SSV::*offset) const; private: /* Low-level primitives for storage engines. These should be overridden by the storage engine class. To call these methods, use the corresponding 'ha_*' method above. */ virtual int open(const char *name, int mode, uint test_if_locked)=0; /* Note: ha_index_read_idx_map() may bypass index_init() */ virtual int index_init(uint idx, bool sorted) { return 0; } virtual int index_end() { return 0; } /** rnd_init() can be called two times without rnd_end() in between (it only makes sense if scan=1). then the second call should prepare for the new table scan (e.g if rnd_init allocates the cursor, second call should position it to the start of the table, no need to deallocate and allocate it again */ virtual int rnd_init(bool scan)= 0; virtual int rnd_end() { return 0; } virtual int write_row(const uchar *buf __attribute__((unused))) { return HA_ERR_WRONG_COMMAND; } /** Update a single row. Note: If HA_ERR_FOUND_DUPP_KEY is returned, the handler must read all columns of the row so MySQL can create an error message. If the columns required for the error message are not read, the error message will contain garbage. */ virtual int update_row(const uchar *old_data __attribute__((unused)), const uchar *new_data __attribute__((unused))) { return HA_ERR_WRONG_COMMAND; } /* Optimized function for updating the first row. Only used by sequence tables */ virtual int update_first_row(const uchar *new_data); virtual int delete_row(const uchar *buf __attribute__((unused))) { return HA_ERR_WRONG_COMMAND; } /* Perform initialization for a direct update request */ public: int ha_direct_update_rows(ha_rows *update_rows, ha_rows *found_rows); virtual int direct_update_rows_init(List *update_fields) { return HA_ERR_WRONG_COMMAND; } private: virtual int pre_direct_update_rows_init(List *update_fields) { return HA_ERR_WRONG_COMMAND; } virtual int direct_update_rows(ha_rows *update_rows __attribute__((unused)), ha_rows *found_rows __attribute__((unused))) { return HA_ERR_WRONG_COMMAND; } virtual int pre_direct_update_rows() { return HA_ERR_WRONG_COMMAND; } /* Perform initialization for a direct delete request */ public: int ha_direct_delete_rows(ha_rows *delete_rows); virtual int direct_delete_rows_init() { return HA_ERR_WRONG_COMMAND; } private: virtual int pre_direct_delete_rows_init() { return HA_ERR_WRONG_COMMAND; } virtual int direct_delete_rows(ha_rows *delete_rows __attribute__((unused))) { return HA_ERR_WRONG_COMMAND; } virtual int pre_direct_delete_rows() { return HA_ERR_WRONG_COMMAND; } /** Reset state of file to after 'open'. This function is called after every statement for all tables used by that statement. */ virtual int reset() { return 0; } virtual Table_flags table_flags(void) const= 0; /** Is not invoked for non-transactional temporary tables. Tells the storage engine that we intend to read or write data from the table. This call is prefixed with a call to handler::store_lock() and is invoked only for those handler instances that stored the lock. Calls to rnd_init/index_init are prefixed with this call. When table IO is complete, we call external_lock(F_UNLCK). A storage engine writer should expect that each call to ::external_lock(F_[RD|WR]LOCK is followed by a call to ::external_lock(F_UNLCK). If it is not, it is a bug in MySQL. The name and signature originate from the first implementation in MyISAM, which would call fcntl to set/clear an advisory lock on the data file in this method. @param lock_type F_RDLCK, F_WRLCK, F_UNLCK @return non-0 in case of failure, 0 in case of success. When lock_type is F_UNLCK, the return value is ignored. */ virtual int external_lock(THD *thd __attribute__((unused)), int lock_type __attribute__((unused))) { return 0; } virtual void release_auto_increment() { return; }; /** admin commands - called from mysql_admin_table */ virtual int check_for_upgrade(HA_CHECK_OPT *check_opt) { return 0; } virtual int check(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; } /** In this method check_opt can be modified to specify CHECK option to use to call check() upon the table. */ virtual int repair(THD* thd, HA_CHECK_OPT* check_opt) { DBUG_ASSERT(!(ha_table_flags() & HA_CAN_REPAIR)); return HA_ADMIN_NOT_IMPLEMENTED; } protected: virtual void start_bulk_insert(ha_rows rows, uint flags) {} virtual int end_bulk_insert() { return 0; } virtual int index_read(uchar * buf, const uchar * key, uint key_len, enum ha_rkey_function find_flag) { return HA_ERR_WRONG_COMMAND; } virtual int index_read_last(uchar * buf, const uchar * key, uint key_len) { my_errno= HA_ERR_WRONG_COMMAND; return HA_ERR_WRONG_COMMAND; } friend class ha_partition; friend class ha_sequence; public: /** This method is similar to update_row, however the handler doesn't need to execute the updates at this point in time. The handler can be certain that another call to bulk_update_row will occur OR a call to exec_bulk_update before the set of updates in this query is concluded. @param old_data Old record @param new_data New record @param dup_key_found Number of duplicate keys found @retval 0 Bulk delete used by handler @retval 1 Bulk delete not used, normal operation used */ virtual int bulk_update_row(const uchar *old_data, const uchar *new_data, ha_rows *dup_key_found) { DBUG_ASSERT(FALSE); return HA_ERR_WRONG_COMMAND; } /** This is called to delete all rows in a table If the handler don't support this, then this function will return HA_ERR_WRONG_COMMAND and MySQL will delete the rows one by one. */ virtual int delete_all_rows() { return (my_errno=HA_ERR_WRONG_COMMAND); } /** Quickly remove all rows from a table. @remark This method is responsible for implementing MySQL's TRUNCATE TABLE statement, which is a DDL operation. As such, a engine can bypass certain integrity checks and in some cases avoid fine-grained locking (e.g. row locks) which would normally be required for a DELETE statement. @remark Typically, truncate is not used if it can result in integrity violation. For example, truncate is not used when a foreign key references the table, but it might be used if foreign key checks are disabled. @remark Engine is responsible for resetting the auto-increment counter. @remark The table is locked in exclusive mode. */ virtual int truncate() { int error= delete_all_rows(); return error ? error : reset_auto_increment(0); } /** Reset the auto-increment counter to the given value, i.e. the next row inserted will get the given value. */ virtual int reset_auto_increment(ulonglong value) { return 0; } virtual int optimize(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; } virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; } virtual bool check_and_repair(THD *thd) { return TRUE; } virtual int disable_indexes(key_map map, bool persist) { return HA_ERR_WRONG_COMMAND; } virtual int enable_indexes(key_map map, bool persist) { return HA_ERR_WRONG_COMMAND; } virtual int discard_or_import_tablespace(my_bool discard) { return (my_errno=HA_ERR_WRONG_COMMAND); } virtual void drop_table(const char *name); virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; virtual int create_partitioning_metadata(const char *name, const char *old_name, chf_create_flags action_flag) { return FALSE; } virtual int change_partitions(HA_CREATE_INFO *create_info, const char *path, ulonglong * const copied, ulonglong * const deleted, const uchar *pack_frm_data, size_t pack_frm_len) { return HA_ERR_WRONG_COMMAND; } /* @return true if it's necessary to switch current statement log format from STATEMENT to ROW if binary log format is MIXED and autoincrement values are changed in the statement */ virtual bool autoinc_lock_mode_stmt_unsafe() const { return false; } virtual int drop_partitions(const char *path) { return HA_ERR_WRONG_COMMAND; } virtual int rename_partitions(const char *path) { return HA_ERR_WRONG_COMMAND; } virtual bool set_ha_share_ref(Handler_share **arg_ha_share) { DBUG_ASSERT(!ha_share); DBUG_ASSERT(arg_ha_share); if (ha_share || !arg_ha_share) return true; ha_share= arg_ha_share; return false; } void set_table(TABLE* table_arg) { table= table_arg; } int get_lock_type() const { return m_lock_type; } public: /* XXX to be removed, see ha_partition::partition_ht() */ virtual handlerton *partition_ht() const { return ht; } virtual bool partition_engine() { return 0;} /* Used with 'wrapper' engines, like SEQUENCE, to access to the underlaying engine used for storage. */ virtual handlerton *storage_ht() const { return ht; } inline int ha_write_tmp_row(uchar *buf); inline int ha_delete_tmp_row(uchar *buf); inline int ha_update_tmp_row(const uchar * old_data, uchar * new_data); virtual void set_lock_type(enum thr_lock_type lock); friend check_result_t handler_index_cond_check(void* h_arg); friend check_result_t handler_rowid_filter_check(void *h_arg); /** Find unique record by index or unique constrain @param record record to find (also will be fillded with actual record fields) @param unique_ref index or unique constraiun number (depends on what used in the engine @retval -1 Error @retval 1 Not found @retval 0 Found */ virtual int find_unique_row(uchar *record, uint unique_ref) { return -1; /*unsupported */} bool native_versioned() const { DBUG_ASSERT(ht); return partition_ht()->flags & HTON_NATIVE_SYS_VERSIONING; } virtual void update_partition(uint part_id) {} /** Some engines can perform column type conversion with ALGORITHM=INPLACE. These functions check for such possibility. Implementation could be based on Field_xxx::is_equal() */ virtual bool can_convert_nocopy(const Field &, const Column_definition &) const { return false; } /* If the table is using sql level unique constraints on some column */ inline bool has_long_unique(); /* Used for ALTER TABLE. Some engines can handle some differences in indexes by themself. */ virtual Compare_keys compare_key_parts(const Field &old_field, const Column_definition &new_field, const KEY_PART_INFO &old_part, const KEY_PART_INFO &new_part) const; /* If lower_case_table_names == 2 (case-preserving but case-insensitive file system) and the storage is not HA_FILE_BASED, we need to provide a lowercase file name for the engine. */ inline bool needs_lower_case_filenames() { return (lower_case_table_names == 2 && !(ha_table_flags() & HA_FILE_BASED)); } bool log_not_redoable_operation(const char *operation); protected: Handler_share *get_ha_share_ptr(); void set_ha_share_ptr(Handler_share *arg_ha_share); void lock_shared_ha_data(); void unlock_shared_ha_data(); }; #include "multi_range_read.h" #include "group_by_handler.h" bool key_uses_partial_cols(TABLE_SHARE *table, uint keyno); /* Some extern variables used with handlers */ extern const LEX_CSTRING ha_row_type[]; extern MYSQL_PLUGIN_IMPORT const char *tx_isolation_names[]; extern MYSQL_PLUGIN_IMPORT const char *binlog_format_names[]; extern TYPELIB tx_isolation_typelib; extern const char *myisam_stats_method_names[]; extern ulong total_ha, total_ha_2pc; /* lookups */ plugin_ref ha_resolve_by_name(THD *thd, const LEX_CSTRING *name, bool tmp_table); plugin_ref ha_lock_engine(THD *thd, const handlerton *hton); handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type); handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc, handlerton *db_type); handlerton *ha_checktype(THD *thd, handlerton *hton, bool no_substitute); static inline handlerton *ha_checktype(THD *thd, enum legacy_db_type type, bool no_substitute = 0) { return ha_checktype(thd, ha_resolve_by_legacy_type(thd, type), no_substitute); } static inline enum legacy_db_type ha_legacy_type(const handlerton *db_type) { return (db_type == NULL) ? DB_TYPE_UNKNOWN : db_type->db_type; } static inline const char *ha_resolve_storage_engine_name(const handlerton *db_type) { return (db_type == NULL ? "UNKNOWN" : db_type == view_pseudo_hton ? "VIEW" : hton_name(db_type)->str); } static inline bool ha_check_storage_engine_flag(const handlerton *db_type, uint32 flag) { return db_type && (db_type->flags & flag); } static inline bool ha_storage_engine_is_enabled(const handlerton *db_type) { return db_type && db_type->create; } /* basic stuff */ int ha_init_errors(void); int ha_init(void); int ha_end(void); int ha_initialize_handlerton(void *plugin); int ha_finalize_handlerton(void *plugin); TYPELIB *ha_known_exts(void); int ha_panic(enum ha_panic_function flag); void ha_close_connection(THD* thd); void ha_kill_query(THD* thd, enum thd_kill_levels level); void ha_signal_ddl_recovery_done(); bool ha_flush_logs(); void ha_drop_database(const char* path); void ha_checkpoint_state(bool disable); void ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *)); int ha_create_table(THD *thd, const char *path, const char *db, const char *table_name, HA_CREATE_INFO *create_info, LEX_CUSTRING *frm, bool skip_frm_file); int ha_delete_table(THD *thd, handlerton *db_type, const char *path, const LEX_CSTRING *db, const LEX_CSTRING *alias, bool generate_warning); int ha_delete_table_force(THD *thd, const char *path, const LEX_CSTRING *db, const LEX_CSTRING *alias); void ha_prepare_for_backup(); void ha_end_backup(); void ha_pre_shutdown(); void ha_disable_internal_writes(bool disable); /* statistics and info */ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat); /* discovery */ #ifdef MYSQL_SERVER class Discovered_table_list: public handlerton::discovered_list { THD *thd; const char *wild, *wend; bool with_temps; // whether to include temp tables in the result public: Dynamic_array *tables; Discovered_table_list(THD *thd_arg, Dynamic_array *tables_arg, const LEX_CSTRING *wild_arg); Discovered_table_list(THD *thd_arg, Dynamic_array *tables_arg) : thd(thd_arg), wild(NULL), with_temps(true), tables(tables_arg) {} ~Discovered_table_list() = default; bool add_table(const char *tname, size_t tlen) override; bool add_file(const char *fname) override; void sort(); void remove_duplicates(); // assumes that the list is sorted #ifndef DBUG_OFF /* Used to find unstable mtr tests querying INFORMATION_SCHEMA.TABLES without ORDER BY. */ void sort_desc(); #endif /* DBUG_OFF */ }; int ha_discover_table(THD *thd, TABLE_SHARE *share); int ha_discover_table_names(THD *thd, LEX_CSTRING *db, MY_DIR *dirp, Discovered_table_list *result, bool reusable); bool ha_table_exists(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table_name, LEX_CUSTRING *table_version= 0, LEX_CSTRING *partition_engine_name= 0, handlerton **hton= 0, bool *is_sequence= 0); bool ha_check_if_updates_are_ignored(THD *thd, handlerton *hton, const char *op); #endif /* MYSQL_SERVER */ /* key cache */ extern "C" int ha_init_key_cache(const char *name, KEY_CACHE *key_cache, void *); int ha_resize_key_cache(KEY_CACHE *key_cache); int ha_change_key_cache_param(KEY_CACHE *key_cache); int ha_repartition_key_cache(KEY_CACHE *key_cache); int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache); /* transactions: interface to handlerton functions */ int ha_start_consistent_snapshot(THD *thd); int ha_commit_or_rollback_by_xid(XID *xid, bool commit); int ha_commit_one_phase(THD *thd, bool all); int ha_commit_trans(THD *thd, bool all); int ha_rollback_trans(THD *thd, bool all); int ha_prepare(THD *thd); int ha_recover(HASH *commit_list, MEM_ROOT *mem_root= NULL); uint ha_recover_complete(HASH *commit_list, Binlog_offset *coord= NULL); /* transactions: these functions never call handlerton functions directly */ int ha_enable_transaction(THD *thd, bool on); /* savepoints */ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv); bool ha_rollback_to_savepoint_can_release_mdl(THD *thd); int ha_savepoint(THD *thd, SAVEPOINT *sv); int ha_release_savepoint(THD *thd, SAVEPOINT *sv); #ifdef WITH_WSREP int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal); #endif /* these are called by storage engines */ void trans_register_ha(THD *thd, bool all, handlerton *ht, ulonglong trxid); /* Storage engine has to assume the transaction will end up with 2pc if - there is more than one 2pc-capable storage engine available - in the current transaction 2pc was not disabled yet */ #define trans_need_2pc(thd, all) ((total_ha_2pc > 1) && \ !((all ? &thd->transaction.all : &thd->transaction.stmt)->no_2pc)) const char *get_canonical_filename(handler *file, const char *path, char *tmp_path); void commit_checkpoint_notify_ha(void *cookie); inline const LEX_CSTRING *table_case_name(HA_CREATE_INFO *info, const LEX_CSTRING *name) { return ((lower_case_table_names == 2 && info->alias.str) ? &info->alias : name); } typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*); int binlog_log_row(TABLE* table, const uchar *before_record, const uchar *after_record, Log_func *log_func); /** @def MYSQL_TABLE_IO_WAIT Instrumentation helper for table io_waits. Note that this helper is intended to be used from within the handler class only, as it uses members from @c handler Performance schema events are instrumented as follows: - in non batch mode, one event is generated per call - in batch mode, the number of rows affected is saved in @c m_psi_numrows, so that @c end_psi_batch_mode() generates a single event for the batch. @param OP the table operation to be performed @param INDEX the table index used if any, or MAX_KEY. @param PAYLOAD instrumented code to execute @sa handler::end_psi_batch_mode. */ #ifdef HAVE_PSI_TABLE_INTERFACE #define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD) \ { \ if (m_psi != NULL) \ { \ switch (m_psi_batch_mode) \ { \ case PSI_BATCH_MODE_NONE: \ { \ PSI_table_locker *sub_locker= NULL; \ PSI_table_locker_state reentrant_safe_state; \ sub_locker= PSI_TABLE_CALL(start_table_io_wait) \ (& reentrant_safe_state, m_psi, OP, INDEX, \ __FILE__, __LINE__); \ PAYLOAD \ if (sub_locker != NULL) \ PSI_TABLE_CALL(end_table_io_wait) \ (sub_locker, 1); \ break; \ } \ case PSI_BATCH_MODE_STARTING: \ { \ m_psi_locker= PSI_TABLE_CALL(start_table_io_wait) \ (& m_psi_locker_state, m_psi, OP, INDEX, \ __FILE__, __LINE__); \ PAYLOAD \ if (!RESULT) \ m_psi_numrows++; \ m_psi_batch_mode= PSI_BATCH_MODE_STARTED; \ break; \ } \ case PSI_BATCH_MODE_STARTED: \ default: \ { \ DBUG_ASSERT(m_psi_batch_mode \ == PSI_BATCH_MODE_STARTED); \ PAYLOAD \ if (!RESULT) \ m_psi_numrows++; \ break; \ } \ } \ } \ else \ { \ PAYLOAD \ } \ } #else #define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD) \ PAYLOAD #endif #define TABLE_IO_WAIT(TRACKER, OP, INDEX, RESULT, PAYLOAD) \ { \ Exec_time_tracker *this_tracker; \ if (unlikely((this_tracker= tracker))) \ tracker->start_tracking(table->in_use); \ \ MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD); \ \ if (unlikely(this_tracker)) \ tracker->stop_tracking(table->in_use); \ } void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag); void print_keydup_error(TABLE *table, KEY *key, myf errflag); int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info); int del_global_table_stat(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table); uint ha_count_rw_all(THD *thd, Ha_trx_info **ptr_ha_info); bool non_existing_table_error(int error); uint ha_count_rw_2pc(THD *thd, bool all); uint ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list, bool all, bool *no_rollback); int get_select_field_pos(Alter_info *alter_info, int select_field_count, bool versioned); #ifndef DBUG_OFF String dbug_format_row(TABLE *table, const uchar *rec, bool print_names= true); #endif /* DBUG_OFF */ #endif /* HANDLER_INCLUDED */ server/private/rpl_record.h000064400000003061151031265040012025 0ustar00/* Copyright (c) 2007, 2013, Oracle and/or its affiliates. Copyright (c) 2008, 2013, SkySQL Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef RPL_RECORD_H #define RPL_RECORD_H #include struct rpl_group_info; struct TABLE; typedef struct st_bitmap MY_BITMAP; #if !defined(MYSQL_CLIENT) size_t pack_row(TABLE* table, MY_BITMAP const* cols, uchar *row_data, const uchar *data); #endif #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) int unpack_row(rpl_group_info *rgi, TABLE *table, uint const colcnt, uchar const *const row_data, MY_BITMAP const *cols, uchar const **const curr_row_end, ulong *const master_reclength, uchar const *const row_end); // Fill table's record[0] with default values. int prepare_record(TABLE *const table, const uint skip, const bool check); int fill_extra_persistent_columns(TABLE *table, int master_cols); #endif #endif server/private/create_options.h000064400000010654151031265040012716 0ustar00/* Copyright (C) 2010 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Engine defined options of tables/fields/keys in CREATE/ALTER TABLE. */ #ifndef SQL_CREATE_OPTIONS_INCLUDED #define SQL_CREATE_OPTIONS_INCLUDED #include "sql_class.h" enum { ENGINE_OPTION_MAX_LENGTH=32767 }; class engine_option_value: public Sql_alloc { public: LEX_CSTRING name; LEX_CSTRING value; engine_option_value *next; ///< parser puts them in a FIFO linked list bool parsed; ///< to detect unrecognized options bool quoted_value; ///< option=VAL vs. option='VAL' engine_option_value(engine_option_value *src, engine_option_value **start, engine_option_value **end) : name(src->name), value(src->value), next(NULL), parsed(src->parsed), quoted_value(src->quoted_value) { link(start, end); } engine_option_value(LEX_CSTRING &name_arg, LEX_CSTRING &value_arg, bool quoted, engine_option_value **start, engine_option_value **end) : name(name_arg), value(value_arg), next(NULL), parsed(false), quoted_value(quoted) { link(start, end); } engine_option_value(LEX_CSTRING &name_arg, engine_option_value **start, engine_option_value **end) : name(name_arg), value(null_clex_str), next(NULL), parsed(false), quoted_value(false) { link(start, end); } engine_option_value(LEX_CSTRING &name_arg, ulonglong value_arg, engine_option_value **start, engine_option_value **end, MEM_ROOT *root) : name(name_arg), next(NULL), parsed(false), quoted_value(false) { char *str; if (likely((value.str= str= (char *)alloc_root(root, 22)))) { value.length= longlong10_to_str(value_arg, str, 10) - str; link(start, end); } } static uchar *frm_read(const uchar *buff, const uchar *buff_end, engine_option_value **start, engine_option_value **end, MEM_ROOT *root); void link(engine_option_value **start, engine_option_value **end); uint frm_length(); uchar *frm_image(uchar *buff); }; typedef struct st_key KEY; class Create_field; bool resolve_sysvar_table_options(handlerton *hton); void free_sysvar_table_options(handlerton *hton); bool parse_engine_table_options(THD *thd, handlerton *ht, TABLE_SHARE *share); bool parse_option_list(THD* thd, void *option_struct, engine_option_value **option_list, ha_create_table_option *rules, bool suppress_warning, MEM_ROOT *root); bool extend_option_list(THD* thd, handlerton *hton, bool create, engine_option_value **option_list, ha_create_table_option *rules); bool engine_table_options_frm_read(const uchar *buff, size_t length, TABLE_SHARE *share); engine_option_value *merge_engine_table_options(engine_option_value *source, engine_option_value *changes, MEM_ROOT *root); uint engine_table_options_frm_length(engine_option_value *table_option_list, List &create_fields, uint keys, KEY *key_info); uchar *engine_table_options_frm_image(uchar *buff, engine_option_value *table_option_list, List &create_fields, uint keys, KEY *key_info); bool engine_options_differ(void *old_struct, void *new_struct, ha_create_table_option *rules); bool is_engine_option_known(engine_option_value *opt, ha_create_table_option *rules); #endif server/private/sql_bitmap.h000064400000017245151031265040012036 0ustar00/* Copyright (c) 2003, 2013, Oracle and/or its affiliates Copyright (c) 2009, 2013, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Implementation of a bitmap type. The idea with this is to be able to handle any constant number of bits but also be able to use 32 or 64 bits bitmaps very efficiently */ #ifndef SQL_BITMAP_INCLUDED #define SQL_BITMAP_INCLUDED #include #include #include /* An iterator to quickly walk over bits in ulonglong bitmap. */ class Table_map_iterator { ulonglong bmp; public: Table_map_iterator(ulonglong t): bmp(t){} uint next_bit() { if (!bmp) return BITMAP_END; uint bit= my_find_first_bit(bmp); bmp &= ~(1ULL << bit); return bit; } int operator++(int) { return next_bit(); } enum { BITMAP_END= 64 }; }; template class Bitmap { /* Workaround GCC optimizer bug (generating SSE instuctions on unaligned data) */ #if defined (__GNUC__) && defined(__x86_64__) && (__GNUC__ < 6) && !defined(__clang__) #define NEED_GCC_NO_SSE_WORKAROUND #endif #ifdef NEED_GCC_NO_SSE_WORKAROUND #pragma GCC push_options #pragma GCC target ("no-sse") #endif private: static const int BITS_PER_ELEMENT= sizeof(ulonglong) * 8; static const int ARRAY_ELEMENTS= (width + BITS_PER_ELEMENT - 1) / BITS_PER_ELEMENT; static const ulonglong ALL_BITS_SET= ULLONG_MAX; ulonglong buffer[ARRAY_ELEMENTS]; uint bit_index(uint n) const { DBUG_ASSERT(n < width); return ARRAY_ELEMENTS == 1 ? 0 : n / BITS_PER_ELEMENT; } ulonglong bit_mask(uint n) const { DBUG_ASSERT(n < width); return ARRAY_ELEMENTS == 1 ? 1ULL << n : 1ULL << (n % BITS_PER_ELEMENT); } ulonglong last_element_mask(int n) const { DBUG_ASSERT(n % BITS_PER_ELEMENT != 0); return bit_mask(n) - 1; } public: /* The default constructor does nothing. The caller is supposed to either zero the memory or to call set_all()/clear_all()/set_prefix() to initialize bitmap. */ Bitmap() = default; explicit Bitmap(uint prefix) { set_prefix(prefix); } void init(uint prefix) { set_prefix(prefix); } uint length() const { return width; } void set_bit(uint n) { buffer[bit_index(n)] |= bit_mask(n); } void clear_bit(uint n) { buffer[bit_index(n)] &= ~bit_mask(n); } bool is_set(uint n) const { return buffer[bit_index(n)] & bit_mask(n); } void set_prefix(uint prefix_size) { set_if_smaller(prefix_size, width); size_t idx= prefix_size / BITS_PER_ELEMENT; for (size_t i= 0; i < idx; i++) buffer[i]= ALL_BITS_SET; if (prefix_size % BITS_PER_ELEMENT) buffer[idx++]= last_element_mask(prefix_size); for (size_t i= idx; i < ARRAY_ELEMENTS; i++) buffer[i]= 0; } bool is_prefix(uint prefix_size) const { DBUG_ASSERT(prefix_size <= width); size_t idx= prefix_size / BITS_PER_ELEMENT; for (size_t i= 0; i < idx; i++) if (buffer[i] != ALL_BITS_SET) return false; if (prefix_size % BITS_PER_ELEMENT) if (buffer[idx++] != last_element_mask(prefix_size)) return false; for (size_t i= idx; i < ARRAY_ELEMENTS; i++) if (buffer[i] != 0) return false; return true; } void set_all() { if (width % BITS_PER_ELEMENT) set_prefix(width); else if (ARRAY_ELEMENTS > 1) memset(buffer, 0xff, sizeof(buffer)); else buffer[0] = ALL_BITS_SET; } void clear_all() { if (ARRAY_ELEMENTS > 1) memset(buffer, 0, sizeof(buffer)); else buffer[0]= 0; } void intersect(const Bitmap& map2) { for (size_t i= 0; i < ARRAY_ELEMENTS; i++) buffer[i] &= map2.buffer[i]; } private: /* Intersect with a bitmap represented as as longlong. In addition, pad the rest of the bitmap with 0 or 1 bits depending on pad_with_ones parameter. */ void intersect_and_pad(ulonglong map2buff, bool pad_with_ones) { buffer[0] &= map2buff; for (size_t i= 1; i < ARRAY_ELEMENTS; i++) buffer[i]= pad_with_ones ? ALL_BITS_SET : 0; if (ARRAY_ELEMENTS > 1 && (width % BITS_PER_ELEMENT) && pad_with_ones) buffer[ARRAY_ELEMENTS - 1]= last_element_mask(width); } public: void intersect(ulonglong map2buff) { intersect_and_pad(map2buff, 0); } /* Use highest bit for all bits above first element. */ void intersect_extended(ulonglong map2buff) { intersect_and_pad(map2buff, (map2buff & (1ULL << 63))); } void subtract(const Bitmap& map2) { for (size_t i= 0; i < ARRAY_ELEMENTS; i++) buffer[i] &= ~(map2.buffer[i]); } void merge(const Bitmap& map2) { for (size_t i= 0; i < ARRAY_ELEMENTS; i++) buffer[i] |= map2.buffer[i]; } bool is_clear_all() const { for (size_t i= 0; i < ARRAY_ELEMENTS; i++) if (buffer[i]) return false; return true; } bool is_subset(const Bitmap& map2) const { for (size_t i= 0; i < ARRAY_ELEMENTS; i++) if (buffer[i] & ~(map2.buffer[i])) return false; return true; } bool is_overlapping(const Bitmap& map2) const { for (size_t i= 0; i < ARRAY_ELEMENTS; i++) if (buffer[i] & map2.buffer[i]) return true; return false; } bool operator==(const Bitmap& map2) const { if (ARRAY_ELEMENTS > 1) return !memcmp(buffer,map2.buffer,sizeof(buffer)); return buffer[0] == map2.buffer[0]; } bool operator!=(const Bitmap& map2) const { return !(*this == map2); } /* Print hexadecimal representation of bitmap. Truncate trailing zeros. */ char *print(char *buf) const { size_t last; /*index of the last non-zero element, or 0. */ for (last= ARRAY_ELEMENTS - 1; last && !buffer[last]; last--){} const int HEX_DIGITS_PER_ELEMENT= BITS_PER_ELEMENT / 4; for (size_t i= 0; i < last; i++) { ulonglong num = buffer[i]; uint shift = BITS_PER_ELEMENT - 4; size_t pos= i * HEX_DIGITS_PER_ELEMENT; for (size_t j= 0; j < HEX_DIGITS_PER_ELEMENT; j++) { buf[pos + j]= _dig_vec_upper[(num >> shift) & 0xf]; shift += 4; } } longlong2str(buffer[last], buf, 16); return buf; } ulonglong to_ulonglong() const { return buffer[0]; } uint bits_set() { uint res= 0; for (size_t i= 0; i < ARRAY_ELEMENTS; i++) res += my_count_bits(buffer[i]); return res; } class Iterator { const Bitmap& map; uint offset; Table_map_iterator tmi; public: Iterator(const Bitmap& map2) : map(map2), offset(0), tmi(map2.buffer[0]) {} int operator++(int) { for (;;) { int nextbit= tmi++; if (nextbit != Table_map_iterator::BITMAP_END) return offset + nextbit; if (offset + BITS_PER_ELEMENT >= map.length()) return BITMAP_END; offset += BITS_PER_ELEMENT; tmi= Table_map_iterator(map.buffer[offset / BITS_PER_ELEMENT]); } } enum { BITMAP_END = width }; }; #ifdef NEED_GCC_NO_SSE_WORKAROUND #pragma GCC pop_options #undef NEED_GCC_NO_SSE_WORKAROUND #endif }; typedef Bitmap key_map; /* Used for finding keys */ #endif /* SQL_BITMAP_INCLUDED */ server/private/semisync_slave.h000064400000007225151031265040012724 0ustar00/* Copyright (c) 2006 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SEMISYNC_SLAVE_H #define SEMISYNC_SLAVE_H #include "semisync.h" #include "my_global.h" #include "sql_priv.h" #include "rpl_mi.h" #include "mysql.h" #include class Master_info; /** The extension class for the slave of semi-synchronous replication */ class Repl_semi_sync_slave :public Repl_semi_sync_base { public: Repl_semi_sync_slave() :m_slave_enabled(false) {} ~Repl_semi_sync_slave() = default; void set_trace_level(unsigned long trace_level) { m_trace_level = trace_level; } /* Initialize this class after MySQL parameters are initialized. this * function should be called once at bootstrap time. */ int init_object(); inline bool get_slave_enabled() { return m_slave_enabled; } void set_slave_enabled(bool enabled) { m_slave_enabled = enabled; } inline bool is_delay_master(){ return m_delay_master; } void set_delay_master(bool enabled) { m_delay_master = enabled; } void set_kill_conn_timeout(unsigned int timeout) { m_kill_conn_timeout = timeout; } /* A slave reads the semi-sync packet header and separate the metadata * from the payload data. * * Input: * header - (IN) packet header pointer * total_len - (IN) total packet length: metadata + payload * semi_flags - (IN) store flags: SEMI_SYNC_SLAVE_DELAY_SYNC and SEMI_SYNC_NEED_ACK * payload - (IN) payload: the replication event * payload_len - (IN) payload length * * Return: * 0: success; non-zero: error */ int slave_read_sync_header(const uchar *header, unsigned long total_len, int *semi_flags, const uchar **payload, unsigned long *payload_len); /* A slave replies to the master indicating its replication process. It * indicates that the slave has received all events before the specified * binlog position. */ int slave_reply(Master_info* mi); void slave_start(Master_info *mi); void slave_stop(Master_info *mi); void slave_reconnect(Master_info *mi); int request_transmit(Master_info *mi); void kill_connection(MYSQL *mysql); private: /* True when init_object has been called */ bool m_init_done; bool m_slave_enabled; /* semi-sync is enabled on the slave */ bool m_delay_master; unsigned int m_kill_conn_timeout; }; /* System and status variables for the slave component */ extern my_bool global_rpl_semi_sync_slave_enabled; extern ulong rpl_semi_sync_slave_trace_level; extern Repl_semi_sync_slave repl_semisync_slave; extern char rpl_semi_sync_slave_delay_master; extern unsigned int rpl_semi_sync_slave_kill_conn_timeout; extern unsigned long long rpl_semi_sync_slave_send_ack; extern int rpl_semi_sync_enabled(THD *thd, SHOW_VAR *var, void *buff, system_status_var *status_var, enum_var_type scope); #endif /* SEMISYNC_SLAVE_H */ server/private/sql_do.h000064400000001672151031265040011161 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_DO_INCLUDED #define SQL_DO_INCLUDED #include "sql_list.h" /* List */ class THD; class Item; bool mysql_do(THD *thd, List &values); #endif /* SQL_DO_INCLUDED */ server/private/opt_trace_context.h000064400000006333151031265040013423 0ustar00#ifndef OPT_TRACE_CONTEXT_INCLUDED #define OPT_TRACE_CONTEXT_INCLUDED #include "sql_array.h" class Opt_trace_context; struct Opt_trace_info; class Json_writer; class Opt_trace_stmt { public: /** Constructor, starts a trace for information_schema and dbug. @param ctx_arg context */ Opt_trace_stmt(Opt_trace_context *ctx_arg); ~Opt_trace_stmt(); void set_query(const char *query_ptr, size_t length, const CHARSET_INFO *charset); void open_struct(const char *key, char opening_bracket); void close_struct(const char *saved_key, char closing_bracket); void fill_info(Opt_trace_info* info); void add(const char *key, char *opening_bracket, size_t val_length); Json_writer* get_current_json() {return current_json;} void missing_privilege(); void disable_tracing_for_children(); void enable_tracing_for_children(); bool is_enabled() { return I_S_disabled == 0; } void set_allowed_mem_size(size_t mem_size); size_t get_length(); size_t get_truncated_bytes(); bool get_missing_priv() { return missing_priv; } private: Opt_trace_context *ctx; String query; // store the query sent by the user Json_writer *current_json; // stores the trace bool missing_priv; ///< whether user lacks privilege to see this trace /* 0 <=> this trace should be in information_schema. !=0 tracing is disabled, this currently happens when we want to trace a sub-statement. For now traces are only collect for the top statement not for the sub-statments. */ uint I_S_disabled; }; class Opt_trace_context { public: Opt_trace_context(); ~Opt_trace_context(); void start(THD *thd, TABLE_LIST *tbl, enum enum_sql_command sql_command, const char *query, size_t query_length, const CHARSET_INFO *query_charset, ulong max_mem_size_arg); void end(); void set_query(const char *query, size_t length, const CHARSET_INFO *charset); void delete_traces(); void set_allowed_mem_size(size_t mem_size); size_t remaining_mem_size(); private: Opt_trace_stmt* top_trace() { return *(traces.front()); } public: /* This returns the top trace from the list of traces. This function is used when we want to see the contents of the INFORMATION_SCHEMA.OPTIMIZER_TRACE table. */ Opt_trace_stmt* get_top_trace() { if (!traces.elements()) return NULL; return top_trace(); } /* This returns the current trace, to which we are still writing and has not been finished */ Json_writer* get_current_json() { if (!is_started()) return NULL; return current_trace->get_current_json(); } bool empty() { return static_cast(traces.elements()) == 0; } bool is_started() { return current_trace && current_trace->is_enabled(); } bool disable_tracing_if_required(); bool enable_tracing_if_required(); bool is_enabled(); void missing_privilege(); static const char *flag_names[]; enum { FLAG_DEFAULT = 0, FLAG_ENABLED = 1 << 0 }; private: /* List of traces (currently it stores only 1 trace) */ Dynamic_array traces; Opt_trace_stmt *current_trace; size_t max_mem_size; }; #endif /* OPT_TRACE_CONTEXT_INCLUDED */ server/private/field.h000064400000657137151031265040011000 0ustar00#ifndef FIELD_INCLUDED #define FIELD_INCLUDED /* Copyright (c) 2000, 2015, Oracle and/or its affiliates. Copyright (c) 2008, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Because of the function make_new_field() all field classes that have static variables must declare the size_of() member function. */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "mysqld.h" /* system_charset_info */ #include "table.h" /* TABLE */ #include "sql_string.h" /* String */ #include "my_decimal.h" /* my_decimal */ #include "sql_error.h" /* Sql_condition */ #include "compat56.h" #include "sql_type.h" /* Type_std_attributes */ #include "field_comp.h" class Send_field; class Copy_field; class Protocol; class Protocol_text; class Create_field; class Relay_log_info; class Field; class Column_statistics; class Column_statistics_collected; class Item_func; class Item_bool_func; class Item_equal; class Virtual_tmp_table; class Qualified_column_ident; class Table_ident; class SEL_ARG; class RANGE_OPT_PARAM; struct KEY_PART; struct SORT_FIELD; struct SORT_FIELD_ATTR; enum enum_check_fields { CHECK_FIELD_IGNORE, CHECK_FIELD_EXPRESSION, CHECK_FIELD_WARN, CHECK_FIELD_ERROR_FOR_NULL, }; enum ignore_value_reaction { IGNORE_MEANS_ERROR, IGNORE_MEANS_DEFAULT, IGNORE_MEANS_FIELD_VALUE }; ignore_value_reaction find_ignore_reaction(THD *thd); enum enum_conv_type { CONV_TYPE_PRECISE, CONV_TYPE_VARIANT, CONV_TYPE_SUBSET_TO_SUPERSET, CONV_TYPE_SUPERSET_TO_SUBSET, CONV_TYPE_IMPOSSIBLE }; class Conv_param { uint16 m_table_def_flags; public: Conv_param(uint16 table_def_flags) :m_table_def_flags(table_def_flags) { } uint16 table_def_flags() const { return m_table_def_flags; } }; class Conv_source: public Type_handler_hybrid_field_type { uint16 m_metadata; CHARSET_INFO *m_cs; public: Conv_source(const Type_handler *h, uint16 metadata, CHARSET_INFO *cs) :Type_handler_hybrid_field_type(h), m_metadata(metadata), m_cs(cs) { DBUG_ASSERT(cs); } uint16 metadata() const { return m_metadata; } uint mbmaxlen() const { return m_cs->mbmaxlen; } }; /* Common declarations for Field and Item */ class Value_source { protected: // Parameters for warning and note generation class Warn_filter { bool m_want_warning_edom; bool m_want_note_truncated_spaces; public: Warn_filter(bool want_warning_edom, bool want_note_truncated_spaces) : m_want_warning_edom(want_warning_edom), m_want_note_truncated_spaces(want_note_truncated_spaces) { } Warn_filter(const THD *thd); bool want_warning_edom() const { return m_want_warning_edom; } bool want_note_truncated_spaces() const { return m_want_note_truncated_spaces; } }; class Warn_filter_all: public Warn_filter { public: Warn_filter_all() :Warn_filter(true, true) { } }; class Converter_double_to_longlong { protected: bool m_error; longlong m_result; public: Converter_double_to_longlong(double nr, bool unsigned_flag); longlong result() const { return m_result; } bool error() const { return m_error; } void push_warning(THD *thd, double nr, bool unsigned_flag); }; class Converter_double_to_longlong_with_warn: public Converter_double_to_longlong { public: Converter_double_to_longlong_with_warn(THD *thd, double nr, bool unsigned_flag) :Converter_double_to_longlong(nr, unsigned_flag) { if (m_error) push_warning(thd, nr, unsigned_flag); } Converter_double_to_longlong_with_warn(double nr, bool unsigned_flag) :Converter_double_to_longlong(nr, unsigned_flag) { if (m_error) push_warning(current_thd, nr, unsigned_flag); } }; // String-to-number converters class Converter_string_to_number { protected: char *m_end_of_num; // Where the low-level conversion routine stopped int m_error; // The error code returned by the low-level routine bool m_edom; // If EDOM-alike error happened during conversion /** Check string-to-number conversion and produce a warning if - could not convert any digits (EDOM-alike error) - found garbage at the end of the string - found extra spaces at the end (a note) See also Field_num::check_edom_and_truncation() for a similar function. @param thd - the thread that will be used to generate warnings. Can be NULL (which means current_thd will be used if a warning is really necessary). @param type - name of the data type (e.g. "INTEGER", "DECIMAL", "DOUBLE") @param cs - character set of the original string @param str - the original string @param end - the end of the string @param allow_notes - tells if trailing space notes should be displayed or suppressed. Unlike Field_num::check_edom_and_truncation(), this function does not distinguish between EDOM and truncation and reports the same warning for both cases. Perhaps we should eventually print different warnings, to make the explicit CAST work closer to the implicit cast in Field_xxx::store(). */ void check_edom_and_truncation(THD *thd, Warn_filter filter, const char *type, CHARSET_INFO *cs, const char *str, size_t length) const; public: int error() const { return m_error; } }; class Converter_strntod: public Converter_string_to_number { double m_result; public: Converter_strntod(CHARSET_INFO *cs, const char *str, size_t length) { m_result= cs->strntod((char *) str, length, &m_end_of_num, &m_error); // strntod() does not set an error if the input string was empty m_edom= m_error !=0 || str == m_end_of_num; } double result() const { return m_result; } }; class Converter_string_to_longlong: public Converter_string_to_number { protected: longlong m_result; public: longlong result() const { return m_result; } }; class Converter_strntoll: public Converter_string_to_longlong { public: Converter_strntoll(CHARSET_INFO *cs, const char *str, size_t length) { m_result= cs->strntoll(str, length, 10, &m_end_of_num, &m_error); /* All non-zero errors means EDOM error. strntoll() does not set an error if the input string was empty. Check it here. Notice the different with the same condition in Converter_strntoll10. */ m_edom= m_error != 0 || str == m_end_of_num; } }; class Converter_strtoll10: public Converter_string_to_longlong { public: Converter_strtoll10(CHARSET_INFO *cs, const char *str, size_t length) { m_end_of_num= (char *) str + length; m_result= cs->strtoll10(str, &m_end_of_num, &m_error); /* Negative error means "good negative number". Only a positive m_error value means a real error. strtoll10() sets error to MY_ERRNO_EDOM in case of an empty string, so we don't have to additionally catch empty strings here. */ m_edom= m_error > 0; } }; class Converter_str2my_decimal: public Converter_string_to_number { public: Converter_str2my_decimal(uint mask, CHARSET_INFO *cs, const char *str, size_t length, my_decimal *buf) { DBUG_ASSERT(length < UINT_MAX32); m_error= str2my_decimal(mask, str, length, cs, buf, (const char **) &m_end_of_num); // E_DEC_TRUNCATED means a very minor truncation: '1e-100' -> 0 m_edom= m_error && m_error != E_DEC_TRUNCATED; } }; // String-to-number converters with automatic warning generation class Converter_strntod_with_warn: public Converter_strntod { public: Converter_strntod_with_warn(THD *thd, Warn_filter filter, CHARSET_INFO *cs, const char *str, size_t length) :Converter_strntod(cs, str, length) { check_edom_and_truncation(thd, filter, "DOUBLE", cs, str, length); } }; class Converter_strntoll_with_warn: public Converter_strntoll { public: Converter_strntoll_with_warn(THD *thd, Warn_filter filter, CHARSET_INFO *cs, const char *str, size_t length) :Converter_strntoll(cs, str, length) { check_edom_and_truncation(thd, filter, "INTEGER", cs, str, length); } }; class Converter_strtoll10_with_warn: public Converter_strtoll10 { public: Converter_strtoll10_with_warn(THD *thd, Warn_filter filter, CHARSET_INFO *cs, const char *str, size_t length) :Converter_strtoll10(cs, str, length) { check_edom_and_truncation(thd, filter, "INTEGER", cs, str, length); } }; class Converter_str2my_decimal_with_warn: public Converter_str2my_decimal { public: Converter_str2my_decimal_with_warn(THD *thd, Warn_filter filter, uint mask, CHARSET_INFO *cs, const char *str, size_t length, my_decimal *buf) :Converter_str2my_decimal(mask, cs, str, length, buf) { check_edom_and_truncation(thd, filter, "DECIMAL", cs, str, length); } }; // String-to-number conversion methods for the old code compatibility longlong longlong_from_string_with_check(CHARSET_INFO *cs, const char *cptr, const char *end) const { /* TODO: Give error if we wanted a signed integer and we got an unsigned one Notice, longlong_from_string_with_check() honors thd->no_error, because it's used to handle queries like this: SELECT COUNT(@@basedir); and is called when Item_func_get_system_var::update_null_value() suppresses warnings and then calls val_int(). The other methods {double|decimal}_from_string_with_check() ignore thd->no_errors, because they are not used for update_null_value() and they always allow all kind of warnings. */ THD *thd= current_thd; return Converter_strtoll10_with_warn(thd, Warn_filter(thd), cs, cptr, end - cptr).result(); } double double_from_string_with_check(CHARSET_INFO *cs, const char *cptr, const char *end) const { return Converter_strntod_with_warn(NULL, Warn_filter_all(), cs, cptr, end - cptr).result(); } my_decimal *decimal_from_string_with_check(my_decimal *decimal_value, CHARSET_INFO *cs, const char *cptr, const char *end) { Converter_str2my_decimal_with_warn(NULL, Warn_filter_all(), E_DEC_FATAL_ERROR & ~E_DEC_BAD_NUM, cs, cptr, end - cptr, decimal_value); return decimal_value; } longlong longlong_from_hex_hybrid(const char *str, size_t length) { const char *end= str + length; const char *ptr= end - MY_MIN(length, sizeof(longlong)); ulonglong value= 0; for ( ; ptr != end ; ptr++) value= (value << 8) + (ulonglong) (uchar) *ptr; return (longlong) value; } longlong longlong_from_string_with_check(const String *str) const { return longlong_from_string_with_check(str->charset(), str->ptr(), str->end()); } double double_from_string_with_check(const String *str) const { return double_from_string_with_check(str->charset(), str->ptr(), str->end()); } my_decimal *decimal_from_string_with_check(my_decimal *decimal_value, const String *str) { return decimal_from_string_with_check(decimal_value, str->charset(), str->ptr(), str->end()); } // End of String-to-number conversion methods public: /* The enumeration Subst_constraint is currently used only in implementations of the virtual function subst_argument_checker. */ enum Subst_constraint { ANY_SUBST, /* Any substitution for a field is allowed */ IDENTITY_SUBST /* Substitution for a field is allowed if any two different values of the field type are not equal */ }; /* Item context attributes. Comparison functions pass their attributes to propagate_equal_fields(). For example, for string comparison, the collation of the comparison operation is important inside propagate_equal_fields(). */ class Context { /* Which type of propagation is allowed: - ANY_SUBST (loose equality, according to the collation), or - IDENTITY_SUBST (strict binary equality). */ Subst_constraint m_subst_constraint; /* Comparison type. Important only when ANY_SUBSTS. */ const Type_handler *m_compare_handler; /* Collation of the comparison operation. Important only when ANY_SUBST. */ CHARSET_INFO *m_compare_collation; public: Context(Subst_constraint subst, const Type_handler *h, CHARSET_INFO *cs) :m_subst_constraint(subst), m_compare_handler(h), m_compare_collation(cs) { DBUG_ASSERT(h == h->type_handler_for_comparison()); } Subst_constraint subst_constraint() const { return m_subst_constraint; } const Type_handler *compare_type_handler() const { DBUG_ASSERT(m_subst_constraint == ANY_SUBST); return m_compare_handler; } CHARSET_INFO *compare_collation() const { DBUG_ASSERT(m_subst_constraint == ANY_SUBST); return m_compare_collation; } }; class Context_identity: public Context { // Use this to request only exact value, no invariants. public: Context_identity() :Context(IDENTITY_SUBST, &type_handler_long_blob, &my_charset_bin) { } }; class Context_boolean: public Context { // Use this when an item is [a part of] a boolean expression public: Context_boolean() :Context(ANY_SUBST, &type_handler_slonglong, &my_charset_bin) { } }; }; #define STORAGE_TYPE_MASK 7 #define COLUMN_FORMAT_MASK 7 #define COLUMN_FORMAT_SHIFT 3 /* The length of the header part for each virtual column in the .frm file */ #define FRM_VCOL_OLD_HEADER_SIZE(b) (3 + MY_TEST(b)) #define FRM_VCOL_NEW_BASE_SIZE 16 #define FRM_VCOL_NEW_HEADER_SIZE 6 class Count_distinct_field; struct ha_field_option_struct; struct st_cache_field; int field_conv(Field *to,Field *from); int truncate_double(double *nr, uint field_length, decimal_digits_t dec, bool unsigned_flag, double max_value); inline uint get_enum_pack_length(int elements) { return elements < 256 ? 1 : 2; } inline uint get_set_pack_length(int elements) { uint len= (elements + 7) / 8; return len > 4 ? 8 : len; } /** Tests if field type is temporal and has date part, i.e. represents DATE, DATETIME or TIMESTAMP types in SQL. @param type Field type, as returned by field->type(). @retval true If field type is temporal type with date part. @retval false If field type is not temporal type with date part. */ inline bool is_temporal_type_with_date(enum_field_types type) { switch (type) { case MYSQL_TYPE_DATE: case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: return true; case MYSQL_TYPE_DATETIME2: case MYSQL_TYPE_TIMESTAMP2: DBUG_ASSERT(0); // field->real_type() should not get to here. return false; default: return false; } } enum enum_vcol_info_type { VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED, VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE, VCOL_USING_HASH, /* Additional types should be added here */ VCOL_GENERATED_VIRTUAL_INDEXED, // this is never written in .frm /* Following is the highest value last */ VCOL_TYPE_NONE = 127 // Since the 0 value is already in use }; static inline const char *vcol_type_name(enum_vcol_info_type type) { switch (type) { case VCOL_GENERATED_VIRTUAL: case VCOL_GENERATED_VIRTUAL_INDEXED: case VCOL_GENERATED_STORED: return "GENERATED ALWAYS AS"; case VCOL_DEFAULT: return "DEFAULT"; case VCOL_CHECK_FIELD: case VCOL_CHECK_TABLE: return "CHECK"; case VCOL_USING_HASH: return "USING HASH"; case VCOL_TYPE_NONE: return "UNTYPED"; } return 0; } /* Flags for Virtual_column_info. If none is set, the expression must be a constant with no side-effects, so it's calculated at CREATE TABLE time, stored in table->record[2], and not recalculated for every statement. */ #define VCOL_FIELD_REF 1 #define VCOL_NON_DETERMINISTIC 2 #define VCOL_SESSION_FUNC 4 /* uses session data, e.g. USER or DAYNAME */ #define VCOL_TIME_FUNC 8 /* safe for SBR */ #define VCOL_AUTO_INC 16 #define VCOL_IMPOSSIBLE 32 #define VCOL_NEXTVAL 64 /* NEXTVAL is not implemented for vcols */ #define VCOL_NOT_STRICTLY_DETERMINISTIC \ (VCOL_NON_DETERMINISTIC | VCOL_TIME_FUNC | VCOL_SESSION_FUNC) /* Virtual_column_info is the class to contain additional characteristics that is specific for a virtual/computed field such as: - the defining expression that is evaluated to compute the value of the field - whether the field is to be stored in the database - whether the field is used in a partitioning expression */ class Virtual_column_info: public Sql_alloc, private Type_handler_hybrid_field_type { private: enum_vcol_info_type vcol_type; /* Virtual column expression type */ /* The following data is only updated by the parser and read when a Create_field object is created/initialized. */ /* Flag indicating that the field used in a partitioning expression */ bool in_partitioning_expr; public: /* Flag indicating that the field is physically stored in the database */ bool stored_in_db; bool utf8; /* Already in utf8 */ bool automatic_name; bool if_not_exists; Item *expr; Lex_ident name; /* Name of constraint */ /* see VCOL_* (VCOL_FIELD_REF, ...) */ uint flags; Virtual_column_info() :Type_handler_hybrid_field_type(&type_handler_null), vcol_type((enum_vcol_info_type)VCOL_TYPE_NONE), in_partitioning_expr(FALSE), stored_in_db(FALSE), utf8(TRUE), automatic_name(FALSE), expr(NULL), flags(0) { name.str= NULL; name.length= 0; }; Virtual_column_info* clone(THD *thd); ~Virtual_column_info() = default; enum_vcol_info_type get_vcol_type() const { return vcol_type; } void set_vcol_type(enum_vcol_info_type v_type) { vcol_type= v_type; } const char *get_vcol_type_name() const { DBUG_ASSERT(vcol_type != VCOL_TYPE_NONE); return vcol_type_name(vcol_type); } void set_handler(const Type_handler *handler) { /* Calling this function can only be done once. */ DBUG_ASSERT(type_handler() == &type_handler_null); Type_handler_hybrid_field_type::set_handler(handler); } bool is_stored() const { return stored_in_db; } void set_stored_in_db_flag(bool stored) { stored_in_db= stored; } bool is_in_partitioning_expr() const { return in_partitioning_expr; } void mark_as_in_partitioning_expr() { in_partitioning_expr= TRUE; } bool need_refix() const { return flags & VCOL_SESSION_FUNC; } bool fix_expr(THD *thd); bool fix_session_expr(THD *thd); bool cleanup_session_expr(); bool fix_and_check_expr(THD *thd, TABLE *table); bool check_access(THD *thd); inline bool is_equal(const Virtual_column_info* vcol) const; /* Same as is_equal() but for comparing with different table */ bool is_equivalent(THD *thd, TABLE_SHARE *share, TABLE_SHARE *vcol_share, const Virtual_column_info* vcol, bool &error) const; inline void print(String*); }; class Binlog_type_info { public: enum binlog_sign_t { SIGN_SIGNED, SIGN_UNSIGNED, SIGN_NOT_APPLICABLE // for non-numeric types }; /** Retrieve the field metadata for fields. */ CHARSET_INFO *m_cs; // NULL if not relevant TYPELIB *m_enum_typelib; // NULL if not relevant TYPELIB *m_set_typelib; // NULL if not relevant binlog_sign_t m_signedness; uint16 m_metadata; uint8 m_metadata_size; uchar m_type_code; // according to Field::binlog_type() uchar m_geom_type; // Non-geometry fields can return 0 Binlog_type_info(uchar type_code, uint16 metadata, uint8 metadata_size) :m_cs(NULL), m_enum_typelib(NULL), m_set_typelib(NULL), m_signedness(SIGN_NOT_APPLICABLE), m_metadata(metadata), m_metadata_size(metadata_size), m_type_code(type_code), m_geom_type(0) {}; Binlog_type_info(uchar type_code, uint16 metadata, uint8 metadata_size, binlog_sign_t signedness) : m_cs(NULL), m_enum_typelib(NULL), m_set_typelib(NULL), m_signedness(signedness), m_metadata(metadata), m_metadata_size(metadata_size), m_type_code(type_code), m_geom_type(0) {}; Binlog_type_info(uchar type_code, uint16 metadata, uint8 metadata_size, CHARSET_INFO *cs) :m_cs(cs), m_enum_typelib(NULL), m_set_typelib(NULL), m_signedness(SIGN_NOT_APPLICABLE), m_metadata(metadata), m_metadata_size(metadata_size), m_type_code(type_code), m_geom_type(0) {}; Binlog_type_info(uchar type_code, uint16 metadata, uint8 metadata_size, CHARSET_INFO *cs, TYPELIB *t_enum, TYPELIB *t_set) :m_cs(cs), m_enum_typelib(t_enum), m_set_typelib(t_set), m_signedness(SIGN_NOT_APPLICABLE), m_metadata(metadata), m_metadata_size(metadata_size), m_type_code(type_code), m_geom_type(0) {}; Binlog_type_info(uchar type_code, uint16 metadata, uint8 metadata_size, CHARSET_INFO *cs, uchar geom_type) :m_cs(cs), m_enum_typelib(NULL), m_set_typelib(NULL), m_signedness(SIGN_NOT_APPLICABLE), m_metadata(metadata), m_metadata_size(metadata_size), m_type_code(type_code), m_geom_type(geom_type) {}; static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return alloc_root(mem_root, size); } }; class Binlog_type_info_fixed_string: public Binlog_type_info { public: Binlog_type_info_fixed_string(uchar type_code, uint32 octet_length, CHARSET_INFO *cs); }; class Field: public Value_source { Field(const Item &); /* Prevent use of these */ void operator=(Field &); protected: int save_in_field_str(Field *to) { StringBuffer result(charset()); val_str(&result); return to->store(result.ptr(), result.length(), charset()); } void error_generated_column_function_is_not_allowed(THD *thd, bool error) const; static void do_field_eq(Copy_field *copy); static void do_field_int(Copy_field *copy); static void do_field_real(Copy_field *copy); static void do_field_string(Copy_field *copy); static void do_field_date(Copy_field *copy); static void do_field_temporal(Copy_field *copy, date_mode_t fuzzydate); static void do_field_datetime(Copy_field *copy); static void do_field_timestamp(Copy_field *copy); static void do_field_decimal(Copy_field *copy); public: static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return alloc_root(mem_root, size); } static void *operator new(size_t size) throw () { DBUG_ASSERT(size < UINT_MAX32); return thd_alloc(current_thd, (uint) size); } static void operator delete(void *ptr_arg, size_t size) { TRASH_FREE(ptr_arg, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) { DBUG_ASSERT(0); } bool marked_for_read() const; bool marked_for_write_or_computed() const; /** Used by System Versioning. */ virtual void set_max() { DBUG_ASSERT(0); } virtual bool is_max() { DBUG_ASSERT(0); return false; } uchar *ptr; // Position to field in record /** Byte where the @c NULL bit is stored inside a record. If this Field is a @c NOT @c NULL field, this member is @c NULL. */ uchar *null_ptr; /* Note that you can use table->in_use as replacement for current_thd member only inside of val_*() and store() members (e.g. you can't use it in cons) */ TABLE *table; // Pointer for table TABLE *orig_table; // Pointer to original table const char * const *table_name; // Pointer to alias in TABLE LEX_CSTRING field_name; LEX_CSTRING comment; /** reference to the list of options or NULL */ engine_option_value *option_list; ha_field_option_struct *option_struct; /* structure with parsed options */ /* Field is part of the following keys */ key_map key_start, part_of_key, part_of_key_not_clustered; /* Bitmap of indexes that have records ordered by col1, ... this_field, ... For example, INDEX (col(prefix_n)) is not present in col.part_of_sortkey. */ key_map part_of_sortkey; /* We use three additional unireg types for TIMESTAMP to overcome limitation of current binary format of .frm file. We'd like to be able to support NOW() as default and on update value for such fields but unable to hold this info anywhere except unireg_check field. This issue will be resolved in more clean way with transition to new text based .frm format. See also comment for Field_timestamp::Field_timestamp(). */ enum __attribute__((packed)) utype { NONE=0, NEXT_NUMBER=15, // AUTO_INCREMENT TIMESTAMP_OLD_FIELD=18, // TIMESTAMP created before 4.1.3 TIMESTAMP_DN_FIELD=21, // TIMESTAMP DEFAULT NOW() TIMESTAMP_UN_FIELD=22, // TIMESTAMP ON UPDATE NOW() TIMESTAMP_DNUN_FIELD=23, // TIMESTAMP DEFAULT NOW() ON UPDATE NOW() TMYSQL_COMPRESSED= 24, // Compatibility with TMySQL }; enum imagetype { itRAW, itMBR}; utype unireg_check; field_visibility_t invisible; uint32 field_length; // Length of field uint32 flags; field_index_t field_index; // field number in fields array uchar null_bit; // Bit used to test null bit /** If true, this field was created in create_tmp_field_from_item from a NULL value. This means that the type of the field is just a guess, and the type may be freely coerced to another type. @see create_tmp_field_from_item @see Item_type_holder::get_real_type */ bool is_created_from_null_item; /* Selectivity of the range condition over this field. When calculating this selectivity a range predicate is taken into account only if: - it is extracted from the WHERE clause - it depends only on the table the field belongs to */ double cond_selectivity; /* The next field in the class of equal fields at the top AND level of the WHERE clause */ Field *next_equal_field; /* This structure is used for statistical data on the column that has been read from the statistical table column_stat */ Column_statistics *read_stats; /* This structure is used for statistical data on the column that is collected by the function collect_statistics_for_table */ Column_statistics_collected *collected_stats; /* This is additional data provided for any computed(virtual) field, default function or check constraint. In particular it includes a pointer to the item by which this field can be computed from other fields. */ Virtual_column_info *vcol_info, *check_constraint, *default_value; Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg); virtual ~Field() = default; virtual Type_numeric_attributes type_numeric_attributes() const { return Type_numeric_attributes(field_length, decimals(), is_unsigned()); } Type_std_attributes type_std_attributes() const { return Type_std_attributes(type_numeric_attributes(), dtcollation()); } bool is_unsigned() const { return flags & UNSIGNED_FLAG; } /** Convenience definition of a copy function returned by Field::get_copy_func() */ typedef void Copy_func(Copy_field*); virtual Copy_func *get_copy_func(const Field *from) const= 0; virtual Copy_func *get_copy_func_to(const Field *to) const { return to->get_copy_func(this); } /* Store functions returns 1 on overflow and -1 on fatal error */ virtual int store_field(Field *from) { return from->save_in_field(this); } virtual int save_in_field(Field *to)= 0; /** Check if it is possible just copy the value of the field 'from' to the field 'this', e.g. for INSERT INTO t1 (field1) SELECT field2 FROM t2; @param from - The field to copy from @retval true - it is possible to just copy value of 'from' to 'this' @retval false - conversion is needed */ virtual bool memcpy_field_possible(const Field *from) const= 0; virtual bool make_empty_rec_store_default_value(THD *thd, Item *item); virtual void make_empty_rec_reset(THD *thd) { reset(); } virtual int store(const char *to, size_t length,CHARSET_INFO *cs)=0; /* This is used by engines like CSV and Federated to signal the field that the data is going to be in text (rather than binary) representation, even if cs points to &my_charset_bin. If a Field distinguishes between text and binary formats (e.g. INET6), we cannot call store(str,length,&my_charset_bin), to avoid "field" mis-interpreting the data format as binary. */ virtual int store_text(const char *to, size_t length, CHARSET_INFO *cs) { return store(to, length, cs); } virtual int store_binary(const char *to, size_t length) { return store(to, length, &my_charset_bin); } virtual int store_hex_hybrid(const char *str, size_t length); virtual int store(double nr)=0; virtual int store(longlong nr, bool unsigned_val)=0; virtual int store_decimal(const my_decimal *d)=0; virtual int store_time_dec(const MYSQL_TIME *ltime, uint dec); virtual int store_timestamp_dec(const timeval &ts, uint dec); int store_timestamp(my_time_t timestamp, ulong sec_part) { return store_timestamp_dec(Timeval(timestamp, sec_part), TIME_SECOND_PART_DIGITS); } /** Store a value represented in native format */ virtual int store_native(const Native &value) { DBUG_ASSERT(0); reset(); return 0; } int store_time(const MYSQL_TIME *ltime) { return store_time_dec(ltime, TIME_SECOND_PART_DIGITS); } int store(const char *to, size_t length, CHARSET_INFO *cs, enum_check_fields check_level); int store_text(const char *to, size_t length, CHARSET_INFO *cs, enum_check_fields check_level); int store(const LEX_STRING *ls, CHARSET_INFO *cs) { DBUG_ASSERT(ls->length < UINT_MAX32); return store(ls->str, (uint) ls->length, cs); } int store(const LEX_CSTRING *ls, CHARSET_INFO *cs) { DBUG_ASSERT(ls->length < UINT_MAX32); return store(ls->str, (uint) ls->length, cs); } int store(const LEX_CSTRING &ls, CHARSET_INFO *cs) { DBUG_ASSERT(ls.length < UINT_MAX32); return store(ls.str, (uint) ls.length, cs); } /* @brief Store minimum/maximum value of a column in the statistics table. @param field statistical table field str value buffer */ virtual int store_to_statistical_minmax_field(Field *field, String *str); /* @brief Store minimum/maximum value of a column from the statistical table. @param field statistical table field str value buffer */ virtual int store_from_statistical_minmax_field(Field *field, String *str, MEM_ROOT *mem); #ifdef HAVE_MEM_CHECK /** Mark unused memory in the field as defined. Mainly used to ensure that if we write full field to disk (for example in Count_distinct_field::add(), we don't write unitalized data to disk which would confuse valgrind or MSAN. */ virtual void mark_unused_memory_as_defined() {} #else void mark_unused_memory_as_defined() {} #endif virtual double val_real()=0; virtual longlong val_int()=0; /* Get ulonglong representation. Negative values are truncated to 0. */ virtual ulonglong val_uint(void) { longlong nr= val_int(); return nr < 0 ? 0 : (ulonglong) nr; } virtual bool val_bool()= 0; virtual my_decimal *val_decimal(my_decimal *)=0; inline String *val_str(String *str) { return val_str(str, str); } /* val_str(buf1, buf2) gets two buffers and should use them as follows: if it needs a temp buffer to convert result to string - use buf1 example Field_tiny::val_str() if the value exists as a string already - use buf2 example Field_string::val_str() consequently, buf2 may be created as 'String buf;' - no memory will be allocated for it. buf1 will be allocated to hold a value if it's too small. Using allocated buffer for buf2 may result in an unnecessary free (and later, may be an alloc). This trickery is used to decrease a number of malloc calls. */ virtual String *val_str(String*,String *)=0; virtual bool val_native(Native *to) { DBUG_ASSERT(!is_null()); return to->copy((const char *) ptr, pack_length()); } String *val_int_as_str(String *val_buffer, bool unsigned_flag); /* Return the field value as a LEX_CSTRING, without padding to full length (MODE_PAD_CHAR_TO_FULL_LENGTH is temporarily suppressed during the call). In case of an empty value, to[0] is assigned to empty_clex_string, memory is not allocated. In case of a non-empty value, the memory is allocated on mem_root. In case of a memory allocation failure, to[0] is assigned to {NULL,0}. @param [IN] mem_root store non-empty values here @param [OUT to return the string here @retval false (success) @retval true (EOM) */ bool val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to); fast_field_copier get_fast_field_copier(const Field *from); /* str_needs_quotes() returns TRUE if the value returned by val_str() needs to be quoted when used in constructing an SQL query. */ virtual bool str_needs_quotes() const { return false; } const Type_handler *type_handler_for_comparison() const { return type_handler()->type_handler_for_comparison(); } Item_result result_type () const { return type_handler()->result_type(); } Item_result cmp_type () const { return type_handler()->cmp_type(); } virtual bool eq(Field *field) { return (ptr == field->ptr && null_ptr == field->null_ptr && null_bit == field->null_bit && field->type() == type()); } virtual bool eq_def(const Field *field) const; /* pack_length() returns size (in bytes) used to store field data in memory (i.e. it returns the maximum size of the field in a row of the table, which is located in RAM). */ virtual uint32 pack_length() const { return (uint32) field_length; } /* pack_length_in_rec() returns size (in bytes) used to store field data on storage (i.e. it returns the maximal size of the field in a row of the table, which is located on disk). */ virtual uint32 pack_length_in_rec() const { return pack_length(); } virtual bool compatible_field_size(uint metadata, const Relay_log_info *rli, uint16 mflags, int *order) const; virtual uint pack_length_from_metadata(uint field_metadata) const { DBUG_ENTER("Field::pack_length_from_metadata"); DBUG_RETURN(field_metadata); } virtual uint row_pack_length() const { return 0; } /* data_length() return the "real size" of the data in memory. */ virtual uint32 data_length() { return pack_length(); } virtual uint32 sort_length() const { return pack_length(); } /* sort_suffix_length() return the length bytes needed to store the length for binary charset */ virtual uint32 sort_suffix_length() const { return 0; } /* Get the number bytes occupied by the value in the field. CHAR values are stripped of trailing spaces. Flexible values are stripped of their length. */ virtual uint32 value_length() { uint len; if (!zero_pack() && (type() == MYSQL_TYPE_STRING && (len= pack_length()) >= 4 && len < 256)) { uchar *str, *end; for (str= ptr, end= str+len; end > str && end[-1] == ' '; end--) {} len=(uint) (end-str); return len; } return data_length(); } /** Get the maximum size of the data in packed format. @return Maximum data length of the field when packed using the Field::pack() function. */ virtual uint32 max_data_length() const { return pack_length(); }; virtual int reset() { bzero(ptr,pack_length()); return 0; } virtual void reset_fields() {} const uchar *ptr_in_record(const uchar *record) const { my_ptrdiff_t l_offset= (my_ptrdiff_t) (ptr - table->record[0]); DBUG_ASSERT(l_offset >= 0 && table->s->rec_buff_length - l_offset > 0); return record + l_offset; } virtual int set_default(); bool has_update_default_function() const { return flags & ON_UPDATE_NOW_FLAG; } bool has_default_now_unireg_check() const { return unireg_check == TIMESTAMP_DN_FIELD || unireg_check == TIMESTAMP_DNUN_FIELD; } /* Mark the field as having a value supplied by the client, thus it should not be auto-updated. */ void set_has_explicit_value() { bitmap_set_bit(&table->has_value_set, field_index); } bool has_explicit_value() { return bitmap_is_set(&table->has_value_set, field_index); } void clear_has_explicit_value() { bitmap_clear_bit(&table->has_value_set, field_index); } virtual my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const { DBUG_ASSERT(0); return 0; } my_time_t get_timestamp(ulong *sec_part) const { return get_timestamp(ptr, sec_part); } virtual bool binary() const { return 1; } virtual bool zero_pack() const { return 1; } virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } virtual uint16 key_part_flag() const { return 0; } virtual uint16 key_part_length_bytes() const { return 0; } virtual uint32 key_length() const { return pack_length(); } virtual const Type_handler *type_handler() const = 0; virtual enum_field_types type() const { return type_handler()->field_type(); } virtual enum_field_types real_type() const { return type_handler()->real_field_type(); } virtual enum_field_types binlog_type() const { /* Binlog stores field->type() as type code by default. For example, it puts MYSQL_TYPE_STRING in case of CHAR, VARCHAR, SET and ENUM, with extra data type details put into metadata. Binlog behaviour slightly differs between various MySQL and MariaDB versions for the temporal data types TIME, DATETIME and TIMESTAMP. MySQL prior to 5.6 uses MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP type codes in binlog and stores no additional metadata. MariaDB-5.3 implements new versions for TIME, DATATIME, TIMESTAMP with fractional second precision, but uses the old format for the types TIME(0), DATETIME(0), TIMESTAMP(0), and it still stores MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP in binlog, with no additional metadata. So row-based replication between temporal data types of different precision is not possible in MariaDB. MySQL-5.6 also implements a new version of TIME, DATETIME, TIMESTAMP which support fractional second precision 0..6, and use the new format even for the types TIME(0), DATETIME(0), TIMESTAMP(0). For these new data types, MySQL-5.6 stores new type codes MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, MYSQL_TYPE_TIMESTAMP2 in binlog, with fractional precision 0..6 put into metadata. This makes it in theory possible to do row-based replication between columns of different fractional precision (e.g. from TIME(1) on master to TIME(6) on slave). However, it's not currently fully implemented yet. MySQL-5.6 can only do row-based replication from the old types TIME, DATETIME, TIMESTAMP (represented by MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP type codes in binlog) to the new corresponding types TIME(0), DATETIME(0), TIMESTAMP(0). Note: MariaDB starting from the version 10.0 understands the new MySQL-5.6 type codes MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, MYSQL_TYPE_TIMESTAMP2. When started over MySQL-5.6 tables both on master and on slave, MariaDB-10.0 can also do row-based replication from the old types TIME, DATETIME, TIMESTAMP to the new MySQL-5.6 types TIME(0), DATETIME(0), TIMESTAMP(0). Note: perhaps binlog should eventually be modified to store real_type() instead of type() for all column types. */ return type(); } virtual Binlog_type_info binlog_type_info() const { DBUG_ASSERT(Field::type() == binlog_type()); return Binlog_type_info(Field::type(), 0, 0); } virtual en_fieldtype tmp_engine_column_type(bool use_packed_rows) const { return FIELD_NORMAL; } /* Conversion type for from the source to the current field. */ virtual enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const= 0; enum_conv_type rpl_conv_type_from_same_data_type(uint16 metadata, const Relay_log_info *rli, const Conv_param ¶m) const; inline int cmp(const uchar *str) const { return cmp(ptr,str); } /* The following method is used for comparing prefix keys. Currently it's only used in partitioning. */ virtual int cmp_prefix(const uchar *a, const uchar *b, size_t prefix_char_len) const { return cmp(a, b); } virtual int cmp(const uchar *,const uchar *) const=0; virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) const { return memcmp(a,b,pack_length()); } virtual int cmp_offset(my_ptrdiff_t row_offset) { return cmp(ptr,ptr+row_offset); } virtual int cmp_binary_offset(uint row_offset) { return cmp_binary(ptr, ptr+row_offset); }; virtual int key_cmp(const uchar *a,const uchar *b) const { return cmp(a, b); } virtual int key_cmp(const uchar *str, uint length) const { return cmp(ptr,str); } /* Update the value m of the 'min_val' field with the current value v of this field if force_update is set to TRUE or if v < m. Return TRUE if the value has been updated. */ virtual bool update_min(Field *min_val, bool force_update) { bool update_fl= force_update || cmp(ptr, min_val->ptr) < 0; if (update_fl) { min_val->set_notnull(); memcpy(min_val->ptr, ptr, pack_length()); } return update_fl; } /* Update the value m of the 'max_val' field with the current value v of this field if force_update is set to TRUE or if v > m. Return TRUE if the value has been updated. */ virtual bool update_max(Field *max_val, bool force_update) { bool update_fl= force_update || cmp(ptr, max_val->ptr) > 0; if (update_fl) { max_val->set_notnull(); memcpy(max_val->ptr, ptr, pack_length()); } return update_fl; } virtual void store_field_value(uchar *val, uint len) { memcpy(ptr, val, len); } virtual decimal_digits_t decimals() const { return 0; } virtual Information_schema_numeric_attributes information_schema_numeric_attributes() const { return Information_schema_numeric_attributes(); } virtual Information_schema_character_attributes information_schema_character_attributes() const { return Information_schema_character_attributes(); } virtual void update_data_type_statistics(Data_type_statistics *st) const { } /* Caller beware: sql_type can change str.Ptr, so check ptr() to see if it changed if you are using your own buffer in str and restore it with set() if needed */ virtual void sql_type(String &str) const =0; virtual void sql_rpl_type(String *str) const { sql_type(*str); } virtual uint size_of() const =0; // For new field inline bool is_null(my_ptrdiff_t row_offset= 0) const { /* The table may have been marked as containing only NULL values for all fields if it is a NULL-complemented row of an OUTER JOIN or if the query is an implicitly grouped query (has aggregate functions but no GROUP BY clause) with no qualifying rows. If this is the case (in which TABLE::null_row is true), the field is considered to be NULL. Note that if a table->null_row is set then also all null_bits are set for the row. In the case of the 'result_field' for GROUP BY, table->null_row might refer to the *next* row in the table (when the algorithm is: read the next row, see if any of group column values have changed, send the result - grouped - row to the client if yes). So, table->null_row might be wrong, but such a result_field is always nullable (that's defined by original_field->maybe_null()) and we trust its null bit. */ return null_ptr ? null_ptr[row_offset] & null_bit : table->null_row; } inline bool is_real_null(my_ptrdiff_t row_offset= 0) const { return null_ptr && (null_ptr[row_offset] & null_bit); } inline bool is_null_in_record(const uchar *record) const { if (maybe_null_in_table()) return record[(uint) (null_ptr - table->record[0])] & null_bit; return 0; } inline void set_null(my_ptrdiff_t row_offset= 0) { if (null_ptr) null_ptr[row_offset]|= null_bit; } inline void set_notnull(my_ptrdiff_t row_offset= 0) { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; } inline bool maybe_null(void) const { return null_ptr != 0 || table->maybe_null; } // Set to NULL on LOAD DATA or LOAD XML virtual bool load_data_set_null(THD *thd); // Reset when a LOAD DATA file ended unexpectedly virtual bool load_data_set_no_data(THD *thd, bool fixed_format); void load_data_set_value(const char *pos, uint length, CHARSET_INFO *cs); /* @return true if this field is NULL-able (even if temporarily) */ inline bool real_maybe_null() const { return null_ptr != 0; } uint null_offset(const uchar *record) const { return (uint) (null_ptr - record); } /* For a NULL-able field (that can actually store a NULL value in a table) null_ptr points to the "null bitmap" in the table->record[0] header. For NOT NULL fields it is either 0 or points outside table->record[0] into the table->triggers->extra_null_bitmap (so that the field can store a NULL value temporarily, only in memory) */ bool maybe_null_in_table() const { return null_ptr >= table->record[0] && null_ptr <= ptr; } uint null_offset() const { return null_offset(table->record[0]); } void set_null_ptr(uchar *p_null_ptr, uint p_null_bit) { null_ptr= p_null_ptr; null_bit= static_cast(p_null_bit); } bool stored_in_db() const { return !vcol_info || vcol_info->stored_in_db; } bool check_vcol_sql_mode_dependency(THD *, vcol_init_mode mode) const; virtual sql_mode_t value_depends_on_sql_mode() const { return 0; } virtual sql_mode_t conversion_depends_on_sql_mode(THD *thd, Item *expr) const { return (sql_mode_t) 0; } virtual sql_mode_t can_handle_sql_mode_dependency_on_store() const { return 0; } inline THD *get_thd() const { return likely(table) ? table->in_use : current_thd; } enum { LAST_NULL_BYTE_UNDEF= 0 }; /* Find the position of the last null byte for the field. SYNOPSIS last_null_byte() DESCRIPTION Return a pointer to the last byte of the null bytes where the field conceptually is placed. RETURN VALUE The position of the last null byte relative to the beginning of the record. If the field does not use any bits of the null bytes, the value 0 (LAST_NULL_BYTE_UNDEF) is returned. */ size_t last_null_byte() const { size_t bytes= do_last_null_byte(); DBUG_PRINT("debug", ("last_null_byte() ==> %ld", (long) bytes)); DBUG_ASSERT(bytes <= table->s->null_bytes); return bytes; } /* Create mem-comparable sort key part for a sort key */ void make_sort_key_part(uchar *buff, uint length); /* create a compact sort key which can be compared with a comparison function. They are called packed sort keys */ virtual uint make_packed_sort_key_part(uchar *buff, const SORT_FIELD_ATTR *sort_field); virtual void make_send_field(Send_field *); /* Some implementations actually may write up to 8 bytes regardless of what size was requested. This is due to the minimum value of the system variable max_sort_length. */ virtual void sort_string(uchar *buff,uint length)=0; virtual bool optimize_range(uint idx, uint part) const; virtual void free() {} virtual Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table, uchar *new_ptr, uint32 length, uchar *new_null_ptr, uint new_null_bit); Field *create_tmp_field(MEM_ROOT *root, TABLE *new_table, bool maybe_null_arg); Field *create_tmp_field(MEM_ROOT *root, TABLE *new_table) { return create_tmp_field(root, new_table, maybe_null()); } Field *clone(MEM_ROOT *mem_root, TABLE *new_table); Field *clone(MEM_ROOT *mem_root, TABLE *new_table, my_ptrdiff_t diff); inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg) { ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg; } inline void move_field(uchar *ptr_arg) { ptr=ptr_arg; } inline uchar *record_ptr() // record[0] or wherever the field was moved to { my_ptrdiff_t offset= table->s->field[field_index]->ptr - table->s->default_values; return ptr - offset; } virtual void move_field_offset(my_ptrdiff_t ptr_diff) { ptr=ADD_TO_PTR(ptr,ptr_diff, uchar*); if (null_ptr) { null_ptr=ADD_TO_PTR(null_ptr,ptr_diff,uchar*); if (table) { DBUG_ASSERT(null_ptr < ptr); DBUG_ASSERT(ptr - null_ptr <= (int)table->s->rec_buff_length); } } } void get_image(uchar *buff, uint length, CHARSET_INFO *cs) const { get_image(buff, length, ptr, cs); } virtual void get_image(uchar *buff, uint length, const uchar *ptr_arg, CHARSET_INFO *cs) const { memcpy(buff,ptr_arg,length); } virtual void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) { memcpy(ptr,buff,length); } /* Copy a field part into an output buffer. SYNOPSIS Field::get_key_image() buff [out] output buffer length output buffer size type itMBR for geometry blobs, otherwise itRAW DESCRIPTION This function makes a copy of field part of size equal to or less than "length" parameter value. For fields of string types (CHAR, VARCHAR, TEXT) the rest of buffer is padded by zero byte. NOTES For variable length character fields (i.e. UTF-8) the "length" parameter means a number of output buffer bytes as if all field characters have maximal possible size (mbmaxlen). In the other words, "length" parameter is a number of characters multiplied by field_charset->mbmaxlen. RETURN Number of copied bytes (excluding padded zero bytes -- see above). */ uint get_key_image(uchar *buff, uint length, imagetype type_arg) const { return get_key_image(buff, length, ptr, type_arg); } virtual uint get_key_image(uchar *buff, uint length, const uchar *ptr_arg, imagetype type_arg) const { get_image(buff, length, ptr_arg, &my_charset_bin); return length; } virtual void set_key_image(const uchar *buff,uint length) { set_image(buff,length, &my_charset_bin); } inline longlong val_int_offset(uint row_offset) { ptr+=row_offset; longlong tmp=val_int(); ptr-=row_offset; return tmp; } inline longlong val_int(const uchar *new_ptr) { uchar *old_ptr= ptr; longlong return_value; ptr= (uchar*) new_ptr; return_value= val_int(); ptr= old_ptr; return return_value; } inline String *val_str(String *str, const uchar *new_ptr) { uchar *old_ptr= ptr; ptr= (uchar*) new_ptr; val_str(str); ptr= old_ptr; return str; } virtual bool send(Protocol *protocol); virtual uchar *pack(uchar *to, const uchar *from, uint max_length); /** @overload Field::pack(uchar*, const uchar*, uint, bool) */ uchar *pack(uchar *to, const uchar *from) { DBUG_ENTER("Field::pack"); uchar *result= this->pack(to, from, UINT_MAX); DBUG_RETURN(result); } virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data=0); virtual uint packed_col_length(const uchar *to, uint length) { return length;} virtual uint max_packed_col_length(uint max_length) { return max_length;} virtual bool is_packable() const { return false; } uint offset(const uchar *record) const { return (uint) (ptr - record); } void copy_from_tmp(int offset); uint fill_cache_field(struct st_cache_field *copy); virtual bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate); virtual longlong val_datetime_packed(THD *thd); virtual longlong val_time_packed(THD *thd); virtual const TYPELIB *get_typelib() const { return NULL; } virtual CHARSET_INFO *charset() const= 0; /* returns TRUE if the new charset differs. */ virtual void change_charset(const DTCollation &new_cs) {} virtual const DTCollation &dtcollation() const= 0; virtual CHARSET_INFO *charset_for_protocol(void) const { return binary() ? &my_charset_bin : charset(); } virtual CHARSET_INFO *sort_charset(void) const { return charset(); } virtual bool has_charset(void) const { return FALSE; } virtual int set_time() { return 1; } bool set_warning(Sql_condition::enum_warning_level, unsigned int code, int cuted_increment, ulong current_row=0) const; virtual void print_key_value(String *out, uint32 length); void print_key_part_value(String *out, const uchar *key, uint32 length); void print_key_value_binary(String *out, const uchar* key, uint32 length); void raise_note_cannot_use_key_part(THD *thd, uint keynr, uint part, const LEX_CSTRING &op, CHARSET_INFO *op_collation, Item *value, const Data_type_compatibility reason) const; void raise_note_key_become_unused(THD *thd, const String &expr) const; protected: bool set_warning(unsigned int code, int cuted_increment) const { return set_warning(Sql_condition::WARN_LEVEL_WARN, code, cuted_increment); } bool set_note(unsigned int code, int cuted_increment) const { return set_warning(Sql_condition::WARN_LEVEL_NOTE, code, cuted_increment); } void set_datetime_warning(Sql_condition::enum_warning_level, uint code, const ErrConv *str, const char *typestr, int cuted_increment) const; void set_datetime_warning(uint code, const ErrConv *str, const char *typestr, int cuted_increment) const { set_datetime_warning(Sql_condition::WARN_LEVEL_WARN, code, str, typestr, cuted_increment); } void set_warning_truncated_wrong_value(const char *type, const char *value); inline bool check_overflow(int op_result) { return (op_result == E_DEC_OVERFLOW); } int warn_if_overflow(int op_result); Copy_func *get_identical_copy_func() const; bool cmp_is_done_using_type_handler_of_this(const Item_bool_func *cond, const Item *item) const; Data_type_compatibility can_optimize_scalar_range( const RANGE_OPT_PARAM *param, const KEY_PART *key_part, const Item_bool_func *cond, scalar_comparison_op op, Item *value) const; uchar *make_key_image(MEM_ROOT *mem_root, const KEY_PART *key_part); SEL_ARG *get_mm_leaf_int(RANGE_OPT_PARAM *param, KEY_PART *key_part, const Item_bool_func *cond, scalar_comparison_op op, Item *value, bool unsigned_field); /* Make a leaf tree for the cases when the value was stored to the field exactly, without any truncation, rounding or adjustments. For example, if we stored an INT value into an INT column, and value->save_in_field_no_warnings() returned 0, we know that the value was stored exactly. */ SEL_ARG *stored_field_make_mm_leaf_exact(RANGE_OPT_PARAM *param, KEY_PART *key_part, scalar_comparison_op op, Item *value); /* Make a leaf tree for the cases when we don't know if the value was stored to the field without any data loss, or was modified to a smaller or a greater value. Used for the data types whose methods Field::store*() silently adjust the value. This is the most typical case. */ SEL_ARG *stored_field_make_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, scalar_comparison_op op, Item *value); /* Make a leaf tree when an INT value was stored into a field of INT type, and some truncation happened. Tries to adjust the range search condition when possible, e.g. "tinytint < 300" -> "tinyint <= 127". Can also return SEL_ARG_IMPOSSIBLE(), and NULL (not sargable). */ SEL_ARG *stored_field_make_mm_leaf_bounded_int(RANGE_OPT_PARAM *param, KEY_PART *key_part, scalar_comparison_op op, Item *value, bool unsigned_field); /* Make a leaf tree when some truncation happened during value->save_in_field_no_warning(this), and we cannot yet adjust the range search condition for the current combination of the field and the value data types. Returns SEL_ARG_IMPOSSIBLE() for "=" and "<=>". Returns NULL (not sargable) for other comparison operations. */ SEL_ARG *stored_field_make_mm_leaf_truncated(RANGE_OPT_PARAM *prm, scalar_comparison_op, Item *value); public: void set_table_name(String *alias) { table_name= &alias->Ptr; } void init(TABLE *table_arg) { orig_table= table= table_arg; set_table_name(&table_arg->alias); } virtual void init_for_tmp_table(Field *org_field, TABLE *new_table) { init(new_table); orig_table= org_field->orig_table; vcol_info= 0; cond_selectivity= 1.0; next_equal_field= NULL; option_list= NULL; option_struct= NULL; if (org_field->type() == MYSQL_TYPE_VAR_STRING || org_field->type() == MYSQL_TYPE_VARCHAR) new_table->s->db_create_options|= HA_OPTION_PACK_RECORD; } void init_for_make_new_field(TABLE *new_table_arg, TABLE *orig_table_arg) { init(new_table_arg); /* Normally orig_table is different from table only if field was created via ::make_new_field. Here we alter the type of field, so ::make_new_field is not applicable. But we still need to preserve the original field metadata for the client-server protocol. */ orig_table= orig_table_arg; } /* maximum possible display length */ virtual uint32 max_display_length() const= 0; /** Whether a field being created has the samle type. Used by the ALTER TABLE */ virtual bool is_equal(const Column_definition &new_field) const= 0; /* convert decimal to longlong with overflow check */ longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, int *err); /* Maximum number of bytes in character representation. - For string types it is equal to the field capacity, in bytes. - For non-string types it represents the longest possible string length after conversion to string. */ virtual uint32 character_octet_length() const { return field_length; } /* The max. number of characters */ virtual uint32 char_length() const { return field_length / charset()->mbmaxlen; } ha_storage_media field_storage_type() const { return (ha_storage_media) ((flags >> FIELD_FLAGS_STORAGE_MEDIA) & 3); } void set_storage_type(ha_storage_media storage_type_arg) { DBUG_ASSERT(field_storage_type() == HA_SM_DEFAULT); flags |= static_cast(storage_type_arg) << FIELD_FLAGS_STORAGE_MEDIA; } column_format_type column_format() const { return (column_format_type) ((flags >> FIELD_FLAGS_COLUMN_FORMAT) & 3); } void set_column_format(column_format_type column_format_arg) { DBUG_ASSERT(column_format() == COLUMN_FORMAT_TYPE_DEFAULT); flags |= static_cast(column_format_arg) << FIELD_FLAGS_COLUMN_FORMAT; } bool vers_sys_field() const { return flags & (VERS_ROW_START | VERS_ROW_END); } bool vers_sys_start() const { return flags & VERS_ROW_START; } bool vers_sys_end() const { return flags & VERS_ROW_END; } bool vers_update_unversioned() const { return flags & VERS_UPDATE_UNVERSIONED_FLAG; } /* Validate a non-null field value stored in the given record according to the current thread settings, e.g. sql_mode. @param thd - the thread @param record - the record to check in */ virtual bool validate_value_in_record(THD *thd, const uchar *record) const { return false; } bool validate_value_in_record_with_warn(THD *thd, const uchar *record); key_map get_possible_keys(); /* Hash value */ void hash(Hasher *hasher) { if (is_null()) hasher->add_null(); else hash_not_null(hasher); } virtual void hash_not_null(Hasher *hasher); /** Get the upper limit of the MySQL integral and floating-point type. @return maximum allowed value for the field */ virtual ulonglong get_max_int_value() const { DBUG_ASSERT(false); return 0ULL; } /** Checks whether a string field is part of write_set. @return FALSE - If field is not char/varchar/.... - If field is char/varchar/.. and is not part of write set. TRUE - If field is char/varchar/.. and is part of write set. */ virtual bool is_varchar_and_in_write_set() const { return FALSE; } /* Check whether the field can be used as a join attribute in hash join */ virtual bool hash_join_is_possible() { return TRUE; } virtual bool eq_cmp_as_binary() { return TRUE; } /* Position of the field value within the interval of [min, max] */ virtual double pos_in_interval(Field *min, Field *max) { return (double) 0.5; } /* Check if comparison between the field and an item unambiguously identifies a distinct field value. Example1: SELECT * FROM t1 WHERE int_column=10; This example returns distinct integer value of 10. Example2: SELECT * FROM t1 WHERE varchar_column=DATE'2001-01-01' This example returns non-distinct values. Comparison as DATE will return '2001-01-01' and '2001-01-01x', but these two values are not equal to each other as VARCHARs. See also the function with the same name in sql_select.cc. */ virtual bool test_if_equality_guarantees_uniqueness(const Item *const_item) const; virtual bool can_be_substituted_to_equal_item(const Context &ctx, const Item_equal *item); virtual Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) { return const_item; } virtual Data_type_compatibility can_optimize_keypart_ref( const Item_bool_func *cond, const Item *item) const; virtual Data_type_compatibility can_optimize_hash_join( const Item_bool_func *cond, const Item *item) const { return can_optimize_keypart_ref(cond, item); } virtual Data_type_compatibility can_optimize_group_min_max( const Item_bool_func *cond, const Item *const_item) const; /** Test if Field can use range optimizer for a standard comparison operation: <=, <, =, <=>, >, >= Note, this method does not cover spatial operations. */ virtual Data_type_compatibility can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const; virtual SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, const Item_bool_func *cond, scalar_comparison_op op, Item *value)= 0; Data_type_compatibility can_optimize_outer_join_table_elimination( const Item_bool_func *cond, const Item *item) const { // Exactly the same rules with REF access return can_optimize_keypart_ref(cond, item); } bool save_in_field_default_value(bool view_eror_processing); bool save_in_field_ignore_value(bool view_error_processing); /* Mark field in read map. Updates also virtual fields */ void register_field_in_read_map(); virtual Compression_method *compression_method() const { return 0; } virtual Virtual_tmp_table **virtual_tmp_table_addr() { return NULL; } virtual bool sp_prepare_and_store_item(THD *thd, Item **value); friend int cre_myisam(char * name, TABLE *form, uint options, ulonglong auto_increment_value); friend class Copy_field; friend class Item_avg_field; friend class Item_std_field; friend class Item_sum_num; friend class Item_sum_sum; friend class Item_sum_count; friend class Item_sum_avg; friend class Item_sum_std; friend class Item_sum_min; friend class Item_sum_max; friend class Item_func_group_concat; private: /* Primitive for implementing last_null_byte(). SYNOPSIS do_last_null_byte() DESCRIPTION Primitive for the implementation of the last_null_byte() function. This represents the inheritance interface and can be overridden by subclasses. */ virtual size_t do_last_null_byte() const; protected: uchar *pack_int(uchar *to, const uchar *from, size_t size) { memcpy(to, from, size); return to + size; } const uchar *unpack_int(uchar* to, const uchar *from, const uchar *from_end, size_t size) { if (from + size > from_end) return 0; memcpy(to, from, size); return from + size; } uchar *pack_int16(uchar *to, const uchar *from) { return pack_int(to, from, 2); } const uchar *unpack_int16(uchar* to, const uchar *from, const uchar *from_end) { return unpack_int(to, from, from_end, 2); } uchar *pack_int24(uchar *to, const uchar *from) { return pack_int(to, from, 3); } const uchar *unpack_int24(uchar* to, const uchar *from, const uchar *from_end) { return unpack_int(to, from, from_end, 3); } uchar *pack_int32(uchar *to, const uchar *from) { return pack_int(to, from, 4); } const uchar *unpack_int32(uchar* to, const uchar *from, const uchar *from_end) { return unpack_int(to, from, from_end, 4); } uchar *pack_int64(uchar* to, const uchar *from) { return pack_int(to, from, 8); } const uchar *unpack_int64(uchar* to, const uchar *from, const uchar *from_end) { return unpack_int(to, from, from_end, 8); } double pos_in_interval_val_real(Field *min, Field *max); double pos_in_interval_val_str(Field *min, Field *max, uint data_offset); }; class Field_num :public Field { protected: int check_edom_and_important_data_truncation(const char *type, bool edom, CHARSET_INFO *cs, const char *str, size_t length, const char *end_of_num); int check_edom_and_truncation(const char *type, bool edom, CHARSET_INFO *cs, const char *str, size_t length, const char *end_of_num); int check_int(CHARSET_INFO *cs, const char *str, size_t length, const char *int_end, int error) { return check_edom_and_truncation("integer", error == MY_ERRNO_EDOM || str == int_end, cs, str, length, int_end); } bool get_int(CHARSET_INFO *cs, const char *from, size_t len, longlong *rnd, ulonglong unsigned_max, longlong signed_min, longlong signed_max); void prepend_zeros(String *value) const; Item *get_equal_zerofill_const_item(THD *thd, const Context &ctx, Item *const_item); Binlog_type_info::binlog_sign_t binlog_signedness() const { return (flags & UNSIGNED_FLAG) ? Binlog_type_info::SIGN_UNSIGNED : Binlog_type_info::SIGN_SIGNED; } bool send_numeric_zerofill_str(Protocol_text *protocol, protocol_send_type_t send_type); public: const decimal_digits_t dec; bool zerofill,unsigned_flag; // Purify cannot handle bit fields Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg, bool zero_arg, bool unsigned_arg); CHARSET_INFO *charset() const override { return DTCollation_numeric::singleton().collation; } const DTCollation &dtcollation() const override { return DTCollation_numeric::singleton(); } sql_mode_t can_handle_sql_mode_dependency_on_store() const override; Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) override { return (flags & ZEROFILL_FLAG) ? get_equal_zerofill_const_item(thd, ctx, const_item) : const_item; } void add_zerofill_and_unsigned(String &res) const; friend class Create_field; void make_send_field(Send_field *) override; decimal_digits_t decimals() const override { return dec; } uint size_of() const override { return sizeof(*this); } bool eq_def(const Field *field) const override; Copy_func *get_copy_func(const Field *from) const override { if (unsigned_flag && from->cmp_type() == DECIMAL_RESULT) return do_field_decimal; return do_field_int; } int save_in_field(Field *to) override { return to->store(val_int(), MY_TEST(flags & UNSIGNED_FLAG)); } bool is_equal(const Column_definition &new_field) const override; uint row_pack_length() const override { return pack_length(); } uint32 pack_length_from_metadata(uint field_metadata) const override { uint32 length= pack_length(); DBUG_PRINT("result", ("pack_length_from_metadata(%d): %u", field_metadata, length)); return length; } double pos_in_interval(Field *min, Field *max) override { return pos_in_interval_val_real(min, max); } SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, const Item_bool_func *cond, scalar_comparison_op op, Item *value) override; Binlog_type_info binlog_type_info() const override { DBUG_ASSERT(Field_num::type() == binlog_type()); return Binlog_type_info(Field_num::type(), 0, 0, binlog_signedness()); } }; class Field_str :public Field { protected: DTCollation m_collation; // A short alias for m_collation.collation with non-virtual linkage const CHARSET_INFO *field_charset() const { return m_collation.collation; } uint mbmaxlen() const { return m_collation.collation->mbmaxlen; } public: bool can_be_substituted_to_equal_item(const Context &ctx, const Item_equal *item_equal) override; Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, const DTCollation &collation); decimal_digits_t decimals() const override { return is_created_from_null_item ? 0 : DECIMAL_NOT_SPECIFIED; } int save_in_field(Field *to) override { return save_in_field_str(to); } bool memcpy_field_possible(const Field *from) const override { return real_type() == from->real_type() && pack_length() == from->pack_length() && charset() == from->charset(); } int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int store_decimal(const my_decimal *) override; int store(const char *to,size_t length,CHARSET_INFO *cs) override=0; int store_hex_hybrid(const char *str, size_t length) override { return store(str, length, &my_charset_bin); } CHARSET_INFO *charset() const override { return m_collation.collation; } const DTCollation &dtcollation() const override { return m_collation; } void change_charset(const DTCollation &new_cs) override; bool binary() const override { return field_charset() == &my_charset_bin; } uint32 max_display_length() const override { return field_length; } uint32 character_octet_length() const override { return field_length; } uint32 char_length() const override { return field_length / mbmaxlen(); } Information_schema_character_attributes information_schema_character_attributes() const override { return Information_schema_character_attributes(max_display_length(), char_length()); } friend class Create_field; my_decimal *val_decimal(my_decimal *) override; bool val_bool() override { return val_real() != 0e0; } bool str_needs_quotes() const override { return true; } bool eq_cmp_as_binary() override { return MY_TEST(flags & BINARY_FLAG); } virtual uint length_size() const { return 0; } double pos_in_interval(Field *min, Field *max) override { return pos_in_interval_val_str(min, max, length_size()); } bool test_if_equality_guarantees_uniqueness(const Item *const_item) const override; SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, const Item_bool_func *cond, scalar_comparison_op op, Item *value) override; Binlog_type_info binlog_type_info() const override { DBUG_ASSERT(Field_str::type() == binlog_type()); return Binlog_type_info(Field_str::type(), 0, 0, charset()); } }; /* base class for Field_string, Field_varstring and Field_blob */ class Field_longstr :public Field_str { protected: int report_if_important_data(const char *ptr, const char *end, bool count_spaces); bool check_string_copy_error(const String_copier *copier, const char *end, CHARSET_INFO *cs); int check_conversion_status(const String_copier *copier, const char *end, CHARSET_INFO *cs, bool count_spaces) { if (check_string_copy_error(copier, end, cs)) return 2; return report_if_important_data(copier->source_end_pos(), end, count_spaces); } int well_formed_copy_with_check(char *to, size_t to_length, CHARSET_INFO *from_cs, const char *from, size_t from_length, size_t nchars, bool count_spaces, uint *copy_length) { String_copier copier; *copy_length= copier.well_formed_copy(field_charset(), to, to_length, from_cs, from, from_length, nchars); return check_conversion_status(&copier, from + from_length, from_cs, count_spaces); } Data_type_compatibility cmp_to_string_with_same_collation( const Item_bool_func *cond, const Item *item) const; Data_type_compatibility cmp_to_string_with_stricter_collation( const Item_bool_func *cond, const Item *item) const; int compress(char *to, uint to_length, const char *from, uint length, uint max_length, uint *out_length, CHARSET_INFO *cs, size_t nchars); String *uncompress(String *val_buffer, String *val_ptr, const uchar *from, uint from_length) const; public: Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, const DTCollation &collation) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, collation) {} enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; int store_decimal(const my_decimal *d) override; uint32 max_data_length() const override; void make_send_field(Send_field *) override; bool send(Protocol *protocol) override; bool is_varchar_and_in_write_set() const override { DBUG_ASSERT(table && table->write_set); return bitmap_is_set(table->write_set, field_index); } bool match_collation_to_optimize_range() const { return true; } Data_type_compatibility can_optimize_keypart_ref(const Item_bool_func *cond, const Item *item) const override; Data_type_compatibility can_optimize_hash_join(const Item_bool_func *cond, const Item *item) const override; Data_type_compatibility can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const override; Data_type_compatibility can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const override; bool is_packable() const override { return true; } uint make_packed_sort_key_part(uchar *buff, const SORT_FIELD_ATTR *sort_field)override; uchar* pack_sort_string(uchar *to, const SORT_FIELD_ATTR *sort_field); }; /* base class for float and double and decimal (old one) */ class Field_real :public Field_num { protected: double get_double(const char *str, size_t length, CHARSET_INFO *cs, int *err); public: bool not_fixed; Field_real(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg, bool zero_arg, bool unsigned_arg) :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg), not_fixed(dec_arg >= FLOATING_POINT_DECIMALS) {} Copy_func *get_copy_func(const Field *from) const override { return do_field_real; } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; Information_schema_numeric_attributes information_schema_numeric_attributes() const override { return dec == DECIMAL_NOT_SPECIFIED ? Information_schema_numeric_attributes(field_length) : Information_schema_numeric_attributes(field_length, dec); } void sql_type(String &str) const override; int save_in_field(Field *to) override { return to->store(val_real()); } bool memcpy_field_possible(const Field *from) const override { /* Cannot do memcpy from a longer field to a shorter field, e.g. a DOUBLE(53,10) into a DOUBLE(10,10). But it should be OK the other way around. */ return real_type() == from->real_type() && pack_length() == from->pack_length() && is_unsigned() <= from->is_unsigned() && decimals() == from->decimals() && field_length >= from->field_length; } int store_decimal(const my_decimal *dec) override { return store(dec->to_double()); } int store_time_dec(const MYSQL_TIME *ltime, uint dec) override; bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override; my_decimal *val_decimal(my_decimal *) override; bool val_bool() override { return val_real() != 0e0; } uint32 max_display_length() const override { return field_length; } uint size_of() const override { return sizeof *this; } Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) override; }; class Field_decimal final :public Field_real { public: Field_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg, bool zero_arg,bool unsigned_arg) :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg) {} Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type) override; const Type_handler *type_handler() const override { return &type_handler_olddecimal; } enum ha_base_keytype key_type() const override { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } Information_schema_numeric_attributes information_schema_numeric_attributes() const override { uint tmp= dec ? 2 : 1; // The sign and the decimal point return Information_schema_numeric_attributes(field_length - tmp, dec); } Copy_func *get_copy_func(const Field *from) const override { return eq_def(from) ? get_identical_copy_func() : do_field_string; } int reset() override; int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; void overflow(bool negative); bool zero_pack() const override { return false; } void sql_type(String &str) const override; uchar *pack(uchar* to, const uchar *from, uint max_length) override { return Field::pack(to, from, max_length); } }; /* New decimal/numeric field which use fixed point arithmetic */ class Field_new_decimal final :public Field_num { public: /* The maximum number of decimal digits can be stored */ decimal_digits_t precision; uint32 bin_size; /* Constructors take max_length of the field as a parameter - not the precision as the number of decimal digits allowed. So for example we need to count length from precision handling CREATE TABLE ( DECIMAL(x,y)) */ Field_new_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg, bool zero_arg, bool unsigned_arg); const Type_handler *type_handler() const override { return &type_handler_newdecimal; } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; } Copy_func *get_copy_func(const Field *from) const override { // if (from->real_type() == MYSQL_TYPE_BIT) // QQ: why? // return do_field_int; return do_field_decimal; } int save_in_field(Field *to) override { my_decimal tmp(ptr, precision, dec); return to->store_decimal(&tmp); } bool memcpy_field_possible(const Field *from) const override { return real_type() == from->real_type() && pack_length() == from->pack_length() && is_unsigned() <= from->is_unsigned() && decimals() == from->decimals() && field_length == from->field_length; } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; int reset() override; bool store_value(const my_decimal *decimal_value); bool store_value(const my_decimal *decimal_value, int *native_error); void set_value_on_overflow(my_decimal *decimal_value, bool sign); int store(const char *to, size_t length, CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int store_time_dec(const MYSQL_TIME *ltime, uint dec) override; int store_decimal(const my_decimal *) override; double val_real() override { return my_decimal(ptr, precision, dec).to_double(); } longlong val_int() override { return my_decimal(ptr, precision, dec).to_longlong(unsigned_flag); } ulonglong val_uint() override { return (ulonglong) my_decimal(ptr, precision, dec).to_longlong(true); } my_decimal *val_decimal(my_decimal *) override; String *val_str(String *val_buffer, String *) override { uint fixed_precision= zerofill ? precision : 0; return my_decimal(ptr, precision, dec). to_string(val_buffer, fixed_precision, dec, '0'); } bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override { my_decimal nr(ptr, precision, dec); return decimal_to_datetime_with_warn(get_thd(), &nr, ltime, fuzzydate, table->s, field_name.str); } bool val_bool() override { return my_decimal(ptr, precision, dec).to_bool(); } int cmp(const uchar *, const uchar *) const override; void sort_string(uchar *buff, uint length) override; bool zero_pack() const override { return false; } void sql_type(String &str) const override; uint32 max_display_length() const override { return field_length; } Information_schema_numeric_attributes information_schema_numeric_attributes() const override { return Information_schema_numeric_attributes(precision, dec); } uint size_of() const override { return sizeof *this; } uint32 pack_length() const override { return bin_size; } uint pack_length_from_metadata(uint field_metadata) const override; uint row_pack_length() const override { return pack_length(); } bool compatible_field_size(uint field_metadata, const Relay_log_info *rli, uint16 mflags, int *order_var) const override; bool is_equal(const Column_definition &new_field) const override; const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data) override; Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) override; Binlog_type_info binlog_type_info() const override; }; class Field_int :public Field_num { protected: String *val_str_from_long(String *val_buffer, uint max_char_length, int radix, long nr); public: Field_int(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, bool zero_arg, bool unsigned_arg) :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, 0, zero_arg, unsigned_arg) {} enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; bool memcpy_field_possible(const Field *from) const override { return real_type() == from->real_type() && pack_length() == from->pack_length() && is_unsigned() == from->is_unsigned(); } int store_decimal(const my_decimal *) override; my_decimal *val_decimal(my_decimal *) override; bool val_bool() override { return val_int() != 0; } ulonglong val_uint() override { longlong nr= val_int(); return nr < 0 && !unsigned_flag ? 0 : (ulonglong) nr; } int store_time_dec(const MYSQL_TIME *ltime, uint dec) override; bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override; virtual const Type_limits_int *type_limits_int() const= 0; uint32 max_display_length() const override { return type_limits_int()->char_length(); } Type_numeric_attributes type_numeric_attributes() const override { /* For integer data types, the user-specified length does not constrain the supported range, so e.g. a column of the INT(1) data type supports the full integer range anyway. Choose the maximum from the user-specified length and the maximum possible length determined by the data type capacity: INT(1) -> 11 INT(10) -> 11 INT(40) -> 40 */ uint32 length1= max_display_length(); uint32 length2= field_length; return Type_numeric_attributes(MY_MAX(length1, length2), decimals(), is_unsigned()); } Information_schema_numeric_attributes information_schema_numeric_attributes() const override { uint32 prec= type_limits_int()->precision(); return Information_schema_numeric_attributes(prec, 0); } void sql_type(String &str) const override; SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, const Item_bool_func *cond, scalar_comparison_op op, Item *value) override { return get_mm_leaf_int(param, key_part, cond, op, value, unsigned_flag); } }; class Field_tiny :public Field_int { const Type_handler_general_purpose_int *type_handler_priv() const { if (is_unsigned()) return &type_handler_utiny; return &type_handler_stiny; } public: Field_tiny(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, bool zero_arg, bool unsigned_arg) :Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, zero_arg, unsigned_arg) {} const Type_handler *type_handler() const override { return type_handler_priv(); } enum ha_base_keytype key_type() const override { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; } int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int reset() override { ptr[0]=0; return 0; } double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 1; } const Type_limits_int *type_limits_int() const override { return type_handler_priv()->type_limits_int(); } uchar *pack(uchar* to, const uchar *from, uint max_length) override { *to= *from; return to + 1; } const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data) override { if (from == from_end) return 0; *to= *from; return from + 1; } ulonglong get_max_int_value() const override { return unsigned_flag ? 0xFFULL : 0x7FULL; } }; class Field_short final :public Field_int { const Type_handler_general_purpose_int *type_handler_priv() const { if (is_unsigned()) return &type_handler_ushort; return &type_handler_sshort; } public: Field_short(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, bool zero_arg, bool unsigned_arg) :Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, zero_arg, unsigned_arg) {} Field_short(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, bool unsigned_arg) :Field_int((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, 0, unsigned_arg) {} const Type_handler *type_handler() const override { return type_handler_priv(); } enum ha_base_keytype key_type() const override { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;} int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int reset() override { ptr[0]=ptr[1]=0; return 0; } double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 2; } const Type_limits_int *type_limits_int() const override { return type_handler_priv()->type_limits_int(); } uchar *pack(uchar* to, const uchar *from, uint) override { return pack_int16(to, from); } const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint) override { return unpack_int16(to, from, from_end); } ulonglong get_max_int_value() const override { return unsigned_flag ? 0xFFFFULL : 0x7FFFULL; } }; class Field_medium final :public Field_int { const Type_handler_general_purpose_int *type_handler_priv() const { if (is_unsigned()) return &type_handler_uint24; return &type_handler_sint24; } public: Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, bool zero_arg, bool unsigned_arg) :Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, zero_arg, unsigned_arg) {} const Type_handler *type_handler() const override { return type_handler_priv(); } enum ha_base_keytype key_type() const override { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; } int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int reset() override { ptr[0]=ptr[1]=ptr[2]=0; return 0; } double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 3; } const Type_limits_int *type_limits_int() const override { return type_handler_priv()->type_limits_int(); } uchar *pack(uchar* to, const uchar *from, uint max_length) override { return Field::pack(to, from, max_length); } ulonglong get_max_int_value() const override { return unsigned_flag ? 0xFFFFFFULL : 0x7FFFFFULL; } }; class Field_long final :public Field_int { const Type_handler_general_purpose_int *type_handler_priv() const { if (is_unsigned()) return &type_handler_ulong; return &type_handler_slong; } public: Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, bool zero_arg, bool unsigned_arg) :Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, zero_arg, unsigned_arg) {} Field_long(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, bool unsigned_arg) :Field_int((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, 0, unsigned_arg) {} const Type_handler *type_handler() const override { return type_handler_priv(); } enum ha_base_keytype key_type() const override { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; } int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int reset() override { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } double val_real() override; longlong val_int() override; bool send(Protocol *protocol) override; String *val_str(String *, String *) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 4; } const Type_limits_int *type_limits_int() const override { return type_handler_priv()->type_limits_int(); } uchar *pack(uchar* to, const uchar *from, uint) override { return pack_int32(to, from); } const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint) override { return unpack_int32(to, from, from_end); } ulonglong get_max_int_value() const override { return unsigned_flag ? 0xFFFFFFFFULL : 0x7FFFFFFFULL; } }; class Field_longlong :public Field_int { const Type_handler_general_purpose_int *type_handler_priv() const { if (is_unsigned()) return &type_handler_ulonglong; return &type_handler_slonglong; } public: Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, bool zero_arg, bool unsigned_arg) :Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, zero_arg, unsigned_arg) {} Field_longlong(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, bool unsigned_arg) :Field_int((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, 0, unsigned_arg) {} const Type_handler *type_handler() const override { return type_handler_priv(); } enum ha_base_keytype key_type() const override { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; } int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int reset() override { ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; return 0; } double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 8; } const Type_limits_int *type_limits_int() const override { return type_handler_priv()->type_limits_int(); } uchar *pack(uchar* to, const uchar *from, uint) override { return pack_int64(to, from); } const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint) override { return unpack_int64(to, from, from_end); } void set_max() override; bool is_max() override; ulonglong get_max_int_value() const override { return unsigned_flag ? 0xFFFFFFFFFFFFFFFFULL : 0x7FFFFFFFFFFFFFFFULL; } }; class Field_vers_trx_id :public Field_longlong { MYSQL_TIME cache; ulonglong cached; public: Field_vers_trx_id(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, bool zero_arg, bool unsigned_arg) : Field_longlong(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, zero_arg, unsigned_arg), cached(0) {} const Type_handler *type_handler() const override { return &type_handler_vers_trx_id; } uint size_of() const override { return sizeof *this; } bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate, ulonglong trx_id); bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date(ltime, fuzzydate, (ulonglong) val_int()); } bool test_if_equality_guarantees_uniqueness(const Item *item) const override; Data_type_compatibility can_optimize_keypart_ref(const Item_bool_func *, const Item *) const override { return Data_type_compatibility::OK; } Data_type_compatibility can_optimize_group_min_max(const Item_bool_func *, const Item *) const override { return Data_type_compatibility::OK; } Data_type_compatibility can_optimize_range(const Item_bool_func *, const Item *, bool is_eq_func) const override { return Data_type_compatibility::OK; } /* cmp_type() cannot be TIME_RESULT, because we want to compare this field against integers. But in all other cases we treat it as TIME_RESULT! */ }; static inline decimal_digits_t fix_dec_arg(decimal_digits_t dec_arg) { return dec_arg >= FLOATING_POINT_DECIMALS ? DECIMAL_NOT_SPECIFIED : dec_arg; } class Field_float final :public Field_real { public: Field_float(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg,bool zero_arg,bool unsigned_arg) :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, fix_dec_arg(dec_arg), zero_arg, unsigned_arg) { } Field_float(uint32 len_arg, bool maybe_null_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg) :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, NONE, field_name_arg, fix_dec_arg(dec_arg), 0, 0) { } const Type_handler *type_handler() const override { return &type_handler_float; } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_FLOAT; } int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int reset() override { bzero(ptr,sizeof(float)); return 0; } double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff, uint length) override; uint32 pack_length() const override { return sizeof(float); } uint row_pack_length() const override { return pack_length(); } ulonglong get_max_int_value() const override { /* We use the maximum as per IEEE754-2008 standard, 2^24 */ return 0x1000000ULL; } Binlog_type_info binlog_type_info() const override; }; class Field_double :public Field_real { longlong val_int_from_real(bool want_unsigned_result); public: Field_double(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg,bool zero_arg,bool unsigned_arg) :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, fix_dec_arg(dec_arg), zero_arg, unsigned_arg) { } Field_double(uint32 len_arg, bool maybe_null_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg) :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, NONE, field_name_arg, fix_dec_arg(dec_arg), 0, 0) { } Field_double(uint32 len_arg, bool maybe_null_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg, bool not_fixed_arg) :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, NONE, field_name_arg, fix_dec_arg(dec_arg), 0, 0) { not_fixed= not_fixed_arg; } void init_for_tmp_table(Field *org_field, TABLE *new_table) override { Field::init_for_tmp_table(org_field, new_table); not_fixed= true; } const Type_handler *type_handler() const override { return &type_handler_double; } enum ha_base_keytype key_type() const override final { return HA_KEYTYPE_DOUBLE; } int store(const char *to,size_t length,CHARSET_INFO *charset) override final; int store(double nr) override final; int store(longlong nr, bool unsigned_val) override final; int reset() override final { bzero(ptr,sizeof(double)); return 0; } double val_real() override final; longlong val_int() override final { return val_int_from_real(false); } ulonglong val_uint() override final { return (ulonglong) val_int_from_real(true); } String *val_str(String *, String *) override final; bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override final; void sort_string(uchar *buff, uint length) override final; uint32 pack_length() const override final { return sizeof(double); } uint row_pack_length() const override final { return pack_length(); } ulonglong get_max_int_value() const override final { /* We use the maximum as per IEEE754-2008 standard, 2^53 */ return 0x20000000000000ULL; } Binlog_type_info binlog_type_info() const override final; }; /* Everything saved in this will disappear. It will always return NULL */ class Field_null :public Field_str { static uchar null[1]; public: Field_null(uchar *ptr_arg, uint32 len_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, const DTCollation &collation) :Field_str(ptr_arg, len_arg, null, 1, unireg_check_arg, field_name_arg, collation) {} const Type_handler *type_handler() const override { return &type_handler_null; } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; Information_schema_character_attributes information_schema_character_attributes() const override { return Information_schema_character_attributes(); } Copy_func *get_copy_func(const Field *from) const override { return do_field_string; } int store(const char *to, size_t length, CHARSET_INFO *cs) override final { null[0]=1; return 0; } int store(double nr) override final { null[0]=1; return 0; } int store(longlong nr, bool unsigned_val) override final { null[0]=1; return 0; } int store_decimal(const my_decimal *d) override final { null[0]=1; return 0; } int reset() override final { return 0; } double val_real() override final { return 0.0;} longlong val_int() override final { return 0;} bool val_bool() override final { return false; } my_decimal *val_decimal(my_decimal *) override final { return 0; } String *val_str(String *value,String *value2) override final { value2->length(0); return value2;} bool is_equal(const Column_definition &new_field) const override final; int cmp(const uchar *a, const uchar *b) const override final { return 0;} void sort_string(uchar *buff, uint length) override final {} uint32 pack_length() const override final { return 0; } void sql_type(String &str) const override final; uint size_of() const override final { return sizeof *this; } uint32 max_display_length() const override final { return 4; } void move_field_offset(my_ptrdiff_t ptr_diff) override final {} Data_type_compatibility can_optimize_keypart_ref(const Item_bool_func *cond, const Item *item) const override final { return Data_type_compatibility::INCOMPATIBLE_DATA_TYPE; } Data_type_compatibility can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const override final { return Data_type_compatibility::INCOMPATIBLE_DATA_TYPE; } }; class Field_temporal :public Field { protected: Item *get_equal_const_item_datetime(THD *thd, const Context &ctx, Item *const_item); void set_warnings(Sql_condition::enum_warning_level trunc_level, const ErrConv *str, int was_cut, const char *typestr); int store_TIME_return_code_with_warnings(int warn, const ErrConv *str, const char *typestr) { if (!MYSQL_TIME_WARN_HAVE_WARNINGS(warn) && MYSQL_TIME_WARN_HAVE_NOTES(warn)) { set_warnings(Sql_condition::WARN_LEVEL_NOTE, str, warn | MYSQL_TIME_WARN_TRUNCATED, typestr); return 3; } set_warnings(Sql_condition::WARN_LEVEL_WARN, str, warn, typestr); return warn ? 2 : 0; } int store_invalid_with_warning(const ErrConv *str, int was_cut, const char *typestr) { DBUG_ASSERT(was_cut); reset(); Sql_condition::enum_warning_level level= Sql_condition::WARN_LEVEL_WARN; if (was_cut & MYSQL_TIME_WARN_ZERO_DATE) { set_warnings(level, str, MYSQL_TIME_WARN_OUT_OF_RANGE, typestr); return 2; } set_warnings(level, str, MYSQL_TIME_WARN_TRUNCATED, typestr); return 1; } void sql_type_comment(String &str, const Name &name, const Name &comment) const; void sql_type_dec_comment(String &str, const Name &name, uint dec, const Name &comment) const; void sql_type_opt_dec_comment(String &str, const Name &name, uint dec, const Name &comment) const { if (dec) sql_type_dec_comment(str, name, dec, comment); else sql_type_comment(str, name, comment); } static const Name &type_version_mysql56(); public: Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) { flags|= BINARY_FLAG; } int store_hex_hybrid(const char *str, size_t length) override { return store(str, length, &my_charset_bin); } sql_mode_t can_handle_sql_mode_dependency_on_store() const override; Copy_func *get_copy_func(const Field *from) const override; int save_in_field(Field *to) override { MYSQL_TIME ltime; // For temporal types no truncation needed. Rounding mode is not important. if (get_date(<ime, TIME_CONV_NONE | TIME_FRAC_NONE)) return to->reset(); return to->store_time_dec(<ime, decimals()); } bool memcpy_field_possible(const Field *from) const override; uint32 max_display_length() const override { return field_length; } bool str_needs_quotes() const override { return true; } CHARSET_INFO *charset() const override { return DTCollation_numeric::singleton().collation; } const DTCollation &dtcollation() const override { return DTCollation_numeric::singleton(); } CHARSET_INFO *sort_charset() const override { return &my_charset_bin; } bool binary() const override { return true; } bool val_bool() override { return val_real() != 0e0; } bool is_equal(const Column_definition &new_field) const override; bool eq_def(const Field *field) const override { return (Field::eq_def(field) && decimals() == field->decimals()); } my_decimal *val_decimal(my_decimal*) override; double pos_in_interval(Field *min, Field *max) override { return pos_in_interval_val_real(min, max); } Data_type_compatibility can_optimize_keypart_ref(const Item_bool_func *cond, const Item *item) const override; Data_type_compatibility can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const override; Data_type_compatibility can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const override { return Data_type_compatibility::OK; } SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, const Item_bool_func *cond, scalar_comparison_op op, Item *value) override; }; /** Abstract class for: - DATE - DATETIME - DATETIME(1..6) - DATETIME(0..6) - MySQL56 version */ class Field_temporal_with_date :public Field_temporal { protected: virtual void store_TIME(const MYSQL_TIME *ltime) = 0; void store_datetime(const Datetime &dt) { return store_TIME(dt.get_mysql_time()); } virtual bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const = 0; bool validate_MMDD(bool not_zero_date, uint month, uint day, date_mode_t fuzzydate) const { if (!not_zero_date) return bool(fuzzydate & TIME_NO_ZERO_DATE); if (!month || !day) return bool(fuzzydate & TIME_NO_ZERO_IN_DATE); return false; } public: Field_temporal_with_date(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_temporal(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) {} bool validate_value_in_record(THD *thd, const uchar *record) const override; }; class Field_timestamp :public Field_temporal { protected: int store_TIME_with_warning(THD *, const Datetime *, const ErrConv *, int warn); virtual void store_TIMEVAL(const timeval &tv)= 0; void store_TIMESTAMP(const Timestamp &ts) { store_TIMEVAL(ts.tv()); } int zero_time_stored_return_code_with_warning(); public: Field_timestamp(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share); const Type_handler *type_handler() const override { return &type_handler_timestamp; } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; Copy_func *get_copy_func(const Field *from) const override; sql_mode_t conversion_depends_on_sql_mode(THD *, Item *) const override; int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int store_time_dec(const MYSQL_TIME *ltime, uint dec) override; int store_decimal(const my_decimal *) override; int store_timestamp_dec(const timeval &ts, uint dec) override; int save_in_field(Field *to) override; longlong val_int() override; String *val_str(String *, String *) override; bool zero_pack() const override { return false; } /* This method is used by storage/perfschema and Item_func_now_local::save_in_field(). */ void store_TIME(my_time_t ts, ulong sec_part) { int warn; time_round_mode_t mode= Datetime::default_round_mode(get_thd()); store_TIMESTAMP(Timestamp(ts, sec_part).round(decimals(), mode, &warn)); } bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override; int store_native(const Native &value) override; bool validate_value_in_record(THD *thd, const uchar *record) const override; Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) override { return get_equal_const_item_datetime(thd, ctx, const_item); } bool load_data_set_null(THD *thd) override; bool load_data_set_no_data(THD *thd, bool fixed_format) override; }; class Field_timestamp0 :public Field_timestamp { void store_TIMEVAL(const timeval &tv) override { int4store(ptr, tv.tv_sec); } public: Field_timestamp0(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share) :Field_timestamp(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share) { } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_ULONG_INT; } void sql_type(String &str) const override { sql_type_comment(str, Field_timestamp0::type_handler()->name(), Type_handler::version_mariadb53()); } double val_real() override { return (double) Field_timestamp0::val_int(); } bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 4; } int set_time() override; /* Get TIMESTAMP field value as seconds since begging of Unix Epoch */ my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const override; bool val_native(Native *to) override; uchar *pack(uchar *to, const uchar *from, uint) override { return pack_int32(to, from); } const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint) override { return unpack_int32(to, from, from_end); } uint size_of() const override { return sizeof *this; } }; /** Abstract class for: - TIMESTAMP(1..6) - TIMESTAMP(0..6) - MySQL56 version */ class Field_timestamp_with_dec :public Field_timestamp { protected: decimal_digits_t dec; public: Field_timestamp_with_dec(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, decimal_digits_t dec_arg) : Field_timestamp(ptr_arg, MAX_DATETIME_WIDTH + dec_arg + MY_TEST(dec_arg), null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share), dec(dec_arg) { DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); } decimal_digits_t decimals() const override { return dec; } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; } uchar *pack(uchar *to, const uchar *from, uint max_length) override { return Field::pack(to, from, max_length); } const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data) override { return Field::unpack(to, from, from_end, param_data); } void make_send_field(Send_field *field) override; void sort_string(uchar *to, uint length) override { DBUG_ASSERT(length == pack_length()); memcpy(to, ptr, length); } bool send(Protocol *protocol) override; double val_real() override; my_decimal* val_decimal(my_decimal*) override; int set_time() override; }; class Field_timestamp_hires :public Field_timestamp_with_dec { uint sec_part_bytes(uint dec) const { return Type_handler_timestamp::sec_part_bytes(dec); } void store_TIMEVAL(const timeval &tv) override; public: Field_timestamp_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, decimal_digits_t dec_arg) : Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share, dec_arg) { DBUG_ASSERT(dec); } void sql_type(String &str) const override { sql_type_dec_comment(str, Field_timestamp_hires::type_handler()->name(), dec, Type_handler::version_mariadb53()); } bool val_native(Native *to) override; my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const override; int cmp(const uchar *,const uchar *) const override; uint32 pack_length() const override { return 4 + sec_part_bytes(dec); } uint size_of() const override { return sizeof *this; } }; /** TIMESTAMP(0..6) - MySQL56 version */ class Field_timestampf :public Field_timestamp_with_dec { void store_TIMEVAL(const timeval &tv) override; public: Field_timestampf(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, decimal_digits_t dec_arg) : Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share, dec_arg) {} const Type_handler *type_handler() const override { return &type_handler_timestamp2; } enum_field_types binlog_type() const override { return MYSQL_TYPE_TIMESTAMP2; } void sql_type(String &str) const override { sql_type_opt_dec_comment(str, Field_timestampf::type_handler()->name(), dec, type_version_mysql56()); } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; uint32 pack_length() const override { return my_timestamp_binary_length(dec); } uint row_pack_length() const override { return pack_length(); } uint pack_length_from_metadata(uint field_metadata) const override { DBUG_ENTER("Field_timestampf::pack_length_from_metadata"); uint tmp= my_timestamp_binary_length(field_metadata); DBUG_RETURN(tmp); } int cmp(const uchar *a_ptr,const uchar *b_ptr) const override { return memcmp(a_ptr, b_ptr, pack_length()); } void set_max() override; bool is_max() override; my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const override; bool val_native(Native *to) override; uint size_of() const override { return sizeof *this; } Binlog_type_info binlog_type_info() const override; }; class Field_year final :public Field_tiny { public: Field_year(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, 1, 1) {} const Type_handler *type_handler() const override { return field_length == 2 ? &type_handler_year2 : &type_handler_year; } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; Copy_func *get_copy_func(const Field *from) const override { if (eq_def(from)) return get_identical_copy_func(); switch (from->cmp_type()) { case STRING_RESULT: { const Type_handler *handler= from->type_handler(); if (handler == &type_handler_enum || handler == &type_handler_set) return do_field_int; return do_field_string; } case TIME_RESULT: return do_field_date; case DECIMAL_RESULT: return do_field_decimal; case REAL_RESULT: return do_field_real; case INT_RESULT: break; case ROW_RESULT: default: DBUG_ASSERT(0); break; } return do_field_int; } int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int store_time_dec(const MYSQL_TIME *ltime, uint dec) override; double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool send(Protocol *protocol) override; Information_schema_numeric_attributes information_schema_numeric_attributes() const override { return Information_schema_numeric_attributes(); } uint32 max_display_length() const override { return field_length; } void sql_type(String &str) const override; }; class Field_date_common :public Field_temporal_with_date { protected: int store_TIME_with_warning(const Datetime *ltime, const ErrConv *str, int was_cut); public: Field_date_common(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) {} Copy_func *get_copy_func(const Field *from) const override; SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, const Item_bool_func *cond, scalar_comparison_op op, Item *value) override; int store(const char *to, size_t length, CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int store_time_dec(const MYSQL_TIME *ltime, uint dec) override; int store_decimal(const my_decimal *) override; }; class Field_date final :public Field_date_common { void store_TIME(const MYSQL_TIME *ltime) override; bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const override; public: Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_date_common(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) {} const Type_handler *type_handler() const override { return &type_handler_date; } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_ULONG_INT; } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; int reset() override { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return Field_date::get_TIME(ltime, ptr, fuzzydate); } double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 4; } void sql_type(String &str) const override; uchar *pack(uchar* to, const uchar *from, uint) override { return pack_int32(to, from); } const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint) override { return unpack_int32(to, from, from_end); } uint size_of() const override { return sizeof *this; } }; class Field_newdate final :public Field_date_common { void store_TIME(const MYSQL_TIME *ltime) override; bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const override; public: Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_date_common(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) {} const Type_handler *type_handler() const override { return &type_handler_newdate; } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_UINT24; } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; int reset() override { ptr[0]=ptr[1]=ptr[2]=0; return 0; } double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 3; } void sql_type(String &str) const override; bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return Field_newdate::get_TIME(ltime, ptr, fuzzydate); } longlong val_datetime_packed(THD *thd) override; uint size_of() const override { return sizeof *this; } Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) override; }; class Field_time :public Field_temporal { /* when this Field_time instance is used for storing values for index lookups (see class store_key, Field::new_key_field(), etc), the following might be set to TO_DAYS(CURDATE()). See also Field_time::store_time_dec() */ long curdays; protected: virtual void store_TIME(const MYSQL_TIME *ltime)= 0; void store_TIME(const Time &t) { return store_TIME(t.get_mysql_time()); } int store_TIME_with_warning(const Time *ltime, const ErrConv *str, int warn); bool check_zero_in_date_with_warn(date_mode_t fuzzydate); static void do_field_time(Copy_field *copy); public: Field_time(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg), curdays(0) {} bool can_be_substituted_to_equal_item(const Context &ctx, const Item_equal *item_equal) override; const Type_handler *type_handler() const override { return &type_handler_time; } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; Copy_func *get_copy_func(const Field *from) const override { return from->cmp_type() == REAL_RESULT ? do_field_string : // MDEV-9344 from->type() == MYSQL_TYPE_YEAR ? do_field_int : from->type() == MYSQL_TYPE_BIT ? do_field_int : eq_def(from) ? get_identical_copy_func() : do_field_time; } bool memcpy_field_possible(const Field *from) const override { return real_type() == from->real_type() && decimals() == from->decimals(); } sql_mode_t conversion_depends_on_sql_mode(THD *, Item *) const override; int store_native(const Native &value) override; bool val_native(Native *to) override; int store_time_dec(const MYSQL_TIME *ltime, uint dec) override; int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int store_decimal(const my_decimal *) override; String *val_str(String *, String *) override; bool send(Protocol *protocol) override; void set_curdays(THD *thd); Field *new_key_field(MEM_ROOT *root, TABLE *new_table, uchar *new_ptr, uint32 length, uchar *new_null_ptr, uint new_null_bit) override; Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) override; }; class Field_time0 final :public Field_time { protected: void store_TIME(const MYSQL_TIME *ltime) override; public: Field_time0(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_time(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) { } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_INT24; } void sql_type(String &str) const override { sql_type_comment(str, Field_time0::type_handler()->name(), Type_handler::version_mariadb53()); } double val_real() override; longlong val_int() override; bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 3; } uint size_of() const override { return sizeof *this; } }; /** Abstract class for: - TIME(1..6) - TIME(0..6) - MySQL56 version */ class Field_time_with_dec :public Field_time { protected: decimal_digits_t dec; public: Field_time_with_dec(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg) :Field_time(ptr_arg, MIN_TIME_WIDTH + dec_arg + MY_TEST(dec_arg), null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg), dec(dec_arg) { DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); } decimal_digits_t decimals() const override { return dec; } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; } longlong val_int() override; double val_real() override; void make_send_field(Send_field *) override; }; /** TIME(1..6) */ class Field_time_hires final :public Field_time_with_dec { longlong zero_point; void store_TIME(const MYSQL_TIME *) override; public: Field_time_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg) :Field_time_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, dec_arg) { DBUG_ASSERT(dec); zero_point= sec_part_shift( ((TIME_MAX_VALUE_SECONDS+1LL)*TIME_SECOND_PART_FACTOR), dec); } void sql_type(String &str) const override { sql_type_dec_comment(str, Field_time_hires::type_handler()->name(), dec, Type_handler::version_mariadb53()); } int reset() override; bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return Type_handler_time::hires_bytes(dec); } uint size_of() const override { return sizeof *this; } }; /** TIME(0..6) - MySQL56 version */ class Field_timef final :public Field_time_with_dec { void store_TIME(const MYSQL_TIME *ltime) override; public: Field_timef(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg) :Field_time_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, dec_arg) { DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); } const Type_handler *type_handler() const override { return &type_handler_time2; } enum_field_types binlog_type() const override { return MYSQL_TYPE_TIME2; } void sql_type(String &str) const override { sql_type_opt_dec_comment(str, Field_timef::type_handler()->name(), dec, type_version_mysql56()); } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; uint32 pack_length() const override { return my_time_binary_length(dec); } uint row_pack_length() const override { return pack_length(); } uint pack_length_from_metadata(uint field_metadata) const override { DBUG_ENTER("Field_timef::pack_length_from_metadata"); uint tmp= my_time_binary_length(field_metadata); DBUG_RETURN(tmp); } void sort_string(uchar *to, uint length) override { DBUG_ASSERT(length == Field_timef::pack_length()); memcpy(to, ptr, length); } int cmp(const uchar *a_ptr, const uchar *b_ptr) const override { return memcmp(a_ptr, b_ptr, pack_length()); } int reset() override; bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override; longlong val_time_packed(THD *thd) override; int store_native(const Native &value) override; bool val_native(Native *to) override; uint size_of() const override { return sizeof *this; } Binlog_type_info binlog_type_info() const override; }; class Field_datetime :public Field_temporal_with_date { protected: int store_TIME_with_warning(const Datetime *ltime, const ErrConv *str, int was_cut); public: Field_datetime(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_temporal_with_date(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) { if (unireg_check == TIMESTAMP_UN_FIELD || unireg_check == TIMESTAMP_DNUN_FIELD) flags|= ON_UPDATE_NOW_FLAG; } const Type_handler *type_handler() const override { return &type_handler_datetime; } sql_mode_t conversion_depends_on_sql_mode(THD *, Item *) const override; enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; int store(const char *to, size_t length, CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int store_time_dec(const MYSQL_TIME *ltime, uint dec) override; int store_decimal(const my_decimal *) override; int set_time() override; Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) override { return get_equal_const_item_datetime(thd, ctx, const_item); } }; /* Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte */ class Field_datetime0 final :public Field_datetime { void store_TIME(const MYSQL_TIME *ltime) override; bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const override; public: Field_datetime0(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_datetime(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) {} enum ha_base_keytype key_type() const override { return HA_KEYTYPE_ULONGLONG; } void sql_type(String &str) const override { sql_type_comment(str, Field_datetime0::type_handler()->name(), Type_handler::version_mariadb53()); } double val_real() override { return (double) Field_datetime0::val_int(); } longlong val_int() override; String *val_str(String *, String *) override; bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 8; } bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return Field_datetime0::get_TIME(ltime, ptr, fuzzydate); } uchar *pack(uchar* to, const uchar *from, uint) override { return pack_int64(to, from); } const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint) override { return unpack_int64(to, from, from_end); } uint size_of() const override { return sizeof *this; } }; /** Abstract class for: - DATETIME(1..6) - DATETIME(0..6) - MySQL56 version */ class Field_datetime_with_dec :public Field_datetime { protected: decimal_digits_t dec; public: Field_datetime_with_dec(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg) :Field_datetime(ptr_arg, MAX_DATETIME_WIDTH + dec_arg + MY_TEST(dec_arg), null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg), dec(dec_arg) { DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); } decimal_digits_t decimals() const override final { return dec; } enum ha_base_keytype key_type() const override final { return HA_KEYTYPE_BINARY; } void make_send_field(Send_field *field) override final; bool send(Protocol *protocol) override final; uchar *pack(uchar *to, const uchar *from, uint max_length) override final { return Field::pack(to, from, max_length); } const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data) override final { return Field::unpack(to, from, from_end, param_data); } void sort_string(uchar *to, uint length) override final { DBUG_ASSERT(length == pack_length()); memcpy(to, ptr, length); } double val_real() override final; longlong val_int() override final; String *val_str(String *, String *) override final; }; /** DATETIME(1..6) */ class Field_datetime_hires final :public Field_datetime_with_dec { void store_TIME(const MYSQL_TIME *ltime) override; bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const override; public: Field_datetime_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg) :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, dec_arg) { DBUG_ASSERT(dec); } void sql_type(String &str) const override { sql_type_dec_comment(str, Field_datetime_hires::type_handler()->name(), dec, Type_handler::version_mariadb53()); } int cmp(const uchar *,const uchar *) const override; uint32 pack_length() const override { return Type_handler_datetime::hires_bytes(dec); } bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return Field_datetime_hires::get_TIME(ltime, ptr, fuzzydate); } uint size_of() const override { return sizeof *this; } }; /** DATETIME(0..6) - MySQL56 version */ class Field_datetimef final :public Field_datetime_with_dec { void store_TIME(const MYSQL_TIME *ltime) override; bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const override; public: Field_datetimef(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, decimal_digits_t dec_arg) :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, dec_arg) {} const Type_handler *type_handler() const override { return &type_handler_datetime2; } enum_field_types binlog_type() const override { return MYSQL_TYPE_DATETIME2; } void sql_type(String &str) const override { sql_type_opt_dec_comment(str, Field_datetimef::type_handler()->name(), dec, type_version_mysql56()); } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; uint32 pack_length() const override { return my_datetime_binary_length(dec); } uint row_pack_length() const override { return pack_length(); } uint pack_length_from_metadata(uint field_metadata) const override { DBUG_ENTER("Field_datetimef::pack_length_from_metadata"); uint tmp= my_datetime_binary_length(field_metadata); DBUG_RETURN(tmp); } int cmp(const uchar *a_ptr, const uchar *b_ptr) const override { return memcmp(a_ptr, b_ptr, pack_length()); } int reset() override; bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return Field_datetimef::get_TIME(ltime, ptr, fuzzydate); } longlong val_datetime_packed(THD *thd) override; uint size_of() const override { return sizeof *this; } Binlog_type_info binlog_type_info() const override; }; static inline Field_timestamp * new_Field_timestamp(MEM_ROOT *root,uchar *ptr, uchar *null_ptr, uchar null_bit, enum Field::utype unireg_check, const LEX_CSTRING *field_name, TABLE_SHARE *share, decimal_digits_t dec) { if (dec==0) return new (root) Field_timestamp0(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit, unireg_check, field_name, share); if (dec >= FLOATING_POINT_DECIMALS) dec= MAX_DATETIME_PRECISION; return new (root) Field_timestamp_hires(ptr, null_ptr, null_bit, unireg_check, field_name, share, dec); } static inline Field_time * new_Field_time(MEM_ROOT *root, uchar *ptr, uchar *null_ptr, uchar null_bit, enum Field::utype unireg_check, const LEX_CSTRING *field_name, decimal_digits_t dec) { if (dec == 0) return new (root) Field_time0(ptr, MIN_TIME_WIDTH, null_ptr, null_bit, unireg_check, field_name); if (dec >= FLOATING_POINT_DECIMALS) dec= MAX_DATETIME_PRECISION; return new (root) Field_time_hires(ptr, null_ptr, null_bit, unireg_check, field_name, dec); } static inline Field_datetime * new_Field_datetime(MEM_ROOT *root, uchar *ptr, uchar *null_ptr, uchar null_bit, enum Field::utype unireg_check, const LEX_CSTRING *field_name, decimal_digits_t dec) { if (dec == 0) return new (root) Field_datetime0(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit, unireg_check, field_name); if (dec >= FLOATING_POINT_DECIMALS) dec= MAX_DATETIME_PRECISION; return new (root) Field_datetime_hires(ptr, null_ptr, null_bit, unireg_check, field_name, dec); } class Field_string final :public Field_longstr { class Warn_filter_string: public Warn_filter { public: Warn_filter_string(const THD *thd, const Field_string *field); }; bool is_var_string() const { return can_alter_field_type && orig_table && (orig_table->s->db_create_options & HA_OPTION_PACK_RECORD) && field_length >= 4 && orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR; } LEX_CSTRING to_lex_cstring() const; public: bool can_alter_field_type; Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, const DTCollation &collation) :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, collation), can_alter_field_type(1) {}; Field_string(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, const DTCollation &collation) :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, NONE, field_name_arg, collation), can_alter_field_type(1) {}; const Type_handler *type_handler() const override; enum ha_base_keytype key_type() const override { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; } en_fieldtype tmp_engine_column_type(bool use_packed_rows) const override; bool zero_pack() const override { return false; } Copy_func *get_copy_func(const Field *from) const override; int reset() override { charset()->fill((char*) ptr, field_length, (has_charset() ? ' ' : 0)); return 0; } int store(const char *to,size_t length,CHARSET_INFO *charset) override; using Field_str::store; double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; my_decimal *val_decimal(my_decimal *) override; int cmp(const uchar *,const uchar *) const override; int cmp_prefix(const uchar *a, const uchar *b, size_t prefix_char_len) const override; void sort_string(uchar *buff,uint length) override; void update_data_type_statistics(Data_type_statistics *st) const override { st->m_fixed_string_count++; st->m_fixed_string_total_length+= pack_length(); } void sql_type(String &str) const override; void sql_rpl_type(String*) const override; bool is_equal(const Column_definition &new_field) const override; uchar *pack(uchar *to, const uchar *from, uint max_length) override; const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data) override; uint pack_length_from_metadata(uint field_metadata) const override { DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata)); if (field_metadata == 0) return row_pack_length(); return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff); } bool compatible_field_size(uint field_metadata, const Relay_log_info *rli, uint16 mflags, int *order_var) const override; uint row_pack_length() const override { return field_length; } uint packed_col_length(const uchar *to, uint length) override; uint max_packed_col_length(uint max_length) override; uint size_of() const override { return sizeof *this; } bool has_charset() const override { return charset() != &my_charset_bin; } Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type) override; uint get_key_image(uchar *buff, uint length, const uchar *ptr_arg, imagetype type) const override; sql_mode_t value_depends_on_sql_mode() const override; sql_mode_t can_handle_sql_mode_dependency_on_store() const override; void print_key_value(String *out, uint32 length) override; Binlog_type_info binlog_type_info() const override; }; class Field_varstring :public Field_longstr { public: const uchar *get_data() const { return get_data(ptr); } const uchar *get_data(const uchar *ptr_arg) const { return ptr_arg + length_bytes; } uint get_length() const { return get_length(ptr); } uint get_length(const uchar *ptr_arg) const { return length_bytes == 1 ? (uint) *ptr_arg : uint2korr(ptr_arg); } protected: void store_length(uint32 number) { if (length_bytes == 1) *ptr= (uchar) number; else int2store(ptr, number); } virtual void val_str_from_ptr(String *val, const uchar *ptr) const; public: /* The maximum space available in a Field_varstring, in bytes. See length_bytes. */ static const uint MAX_SIZE; /* Store number of bytes used to store length (1 or 2) */ uint32 length_bytes; Field_varstring(uchar *ptr_arg, uint32 len_arg, uint length_bytes_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, const DTCollation &collation) :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, collation), length_bytes(length_bytes_arg) { share->varchar_fields++; } Field_varstring(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, const DTCollation &collation) :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, NONE, field_name_arg, collation), length_bytes(len_arg < 256 ? 1 :2) { share->varchar_fields++; } const Type_handler *type_handler() const override; en_fieldtype tmp_engine_column_type(bool use_packed_rows) const override { return FIELD_VARCHAR; } enum ha_base_keytype key_type() const override; uint16 key_part_flag() const override { return HA_VAR_LENGTH_PART; } uint16 key_part_length_bytes() const override { return HA_KEY_BLOB_LENGTH; } uint row_pack_length() const override { return field_length; } bool zero_pack() const override { return false; } int reset() override { bzero(ptr,field_length+length_bytes); return 0; } uint32 pack_length() const override { return (uint32) field_length+length_bytes; } uint32 key_length() const override { return (uint32) field_length; } uint32 sort_length() const override { return (uint32) field_length + sort_suffix_length(); } uint32 sort_suffix_length() const override { return (field_charset() == &my_charset_bin ? length_bytes : 0); } Copy_func *get_copy_func(const Field *from) const override; bool memcpy_field_possible(const Field *from) const override; void update_data_type_statistics(Data_type_statistics *st) const override { st->m_variable_string_count++; st->m_variable_string_total_length+= pack_length(); } int store(const char *to,size_t length,CHARSET_INFO *charset) override; using Field_str::store; #ifdef HAVE_MEM_CHECK void mark_unused_memory_as_defined() override; #endif double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; my_decimal *val_decimal(my_decimal *) override; bool send(Protocol *protocol) override; int cmp(const uchar *a,const uchar *b) const override; int cmp_prefix(const uchar *a, const uchar *b, size_t prefix_char_len) const override; void sort_string(uchar *buff,uint length) override; uint get_key_image(uchar *buff, uint length, const uchar *ptr_arg, imagetype type) const override; void set_key_image(const uchar *buff,uint length) override; void sql_type(String &str) const override; void sql_rpl_type(String*) const override; uchar *pack(uchar *to, const uchar *from, uint max_length) override; const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data) override; int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) const override; int key_cmp(const uchar *,const uchar*) const override; int key_cmp(const uchar *str, uint length) const override; uint packed_col_length(const uchar *to, uint length) override; uint max_packed_col_length(uint max_length) override; uint32 data_length() override; uint size_of() const override { return sizeof *this; } bool has_charset() const override { return charset() == &my_charset_bin ? FALSE : TRUE; } Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type) override; Field *new_key_field(MEM_ROOT *root, TABLE *new_table, uchar *new_ptr, uint32 length, uchar *new_null_ptr, uint new_null_bit) override; bool is_equal(const Column_definition &new_field) const override; void hash_not_null(Hasher *hasher) override; uint length_size() const override { return length_bytes; } void print_key_value(String *out, uint32 length) override; Binlog_type_info binlog_type_info() const override; }; class Field_varstring_compressed final :public Field_varstring { public: Field_varstring_compressed(uchar *ptr_arg, uint32 len_arg, uint length_bytes_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, const DTCollation &collation, Compression_method *compression_method_arg): Field_varstring(ptr_arg, len_arg, length_bytes_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share, collation), compression_method_ptr(compression_method_arg) { DBUG_ASSERT(len_arg > 0); } Compression_method *compression_method() const override { return compression_method_ptr; } private: Compression_method *compression_method_ptr; void val_str_from_ptr(String *val, const uchar *ptr) const override; int store(const char *to, size_t length, CHARSET_INFO *charset) override; using Field_str::store; String *val_str(String *, String *) override; double val_real() override; longlong val_int() override; uint size_of() const override { return sizeof *this; } /* We use the default Field::send() implementation, because the derived optimized version (from Field_longstr) is not suitable for compressed fields. */ bool send(Protocol *protocol) override { return Field::send(protocol); } enum_field_types binlog_type() const override { return MYSQL_TYPE_VARCHAR_COMPRESSED; } void sql_type(String &str) const override { Field_varstring::sql_type(str); str.append(STRING_WITH_LEN(" /*M!100301 COMPRESSED*/")); } uint32 max_display_length() const override { return field_length - 1; } uint32 character_octet_length() const override { return field_length - 1; } uint32 char_length() const override { return (field_length - 1) / mbmaxlen(); } int cmp(const uchar *a_ptr, const uchar *b_ptr) const override; /* Compressed fields can't have keys as two rows may have different compression methods or compression levels. */ int key_cmp(const uchar *str, uint length) const override { DBUG_ASSERT(0); return 0; } using Field_varstring::key_cmp; Binlog_type_info binlog_type_info() const override; Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type) override; }; static inline uint8 number_storage_requirement(uint32 n) { return n < 256 ? 1 : n < 65536 ? 2 : n < 16777216 ? 3 : 4; } static inline void store_bigendian(ulonglong num, uchar *to, uint bytes) { switch(bytes) { case 1: mi_int1store(to, num); break; case 2: mi_int2store(to, num); break; case 3: mi_int3store(to, num); break; case 4: mi_int4store(to, num); break; case 5: mi_int5store(to, num); break; case 6: mi_int6store(to, num); break; case 7: mi_int7store(to, num); break; case 8: mi_int8store(to, num); break; default: DBUG_ASSERT(0); } } static inline longlong read_bigendian(const uchar *from, uint bytes) { switch(bytes) { case 1: return mi_uint1korr(from); case 2: return mi_uint2korr(from); case 3: return mi_uint3korr(from); case 4: return mi_uint4korr(from); case 5: return mi_uint5korr(from); case 6: return mi_uint6korr(from); case 7: return mi_uint7korr(from); case 8: return mi_sint8korr(from); default: DBUG_ASSERT(0); return 0; } } static inline void store_lowendian(ulonglong num, uchar *to, uint bytes) { switch(bytes) { case 1: *to= (uchar)num; break; case 2: int2store(to, num); break; case 3: int3store(to, num); break; case 4: int4store(to, num); break; case 8: int8store(to, num); break; default: DBUG_ASSERT(0); } } static inline longlong read_lowendian(const uchar *from, uint bytes) { switch(bytes) { case 1: return from[0]; case 2: return uint2korr(from); case 3: return uint3korr(from); case 4: return uint4korr(from); case 8: return sint8korr(from); default: DBUG_ASSERT(0); return 0; } } extern LEX_CSTRING temp_lex_str; class Field_blob :public Field_longstr { protected: /** The number of bytes used to represent the length of the blob. */ uint packlength; /** The 'value'-object is a cache fronting the storage engine. */ String value; /** Cache for blob values when reading a row with a virtual blob field. This is needed to not destroy the old cached value when updating the blob with a new value when creating the new row. */ String read_value; static void do_copy_blob(Copy_field *copy); static void do_conv_blob(Copy_field *copy); uint get_key_image_itRAW(const uchar *ptr_arg, uchar *buff, uint length) const; public: Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, uint blob_pack_length, const DTCollation &collation); Field_blob(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, const DTCollation &collation) :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, NONE, field_name_arg, collation), packlength(4) { flags|= BLOB_FLAG; } Field_blob(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, const DTCollation &collation, bool set_packlength) :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, NONE, field_name_arg, collation) { flags|= BLOB_FLAG; packlength= set_packlength ? number_storage_requirement(len_arg) : 4; } Field_blob(uint32 packlength_arg) :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, &temp_lex_str, system_charset_info), packlength(packlength_arg) {} const Type_handler *type_handler() const override; /* Note that the default copy constructor is used, in clone() */ enum_field_types type() const override { /* We cannot return type_handler()->field_type() here. Some pieces of the code (e.g. in engines) rely on the fact that Field::type(), Field::real_type() and Item_field::field_type() return MYSQL_TYPE_BLOB for all blob variants. We should eventually fix all such code pieces to expect all BLOB type codes. */ return MYSQL_TYPE_BLOB; } enum_field_types real_type() const override { return MYSQL_TYPE_BLOB; } enum ha_base_keytype key_type() const override { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } uint16 key_part_flag() const override { return HA_BLOB_PART; } uint16 key_part_length_bytes() const override { return HA_KEY_BLOB_LENGTH; } en_fieldtype tmp_engine_column_type(bool use_packed_rows) const override { return FIELD_BLOB; } Type_numeric_attributes type_numeric_attributes() const override { return Type_numeric_attributes(Field_blob::max_display_length(), decimals(), is_unsigned()); } Information_schema_character_attributes information_schema_character_attributes() const override { uint32 octets= Field_blob::character_octet_length(); uint32 chars= octets / field_charset()->mbminlen; return Information_schema_character_attributes(octets, chars); } void update_data_type_statistics(Data_type_statistics *st) const override { st->m_blob_count++; } void make_send_field(Send_field *) override; Copy_func *get_copy_func(const Field *from) const override { /* TODO: MDEV-9331 if (from->type() == MYSQL_TYPE_BIT) return do_field_int; */ if (!(from->flags & BLOB_FLAG) || from->charset() != charset() || !from->compression_method() != !compression_method()) return do_conv_blob; if (from->pack_length() != Field_blob::pack_length()) return do_copy_blob; return get_identical_copy_func(); } int store_field(Field *from) override { // Be sure the value is stored if (field_charset() == &my_charset_bin && from->type_handler()->convert_to_binary_using_val_native()) { NativeBuffer<64> tmp; from->val_native(&tmp); value.copy(tmp.ptr(), tmp.length(), &my_charset_bin); return store(value.ptr(), value.length(), &my_charset_bin); } from->val_str(&value); if (table->copy_blobs || (!value.is_alloced() && from->is_varchar_and_in_write_set())) value.copy(); return store(value.ptr(), value.length(), from->charset()); } bool memcpy_field_possible(const Field *from) const override { return Field_str::memcpy_field_possible(from) && !compression_method() == !from->compression_method() && !table->copy_blobs; } bool make_empty_rec_store_default_value(THD *thd, Item *item) override; int store(const char *to, size_t length, CHARSET_INFO *charset) override; int store_from_statistical_minmax_field(Field *stat_field, String *str, MEM_ROOT *mem) override; using Field_str::store; void hash_not_null(Hasher *hasher) override; double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; my_decimal *val_decimal(my_decimal *) override; int cmp(const uchar *a, const uchar *b) const override; int cmp_prefix(const uchar *a, const uchar *b, size_t prefix_char_len) const override; int cmp(const uchar *a, uint32 a_length, const uchar *b, uint32 b_length) const; int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) const override; int key_cmp(const uchar *,const uchar*) const override; int key_cmp(const uchar *str, uint length) const override; /* Never update the value of min_val for a blob field */ bool update_min(Field *min_val, bool force_update) override { return false; } /* Never update the value of max_val for a blob field */ bool update_max(Field *max_val, bool force_update) override { return false; } uint32 key_length() const override { return 0; } void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return (uint32) (packlength + portable_sizeof_char_ptr); } /** Return the packed length without the pointer size added. This is used to determine the size of the actual data in the row buffer. @returns The length of the raw data itself without the pointer. */ uint32 pack_length_no_ptr() const { return (uint32) (packlength); } uint row_pack_length() const override { return pack_length_no_ptr(); } uint32 sort_length() const override; uint32 sort_suffix_length() const override; uint32 value_length() override { return get_length(); } uint32 max_data_length() const override { return (uint32) (((ulonglong) 1 << (packlength*8)) -1); } int reset() override { bzero(ptr, packlength+sizeof(uchar*)); return 0; } void reset_fields() override { bzero((uchar*) &value, sizeof value); bzero((uchar*) &read_value, sizeof read_value); } uint32 get_field_buffer_size() { return value.alloced_length(); } void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number); void store_length(size_t number) { DBUG_ASSERT(number < UINT_MAX32); store_length(ptr, packlength, (uint32)number); } inline uint32 get_length(my_ptrdiff_t row_offset= 0) const { return get_length(ptr+row_offset, this->packlength); } uint32 get_length(const uchar *ptr, uint packlength) const; uint32 get_length(const uchar *ptr_arg) const { return get_length(ptr_arg, this->packlength); } inline uchar *get_ptr() const { return get_ptr(ptr); } inline uchar *get_ptr(const uchar *ptr_arg) const { uchar *s; memcpy(&s, ptr_arg + packlength, sizeof(uchar*)); return s; } inline void set_ptr(uchar *length, uchar *data) { memcpy(ptr,length,packlength); memcpy(ptr+packlength, &data,sizeof(char*)); } void set_ptr_offset(my_ptrdiff_t ptr_diff, uint32 length, const uchar *data) { uchar *ptr_ofs= ADD_TO_PTR(ptr,ptr_diff,uchar*); store_length(ptr_ofs, packlength, length); memcpy(ptr_ofs+packlength, &data, sizeof(char*)); } inline void set_ptr(uint32 length, uchar *data) { set_ptr_offset(0, length, data); } int copy_value(Field_blob *from); uint get_key_image(uchar *buff, uint length, const uchar *ptr_arg, imagetype type) const override { DBUG_ASSERT(type == itRAW); return get_key_image_itRAW(ptr_arg, buff, length); } void set_key_image(const uchar *buff,uint length) override; Field *make_new_field(MEM_ROOT *, TABLE *new_table, bool keep_type) override; Field *new_key_field(MEM_ROOT *root, TABLE *new_table, uchar *new_ptr, uint32 length, uchar *new_null_ptr, uint new_null_bit) override; void sql_type(String &str) const override; /** Copy blob buffer into internal storage "value" and update record pointer. @retval true Memory allocation error @retval false Success */ bool copy() { uchar *tmp= get_ptr(); if (value.copy((char*) tmp, get_length(), charset())) { Field_blob::reset(); return 1; } tmp=(uchar*) value.ptr(); memcpy(ptr+packlength, &tmp, sizeof(char*)); return 0; } void swap(String &inout, bool set_read_value) { if (set_read_value) read_value.swap(inout); else value.swap(inout); } /** Return pointer to blob cache or NULL if not cached. */ String * cached(bool *set_read_value) { char *tmp= (char *) get_ptr(); if (!value.is_empty() && tmp == value.ptr()) { *set_read_value= false; return &value; } if (!read_value.is_empty() && tmp == read_value.ptr()) { *set_read_value= true; return &read_value; } return NULL; } /* store value for the duration of the current read record */ inline void swap_value_and_read_value() { read_value.swap(value); } inline void set_value(uchar *data) { /* Set value pointer. Lengths are not important */ value.reset((char*) data, 1, 1, &my_charset_bin); } uchar *pack(uchar *to, const uchar *from, uint max_length) override; const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end, uint param_data) override; uint packed_col_length(const uchar *col_ptr, uint length) override; uint max_packed_col_length(uint max_length) override; void free() override { value.free(); read_value.free(); } inline void clear_temporary() { uchar *tmp= get_ptr(); if (likely(value.ptr() == (char*) tmp)) bzero((uchar*) &value, sizeof(value)); else { /* Currently read_value should never point to tmp, the following code is mainly here to make things future proof. */ if (unlikely(read_value.ptr() == (char*) tmp)) bzero((uchar*) &read_value, sizeof(read_value)); } } uint size_of() const override { return sizeof *this; } bool has_charset() const override { return charset() != &my_charset_bin; } uint32 max_display_length() const override; uint32 char_length() const override; uint32 character_octet_length() const override; bool is_equal(const Column_definition &new_field) const override; void print_key_value(String *out, uint32 length) override; Binlog_type_info binlog_type_info() const override; friend void TABLE::remember_blob_values(String *blob_storage); friend void TABLE::restore_blob_values(String *blob_storage); }; class Field_blob_compressed final :public Field_blob { public: Field_blob_compressed(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, uint blob_pack_length, const DTCollation &collation, Compression_method *compression_method_arg): Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share, blob_pack_length, collation), compression_method_ptr(compression_method_arg) {} Compression_method *compression_method() const override { return compression_method_ptr; } private: Compression_method *compression_method_ptr; int store(const char *to, size_t length, CHARSET_INFO *charset) override; using Field_str::store; String *val_str(String *, String *) override; double val_real() override; longlong val_int() override; /* We use the default Field::send() implementation, because the derived optimized version (from Field_longstr) is not suitable for compressed fields. */ bool send(Protocol *protocol) override { return Field::send(protocol); } uint size_of() const override { return sizeof *this; } enum_field_types binlog_type() const override { return MYSQL_TYPE_BLOB_COMPRESSED; } void sql_type(String &str) const override { Field_blob::sql_type(str); str.append(STRING_WITH_LEN(" /*M!100301 COMPRESSED*/")); } /* Compressed fields can't have keys as two rows may have different compression methods or compression levels. */ uint get_key_image(uchar *buff, uint length, const uchar *ptr_arg, imagetype type_arg) const override { DBUG_ASSERT(0); return 0; } void set_key_image(const uchar *, uint) override { DBUG_ASSERT(0); } int key_cmp(const uchar *, const uchar *) const override { DBUG_ASSERT(0); return 0; } int key_cmp(const uchar *, uint) const override { DBUG_ASSERT(0); return 0; } Field *new_key_field(MEM_ROOT *, TABLE *, uchar *, uint32, uchar *, uint) override { DBUG_ASSERT(0); return 0; } Binlog_type_info binlog_type_info() const override; Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type) override; }; class Field_enum :public Field_str { static void do_field_enum(Copy_field *copy_field); longlong val_int(const uchar *) const; Data_type_compatibility can_optimize_range_or_keypart_ref( const Item_bool_func *cond, const Item *item) const; protected: uint packlength; public: const TYPELIB *typelib; Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint packlength_arg, const TYPELIB *typelib_arg, const DTCollation &collation) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, collation), packlength(packlength_arg),typelib(typelib_arg) { flags|=ENUM_FLAG; } Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type) override; const Type_handler *type_handler() const override { return &type_handler_enum; } enum ha_base_keytype key_type() const override; sql_mode_t can_handle_sql_mode_dependency_on_store() const override; enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; Copy_func *get_copy_func(const Field *from) const override { if (eq_def(from)) return get_identical_copy_func(); if (real_type() == MYSQL_TYPE_ENUM && from->real_type() == MYSQL_TYPE_ENUM) return do_field_enum; if (from->result_type() == STRING_RESULT) return do_field_string; return do_field_int; } int store_field(Field *from) override { if (from->real_type() == MYSQL_TYPE_ENUM && from->val_int() == 0) { store_type(0); return 0; } return from->save_in_field(this); } int save_in_field(Field *to) override { if (to->result_type() != STRING_RESULT) return to->store(val_int(), 0); return save_in_field_str(to); } bool memcpy_field_possible(const Field *from) const override { return false; } void make_empty_rec_reset(THD *) override { if (flags & NOT_NULL_FLAG) { set_notnull(); store((longlong) 1, true); } else reset(); } int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return (uint32) packlength; } void store_type(ulonglong value); void sql_type(String &str) const override; uint size_of() const override { return sizeof *this; } uint pack_length_from_metadata(uint field_metadata) const override { return (field_metadata & 0x00ff); } uint row_pack_length() const override { return pack_length(); } bool zero_pack() const override { return false; } bool optimize_range(uint, uint) const override { return false; } bool eq_def(const Field *field) const override; bool has_charset() const override { return true; } /* enum and set are sorted as integers */ CHARSET_INFO *sort_charset() const override { return &my_charset_bin; } decimal_digits_t decimals() const override { return 0; } const TYPELIB *get_typelib() const override { return typelib; } uchar *pack(uchar *to, const uchar *from, uint max_length) override; const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end, uint param_data) override; Data_type_compatibility can_optimize_keypart_ref(const Item_bool_func *cond, const Item *item) const override { return can_optimize_range_or_keypart_ref(cond, item); } Data_type_compatibility can_optimize_group_min_max(const Item_bool_func *cond, const Item *const_item) const override { /* Can't use GROUP_MIN_MAX optimization for ENUM and SET, because the values are stored as numbers in index, while MIN() and MAX() work as strings. It would return the records with min and max enum numeric indexes. "Bug#45300 MAX() and ENUM type" should be fixed first. */ return Data_type_compatibility::INCOMPATIBLE_DATA_TYPE; } Data_type_compatibility can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const override { return can_optimize_range_or_keypart_ref(cond, item); } Binlog_type_info binlog_type_info() const override; private: bool is_equal(const Column_definition &new_field) const override; }; class Field_set final :public Field_enum { public: Field_set(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint32 packlength_arg, const TYPELIB *typelib_arg, const DTCollation &collation) :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, packlength_arg, typelib_arg, collation) { flags=(flags & ~ENUM_FLAG) | SET_FLAG; } void make_empty_rec_reset(THD *thd) override { Field::make_empty_rec_reset(thd); } int store_field(Field *from) override { return from->save_in_field(this); } int store(const char *to,size_t length,CHARSET_INFO *charset) override; int store(double nr) override { return Field_set::store((longlong) nr, FALSE); } int store(longlong nr, bool unsigned_val) override; bool zero_pack() const override { return true; } String *val_str(String *, String *) override; void sql_type(String &str) const override; uint size_of() const override { return sizeof *this; } const Type_handler *type_handler() const override { return &type_handler_set; } bool has_charset() const override { return true; } Binlog_type_info binlog_type_info() const override; }; /* Note: To use Field_bit::cmp_binary() you need to copy the bits stored in the beginning of the record (the NULL bytes) to each memory you want to compare (where the arguments point). This is the reason: - Field_bit::cmp_binary() is only implemented in the base class (Field::cmp_binary()). - Field::cmp_binary() currently uses pack_length() to calculate how long the data is. - pack_length() includes size of the bits stored in the NULL bytes of the record. */ class Field_bit :public Field { public: uchar *bit_ptr; // position in record where 'uneven' bits store uchar bit_ofs; // offset to 'uneven' high bits uint bit_len; // number of 'uneven' high bits uint bytes_in_rec; Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg); const Type_handler *type_handler() const override { return &type_handler_bit; } enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BIT; } uint16 key_part_flag() const override { return HA_BIT_PART; } uint32 key_length() const override { return (uint32) (field_length + 7) / 8; } uint32 max_data_length() const override { return key_length(); } uint32 max_display_length() const override { return field_length; } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; CHARSET_INFO *charset() const override { return &my_charset_bin; } const DTCollation & dtcollation() const override; Information_schema_numeric_attributes information_schema_numeric_attributes() const override { return Information_schema_numeric_attributes(field_length); } void update_data_type_statistics(Data_type_statistics *st) const override { st->m_uneven_bit_length+= field_length & 7; } uint size_of() const override { return sizeof *this; } int reset() override { bzero(ptr, bytes_in_rec); if (bit_ptr && (bit_len > 0)) // reset odd bits among null bits clr_rec_bits(bit_ptr, bit_ofs, bit_len); return 0; } Copy_func *get_copy_func(const Field *from) const override { if (from->cmp_type() == DECIMAL_RESULT) return do_field_decimal; return do_field_int; } int save_in_field(Field *to) override { return to->store(val_int(), true); } bool memcpy_field_possible(const Field *from) const override{ return false; } int store(const char *to, size_t length, CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int store_decimal(const my_decimal *) override; double val_real() override; longlong val_int() override; String *val_str(String*, String *) override; bool str_needs_quotes() const override { return true; } my_decimal *val_decimal(my_decimal *) override; bool val_bool() override { return val_int() != 0; } int cmp(const uchar *a, const uchar *b) const override { DBUG_ASSERT(ptr == a || ptr == b); if (ptr == a) return Field_bit::key_cmp(b, bytes_in_rec + MY_TEST(bit_len)); else return Field_bit::key_cmp(a, bytes_in_rec + MY_TEST(bit_len)) * -1; } int cmp_binary_offset(uint row_offset) override { return cmp_offset(row_offset); } int cmp_prefix(const uchar *a, const uchar *b, size_t prefix_char_length) const override; int key_cmp(const uchar *a, const uchar *b) const override { return cmp_binary((uchar *) a, (uchar *) b); } int key_cmp(const uchar *str, uint length) const override; int cmp_offset(my_ptrdiff_t row_offset) override; bool update_min(Field *min_val, bool force_update) override { longlong val= val_int(); bool update_fl= force_update || val < min_val->val_int(); if (update_fl) { min_val->set_notnull(); min_val->store(val, FALSE); } return update_fl; } bool update_max(Field *max_val, bool force_update) override { longlong val= val_int(); bool update_fl= force_update || val > max_val->val_int(); if (update_fl) { max_val->set_notnull(); max_val->store(val, FALSE); } return update_fl; } void store_field_value(uchar *val, uint) override { store(*((longlong *)val), TRUE); } double pos_in_interval(Field *min, Field *max) override { return pos_in_interval_val_real(min, max); } void get_image(uchar *buff, uint length, const uchar *ptr_arg, CHARSET_INFO *cs) const override { get_key_image(buff, length, ptr_arg, itRAW); } void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) override { Field_bit::store((char *) buff, length, cs); } uint get_key_image(uchar *buff, uint length, const uchar *ptr_arg, imagetype type) const override; void set_key_image(const uchar *buff, uint length) override { Field_bit::store((char*) buff, length, &my_charset_bin); } void sort_string(uchar *buff, uint length) override { get_key_image(buff, length, ptr, itRAW); } uint32 pack_length() const override { return (uint32) (field_length + 7) / 8; } uint32 pack_length_in_rec() const override { return bytes_in_rec; } uint pack_length_from_metadata(uint field_metadata) const override; uint row_pack_length() const override { return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); } bool compatible_field_size(uint metadata, const Relay_log_info *rli, uint16 mflags, int *order_var) const override; void sql_type(String &str) const override; uchar *pack(uchar *to, const uchar *from, uint max_length) override; const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end, uint param_data) override; int set_default() override; Field *new_key_field(MEM_ROOT *root, TABLE *new_table, uchar *new_ptr, uint32 length, uchar *new_null_ptr, uint new_null_bit) override; void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg) { bit_ptr= bit_ptr_arg; bit_ofs= bit_ofs_arg; } bool eq(Field *field) override { return (Field::eq(field) && bit_ptr == ((Field_bit *)field)->bit_ptr && bit_ofs == ((Field_bit *)field)->bit_ofs); } bool is_equal(const Column_definition &new_field) const override; void move_field_offset(my_ptrdiff_t ptr_diff) override { Field::move_field_offset(ptr_diff); /* clang does not like when things are added to a null pointer, even if it is never referenced. */ if (bit_ptr) bit_ptr= ADD_TO_PTR(bit_ptr, ptr_diff, uchar*); } void hash_not_null(Hasher *hasher) override; SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part, const Item_bool_func *cond, scalar_comparison_op op, Item *value) override { return get_mm_leaf_int(param, key_part, cond, op, value, true); } void print_key_value(String *out, uint32 length) override { val_int_as_str(out, 1); } /** Save the field metadata for bit fields. Saves the bit length in the first byte and bytes in record in the second byte of the field metadata array at index of *metadata_ptr and *(metadata_ptr + 1). @param metadata_ptr First byte of field metadata @returns number of bytes written to metadata_ptr */ Binlog_type_info binlog_type_info() const override { DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d", bit_len, bytes_in_rec)); /* Since this class and Field_bit_as_char have different ideas of what should be stored here, we compute the values of the metadata explicitly using the field_length. */ return Binlog_type_info(type(), static_cast((field_length & 7) | ((field_length / 8) << 8)), 2); } private: size_t do_last_null_byte() const override; }; /** BIT field represented as chars for non-MyISAM tables. @todo The inheritance relationship is backwards since Field_bit is an extended version of Field_bit_as_char and not the other way around. Hence, we should refactor it to fix the hierarchy order. */ class Field_bit_as_char final :public Field_bit { public: Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg); enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; } uint size_of() const override { return sizeof *this; } int store(const char *to, size_t length, CHARSET_INFO *charset) override; int store(double nr) override { return Field_bit::store(nr); } int store(longlong nr, bool unsigned_val) override { return Field_bit::store(nr, unsigned_val); } void sql_type(String &str) const override; }; class Field_row final :public Field_null { class Virtual_tmp_table *m_table; public: Field_row(uchar *ptr_arg, const LEX_CSTRING *field_name_arg) :Field_null(ptr_arg, 0, Field::NONE, field_name_arg, &my_charset_bin), m_table(NULL) {} ~Field_row(); en_fieldtype tmp_engine_column_type(bool use_packed_rows) const override { DBUG_ASSERT(0); return Field::tmp_engine_column_type(use_packed_rows); } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override { DBUG_ASSERT(0); return CONV_TYPE_IMPOSSIBLE; } Virtual_tmp_table **virtual_tmp_table_addr() override { return &m_table; } bool sp_prepare_and_store_item(THD *thd, Item **value) override; }; extern const LEX_CSTRING null_clex_str; class Column_definition_attributes { public: /* At various stages in execution this can be length of field in bytes or max number of characters. */ ulonglong length; const TYPELIB *interval; CHARSET_INFO *charset; uint32 srid; uint32 pack_flag; decimal_digits_t decimals; Field::utype unireg_check; Column_definition_attributes() :length(0), interval(NULL), charset(&my_charset_bin), srid(0), pack_flag(0), decimals(0), unireg_check(Field::NONE) { } Column_definition_attributes(const Field *field); Column_definition_attributes(const Type_all_attributes &attr); Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, const Record_addr *rec, const Type_handler *handler, const LEX_CSTRING *field_name, uint32 flags) const; uint temporal_dec(uint intlen) const { return (uint) (length > intlen ? length - intlen - 1 : 0); } uint pack_flag_to_pack_length() const; void frm_pack_basic(uchar *buff) const; void frm_pack_charset(uchar *buff) const; void frm_pack_numeric_with_dec(uchar *buff) const; void frm_unpack_basic(const uchar *buff); bool frm_unpack_charset(TABLE_SHARE *share, const uchar *buff); bool frm_unpack_numeric_with_dec(TABLE_SHARE *share, const uchar *buff); bool frm_unpack_temporal_with_dec(TABLE_SHARE *share, uint intlen, const uchar *buff); void set_length_and_dec(const Lex_length_and_dec_st &attr); CHARSET_INFO *explicit_or_derived_charset(const Column_derived_attributes *derived_attr) const { return charset ? charset : derived_attr->charset(); } }; /* Create field class for CREATE TABLE */ class Column_definition: public Sql_alloc, public Type_handler_hybrid_field_type, public Column_definition_attributes { /** Create "interval" from "interval_list". @param mem_root - memory root to create the TYPELIB instance and its values on @param reuse_interval_list_values - determines if TYPELIB can reuse strings from interval_list, or should always allocate a copy on mem_root, even if character set conversion is not needed @retval false on success @retval true on error (bad values, or EOM) */ bool create_interval_from_interval_list(MEM_ROOT *mem_root, bool reuse_interval_list_values); /* Calculate TYPELIB (set or enum) max and total lengths @param cs charset+collation pair of the interval @param max_length length of the longest item @param tot_length sum of the item lengths After this method call: - ENUM uses max_length - SET uses tot_length. */ void calculate_interval_lengths(uint32 *max_length, uint32 *tot_length) { const char **pos; uint *len; *max_length= *tot_length= 0; for (pos= interval->type_names, len= interval->type_lengths; *pos ; pos++, len++) { size_t length= charset->numchars(*pos, *pos + *len); DBUG_ASSERT(length < UINT_MAX32); *tot_length+= (uint) length; set_if_bigger(*max_length, (uint32)length); } } bool prepare_stage1_check_typelib_default(); bool prepare_stage1_convert_default(THD *, MEM_ROOT *, CHARSET_INFO *to); const Type_handler *field_type() const; // Prevent using this Compression_method *compression_method_ptr; public: Lex_ident field_name; LEX_CSTRING comment; // Comment for field enum enum_column_versioning { VERSIONING_NOT_SET, WITH_VERSIONING, WITHOUT_VERSIONING }; Item *on_update; // ON UPDATE NOW() field_visibility_t invisible; /* The value of `length' as set by parser: is the number of characters for most of the types, or of bytes for BLOBs or numeric types. */ uint32 char_length; uint flags, pack_length; List interval_list; engine_option_value *option_list; bool explicitly_nullable; /* This is additinal data provided for any computed(virtual) field. In particular it includes a pointer to the item by which this field can be computed from other fields. */ Virtual_column_info *vcol_info, // Virtual field *default_value, // Default value *check_constraint; // Check constraint enum_column_versioning versioning; Table_period_info *period; Column_definition() :Type_handler_hybrid_field_type(&type_handler_null), compression_method_ptr(0), comment(null_clex_str), on_update(NULL), invisible(VISIBLE), char_length(0), flags(0), pack_length(0), option_list(NULL), explicitly_nullable(false), vcol_info(0), default_value(0), check_constraint(0), versioning(VERSIONING_NOT_SET), period(NULL) { interval_list.empty(); } Column_definition(THD *thd, Field *field, Field *orig_field); bool set_attributes(THD *thd, const Lex_field_type_st &attr, CHARSET_INFO *cs, column_definition_type_t type); void create_length_to_internal_length_null() { DBUG_ASSERT(length == 0); pack_length= 0; } void create_length_to_internal_length_simple() { pack_length= type_handler()->calc_pack_length((uint32) length); } void create_length_to_internal_length_string() { length*= charset->mbmaxlen; if (real_field_type() == MYSQL_TYPE_VARCHAR && compression_method()) length++; set_if_smaller(length, UINT_MAX32); pack_length= type_handler()->calc_pack_length((uint32) length); } void create_length_to_internal_length_typelib() { /* Pack_length already calculated in sql_parse.cc */ length*= charset->mbmaxlen; } bool vers_sys_field() const { return flags & (VERS_ROW_START | VERS_ROW_END); } void create_length_to_internal_length_bit(); void create_length_to_internal_length_newdecimal(); /* Prepare the "charset" member for string data types, such as CHAR, VARCHAR, TEXT, ENUM, SET: - derive the charset if not specified explicitly - find a _bin collation if the BINARY comparison style was specified, e.g.: CREATE TABLE t1 (a VARCHAR(10) BINARY) CHARSET utf8; */ bool prepare_charset_for_string(const Column_derived_attributes *dattr); /** Prepare a SET/ENUM field. Create "interval" from "interval_list" if needed, and adjust "length". @param mem_root - Memory root to allocate TYPELIB and its values on @param reuse_interval_list_values - determines if TYPELIB can reuse value buffers from interval_list, or should always allocate a copy on mem_root, even if character set conversion is not needed */ bool prepare_interval_field(MEM_ROOT *mem_root, bool reuse_interval_list_values); void prepare_interval_field_calc_length() { uint32 field_length, dummy; if (real_field_type() == MYSQL_TYPE_SET) { calculate_interval_lengths(&dummy, &field_length); length= field_length + (interval->count - 1); } else /* MYSQL_TYPE_ENUM */ { calculate_interval_lengths(&field_length, &dummy); length= field_length; } set_if_smaller(length, MAX_FIELD_WIDTH - 1); } bool prepare_blob_field(THD *thd); bool sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root); bool prepare_stage1(THD *thd, MEM_ROOT *mem_root, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr); void prepare_stage1_simple(CHARSET_INFO *cs) { charset= cs; create_length_to_internal_length_simple(); } bool prepare_stage1_typelib(THD *thd, MEM_ROOT *mem_root, handler *file, ulonglong table_flags); bool prepare_stage1_string(THD *thd, MEM_ROOT *mem_root, handler *file, ulonglong table_flags); bool prepare_stage1_bit(THD *thd, MEM_ROOT *mem_root, handler *file, ulonglong table_flags); bool bulk_alter(const Column_derived_attributes *derived_attr, const Column_bulk_alter_attributes *bulk_attr) { return type_handler()->Column_definition_bulk_alter(this, derived_attr, bulk_attr); } void redefine_stage1_common(const Column_definition *dup_field, const handler *file); bool redefine_stage1(const Column_definition *dup_field, const handler *file) { const Type_handler *handler= dup_field->type_handler(); return handler->Column_definition_redefine_stage1(this, dup_field, file); } bool prepare_stage2(handler *handler, ulonglong table_flags); bool prepare_stage2_blob(handler *handler, ulonglong table_flags, uint field_flags); bool prepare_stage2_varchar(ulonglong table_flags); bool prepare_stage2_typelib(const char *type_name, uint field_flags, uint *dup_val_count); uint pack_flag_numeric() const; uint sign_length() const { return flags & UNSIGNED_FLAG ? 0 : 1; } bool check_length(uint mysql_errno, uint max_allowed_length) const; bool fix_attributes_real(uint default_length); bool fix_attributes_int(uint default_length); bool fix_attributes_decimal(); bool fix_attributes_temporal_with_time(uint int_part_length); bool fix_attributes_bit(); bool check(THD *thd); bool validate_check_constraint(THD *thd); bool stored_in_db() const { return !vcol_info || vcol_info->stored_in_db; } ha_storage_media field_storage_type() const { return (ha_storage_media) ((flags >> FIELD_FLAGS_STORAGE_MEDIA) & 3); } column_format_type column_format() const { return (column_format_type) ((flags >> FIELD_FLAGS_COLUMN_FORMAT) & 3); } bool has_default_function() const { return unireg_check != Field::NONE; } Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, const Record_addr *addr, const LEX_CSTRING *field_name_arg) const { return Column_definition_attributes::make_field(share, mem_root, addr, type_handler(), field_name_arg, flags); } Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *field_name_arg) const { Record_addr addr(true); return make_field(share, mem_root, &addr, field_name_arg); } /* Return true if default is an expression that must be saved explicitly */ bool has_default_expression(); bool has_default_now_unireg_check() const { return unireg_check == Field::TIMESTAMP_DN_FIELD || unireg_check == Field::TIMESTAMP_DNUN_FIELD; } void set_type(const Column_definition &other) { set_handler(other.type_handler()); length= other.length; char_length= other.char_length; decimals= other.decimals; flags= other.flags; pack_length= other.pack_length; unireg_check= other.unireg_check; interval= other.interval; charset= other.charset; srid= other.srid; pack_flag= other.pack_flag; } // Replace the entire value by another definition void set_column_definition(const Column_definition *def) { *this= *def; } bool set_compressed(const char *method); bool set_compressed_deprecated(THD *thd, const char *method); bool set_compressed_deprecated_column_attribute(THD *thd, const char *pos, const char *method); void set_compression_method(Compression_method *compression_method_arg) { compression_method_ptr= compression_method_arg; } Compression_method *compression_method() const { return compression_method_ptr; } bool check_vcol_for_key(THD *thd) const; }; /** List of ROW element definitions, e.g.: DECLARE a ROW(a INT,b VARCHAR(10)) */ class Row_definition_list: public List { public: inline bool eq_name(const Spvar_definition *def, const LEX_CSTRING *name) const; /** Find a ROW field by name. @param [IN] name - the name @param [OUT] offset - if the ROW field found, its offset it returned here @retval NULL - the ROW field was not found @retval !NULL - the pointer to the found ROW field */ Spvar_definition *find_row_field_by_name(const LEX_CSTRING *name, uint *offset) const { // Cast-off the "const" qualifier List_iterator it(*((List*)this)); Spvar_definition *def; for (*offset= 0; (def= it++); (*offset)++) { if (eq_name(def, name)) return def; } return 0; } static Row_definition_list *make(MEM_ROOT *mem_root, Spvar_definition *var) { Row_definition_list *list; if (!(list= new (mem_root) Row_definition_list())) return NULL; return list->push_back(var, mem_root) ? NULL : list; } bool append_uniq(MEM_ROOT *thd, Spvar_definition *var); bool adjust_formal_params_to_actual_params(THD *thd, List *args); bool adjust_formal_params_to_actual_params(THD *thd, Item **args, uint arg_count); bool resolve_type_refs(THD *); }; /** This class is used during a stored routine or a trigger execution, at sp_rcontext::create() time. Currently it can represent: - variables with explicit data types: DECLARE a INT; - variables with data type references: DECLARE a t1.a%TYPE; - ROW type variables Notes: - Scalar variables have m_field_definitions==NULL. - ROW variables are defined as having MYSQL_TYPE_NULL, with a non-empty m_field_definitions. Data type references to other object types will be added soon, e.g.: - DECLARE a table_name%ROWTYPE; - DECLARE a cursor_name%ROWTYPE; - DECLARE a record_name%TYPE; - DECLARE a variable_name%TYPE; */ class Spvar_definition: public Column_definition { Qualified_column_ident *m_column_type_ref; // for %TYPE Table_ident *m_table_rowtype_ref; // for table%ROWTYPE bool m_cursor_rowtype_ref; // for cursor%ROWTYPE uint m_cursor_rowtype_offset; // for cursor%ROWTYPE Row_definition_list *m_row_field_definitions; // for ROW public: Spvar_definition() :m_column_type_ref(NULL), m_table_rowtype_ref(NULL), m_cursor_rowtype_ref(false), m_cursor_rowtype_offset(0), m_row_field_definitions(NULL) { } Spvar_definition(THD *thd, Field *field) :Column_definition(thd, field, NULL), m_column_type_ref(NULL), m_table_rowtype_ref(NULL), m_cursor_rowtype_ref(false), m_cursor_rowtype_offset(0), m_row_field_definitions(NULL) { } const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } bool is_column_type_ref() const { return m_column_type_ref != 0; } bool is_table_rowtype_ref() const { return m_table_rowtype_ref != 0; } bool is_cursor_rowtype_ref() const { return m_cursor_rowtype_ref; } bool is_explicit_data_type() const { return !is_column_type_ref() && !is_table_rowtype_ref() && !is_cursor_rowtype_ref(); } Qualified_column_ident *column_type_ref() const { return m_column_type_ref; } void set_column_type_ref(Qualified_column_ident *ref) { m_column_type_ref= ref; } Table_ident *table_rowtype_ref() const { return m_table_rowtype_ref; } void set_table_rowtype_ref(Table_ident *ref) { DBUG_ASSERT(ref); set_handler(&type_handler_row); m_table_rowtype_ref= ref; } uint cursor_rowtype_offset() const { return m_cursor_rowtype_offset; } void set_cursor_rowtype_ref(uint offset) { set_handler(&type_handler_row); m_cursor_rowtype_ref= true; m_cursor_rowtype_offset= offset; } /* Find a ROW field by name. See Row_field_list::find_row_field_by_name() for details. */ Spvar_definition *find_row_field_by_name(const LEX_CSTRING *name, uint *offset) const { DBUG_ASSERT(m_row_field_definitions); return m_row_field_definitions->find_row_field_by_name(name, offset); } uint is_row() const { return m_row_field_definitions != NULL; } // Check if "this" defines a ROW variable with n elements uint is_row(uint n) const { return m_row_field_definitions != NULL && m_row_field_definitions->elements == n; } Row_definition_list *row_field_definitions() const { return m_row_field_definitions; } void set_row_field_definitions(Row_definition_list *list) { DBUG_ASSERT(list); set_handler(&type_handler_row); m_row_field_definitions= list; } }; inline bool Row_definition_list::eq_name(const Spvar_definition *def, const LEX_CSTRING *name) const { return def->field_name.length == name->length && my_strcasecmp(system_charset_info, def->field_name.str, name->str) == 0; } class Create_field :public Column_definition { public: LEX_CSTRING change; // Old column name if column is renamed by ALTER LEX_CSTRING after; // Put column after this one Field *field; // For alter table const TYPELIB *save_interval; // Temporary copy for the above // Used only for UCS2 intervals /** structure with parsed options (for comparing fields in ALTER TABLE) */ ha_field_option_struct *option_struct; uint offset; uint8 interval_id; bool create_if_not_exists; // Used in ALTER TABLE IF NOT EXISTS Create_field(): Column_definition(), field(0), option_struct(NULL), create_if_not_exists(false) { change= after= null_clex_str; } Create_field(THD *thd, Field *old_field, Field *orig_field): Column_definition(thd, old_field, orig_field), change(old_field->field_name), field(old_field), option_struct(old_field->option_struct), create_if_not_exists(false) { after= null_clex_str; } /* Used to make a clone of this object for ALTER/CREATE TABLE */ Create_field *clone(MEM_ROOT *mem_root) const; static void upgrade_data_types(List &list) { List_iterator it(list); while (Create_field *f= it++) f->type_handler()->Column_definition_implicit_upgrade(f); } }; /* A class for sending info to the client */ class Send_field :public Sql_alloc, public Type_handler_hybrid_field_type, public Send_field_extended_metadata { public: LEX_CSTRING db_name; LEX_CSTRING table_name, org_table_name; LEX_CSTRING col_name, org_col_name; ulong length; uint flags; decimal_digits_t decimals; Send_field(Field *field) { field->make_send_field(this); DBUG_ASSERT(table_name.str != 0); normalize(); } Send_field(THD *thd, Item *item); Send_field(Field *field, const LEX_CSTRING &db_name_arg, const LEX_CSTRING &table_name_arg) :Type_handler_hybrid_field_type(field->type_handler()), db_name(db_name_arg), table_name(table_name_arg), org_table_name(table_name_arg), col_name(field->field_name), org_col_name(field->field_name), length(field->field_length), flags(field->table->maybe_null ? (field->flags & ~NOT_NULL_FLAG) : field->flags), decimals(field->decimals()) { normalize(); } private: void normalize() { /* limit number of decimals for float and double */ if (type_handler()->field_type() == MYSQL_TYPE_FLOAT || type_handler()->field_type() == MYSQL_TYPE_DOUBLE) set_if_smaller(decimals, FLOATING_POINT_DECIMALS); } public: // This should move to Type_handler eventually uint32 max_char_length(CHARSET_INFO *cs) const { return type_handler()->field_type() >= MYSQL_TYPE_TINY_BLOB && type_handler()->field_type() <= MYSQL_TYPE_BLOB ? static_cast(length / cs->mbminlen) : static_cast(length / cs->mbmaxlen); } uint32 max_octet_length(CHARSET_INFO *from, CHARSET_INFO *to) const { /* For TEXT/BLOB columns, field_length describes the maximum data length in bytes. There is no limit to the number of characters that a TEXT column can store, as long as the data fits into the designated space. For the rest of textual columns, field_length is evaluated as char_count * mbmaxlen, where character count is taken from the definition of the column. In other words, the maximum number of characters here is limited by the column definition. When one has a LONG TEXT column with a single-byte character set, and the connection character set is multi-byte, the client may get fields longer than UINT_MAX32, due to -> conversion. In that case column max length would not fit into the 4 bytes reserved for it in the protocol. So we cut it here to UINT_MAX32. */ return char_to_byte_length_safe(max_char_length(from), to->mbmaxlen); } // This should move to Type_handler eventually bool is_sane_float() const { return (decimals <= FLOATING_POINT_DECIMALS || (type_handler()->field_type() != MYSQL_TYPE_FLOAT && type_handler()->field_type() != MYSQL_TYPE_DOUBLE)); } bool is_sane_signess() const { if (type_handler() == type_handler()->type_handler_signed() && type_handler() == type_handler()->type_handler_unsigned()) return true; // Any signess is allowed, e.g. DOUBLE, DECIMAL /* We are here e.g. in case of INT data type. The UNSIGNED_FLAG bit must match in flags and in the type handler. */ return ((bool) (flags & UNSIGNED_FLAG)) == type_handler()->is_unsigned(); } bool is_sane() const { return is_sane_float() && is_sane_signess(); } }; /* A class for quick copying data to fields */ class Copy_field :public Sql_alloc { public: uchar *from_ptr,*to_ptr; uchar *from_null_ptr,*to_null_ptr; bool *null_row; uint from_bit,to_bit; /** Number of bytes in the fields pointed to by 'from_ptr' and 'to_ptr'. Usually this is the number of bytes that are copied from 'from_ptr' to 'to_ptr'. For variable-length fields (VARCHAR), the first byte(s) describe the actual length of the text. For VARCHARs with length < 256 there is 1 length byte >= 256 there is 2 length bytes Thus, if from_field is VARCHAR(10), from_length (and in most cases to_length) is 11. For VARCHAR(1024), the length is 1026. @see Field_varstring::length_bytes Note that for VARCHARs, do_copy() will be do_varstring*() which only copies the length-bytes (1 or 2) + the actual length of the text instead of from/to_length bytes. */ uint from_length,to_length; Field *from_field,*to_field; String tmp; // For items Copy_field() = default; ~Copy_field() = default; void set(Field *to,Field *from,bool save); // Field to field void set(uchar *to,Field *from); // Field to string void (*do_copy)(Copy_field *); void (*do_copy2)(Copy_field *); // Used to handle null values }; uint pack_length_to_packflag(uint type); enum_field_types get_blob_type_from_length(ulong length); int set_field_to_null(Field *field); int set_field_to_null_with_conversions(Field *field, bool no_conversions); int convert_null_to_field_value_or_error(Field *field, uint err); bool check_expression(Virtual_column_info *vcol, const LEX_CSTRING *name, enum_vcol_info_type type, Alter_info *alter_info= NULL); /* The following are for the interface with the .frm file */ #define FIELDFLAG_DECIMAL 1U #define FIELDFLAG_BINARY 1U // Shares same flag #define FIELDFLAG_NUMBER 2U #define FIELDFLAG_ZEROFILL 4U #define FIELDFLAG_PACK 120U // Bits used for packing #define FIELDFLAG_INTERVAL 256U // mangled with decimals! #define FIELDFLAG_BITFIELD 512U // mangled with decimals! #define FIELDFLAG_BLOB 1024U // mangled with decimals! #define FIELDFLAG_GEOM 2048U // mangled with decimals! #define FIELDFLAG_TREAT_BIT_AS_CHAR 4096U /* use Field_bit_as_char */ #define FIELDFLAG_LONG_DECIMAL 8192U #define FIELDFLAG_NO_DEFAULT 16384U /* sql */ #define FIELDFLAG_MAYBE_NULL 32768U // sql #define FIELDFLAG_HEX_ESCAPE 0x10000U #define FIELDFLAG_PACK_SHIFT 3 #define FIELDFLAG_DEC_SHIFT 8 #define FIELDFLAG_MAX_DEC 63U #define FIELDFLAG_DEC_MASK 0x3F00U #define MTYP_TYPENR(type) ((type) & 127U) // Remove bits from type #define f_is_dec(x) ((x) & FIELDFLAG_DECIMAL) #define f_is_num(x) ((x) & FIELDFLAG_NUMBER) #define f_is_zerofill(x) ((x) & FIELDFLAG_ZEROFILL) #define f_is_packed(x) ((x) & FIELDFLAG_PACK) #define f_packtype(x) (((x) >> FIELDFLAG_PACK_SHIFT) & 15) #define f_decimals(x) ((uint8) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC)) #define f_is_alpha(x) (!f_is_num(x)) #define f_is_binary(x) ((x) & FIELDFLAG_BINARY) // 4.0- compatibility #define f_is_enum(x) (((x) & (FIELDFLAG_INTERVAL | FIELDFLAG_NUMBER)) == FIELDFLAG_INTERVAL) #define f_is_bitfield(x) (((x) & (FIELDFLAG_BITFIELD | FIELDFLAG_NUMBER)) == FIELDFLAG_BITFIELD) #define f_is_blob(x) (((x) & (FIELDFLAG_BLOB | FIELDFLAG_NUMBER)) == FIELDFLAG_BLOB) #define f_is_geom(x) (((x) & (FIELDFLAG_GEOM | FIELDFLAG_NUMBER)) == FIELDFLAG_GEOM) #define f_settype(x) (((uint) (x)) << FIELDFLAG_PACK_SHIFT) #define f_maybe_null(x) ((x) & FIELDFLAG_MAYBE_NULL) #define f_no_default(x) ((x) & FIELDFLAG_NO_DEFAULT) #define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) #define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) #define f_visibility(x) (static_cast ((x) & INVISIBLE_MAX_BITS)) inline ulonglong TABLE::vers_end_id() const { DBUG_ASSERT(versioned(VERS_TRX_ID)); return static_cast(vers_end_field()->val_int()); } inline ulonglong TABLE::vers_start_id() const { DBUG_ASSERT(versioned(VERS_TRX_ID)); return static_cast(vers_start_field()->val_int()); } #endif /* FIELD_INCLUDED */ server/private/rpl_tblmap.h000064400000006151151031265040012031 0ustar00/* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef TABLE_MAPPING_H #define TABLE_MAPPING_H /* Forward declarations */ #ifndef MYSQL_CLIENT struct TABLE; #else class Table_map_log_event; typedef Table_map_log_event TABLE; void free_table_map_log_event(TABLE *table); #endif /* CLASS table_mapping RESPONSIBILITIES The table mapping is used to map table id's to table pointers COLLABORATION RELAY_LOG For mapping table id:s to tables when receiving events. */ /* Guilhem to Mats: in the table_mapping class, the memory is allocated and never freed (until destruction). So this is a good candidate for allocating inside a MEM_ROOT: it gives the efficient allocation in chunks (like in expand()). So I have introduced a MEM_ROOT. Note that inheriting from Sql_alloc had no effect: it has effects only when "ptr= new table_mapping" is called, and this is never called. And it would then allocate from thd->mem_root which is a highly volatile object (reset from example after executing each query, see dispatch_command(), it has a free_root() at end); as the table_mapping object is supposed to live longer than a query, it was dangerous. A dedicated MEM_ROOT needs to be used, see below. */ #include "hash.h" /* HASH */ class table_mapping { private: MEM_ROOT m_mem_root; public: enum enum_error { ERR_NO_ERROR = 0, ERR_LIMIT_EXCEEDED, ERR_MEMORY_ALLOCATION }; table_mapping(); ~table_mapping(); TABLE* get_table(ulonglong table_id); int set_table(ulonglong table_id, TABLE* table); int remove_table(ulonglong table_id); void clear_tables(); ulong count() const { return m_table_ids.records; } private: /* This is a POD (Plain Old Data). Keep it that way (we apply offsetof() to it, which only works for PODs) */ struct entry { ulonglong table_id; union { TABLE *table; entry *next; }; }; entry *find_entry(ulonglong table_id) { return (entry *) my_hash_search(&m_table_ids, (uchar*)&table_id, sizeof(table_id)); } int expand(); /* Head of the list of free entries; "free" in the sense that it's an allocated entry free for use, NOT in the sense that it's freed memory. */ entry *m_free; /* Correspondance between an id (a number) and a TABLE object */ HASH m_table_ids; }; #endif server/private/sql_statistics.h000064400000030246151031265040012750 0ustar00/* Copyright 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_STATISTICS_H #define SQL_STATISTICS_H /* For COMPLEMENTARY_FOR_QUERIES and PREFERABLY_FOR_QUERIES they are similar to the COMPLEMENTARY and PREFERABLY respectively except that with these values we would not be collecting EITS for queries like ANALYZE TABLE t1; To collect EITS with these values, we have to use PERSISITENT FOR analyze table t1 persistent for columns (col1,col2...) index (idx1, idx2...) or analyze table t1 persistent for all */ typedef enum enum_use_stat_tables_mode { NEVER, COMPLEMENTARY, PREFERABLY, COMPLEMENTARY_FOR_QUERIES, PREFERABLY_FOR_QUERIES } Use_stat_tables_mode; typedef enum enum_histogram_type { SINGLE_PREC_HB, DOUBLE_PREC_HB } Histogram_type; enum enum_stat_tables { TABLE_STAT, COLUMN_STAT, INDEX_STAT, }; /* These enumeration types comprise the dictionary of three statistical tables table_stat, column_stat and index_stat as they defined in ../scripts/mysql_system_tables.sql. It would be nice if the declarations of these types were generated automatically by the table definitions. */ enum enum_table_stat_col { TABLE_STAT_DB_NAME, TABLE_STAT_TABLE_NAME, TABLE_STAT_CARDINALITY, TABLE_STAT_N_FIELDS }; enum enum_column_stat_col { COLUMN_STAT_DB_NAME, COLUMN_STAT_TABLE_NAME, COLUMN_STAT_COLUMN_NAME, COLUMN_STAT_MIN_VALUE, COLUMN_STAT_MAX_VALUE, COLUMN_STAT_NULLS_RATIO, COLUMN_STAT_AVG_LENGTH, COLUMN_STAT_AVG_FREQUENCY, COLUMN_STAT_HIST_SIZE, COLUMN_STAT_HIST_TYPE, COLUMN_STAT_HISTOGRAM, COLUMN_STAT_N_FIELDS }; enum enum_index_stat_col { INDEX_STAT_DB_NAME, INDEX_STAT_TABLE_NAME, INDEX_STAT_INDEX_NAME, INDEX_STAT_PREFIX_ARITY, INDEX_STAT_AVG_FREQUENCY, INDEX_STAT_N_FIELDS }; inline Use_stat_tables_mode get_use_stat_tables_mode(THD *thd) { return (Use_stat_tables_mode) (thd->variables.use_stat_tables); } inline bool check_eits_collection_allowed(THD *thd) { return (get_use_stat_tables_mode(thd) == COMPLEMENTARY || get_use_stat_tables_mode(thd) == PREFERABLY); } inline bool check_eits_preferred(THD *thd) { return (get_use_stat_tables_mode(thd) == PREFERABLY || get_use_stat_tables_mode(thd) == PREFERABLY_FOR_QUERIES); } int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables); int read_statistics_for_tables(THD *thd, TABLE_LIST *tables, bool force_reload); int collect_statistics_for_table(THD *thd, TABLE *table); int alloc_statistics_for_table(THD *thd, TABLE *table, MY_BITMAP *stat_fields); int update_statistics_for_table(THD *thd, TABLE *table); int delete_statistics_for_table(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *tab); int delete_statistics_for_column(THD *thd, TABLE *tab, Field *col); int delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info, bool ext_prefixes_only); int rename_table_in_stat_tables(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *tab, const LEX_CSTRING *new_db, const LEX_CSTRING *new_tab); int rename_columns_in_stat_table(THD *thd, TABLE *tab, List *fields); int rename_indexes_in_stat_table(THD *thd, TABLE *tab, List *indexes); void set_statistics_for_table(THD *thd, TABLE *table); double get_column_avg_frequency(Field * field); double get_column_range_cardinality(Field *field, key_range *min_endp, key_range *max_endp, uint range_flag); bool is_stat_table(const LEX_CSTRING *db, LEX_CSTRING *table); bool is_eits_usable(Field* field); class Histogram { private: Histogram_type type; uint8 size; /* Size of values array, in bytes */ uchar *values; uint prec_factor() { switch (type) { case SINGLE_PREC_HB: return ((uint) (1 << 8) - 1); case DOUBLE_PREC_HB: return ((uint) (1 << 16) - 1); } return 1; } public: uint get_width() { switch (type) { case SINGLE_PREC_HB: return size; case DOUBLE_PREC_HB: return size / 2; } return 0; } private: uint get_value(uint i) { DBUG_ASSERT(i < get_width()); switch (type) { case SINGLE_PREC_HB: return (uint) (((uint8 *) values)[i]); case DOUBLE_PREC_HB: return (uint) uint2korr(values + i * 2); } return 0; } /* Find the bucket which value 'pos' falls into. */ uint find_bucket(double pos, bool first) { uint val= (uint) (pos * prec_factor()); int lp= 0; int rp= get_width() - 1; int d= get_width() / 2; uint i= lp + d; for ( ; d; d= (rp - lp) / 2, i= lp + d) { if (val == get_value(i)) break; if (val < get_value(i)) rp= i; else if (val > get_value(i + 1)) lp= i + 1; else break; } if (val > get_value(i) && i < (get_width() - 1)) i++; if (val == get_value(i)) { if (first) { while(i && val == get_value(i - 1)) i--; } else { while(i + 1 < get_width() && val == get_value(i + 1)) i++; } } return i; } public: uint get_size() { return (uint) size; } Histogram_type get_type() { return type; } uchar *get_values() { return (uchar *) values; } void set_size (ulonglong sz) { size= (uint8) sz; } void set_type (Histogram_type t) { type= t; } void set_values (uchar *vals) { values= (uchar *) vals; } bool is_available() { return get_size() > 0 && get_values(); } /* This function checks that histograms should be usable only when 1) the level of optimizer_use_condition_selectivity > 3 2) histograms have been collected */ bool is_usable(THD *thd) { return thd->variables.optimizer_use_condition_selectivity > 3 && is_available(); } void set_value(uint i, double val) { switch (type) { case SINGLE_PREC_HB: ((uint8 *) values)[i]= (uint8) (val * prec_factor()); return; case DOUBLE_PREC_HB: int2store(values + i * 2, val * prec_factor()); return; } } void set_prev_value(uint i) { switch (type) { case SINGLE_PREC_HB: ((uint8 *) values)[i]= ((uint8 *) values)[i-1]; return; case DOUBLE_PREC_HB: int2store(values + i * 2, uint2korr(values + i * 2 - 2)); return; } } double range_selectivity(double min_pos, double max_pos) { double sel; double bucket_sel= 1.0/(get_width() + 1); uint min= find_bucket(min_pos, TRUE); uint max= find_bucket(max_pos, FALSE); sel= bucket_sel * (max - min + 1); return sel; } /* Estimate selectivity of "col=const" using a histogram */ double point_selectivity(double pos, double avg_sel); }; class Columns_statistics; class Index_statistics; /* Statistical data on a table */ class Table_statistics { public: my_bool cardinality_is_null; /* TRUE if the cardinality is unknown */ ha_rows cardinality; /* Number of rows in the table */ uchar *min_max_record_buffers; /* Record buffers for min/max values */ Column_statistics *column_stats; /* Array of statistical data for columns */ Index_statistics *index_stats; /* Array of statistical data for indexes */ /* Array of records per key for index prefixes */ ulonglong *idx_avg_frequency; uchar *histograms; /* Sequence of histograms */ }; /* Statistical data on a column Note: objects of this class may be "empty", where they have almost all fields as zeros, for example, get_avg_frequency() will return 0. objects are allocated in alloc_statistics_for_table[_share]. */ class Column_statistics { private: static const uint Scale_factor_nulls_ratio= 100000; static const uint Scale_factor_avg_length= 100000; static const uint Scale_factor_avg_frequency= 100000; public: /* Bitmap indicating what statistical characteristics are available for the column */ uint32 column_stat_nulls; /* For the below two, see comments in get_column_range_cardinality() */ /* Minimum value for the column */ Field *min_value; /* Maximum value for the column */ Field *max_value; private: /* The ratio Z/N multiplied by the scale factor Scale_factor_nulls_ratio, where N is the total number of rows, Z is the number of nulls in the column */ ulong nulls_ratio; /* Average number of bytes occupied by the representation of a value of the column in memory buffers such as join buffer multiplied by the scale factor Scale_factor_avg_length. CHAR values are stripped of trailing spaces. Flexible values are stripped of their length prefixes. */ ulonglong avg_length; /* The ratio N/D multiplied by the scale factor Scale_factor_avg_frequency, where N is the number of rows with not null value in the column, D the number of distinct values among them */ ulonglong avg_frequency; public: Histogram histogram; uint32 no_values_provided_bitmap() { return ((1 << (COLUMN_STAT_HISTOGRAM-COLUMN_STAT_COLUMN_NAME))-1) << (COLUMN_STAT_COLUMN_NAME+1); } void set_all_nulls() { column_stat_nulls= no_values_provided_bitmap(); } void set_not_null(uint stat_field_no) { column_stat_nulls&= ~(1 << stat_field_no); } bool is_null(uint stat_field_no) { return MY_TEST(column_stat_nulls & (1 << stat_field_no)); } double get_nulls_ratio() { return (double) nulls_ratio / Scale_factor_nulls_ratio; } double get_avg_length() { return (double) avg_length / Scale_factor_avg_length; } double get_avg_frequency() { return (double) avg_frequency / Scale_factor_avg_frequency; } void set_nulls_ratio (double val) { nulls_ratio= (ulong) (val * Scale_factor_nulls_ratio); } void set_avg_length (double val) { avg_length= (ulonglong) (val * Scale_factor_avg_length); } void set_avg_frequency (double val) { avg_frequency= (ulonglong) (val * Scale_factor_avg_frequency); } bool min_max_values_are_provided() { return !is_null(COLUMN_STAT_MIN_VALUE) && !is_null(COLUMN_STAT_MAX_VALUE); } /* This function checks whether the values for the fields of the statistical tables that were NULL by DEFAULT for a column have changed or not. @retval TRUE: Statistics are not present for a column FALSE: Statisitics are present for a column */ bool no_stat_values_provided() { return (column_stat_nulls == no_values_provided_bitmap()); } }; /* Statistical data on an index prefixes */ class Index_statistics { private: static const uint Scale_factor_avg_frequency= 100000; /* The k-th element of this array contains the ratio N/D multiplied by the scale factor Scale_factor_avg_frequency, where N is the number of index entries without nulls in the first k components, and D is the number of distinct k-component prefixes among them */ ulonglong *avg_frequency; public: void init_avg_frequency(ulonglong *ptr) { avg_frequency= ptr; } bool avg_frequency_is_inited() { return avg_frequency != NULL; } double get_avg_frequency(uint i) const { return (double) avg_frequency[i] / Scale_factor_avg_frequency; } void set_avg_frequency(uint i, double val) { avg_frequency[i]= (ulonglong) (val * Scale_factor_avg_frequency); } }; #endif /* SQL_STATISTICS_H */ server/private/my_compare.h000064400000025672151031265040012041 0ustar00/* Copyright (c) 2011, Oracle and/or its affiliates. Copyright (c) 1991, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_compare_h #define _my_compare_h #include "myisampack.h" #ifdef __cplusplus extern "C" { #endif #include "m_ctype.h" /* CHARSET_INFO */ /* There is a hard limit for the maximum number of keys as there are only 8 bits in the index file header for the number of keys in a table. This means that 0..255 keys can exist for a table. The idea of HA_MAX_POSSIBLE_KEY is to ensure that one can use myisamchk & tools on a MyISAM table for which one has more keys than MyISAM is normally compiled for. If you don't have this, you will get a core dump when running myisamchk compiled for 128 keys on a table with 255 keys. */ #define HA_MAX_POSSIBLE_KEY 255 /* For myisamchk */ /* The following defines can be increased if necessary. But beware the dependency of MI_MAX_POSSIBLE_KEY_BUFF and HA_MAX_KEY_LENGTH. */ #define HA_MAX_KEY_LENGTH 1000 /* Max length in bytes */ #define HA_MAX_KEY_SEG 32 /* Max segments for key */ #define HA_MAX_POSSIBLE_KEY_BUFF (HA_MAX_KEY_LENGTH + 24+ 6+6) #define HA_MAX_KEY_BUFF (HA_MAX_KEY_LENGTH+HA_MAX_KEY_SEG*6+8+8) typedef struct st_HA_KEYSEG /* Key-portion */ { CHARSET_INFO *charset; uint32 start; /* Start of key in record */ uint32 null_pos; /* position to NULL indicator */ uint16 bit_pos; /* Position to bit part */ uint16 flag; uint16 length; /* Keylength */ uint16 language; uint8 type; /* Type of key (for sort) */ uint8 null_bit; /* bitmask to test for NULL */ uint8 bit_start; uint8 bit_length; /* Length of bit part */ } HA_KEYSEG; #define get_key_length(length,key) \ { if (*(const uchar*) (key) != 255) \ length= (uint) *(const uchar*) ((key)++); \ else \ { length= mi_uint2korr((key)+1); (key)+=3; } \ } #define get_key_length_rdonly(length,key) \ { if (*(const uchar*) (key) != 255) \ length= ((uint) *(const uchar*) ((key))); \ else \ { length= mi_uint2korr((key)+1); } \ } #define get_key_pack_length(length,length_pack,key) \ { if (*(const uchar*) (key) != 255) \ { length= (uint) *(const uchar*) ((key)++); length_pack= 1; }\ else \ { length=mi_uint2korr((key)+1); (key)+= 3; length_pack= 3; } \ } #define store_key_length_inc(key,length) \ { if ((length) < 255) \ { *(key)++= (uchar)(length); } \ else \ { *(key)=255; mi_int2store((key)+1,(length)); (key)+=3; } \ } #define size_to_store_key_length(length) ((length) < 255 ? 1 : 3) static inline uchar get_rec_bits(const uchar *ptr, uchar ofs, uint len) { uint16 val= ptr[0]; if (ofs + len > 8) val|= (uint16)(((uint) ptr[1]) << 8); return (uchar) ((val >> ofs) & ((1 << len) - 1)); } static inline void set_rec_bits(uint16 bits, uchar *ptr, uchar ofs, uint len) { ptr[0]= (uchar) ((ptr[0] & ~(((1 << len) - 1) << ofs)) | (bits << ofs)); if (ofs + len > 8) ptr[1]= (uchar) ((ptr[1] & ~((1 << (len - 8 + ofs)) - 1)) | bits >> (8 - ofs)); } #define clr_rec_bits(bit_ptr, bit_ofs, bit_len) \ set_rec_bits(0, bit_ptr, bit_ofs, bit_len) /* Compare two VARCHAR values. @param charset_info - The character set and collation @param a - The pointer to the first string @param a_length - The length of the first string @param b - The pointer to the second string @param b_length - The length of the second string @param b_is_prefix - Whether "b" is a prefix of "a", e.g. in a prefix key (partial length key). @returns - The result of comparison - If "b_is_prefix" is FALSE, then the two strings are compared taking into account the PAD SPACE/NO PAD attribute of the collation. - If "b_is_prefix" is TRUE, then trailing spaces are compared in NO PAD style. This is done e.g. when we compare a column value to its prefix key value (the value of "a" to the value of "key_a"): CREATE TABLE t1 (a VARCHAR(10), KEY(key_a(5)); */ static inline int ha_compare_char_varying(CHARSET_INFO *charset_info, const uchar *a, size_t a_length, const uchar *b, size_t b_length, my_bool b_is_prefix) { if (!b_is_prefix) return charset_info->coll->strnncollsp(charset_info, a, a_length, b, b_length); return charset_info->coll->strnncoll(charset_info, a, a_length, b, b_length, TRUE/*prefix*/); } /* Compare two CHAR values of the same declared character length, e.g. CHAR(5) to CHAR(5). @param charset_info - The character set and collation @param a - The pointer to the first string @param a_length - The length of the first string @param b - The pointer to the second string @param b_length - The length of the second string @param nchars - The declared length (in characters) @param b_is_prefix - Whether "b" is a prefix of "a", e.g. in a prefix key (partial length key). @returns - The result of comparison - If "b_is_prefix" is FALSE, then the two strings are compared taking into account the PAD SPACE/NO PAD attribute of the collation. Additionally, this function assumes that the underlying storage could optionally apply trailing space compression, so values can come into this comparison function in different states: - all trailing spaces removed - some trailing spaced removed - no trailing spaces removed (exactly "nchars" characters on the two sides) This function virtually reconstructs trailing spaces up to the defined length specified in "nchars". If either of the sides have more than "nchar" characters, then only leftmost "nchar" characters are compared. - If "b_is_prefix" is TRUE, then trailing spaces are compared in NO PAD style. This is done e.g. when we compare a column value to its prefix key value (the value of "a" to the value of "key_a"): CREATE TABLE t1 (a CHAR(10), KEY(key_a(5)); */ static inline int ha_compare_char_fixed(CHARSET_INFO *charset_info, const uchar *a, size_t a_length, const uchar *b, size_t b_length, size_t nchars, my_bool b_is_prefix) { if (!b_is_prefix) return charset_info->coll->strnncollsp_nchars(charset_info, a, a_length, b, b_length, nchars, MY_STRNNCOLLSP_NCHARS_EMULATE_TRIMMED_TRAILING_SPACES); return charset_info->coll->strnncoll(charset_info, a, a_length, b, b_length, TRUE/*prefix*/); } /* A function to compare words of a text. This is a common operation in full-text search: SELECT MATCH (title) AGAINST ('word') FROM t1; */ static inline int ha_compare_word(CHARSET_INFO *charset_info, const uchar *a, size_t a_length, const uchar *b, size_t b_length) { return charset_info->coll->strnncollsp(charset_info, a, a_length, b, b_length); } /* A function to compare a word of a text to a word prefix. This is a common operation in full-text search: SELECT MATCH (title) AGAINST ('wor*' IN BOOLEAN MODE) FROM t1; */ static inline int ha_compare_word_prefix(CHARSET_INFO *charset_info, const uchar *a, size_t a_length, const uchar *b, size_t b_length) { return charset_info->coll->strnncoll(charset_info, a, a_length, b, b_length, TRUE/*b_is_prefix*/); } /* Compare words (full match or prefix match), e.g. for full-text search. */ static inline int ha_compare_word_or_prefix(CHARSET_INFO *charset_info, const uchar *a, size_t a_length, const uchar *b, size_t b_length, my_bool b_is_prefix) { if (!b_is_prefix) return ha_compare_word(charset_info, a, a_length, b, b_length); return ha_compare_word_prefix(charset_info, a, a_length, b, b_length); } extern int ha_key_cmp(HA_KEYSEG *keyseg, const uchar *a, const uchar *b, uint key_length, uint nextflag, uint *diff_pos); extern HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, const uchar *a); /* Inside an in-memory data record, memory pointers to pieces of the record (like BLOBs) are stored in their native byte order and in this amount of bytes. */ #define portable_sizeof_char_ptr 8 #ifdef __cplusplus } #endif /** Return values for pushed index condition or rowid filter check functions. 0=CHECK_NEG - The filter is not satisfied. The engine should discard this index tuple and continue the scan. 1=CHECK_POS - The filter is satisfied. Current index tuple should be returned to the SQL layer. 2=CHECK_OUT_OF_RANGE - the index tuple is outside of the range that we're scanning. (Example: if we're scanning "t.key BETWEEN 10 AND 20" and got a "t.key=21" tuple) Tthe engine should stop scanning and return HA_ERR_END_OF_FILE right away). 3=CHECK_ABORTED_BY_USER - the engine must stop scanning and should return HA_ERR_ABORTED_BY_USER right away -1=CHECK_ERROR - Reserved for internal errors in engines. Should not be returned by ICP or rowid filter check functions. */ typedef enum check_result { CHECK_ERROR=-1, CHECK_NEG=0, CHECK_POS=1, CHECK_OUT_OF_RANGE=2, CHECK_ABORTED_BY_USER=3 } check_result_t; typedef check_result_t (*index_cond_func_t)(void *param); typedef check_result_t (*rowid_filter_func_t)(void *param); typedef int (*rowid_filter_is_active_func_t)(void *param); #endif /* _my_compare_h */ server/private/sql_crypt.h000064400000002635151031265040011720 0ustar00#ifndef SQL_CRYPT_INCLUDED #define SQL_CRYPT_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_alloc.h" /* Sql_alloc */ #include "my_rnd.h" /* rand_struct */ class SQL_CRYPT :public Sql_alloc { struct my_rnd_struct rand,org_rand; char decode_buff[256],encode_buff[256]; uint shift; public: SQL_CRYPT() = default; SQL_CRYPT(ulong *seed) { init(seed); } ~SQL_CRYPT() = default; void init(ulong *seed); void reinit() { shift=0; rand=org_rand; } void encode(char *str, uint length); void decode(char *str, uint length); }; #endif /* SQL_CRYPT_INCLUDED */ server/private/sp_cache.h000064400000003775151031265040011453 0ustar00/* -*- C++ -*- */ /* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _SP_CACHE_H_ #define _SP_CACHE_H_ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif /* Stored procedures/functions cache. This is used as follows: * Each thread has its own cache. * Each sp_head object is put into its thread cache before it is used, and then remains in the cache until deleted. */ class sp_head; class sp_cache; class Database_qualified_name; /* Cache usage scenarios: 1. Application-wide init: sp_cache_init(); 2. SP execution in thread: 2.1 While holding sp_head* pointers: // look up a routine in the cache (no checks if it is up to date or not) sp_cache_lookup(); sp_cache_insert(); sp_cache_invalidate(); 2.2 When not holding any sp_head* pointers: sp_cache_flush_obsolete(); 3. Before thread exit: sp_cache_clear(); */ void sp_cache_init(); void sp_cache_end(); void sp_cache_clear(sp_cache **cp); void sp_cache_insert(sp_cache **cp, sp_head *sp); sp_head *sp_cache_lookup(sp_cache **cp, const Database_qualified_name *name); void sp_cache_invalidate(); void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp); ulong sp_cache_version(); void sp_cache_enforce_limit(sp_cache *cp, ulong upper_limit_for_elements); #endif /* _SP_CACHE_H_ */ server/private/privilege.h000064400000067742151031265040011700 0ustar00#ifndef PRIVILEGE_H_INCLUDED #define PRIVILEGE_H_INCLUDED /* Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_global.h" // ulonglong /* A strict enum to store privilege bits. We should eventually make if even stricter using "enum class privilege_t" and: - Replace all code pieces like `if (priv)` to `if (priv != NO_ACL)` - Remove "delete" comparison operators below */ enum privilege_t: unsigned long long { NO_ACL = (0), SELECT_ACL = (1UL << 0), INSERT_ACL = (1UL << 1), UPDATE_ACL = (1UL << 2), DELETE_ACL = (1UL << 3), CREATE_ACL = (1UL << 4), DROP_ACL = (1UL << 5), RELOAD_ACL = (1UL << 6), SHUTDOWN_ACL = (1UL << 7), PROCESS_ACL = (1UL << 8), FILE_ACL = (1UL << 9), GRANT_ACL = (1UL << 10), REFERENCES_ACL = (1UL << 11), INDEX_ACL = (1UL << 12), ALTER_ACL = (1UL << 13), SHOW_DB_ACL = (1UL << 14), SUPER_ACL = (1UL << 15), CREATE_TMP_ACL = (1UL << 16), LOCK_TABLES_ACL = (1UL << 17), EXECUTE_ACL = (1UL << 18), REPL_SLAVE_ACL = (1UL << 19), BINLOG_MONITOR_ACL = (1UL << 20), // Was REPL_CLIENT_ACL prior to 10.5.2 CREATE_VIEW_ACL = (1UL << 21), SHOW_VIEW_ACL = (1UL << 22), CREATE_PROC_ACL = (1UL << 23), ALTER_PROC_ACL = (1UL << 24), CREATE_USER_ACL = (1UL << 25), EVENT_ACL = (1UL << 26), TRIGGER_ACL = (1UL << 27), CREATE_TABLESPACE_ACL = (1UL << 28), DELETE_HISTORY_ACL = (1UL << 29), // Added in 10.3.4 SET_USER_ACL = (1UL << 30), // Added in 10.5.2 FEDERATED_ADMIN_ACL = (1UL << 31), // Added in 10.5.2 CONNECTION_ADMIN_ACL = (1ULL << 32), // Added in 10.5.2 READ_ONLY_ADMIN_ACL = (1ULL << 33), // Added in 10.5.2 REPL_SLAVE_ADMIN_ACL = (1ULL << 34), // Added in 10.5.2 REPL_MASTER_ADMIN_ACL = (1ULL << 35), // Added in 10.5.2 BINLOG_ADMIN_ACL = (1ULL << 36), // Added in 10.5.2 BINLOG_REPLAY_ACL = (1ULL << 37), // Added in 10.5.2 SLAVE_MONITOR_ACL = (1ULL << 38) // Added in 10.5.8 /* When adding new privilege bits, don't forget to update: In this file: - Add a new LAST_version_ACL - Add a new ALL_KNOWN_ACL_version - Change ALL_KNOWN_ACL to ALL_KNOWN_ACL_version - Change GLOBAL_ACLS if needed - Change SUPER_ADDED_SINCE_USER_TABLE_ACL if needed In other files: - static struct show_privileges_st sys_privileges[] - static const char *command_array[] and static uint command_lengths[] - mysql_system_tables.sql and mysql_system_tables_fix.sql - acl_init() or whatever - to define behaviour for old privilege tables - Update User_table_json::get_access() - sql_yacc.yy - for GRANT/REVOKE to work Important: the enum should contain only single-bit values. In this case, debuggers print bit combinations in the readable form: (gdb) p (privilege_t) (15) $8 = (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL) Bit-OR combinations of the above values should be declared outside! */ }; constexpr static inline privilege_t ALL_KNOWN_BITS(privilege_t x) { return (privilege_t)(x | (x-1)); } // Version markers constexpr privilege_t LAST_100304_ACL= DELETE_HISTORY_ACL; constexpr privilege_t LAST_100502_ACL= BINLOG_REPLAY_ACL; constexpr privilege_t LAST_100508_ACL= SLAVE_MONITOR_ACL; // Current version markers constexpr privilege_t LAST_CURRENT_ACL= LAST_100508_ACL; constexpr uint PRIVILEGE_T_MAX_BIT= my_bit_log2_uint64((ulonglong) LAST_CURRENT_ACL); static_assert((privilege_t)(1ULL << PRIVILEGE_T_MAX_BIT) == LAST_CURRENT_ACL, "Something went fatally badly: " "LAST_CURRENT_ACL and PRIVILEGE_T_MAX_BIT do not match"); // A combination of all bits defined in 10.3.4 (and earlier) constexpr privilege_t ALL_KNOWN_ACL_100304 = ALL_KNOWN_BITS(LAST_100304_ACL); // A combination of all bits defined in 10.5.2 constexpr privilege_t ALL_KNOWN_ACL_100502= ALL_KNOWN_BITS(LAST_100502_ACL); // A combination of all bits defined in 10.5.8 constexpr privilege_t ALL_KNOWN_ACL_100508= ALL_KNOWN_BITS(LAST_100508_ACL); // unfortunately, SLAVE_MONITOR_ACL was added in 10.5.9, but also in 10.5.8-5 // let's stay compatible with that branch too. constexpr privilege_t ALL_KNOWN_ACL_100509= ALL_KNOWN_ACL_100508; // A combination of all bits defined as of the current version constexpr privilege_t ALL_KNOWN_ACL= ALL_KNOWN_BITS(LAST_CURRENT_ACL); // Unary operators static inline constexpr ulonglong operator~(privilege_t access) { return ~static_cast(access); } /* Comparison operators. Delete automatic conversion between to/from integer types as much as possible. This forces to use `(priv == NO_ACL)` instead of `(priv == 0)`. Note: these operators will be gone when we change privilege_t to "enum class privilege_t". See comments above. */ static inline bool operator==(privilege_t, ulonglong)= delete; static inline bool operator==(privilege_t, ulong)= delete; static inline bool operator==(privilege_t, uint)= delete; static inline bool operator==(privilege_t, uchar)= delete; static inline bool operator==(privilege_t, longlong)= delete; static inline bool operator==(privilege_t, long)= delete; static inline bool operator==(privilege_t, int)= delete; static inline bool operator==(privilege_t, char)= delete; static inline bool operator==(privilege_t, bool)= delete; static inline bool operator==(ulonglong, privilege_t)= delete; static inline bool operator==(ulong, privilege_t)= delete; static inline bool operator==(uint, privilege_t)= delete; static inline bool operator==(uchar, privilege_t)= delete; static inline bool operator==(longlong, privilege_t)= delete; static inline bool operator==(long, privilege_t)= delete; static inline bool operator==(int, privilege_t)= delete; static inline bool operator==(char, privilege_t)= delete; static inline bool operator==(bool, privilege_t)= delete; static inline bool operator!=(privilege_t, ulonglong)= delete; static inline bool operator!=(privilege_t, ulong)= delete; static inline bool operator!=(privilege_t, uint)= delete; static inline bool operator!=(privilege_t, uchar)= delete; static inline bool operator!=(privilege_t, longlong)= delete; static inline bool operator!=(privilege_t, long)= delete; static inline bool operator!=(privilege_t, int)= delete; static inline bool operator!=(privilege_t, char)= delete; static inline bool operator!=(privilege_t, bool)= delete; static inline bool operator!=(ulonglong, privilege_t)= delete; static inline bool operator!=(ulong, privilege_t)= delete; static inline bool operator!=(uint, privilege_t)= delete; static inline bool operator!=(uchar, privilege_t)= delete; static inline bool operator!=(longlong, privilege_t)= delete; static inline bool operator!=(long, privilege_t)= delete; static inline bool operator!=(int, privilege_t)= delete; static inline bool operator!=(char, privilege_t)= delete; static inline bool operator!=(bool, privilege_t)= delete; // Dyadic bitwise operators static inline constexpr privilege_t operator&(privilege_t a, privilege_t b) { return static_cast(static_cast(a) & static_cast(b)); } static inline constexpr privilege_t operator&(ulonglong a, privilege_t b) { return static_cast(a & static_cast(b)); } static inline constexpr privilege_t operator&(privilege_t a, ulonglong b) { return static_cast(static_cast(a) & b); } static inline constexpr privilege_t operator|(privilege_t a, privilege_t b) { return static_cast(static_cast(a) | static_cast(b)); } // Dyadyc bitwise assignment operators static inline privilege_t& operator&=(privilege_t &a, privilege_t b) { return a= a & b; } static inline privilege_t& operator&=(privilege_t &a, ulonglong b) { return a= a & b; } static inline privilege_t& operator|=(privilege_t &a, privilege_t b) { return a= a | b; } /* A combination of all SUPER privileges added since the old user table format. These privileges are automatically added when upgrading from the old format mysql.user table if a user has the SUPER privilege. */ constexpr privilege_t GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS= SET_USER_ACL | FEDERATED_ADMIN_ACL | CONNECTION_ADMIN_ACL | READ_ONLY_ADMIN_ACL | REPL_SLAVE_ADMIN_ACL | BINLOG_ADMIN_ACL | BINLOG_REPLAY_ACL; constexpr privilege_t COL_DML_ACLS= SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL; constexpr privilege_t VIEW_ACLS= CREATE_VIEW_ACL | SHOW_VIEW_ACL; constexpr privilege_t STD_TABLE_DDL_ACLS= CREATE_ACL | DROP_ACL | ALTER_ACL; constexpr privilege_t ALL_TABLE_DDL_ACLS= STD_TABLE_DDL_ACLS | INDEX_ACL; constexpr privilege_t COL_ACLS= SELECT_ACL | INSERT_ACL | UPDATE_ACL | REFERENCES_ACL; constexpr privilege_t PROC_DDL_ACLS= CREATE_PROC_ACL | ALTER_PROC_ACL; constexpr privilege_t SHOW_PROC_ACLS= PROC_DDL_ACLS | EXECUTE_ACL; constexpr privilege_t TABLE_ACLS= COL_DML_ACLS | ALL_TABLE_DDL_ACLS | VIEW_ACLS | GRANT_ACL | REFERENCES_ACL | TRIGGER_ACL | DELETE_HISTORY_ACL; constexpr privilege_t DB_ACLS= TABLE_ACLS | PROC_DDL_ACLS | EXECUTE_ACL | CREATE_TMP_ACL | LOCK_TABLES_ACL | EVENT_ACL; constexpr privilege_t PROC_ACLS= ALTER_PROC_ACL | EXECUTE_ACL | GRANT_ACL; constexpr privilege_t GLOBAL_ACLS= DB_ACLS | SHOW_DB_ACL | CREATE_USER_ACL | CREATE_TABLESPACE_ACL | SUPER_ACL | RELOAD_ACL | SHUTDOWN_ACL | PROCESS_ACL | FILE_ACL | REPL_SLAVE_ACL | BINLOG_MONITOR_ACL | GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS | REPL_MASTER_ADMIN_ACL | SLAVE_MONITOR_ACL; constexpr privilege_t DEFAULT_CREATE_PROC_ACLS= ALTER_PROC_ACL | EXECUTE_ACL; constexpr privilege_t SHOW_CREATE_TABLE_ACLS= COL_DML_ACLS | ALL_TABLE_DDL_ACLS | TRIGGER_ACL | REFERENCES_ACL | GRANT_ACL | VIEW_ACLS; /** Table-level privileges which are automatically "granted" to everyone on existing temporary tables (CREATE_ACL is necessary for ALTER ... RENAME). */ constexpr privilege_t TMP_TABLE_ACLS= COL_DML_ACLS | ALL_TABLE_DDL_ACLS | REFERENCES_ACL; constexpr privilege_t PRIV_LOCK_TABLES= SELECT_ACL | LOCK_TABLES_ACL; /* Allow to set an object definer: CREATE DEFINER=xxx {TRIGGER|VIEW|FUNCTION|PROCEDURE} Was SUPER prior to 10.5.2 */ constexpr privilege_t PRIV_DEFINER_CLAUSE= SET_USER_ACL | SUPER_ACL; /* If a VIEW has a `definer=invoker@host` clause and the specified definer does not exists, then - The invoker with REVEAL_MISSING_DEFINER_ACL gets: ERROR: The user specified as a definer ('definer1'@'localhost') doesn't exist - The invoker without MISSING_DEFINER_ACL gets a generic access error, without revealing details that the definer does not exists. TODO: we should eventually test the same privilege when processing other objects that have the DEFINER clause (e.g. routines, triggers). Currently the missing definer is revealed for non-privileged invokers in case of routines, triggers, etc. Was SUPER prior to 10.5.2 */ constexpr privilege_t PRIV_REVEAL_MISSING_DEFINER= SET_USER_ACL | SUPER_ACL; /* Actions that require only the SUPER privilege */ constexpr privilege_t PRIV_DES_DECRYPT_ONE_ARG= SUPER_ACL; constexpr privilege_t PRIV_LOG_BIN_TRUSTED_SP_CREATOR= SUPER_ACL; constexpr privilege_t PRIV_DEBUG= SUPER_ACL; constexpr privilege_t PRIV_SET_GLOBAL_SYSTEM_VARIABLE= SUPER_ACL; constexpr privilege_t PRIV_SET_RESTRICTED_SESSION_SYSTEM_VARIABLE= SUPER_ACL; /* The following variables respected only SUPER_ACL prior to 10.5.2 */ constexpr privilege_t PRIV_SET_SYSTEM_VAR_BINLOG_FORMAT= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_VAR_BINLOG_DIRECT_NON_TRANSACTIONAL_UPDATES= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_VAR_BINLOG_ANNOTATE_ROW_EVENTS= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_VAR_BINLOG_ROW_IMAGE= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_VAR_SQL_LOG_BIN= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_CACHE_SIZE= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_FILE_CACHE_SIZE= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_STMT_CACHE_SIZE= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_COMMIT_WAIT_COUNT= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_COMMIT_WAIT_USEC= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_ROW_METADATA= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_EXPIRE_LOGS_DAYS= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_BIN_COMPRESS= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_BIN_COMPRESS_MIN_LEN= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_LOG_BIN_TRUST_FUNCTION_CREATORS= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_BINLOG_CACHE_SIZE= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_BINLOG_STMT_CACHE_SIZE= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_BINLOG_SIZE= SUPER_ACL | BINLOG_ADMIN_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_BINLOG= SUPER_ACL | BINLOG_ADMIN_ACL; /* Privileges related to --read-only */ // Was super prior to 10.5.2 constexpr privilege_t PRIV_IGNORE_READ_ONLY= READ_ONLY_ADMIN_ACL | SUPER_ACL; // Was super prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_READ_ONLY= READ_ONLY_ADMIN_ACL | SUPER_ACL; /* Privileges related to connection handling. */ // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_IGNORE_INIT_CONNECT= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_IGNORE_MAX_USER_CONNECTIONS= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_IGNORE_MAX_CONNECTIONS= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_IGNORE_MAX_PASSWORD_ERRORS= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_KILL_OTHER_USER_PROCESS= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_CONNECT_TIMEOUT= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_DISCONNECT_ON_EXPIRED_PASSWORD= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_EXTRA_MAX_CONNECTIONS= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_INIT_CONNECT= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_CONNECTIONS= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_CONNECT_ERRORS= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MAX_PASSWORD_ERRORS= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_PROXY_PROTOCOL_NETWORKS= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SECURE_AUTH= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLOW_LAUNCH_TIME= CONNECTION_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_THREAD_POOL= CONNECTION_ADMIN_ACL | SUPER_ACL; /* Binary log related privileges that are checked regardless of active replication running. */ /* This command was renamed from "SHOW MASTER STATUS" to "SHOW BINLOG STATUS" in 10.5.2. Was SUPER_ACL | REPL_CLIENT_ACL prior to 10.5.2 REPL_CLIENT_ACL was renamed to BINLOG_MONITOR_ACL. */ constexpr privilege_t PRIV_STMT_SHOW_BINLOG_STATUS= BINLOG_MONITOR_ACL | SUPER_ACL; /* Was SUPER_ACL | REPL_CLIENT_ACL prior to 10.5.2 REPL_CLIENT_ACL was renamed to BINLOG_MONITOR_ACL. */ constexpr privilege_t PRIV_STMT_SHOW_BINARY_LOGS= BINLOG_MONITOR_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_STMT_PURGE_BINLOG= BINLOG_ADMIN_ACL | SUPER_ACL; // Was REPL_SLAVE_ACL prior to 10.5.2 constexpr privilege_t PRIV_STMT_SHOW_BINLOG_EVENTS= BINLOG_MONITOR_ACL; /* Privileges for replication related statements and commands that are executed on the master. */ constexpr privilege_t PRIV_COM_REGISTER_SLAVE= REPL_SLAVE_ACL; constexpr privilege_t PRIV_COM_BINLOG_DUMP= REPL_SLAVE_ACL; // Was REPL_SLAVE_ACL prior to 10.5.2 constexpr privilege_t PRIV_STMT_SHOW_SLAVE_HOSTS= REPL_MASTER_ADMIN_ACL; /* Replication master related variable privileges. Where SUPER prior to 10.5.2 */ constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_ENABLED= REPL_MASTER_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_TIMEOUT= REPL_MASTER_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_WAIT_NO_SLAVE= REPL_MASTER_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_TRACE_LEVEL= REPL_MASTER_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_WAIT_POINT= REPL_MASTER_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MASTER_VERIFY_CHECKSUM= REPL_MASTER_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_BINLOG_STATE= REPL_MASTER_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SERVER_ID= REPL_MASTER_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_DOMAIN_ID= REPL_MASTER_ADMIN_ACL | SUPER_ACL; /* Privileges for statements that are executed on the slave */ // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_STMT_START_SLAVE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_STMT_STOP_SLAVE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_STMT_CHANGE_MASTER= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; // Was (SUPER_ACL | REPL_CLIENT_ACL) prior to 10.5.2 // Was (SUPER_ACL | REPL_SLAVE_ADMIN_ACL) from 10.5.2 to 10.5.7 constexpr privilege_t PRIV_STMT_SHOW_SLAVE_STATUS= SLAVE_MONITOR_ACL | SUPER_ACL; // Was REPL_SLAVE_ACL prior to 10.5.2 // Was REPL_SLAVE_ADMIN_ACL from 10.5.2 to 10.5.7 constexpr privilege_t PRIV_STMT_SHOW_RELAYLOG_EVENTS= SLAVE_MONITOR_ACL; /* Privileges related to binlog replying. Were SUPER_ACL prior to 10.5.2 */ constexpr privilege_t PRIV_STMT_BINLOG= BINLOG_REPLAY_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_SESSION_VAR_GTID_SEQ_NO= BINLOG_REPLAY_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_SESSION_VAR_PSEUDO_THREAD_ID= BINLOG_REPLAY_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_SESSION_VAR_SERVER_ID= BINLOG_REPLAY_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_SESSION_VAR_GTID_DOMAIN_ID= BINLOG_REPLAY_ACL | SUPER_ACL; /* Privileges for slave related global variables. Were SUPER prior to 10.5.2. */ constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_EVENTS_MARKED_FOR_SKIP= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_DO_DB= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_DO_TABLE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_IGNORE_DB= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_IGNORE_TABLE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_WILD_DO_TABLE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_WILD_IGNORE_TABLE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_READ_BINLOG_SPEED_LIMIT= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_COMPRESSED_PROTOCOL= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_DDL_EXEC_MODE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_DOMAIN_PARALLEL_THREADS= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_EXEC_MODE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_MAX_ALLOWED_PACKET= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_NET_TIMEOUT= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_MAX_QUEUED= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_MODE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_THREADS= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_PARALLEL_WORKERS= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_RUN_TRIGGERS_FOR_RBR= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_SQL_VERIFY_CHECKSUM= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_TRANSACTION_RETRY_INTERVAL= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_TYPE_CONVERSIONS= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_INIT_SLAVE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_ENABLED= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_TRACE_LEVEL= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_DELAY_MASTER= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_SLAVE_KILL_CONN_TIMEOUT= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RELAY_LOG_PURGE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RELAY_LOG_RECOVERY= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_MASTER_INFO= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_RELAY_LOG= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_RELAY_LOG_INFO= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_CLEANUP_BATCH_SIZE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_IGNORE_DUPLICATES= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_POS_AUTO_ENGINES= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_SLAVE_POS= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_STRICT_MODE= REPL_SLAVE_ADMIN_ACL | SUPER_ACL; /* Privileges for federated database related statements */ // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_STMT_CREATE_SERVER= FEDERATED_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_STMT_ALTER_SERVER= FEDERATED_ADMIN_ACL | SUPER_ACL; // Was SUPER_ACL prior to 10.5.2 constexpr privilege_t PRIV_STMT_DROP_SERVER= FEDERATED_ADMIN_ACL | SUPER_ACL; /* Privileges related to processes */ constexpr privilege_t PRIV_COM_PROCESS_INFO= PROCESS_ACL; constexpr privilege_t PRIV_STMT_SHOW_EXPLAIN= PROCESS_ACL; constexpr privilege_t PRIV_STMT_SHOW_ENGINE_STATUS= PROCESS_ACL; constexpr privilege_t PRIV_STMT_SHOW_ENGINE_MUTEX= PROCESS_ACL; constexpr privilege_t PRIV_STMT_SHOW_PROCESSLIST= PROCESS_ACL; /* Defines to change the above bits to how things are stored in tables This is needed as the 'host' and 'db' table is missing a few privileges */ /* Privileges that need to be reallocated (in continous chunks) */ constexpr privilege_t DB_CHUNK0 (COL_DML_ACLS | CREATE_ACL | DROP_ACL); constexpr privilege_t DB_CHUNK1 (GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL); constexpr privilege_t DB_CHUNK2 (CREATE_TMP_ACL | LOCK_TABLES_ACL); constexpr privilege_t DB_CHUNK3 (VIEW_ACLS | PROC_DDL_ACLS); constexpr privilege_t DB_CHUNK4 (EXECUTE_ACL); constexpr privilege_t DB_CHUNK5 (EVENT_ACL | TRIGGER_ACL); constexpr privilege_t DB_CHUNK6 (DELETE_HISTORY_ACL); static inline privilege_t fix_rights_for_db(privilege_t access) { ulonglong A(access); return static_cast (((A) & DB_CHUNK0) | ((A << 4) & DB_CHUNK1) | ((A << 6) & DB_CHUNK2) | ((A << 9) & DB_CHUNK3) | ((A << 2) & DB_CHUNK4) | ((A << 9) & DB_CHUNK5) | ((A << 10) & DB_CHUNK6)); } static inline privilege_t get_rights_for_db(privilege_t access) { ulonglong A(access); return static_cast ((A & DB_CHUNK0) | ((A & DB_CHUNK1) >> 4) | ((A & DB_CHUNK2) >> 6) | ((A & DB_CHUNK3) >> 9) | ((A & DB_CHUNK4) >> 2) | ((A & DB_CHUNK5) >> 9) | ((A & DB_CHUNK6) >> 10)); } #define TBL_CHUNK0 DB_CHUNK0 #define TBL_CHUNK1 DB_CHUNK1 #define TBL_CHUNK2 (CREATE_VIEW_ACL | SHOW_VIEW_ACL) #define TBL_CHUNK3 TRIGGER_ACL #define TBL_CHUNK4 (DELETE_HISTORY_ACL) static inline privilege_t fix_rights_for_table(privilege_t access) { ulonglong A(access); return static_cast ((A & TBL_CHUNK0) | ((A << 4) & TBL_CHUNK1) | ((A << 11) & TBL_CHUNK2) | ((A << 15) & TBL_CHUNK3) | ((A << 16) & TBL_CHUNK4)); } static inline privilege_t get_rights_for_table(privilege_t access) { ulonglong A(access); return static_cast ((A & TBL_CHUNK0) | ((A & TBL_CHUNK1) >> 4) | ((A & TBL_CHUNK2) >> 11) | ((A & TBL_CHUNK3) >> 15) | ((A & TBL_CHUNK4) >> 16)); } static inline privilege_t fix_rights_for_column(privilege_t A) { const ulonglong mask(SELECT_ACL | INSERT_ACL | UPDATE_ACL); return (A & mask) | static_cast((A & ~mask) << 8); } static inline privilege_t get_rights_for_column(privilege_t A) { const ulonglong mask(SELECT_ACL | INSERT_ACL | UPDATE_ACL); return static_cast((static_cast(A) & mask) | (static_cast(A) >> 8)); } static inline privilege_t fix_rights_for_procedure(privilege_t access) { ulonglong A(access); return static_cast (((A << 18) & EXECUTE_ACL) | ((A << 23) & ALTER_PROC_ACL) | ((A << 8) & GRANT_ACL)); } static inline privilege_t get_rights_for_procedure(privilege_t access) { ulonglong A(access); return static_cast (((A & EXECUTE_ACL) >> 18) | ((A & ALTER_PROC_ACL) >> 23) | ((A & GRANT_ACL) >> 8)); } #endif /* PRIVILEGE_H_INCLUDED */ server/private/config.h000064400000034353151031265040011147 0ustar00/* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef MY_CONFIG_H #define MY_CONFIG_H #define DOT_FRM_VERSION 6 /* Headers we may want to use. */ #define STDC_HEADERS 1 #define _GNU_SOURCE 1 #define HAVE_ALLOCA_H 1 #define HAVE_ARPA_INET_H 1 #define HAVE_ASM_TERMBITS_H 1 #define HAVE_CRYPT_H 1 #define HAVE_CURSES_H 1 /* #undef HAVE_BFD_H */ /* #undef HAVE_NDIR_H */ #define HAVE_DIRENT_H 1 #define HAVE_DLFCN_H 1 #define HAVE_EXECINFO_H 1 #define HAVE_FCNTL_H 1 #define HAVE_FCNTL_DIRECT 1 #define HAVE_FENV_H 1 #define HAVE_FLOAT_H 1 #define HAVE_FNMATCH_H 1 #define HAVE_FPU_CONTROL_H 1 #define HAVE_GETMNTENT 1 /* #undef HAVE_GETMNTENT_IN_SYS_MNTAB */ /* #undef HAVE_GETMNTINFO */ /* #undef HAVE_GETMNTINFO64 */ /* #undef HAVE_GETMNTINFO_TAKES_statvfs */ #define HAVE_GRP_H 1 /* #undef HAVE_IA64INTRIN_H */ /* #undef HAVE_IEEEFP_H */ #define HAVE_INTTYPES_H 1 /* #undef HAVE_KQUEUE */ #define HAVE_LIMITS_H 1 #define HAVE_LINK_H 1 #define HAVE_LINUX_UNISTD_H 1 #define HAVE_LINUX_MMAN_H 1 #define HAVE_LOCALE_H 1 #define HAVE_MALLOC_H 1 #define HAVE_MEMORY_H 1 #define HAVE_NETINET_IN_H 1 #define HAVE_PATHS_H 1 #define HAVE_POLL_H 1 #define HAVE_PWD_H 1 #define HAVE_SCHED_H 1 /* #undef HAVE_SELECT_H */ /* #undef HAVE_SOLARIS_LARGE_PAGES */ #define HAVE_STDDEF_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STDARG_H 1 #define HAVE_STRINGS_H 1 #define HAVE_STRING_H 1 #define HAVE_STDINT_H 1 /* #undef HAVE_SYNCH_H */ /* #undef HAVE_SYSENT_H */ #define HAVE_SYS_DIR_H 1 #define HAVE_SYS_FILE_H 1 /* #undef HAVE_SYS_FPU_H */ #define HAVE_SYS_IOCTL_H 1 /* #undef HAVE_SYS_MALLOC_H */ #define HAVE_SYS_MMAN_H 1 /* #undef HAVE_SYS_MNTENT_H */ /* #undef HAVE_SYS_NDIR_H */ /* #undef HAVE_SYS_PTE_H */ /* #undef HAVE_SYS_PTEM_H */ #define HAVE_SYS_PRCTL_H 1 #define HAVE_SYS_RESOURCE_H 1 #define HAVE_SYS_SELECT_H 1 #define HAVE_SYS_SOCKET_H 1 /* #undef HAVE_SYS_SOCKIO_H */ #define HAVE_SYS_UTSNAME_H 1 #define HAVE_SYS_STAT_H 1 /* #undef HAVE_SYS_STREAM_H */ #define HAVE_SYS_SYSCALL_H 1 #define HAVE_SYS_TIMEB_H 1 #define HAVE_SYS_TIMES_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_UN_H 1 /* #undef HAVE_SYS_VADVISE_H */ #define HAVE_SYS_STATVFS_H 1 #define HAVE_UCONTEXT_H 1 #define HAVE_TERM_H 1 /* #undef HAVE_TERMBITS_H */ #define HAVE_TERMIOS_H 1 #define HAVE_TERMIO_H 1 #define HAVE_TERMCAP_H 1 #define HAVE_TIME_H 1 #define HAVE_UNISTD_H 1 #define HAVE_UTIME_H 1 /* #undef HAVE_VARARGS_H */ /* #undef HAVE_SYS_UTIME_H */ #define HAVE_SYS_WAIT_H 1 #define HAVE_SYS_PARAM_H 1 /* Libraries */ /* #undef HAVE_LIBWRAP */ #define HAVE_SYSTEMD 1 #define HAVE_SYSTEMD_SD_LISTEN_FDS_WITH_NAMES 1 /* Does "struct timespec" have a "sec" and "nsec" field? */ /* #undef HAVE_TIMESPEC_TS_SEC */ /* Readline */ /* #undef HAVE_HIST_ENTRY */ /* #undef USE_LIBEDIT_INTERFACE */ #define USE_NEW_READLINE_INTERFACE 1 #define FIONREAD_IN_SYS_IOCTL 1 #define GWINSZ_IN_SYS_IOCTL 1 /* #undef TIOCSTAT_IN_SYS_IOCTL */ /* #undef FIONREAD_IN_SYS_FILIO */ /* Functions we may want to use. */ #define HAVE_ACCEPT4 1 #define HAVE_ACCESS 1 #define HAVE_ALARM 1 #define HAVE_ALLOCA 1 /* #undef HAVE_BFILL */ #define HAVE_INDEX 1 #define HAVE_CLOCK_GETTIME 1 #define HAVE_CRYPT 1 #define HAVE_CUSERID 1 #define HAVE_DLADDR 1 #define HAVE_DLERROR 1 #define HAVE_DLOPEN 1 #define HAVE_FCHMOD 1 #define HAVE_FCNTL 1 #define HAVE_FDATASYNC 1 #define HAVE_DECL_FDATASYNC 1 #define HAVE_FEDISABLEEXCEPT 1 #define HAVE_FESETROUND 1 /* #undef HAVE_FP_EXCEPT */ #define HAVE_FSEEKO 1 #define HAVE_FSYNC 1 #define HAVE_FTIME 1 #define HAVE_GETIFADDRS 1 #define HAVE_GETCWD 1 #define HAVE_GETHOSTBYADDR_R 1 /* #undef HAVE_GETHRTIME */ #define HAVE_GETPAGESIZE 1 /* #undef HAVE_GETPAGESIZES */ #define HAVE_GETPASS 1 /* #undef HAVE_GETPASSPHRASE */ #define HAVE_GETPWNAM 1 #define HAVE_GETPWUID 1 #define HAVE_GETRLIMIT 1 #define HAVE_GETRUSAGE 1 #define HAVE_GETTIMEOFDAY 1 #define HAVE_GETWD 1 #define HAVE_GMTIME_R 1 /* #undef gmtime_r */ #define HAVE_IN_ADDR_T 1 #define HAVE_INITGROUPS 1 #define HAVE_LDIV 1 #define HAVE_LRAND48 1 #define HAVE_LOCALTIME_R 1 #define HAVE_LSTAT 1 /* #define HAVE_MLOCK 1 see Bug#54662 */ #define HAVE_NL_LANGINFO 1 #define HAVE_MADVISE 1 #define HAVE_DECL_MADVISE 1 /* #undef HAVE_DECL_MHA_MAPSIZE_VA */ #define HAVE_MALLINFO 1 /* #undef HAVE_MALLINFO2 */ /* #undef HAVE_MALLOC_ZONE */ #define HAVE_MEMCPY 1 #define HAVE_MEMMOVE 1 #define HAVE_MKSTEMP 1 #define HAVE_MKOSTEMP 1 #define HAVE_MLOCKALL 1 #define HAVE_MMAP 1 #define HAVE_MMAP64 1 #define HAVE_PERROR 1 #define HAVE_POLL 1 #define HAVE_POSIX_FALLOCATE 1 #define HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE 1 #define HAVE_PREAD 1 /* #undef HAVE_READ_REAL_TIME */ /* #undef HAVE_PTHREAD_ATTR_CREATE */ #define HAVE_PTHREAD_ATTR_GETGUARDSIZE 1 #define HAVE_PTHREAD_ATTR_GETSTACKSIZE 1 #define HAVE_PTHREAD_ATTR_SETSCOPE 1 #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 #define HAVE_PTHREAD_GETATTR_NP 1 /* #undef HAVE_PTHREAD_CONDATTR_CREATE */ #define HAVE_PTHREAD_GETAFFINITY_NP 1 #define HAVE_PTHREAD_KEY_DELETE 1 /* #undef HAVE_PTHREAD_KILL */ #define HAVE_PTHREAD_RWLOCK_RDLOCK 1 #define HAVE_PTHREAD_SIGMASK 1 /* #undef HAVE_PTHREAD_YIELD_NP */ #define HAVE_PTHREAD_YIELD_ZERO_ARG 1 #define PTHREAD_ONCE_INITIALIZER PTHREAD_ONCE_INIT #define HAVE_PUTENV 1 /* #undef HAVE_READDIR_R */ #define HAVE_READLINK 1 #define HAVE_REALPATH 1 #define HAVE_RENAME 1 /* #undef HAVE_RWLOCK_INIT */ #define HAVE_SCHED_YIELD 1 #define HAVE_SELECT 1 #define HAVE_SETENV 1 #define HAVE_SETLOCALE 1 #define HAVE_SETMNTENT 1 #define HAVE_SETUPTERM 1 #define HAVE_SIGSET 1 #define HAVE_SIGACTION 1 /* #undef HAVE_SIGTHREADMASK */ #define HAVE_SIGWAIT 1 #define HAVE_SIGWAITINFO 1 #define HAVE_SLEEP 1 #define HAVE_STPCPY 1 #define HAVE_STRERROR 1 #define HAVE_STRCOLL 1 #define HAVE_STRNLEN 1 #define HAVE_STRPBRK 1 #define HAVE_STRTOK_R 1 #define HAVE_STRTOLL 1 #define HAVE_STRTOUL 1 #define HAVE_STRTOULL 1 /* #undef HAVE_TELL */ /* #undef HAVE_THR_YIELD */ #define HAVE_TIME 1 #define HAVE_TIMES 1 #define HAVE_VIDATTR 1 #define HAVE_VIO_READ_BUFF 1 #define HAVE_VASPRINTF 1 #define HAVE_VSNPRINTF 1 #define HAVE_FTRUNCATE 1 #define HAVE_TZNAME 1 /* Symbols we may use */ /* #undef HAVE_SYS_ERRLIST */ /* used by stacktrace functions */ #define HAVE_BACKTRACE 1 #define HAVE_BACKTRACE_SYMBOLS 1 #define HAVE_BACKTRACE_SYMBOLS_FD 1 /* #undef HAVE_PRINTSTACK */ #define HAVE_IPV6 1 /* #undef ss_family */ /* #undef HAVE_SOCKADDR_IN_SIN_LEN */ /* #undef HAVE_SOCKADDR_IN6_SIN6_LEN */ #define STRUCT_TIMESPEC_HAS_TV_SEC 1 #define STRUCT_TIMESPEC_HAS_TV_NSEC 1 /* this means that valgrind headers and macros are available */ #define HAVE_VALGRIND_MEMCHECK_H 1 /* this means WITH_VALGRIND - we change some code paths for valgrind */ /* #undef HAVE_valgrind */ /* Types we may use */ #ifdef __APPLE__ /* Special handling required for OSX to support universal binaries that mix 32 and 64 bit architectures. */ #if(__LP64__) #define SIZEOF_LONG 8 #else #define SIZEOF_LONG 4 #endif #define SIZEOF_VOIDP SIZEOF_LONG #define SIZEOF_CHARP SIZEOF_LONG #define SIZEOF_SIZE_T SIZEOF_LONG #else /* No indentation, to fetch the lines from verification scripts */ #define SIZEOF_LONG 8 #define SIZEOF_VOIDP 8 #define SIZEOF_CHARP 8 #define SIZEOF_SIZE_T 8 #endif #define HAVE_LONG 1 #define HAVE_CHARP 1 #define SIZEOF_INT 4 #define HAVE_INT 1 #define SIZEOF_LONG_LONG 8 #define HAVE_LONG_LONG 1 #define SIZEOF_OFF_T 8 #define HAVE_OFF_T 1 /* #undef SIZEOF_UCHAR */ /* #undef HAVE_UCHAR */ #define SIZEOF_UINT 4 #define HAVE_UINT 1 #define SIZEOF_ULONG 8 #define HAVE_ULONG 1 /* #undef SIZEOF_INT8 */ /* #undef HAVE_INT8 */ /* #undef SIZEOF_UINT8 */ /* #undef HAVE_UINT8 */ /* #undef SIZEOF_INT16 */ /* #undef HAVE_INT16 */ /* #undef SIZEOF_UINT16 */ /* #undef HAVE_UINT16 */ /* #undef SIZEOF_INT32 */ /* #undef HAVE_INT32 */ /* #undef SIZEOF_UINT32 */ /* #undef HAVE_UINT32 */ /* #undef SIZEOF_INT64 */ /* #undef HAVE_INT64 */ /* #undef SIZEOF_UINT64 */ /* #undef HAVE_UINT64 */ #define SOCKET_SIZE_TYPE socklen_t #define HAVE_MBSTATE_T 1 #define MAX_INDEXES 64 #define QSORT_TYPE_IS_VOID 1 #define RETQSORTTYPE void #define RETSIGTYPE void #define VOID_SIGHANDLER 1 #define HAVE_SIGHANDLER_T 1 #define STRUCT_RLIMIT struct rlimit #ifdef __APPLE__ #if __BIG_ENDIAN #define WORDS_BIGENDIAN 1 #endif #else /* #undef WORDS_BIGENDIAN */ #endif /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #define C_HAS_inline 1 #if !(C_HAS_inline) #ifndef __cplusplus # define inline #endif #endif #define TARGET_OS_LINUX 1 #define HAVE_WCTYPE_H 1 #define HAVE_WCHAR_H 1 #define HAVE_LANGINFO_H 1 #define HAVE_MBRLEN 1 #define HAVE_MBSRTOWCS 1 #define HAVE_MBRTOWC 1 #define HAVE_WCWIDTH 1 #define HAVE_ISWLOWER 1 #define HAVE_ISWUPPER 1 #define HAVE_TOWLOWER 1 #define HAVE_TOWUPPER 1 #define HAVE_ISWCTYPE 1 #define HAVE_WCHAR_T 1 #define HAVE_STRCASECMP 1 #define HAVE_TCGETATTR 1 #define HAVE_WEAK_SYMBOL 1 #define HAVE_ABI_CXA_DEMANGLE 1 #define HAVE_ATTRIBUTE_CLEANUP 1 #define HAVE_POSIX_SIGNALS 1 /* #undef HAVE_BSD_SIGNALS */ /* #undef HAVE_SVR3_SIGNALS */ /* #undef HAVE_V7_SIGNALS */ #define HAVE_ERR_remove_thread_state 1 #define HAVE_X509_check_host 1 /* #undef HAVE_SOLARIS_STYLE_GETHOST */ #define HAVE_GCC_C11_ATOMICS 1 /* #undef HAVE_SOLARIS_ATOMIC */ /* #undef NO_FCNTL_NONBLOCK */ #define NO_ALARM 1 /* #undef _LARGE_FILES */ #define _LARGEFILE_SOURCE 1 /* #undef _LARGEFILE64_SOURCE */ #define TIME_WITH_SYS_TIME 1 #define STACK_DIRECTION -1 #define SYSTEM_TYPE "Linux" #define MACHINE_TYPE "x86_64" #define DEFAULT_MACHINE "x86_64" #define HAVE_DTRACE 1 #define SIGNAL_WITH_VIO_CLOSE 1 /* Windows stuff, mostly functions, that have Posix analogs but named differently */ /* #undef S_IROTH */ /* #undef S_IFIFO */ /* #undef IPPROTO_IPV6 */ /* #undef IPV6_V6ONLY */ /* #undef sigset_t */ /* #undef mode_t */ /* #undef SIGQUIT */ /* #undef SIGPIPE */ /* #undef popen */ /* #undef pclose */ /* #undef ssize_t */ /* #undef strcasecmp */ /* #undef strncasecmp */ /* #undef snprintf */ /* #undef strtok_r */ /* #undef strtoll */ /* #undef strtoull */ /* #undef vsnprintf */ #if defined(_MSC_VER) && (_MSC_VER > 1800) #define tzname _tzname #define P_tmpdir "C:\\TEMP" #endif #if defined(_MSC_VER) && (_MSC_VER > 1310) # define HAVE_SETENV #define setenv(a,b,c) _putenv_s(a,b) #endif #define PSAPI_VERSION 1 /* for GetProcessMemoryInfo() */ /* We don't want the min/max macros */ #ifdef _WIN32 #define NOMINMAX 1 #endif /* MySQL features */ #define LOCAL_INFILE_MODE_OFF 0 #define LOCAL_INFILE_MODE_ON 1 #define LOCAL_INFILE_MODE_AUTO 2 #define ENABLED_LOCAL_INFILE LOCAL_INFILE_MODE_AUTO #define ENABLED_PROFILING 1 /* #undef EXTRA_DEBUG */ /* #undef USE_SYMDIR */ /* Character sets and collations */ #define MYSQL_DEFAULT_CHARSET_NAME "latin1" #define MYSQL_DEFAULT_COLLATION_NAME "latin1_swedish_ci" #define USE_MB #define USE_MB_IDENT /* This should mean case insensitive file system */ /* #undef FN_NO_CASE_SENSE */ #define HAVE_CHARSET_armscii8 1 #define HAVE_CHARSET_ascii 1 #define HAVE_CHARSET_big5 1 #define HAVE_CHARSET_cp1250 1 #define HAVE_CHARSET_cp1251 1 #define HAVE_CHARSET_cp1256 1 #define HAVE_CHARSET_cp1257 1 #define HAVE_CHARSET_cp850 1 #define HAVE_CHARSET_cp852 1 #define HAVE_CHARSET_cp866 1 #define HAVE_CHARSET_cp932 1 #define HAVE_CHARSET_dec8 1 #define HAVE_CHARSET_eucjpms 1 #define HAVE_CHARSET_euckr 1 #define HAVE_CHARSET_gb2312 1 #define HAVE_CHARSET_gbk 1 #define HAVE_CHARSET_geostd8 1 #define HAVE_CHARSET_greek 1 #define HAVE_CHARSET_hebrew 1 #define HAVE_CHARSET_hp8 1 #define HAVE_CHARSET_keybcs2 1 #define HAVE_CHARSET_koi8r 1 #define HAVE_CHARSET_koi8u 1 #define HAVE_CHARSET_latin1 1 #define HAVE_CHARSET_latin2 1 #define HAVE_CHARSET_latin5 1 #define HAVE_CHARSET_latin7 1 #define HAVE_CHARSET_macce 1 #define HAVE_CHARSET_macroman 1 #define HAVE_CHARSET_sjis 1 #define HAVE_CHARSET_swe7 1 #define HAVE_CHARSET_tis620 1 #define HAVE_CHARSET_ucs2 1 #define HAVE_CHARSET_ujis 1 #define HAVE_CHARSET_utf8mb4 1 #define HAVE_CHARSET_utf8mb3 1 #define HAVE_CHARSET_utf16 1 #define HAVE_CHARSET_utf32 1 #define HAVE_UCA_COLLATIONS 1 #define HAVE_COMPRESS 1 #define HAVE_EncryptAes128Ctr 1 #define HAVE_EncryptAes128Gcm 1 #define HAVE_des 1 /* Stuff that always need to be defined (compile breaks without it) */ #define HAVE_SPATIAL 1 #define HAVE_RTREE_KEYS 1 #define HAVE_QUERY_CACHE 1 #define BIG_TABLES 1 /* Important storage engines (those that really need define WITH__STORAGE_ENGINE for the whole server) */ #define WITH_INNOBASE_STORAGE_ENGINE 1 #define WITH_PARTITION_STORAGE_ENGINE 1 #define WITH_PERFSCHEMA_STORAGE_ENGINE 1 #define WITH_ARIA_STORAGE_ENGINE 1 #define USE_ARIA_FOR_TMP_TABLES 1 #define DEFAULT_MYSQL_HOME "/usr" #define SHAREDIR "/usr/share/mysql" #define DEFAULT_BASEDIR "/usr" #define MYSQL_DATADIR "/var/lib/mysql" #define DEFAULT_CHARSET_HOME "/usr" #define PLUGINDIR "/usr/lib64/mysql/plugin" #define DEFAULT_SYSCONFDIR "/etc" #define DEFAULT_TMPDIR P_tmpdir /* #undef SO_EXT */ #define MYSQL_VERSION_MAJOR 10 #define MYSQL_VERSION_MINOR 6 #define MYSQL_VERSION_PATCH 23 #define MYSQL_VERSION_EXTRA "" #define PACKAGE "mysql" #define PACKAGE_BUGREPORT "" #define PACKAGE_NAME "MySQL Server" #define PACKAGE_STRING "MySQL Server 10.6.23" #define PACKAGE_TARNAME "mysql" #define PACKAGE_VERSION "10.6.23" #define VERSION "10.6.23" #define PROTOCOL_VERSION 10 #define PCRE2_CODE_UNIT_WIDTH 8 #define MALLOC_LIBRARY "system" /* time_t related defines */ #define SIZEOF_TIME_T 8 /* #undef TIME_T_UNSIGNED */ #ifndef EMBEDDED_LIBRARY /* #undef WSREP_INTERFACE_VERSION */ #define WITH_WSREP 1 #define WSREP_PROC_INFO 1 #endif #if !defined(__STDC_FORMAT_MACROS) #define __STDC_FORMAT_MACROS #endif // !defined(__STDC_FORMAT_MACROS) #endif #define HAVE_VFORK 1 server/private/span.h000064400000007533151031265040010643 0ustar00/***************************************************************************** Copyright (c) 2019, 2020 MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *****************************************************************************/ #pragma once #include #include namespace st_ { namespace detail { template struct remove_cv { typedef T type; }; template struct remove_cv { typedef T type; }; template struct remove_cv { typedef T type; }; template struct remove_cv { typedef T type; }; } // namespace detail template class span { public: typedef ElementType element_type; typedef typename detail::remove_cv::type value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef element_type *pointer; typedef const element_type *const_pointer; typedef element_type &reference; typedef const element_type &const_reference; typedef pointer iterator; typedef const_pointer const_iterator; typedef std::reverse_iterator reverse_iterator; span() : data_(NULL), size_(0) {} span(pointer ptr, size_type count) : data_(ptr), size_(count) {} span(pointer first, pointer last) : data_(first), size_(last - first) {} template span(element_type (&arr)[N]) : data_(arr), size_(N) {} template span(Container &cont) : data_(cont.data()), size_(cont.size()) { } template span(const Container &cont) : data_(cont.data()), size_(cont.size()) { } span(const span &other) : data_(other.data_), size_(other.size_) {} ~span() = default; span &operator=(const span &other) { data_= other.data(); size_= other.size(); return *this; } template span first() const { assert(!empty()); return span(data(), 1); } template span last() const { assert(!empty()); return span(data() + size() - 1, 1); } span first(size_type count) const { assert(!empty()); return span(data(), 1); } span last(size_type count) const { assert(!empty()); return span(data() + size() - 1, 1); } span subspan(size_type offset, size_type count) const { assert(!empty()); assert(size() >= offset + count); return span(data() + offset, count); } size_type size() const { return size_; } size_type size_bytes() const { return size() * sizeof(ElementType); } bool empty() const __attribute__((warn_unused_result)) { return size() == 0; } reference operator[](size_type idx) const { assert(size() > idx); return data()[idx]; } reference front() const { assert(!empty()); return data()[0]; } reference back() const { assert(!empty()); return data()[size() - 1]; } pointer data() const { return data_; } iterator begin() const { return data_; } iterator end() const { return data_ + size_; } reverse_iterator rbegin() const { return std::reverse_iterator(end()); } reverse_iterator rend() const { return std::reverse_iterator(begin()); } private: pointer data_; size_type size_; }; } // namespace st_ server/private/pfs_file_provider.h000064400000006121151031265040013373 0ustar00/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef PFS_FILE_PROVIDER_H #define PFS_FILE_PROVIDER_H /** @file include/pfs_file_provider.h Performance schema instrumentation (declarations). */ #ifdef HAVE_PSI_FILE_INTERFACE #ifdef MYSQL_SERVER #ifndef EMBEDDED_LIBRARY #ifndef MYSQL_DYNAMIC_PLUGIN #include "mysql/psi/psi.h" #define PSI_FILE_CALL(M) pfs_ ## M ## _v1 C_MODE_START void pfs_register_file_v1(const char *category, PSI_file_info_v1 *info, int count); void pfs_create_file_v1(PSI_file_key key, const char *name, File file); PSI_file_locker* pfs_get_thread_file_name_locker_v1(PSI_file_locker_state *state, PSI_file_key key, PSI_file_operation op, const char *name, const void *identity); PSI_file_locker* pfs_get_thread_file_stream_locker_v1(PSI_file_locker_state *state, PSI_file *file, PSI_file_operation op); PSI_file_locker* pfs_get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state, File file, PSI_file_operation op); void pfs_start_file_open_wait_v1(PSI_file_locker *locker, const char *src_file, uint src_line); PSI_file* pfs_end_file_open_wait_v1(PSI_file_locker *locker, void *result); void pfs_end_file_open_wait_and_bind_to_descriptor_v1 (PSI_file_locker *locker, File file); void pfs_end_temp_file_open_wait_and_bind_to_descriptor_v1 (PSI_file_locker *locker, File file, const char *filename); void pfs_start_file_wait_v1(PSI_file_locker *locker, size_t count, const char *src_file, uint src_line); void pfs_end_file_wait_v1(PSI_file_locker *locker, size_t byte_count); void pfs_start_file_close_wait_v1(PSI_file_locker *locker, const char *src_file, uint src_line); void pfs_end_file_close_wait_v1(PSI_file_locker *locker, int rc); void pfs_end_file_rename_wait_v1(PSI_file_locker *locker, const char *old_name, const char *new_name, int rc); C_MODE_END #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* MYSQL_SERVER */ #endif /* HAVE_PSI_FILE_INTERFACE */ #endif server/private/sql_insert.h000064400000005133151031265040012057 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_INSERT_INCLUDED #define SQL_INSERT_INCLUDED #include "sql_class.h" /* enum_duplicates */ #include "sql_list.h" /* Instead of including sql_lex.h we add this typedef here */ typedef List List_item; typedef struct st_copy_info COPY_INFO; int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, List &fields, List_item *values, List &update_fields, List &update_values, enum_duplicates duplic, COND **where, bool select_insert, bool * const cache_results); bool mysql_insert(THD *thd,TABLE_LIST *table,List &fields, List &values, List &update_fields, List &update_values, enum_duplicates flag, bool ignore, select_result* result); void upgrade_lock_type_for_insert(THD *thd, thr_lock_type *lock_type, enum_duplicates duplic, bool is_multi_insert); int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, TABLE_LIST *table_list); int vers_insert_history_row(TABLE *table); int check_duplic_insert_without_overlaps(THD *thd, TABLE *table, enum_duplicates duplic); int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *returning= NULL); void kill_delayed_threads(void); bool binlog_create_table(THD *thd, TABLE *table, bool replace); bool binlog_drop_table(THD *thd, TABLE *table); static inline void restore_default_record_for_insert(TABLE *t) { restore_record(t,s->default_values); if (t->triggers) t->triggers->default_extra_null_bitmap(); } #ifdef EMBEDDED_LIBRARY inline void kill_delayed_threads(void) {} #endif #endif /* SQL_INSERT_INCLUDED */ server/private/pfs_thread_provider.h000064400000012670151031265040013731 0ustar00/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef PFS_THREAD_PROVIDER_H #define PFS_THREAD_PROVIDER_H /** @file include/pfs_thread_provider.h Performance schema instrumentation (declarations). */ #ifdef HAVE_PSI_THREAD_INTERFACE #ifdef MYSQL_SERVER #ifndef EMBEDDED_LIBRARY #ifndef MYSQL_DYNAMIC_PLUGIN #include "mysql/psi/psi.h" #define PSI_MUTEX_CALL(M) pfs_ ## M ## _v1 #define PSI_RWLOCK_CALL(M) pfs_ ## M ## _v1 #define PSI_COND_CALL(M) pfs_ ## M ## _v1 #define PSI_THREAD_CALL(M) pfs_ ## M ## _v1 C_MODE_START void pfs_register_mutex_v1(const char *category, PSI_mutex_info_v1 *info, int count); void pfs_register_rwlock_v1(const char *category, PSI_rwlock_info_v1 *info, int count); void pfs_register_cond_v1(const char *category, PSI_cond_info_v1 *info, int count); void pfs_register_thread_v1(const char *category, PSI_thread_info_v1 *info, int count); PSI_mutex* pfs_init_mutex_v1(PSI_mutex_key key, void *identity); void pfs_destroy_mutex_v1(PSI_mutex* mutex); PSI_rwlock* pfs_init_rwlock_v1(PSI_rwlock_key key, void *identity); void pfs_destroy_rwlock_v1(PSI_rwlock* rwlock); PSI_cond* pfs_init_cond_v1(PSI_cond_key key, void *identity); void pfs_destroy_cond_v1(PSI_cond* cond); int pfs_spawn_thread_v1(PSI_thread_key key, pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg); PSI_thread* pfs_new_thread_v1(PSI_thread_key key, const void *identity, ulonglong processlist_id); void pfs_set_thread_id_v1(PSI_thread *thread, ulonglong processlist_id); void pfs_set_thread_THD_v1(PSI_thread *thread, THD *thd); void pfs_set_thread_os_id_v1(PSI_thread *thread); PSI_thread* pfs_get_thread_v1(void); void pfs_set_thread_user_v1(const char *user, int user_len); void pfs_set_thread_account_v1(const char *user, int user_len, const char *host, int host_len); void pfs_set_thread_db_v1(const char* db, int db_len); void pfs_set_thread_command_v1(int command); void pfs_set_thread_start_time_v1(time_t start_time); void pfs_set_thread_state_v1(const char* state); void pfs_set_connection_type_v1(opaque_vio_type conn_type); void pfs_set_thread_info_v1(const char* info, uint info_len); void pfs_set_thread_v1(PSI_thread* thread); void pfs_set_thread_peer_port_v1(PSI_thread *thread, uint port); void pfs_delete_current_thread_v1(void); void pfs_delete_thread_v1(PSI_thread *thread); PSI_mutex_locker* pfs_start_mutex_wait_v1(PSI_mutex_locker_state *state, PSI_mutex *mutex, PSI_mutex_operation op, const char *src_file, uint src_line); PSI_rwlock_locker* pfs_start_rwlock_rdwait_v1(PSI_rwlock_locker_state *state, PSI_rwlock *rwlock, PSI_rwlock_operation op, const char *src_file, uint src_line); PSI_rwlock_locker* pfs_start_rwlock_wrwait_v1(PSI_rwlock_locker_state *state, PSI_rwlock *rwlock, PSI_rwlock_operation op, const char *src_file, uint src_line); PSI_cond_locker* pfs_start_cond_wait_v1(PSI_cond_locker_state *state, PSI_cond *cond, PSI_mutex *mutex, PSI_cond_operation op, const char *src_file, uint src_line); PSI_table_locker* pfs_start_table_io_wait_v1(PSI_table_locker_state *state, PSI_table *table, PSI_table_io_operation op, uint index, const char *src_file, uint src_line); PSI_table_locker* pfs_start_table_lock_wait_v1(PSI_table_locker_state *state, PSI_table *table, PSI_table_lock_operation op, ulong op_flags, const char *src_file, uint src_line); void pfs_unlock_mutex_v1(PSI_mutex *mutex); void pfs_unlock_rwlock_v1(PSI_rwlock *rwlock); void pfs_signal_cond_v1(PSI_cond* cond); void pfs_broadcast_cond_v1(PSI_cond* cond); void pfs_end_mutex_wait_v1(PSI_mutex_locker* locker, int rc); void pfs_end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc); void pfs_end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc); void pfs_end_cond_wait_v1(PSI_cond_locker* locker, int rc); int pfs_set_thread_connect_attrs_v1(const char *buffer, uint length, const void *from_cs); C_MODE_END #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* MYSQL_SERVER */ #endif /* HAVE_PSI_THREAD_INTERFACE */ #endif server/private/t_ctype.h000064400000013007151031265040011342 0ustar00/* Copyright (C) 2000 MySQL AB Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Copyright (C) 1998, 1999 by Pruet Boonma, all rights reserved. Copyright (C) 1998 by Theppitak Karoonboonyanan, all rights reserved. Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies. Smaphan Raruenrom and Pruet Boonma makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. */ /* LC_COLLATE category + Level information */ #ifndef _t_ctype_h #define _t_ctype_h #define TOT_LEVELS 5 #define LAST_LEVEL 4 /* TOT_LEVELS - 1 */ #define IGNORE 0 /* level 1 symbols & order */ enum l1_symbols { L1_08 = TOT_LEVELS, L1_18, L1_28, L1_38, L1_48, L1_58, L1_68, L1_78, L1_88, L1_98, L1_A8, L1_B8, L1_C8, L1_D8, L1_E8, L1_F8, L1_G8, L1_H8, L1_I8, L1_J8, L1_K8, L1_L8, L1_M8, L1_N8, L1_O8, L1_P8, L1_Q8, L1_R8, L1_S8, L1_T8, L1_U8, L1_V8, L1_W8, L1_X8, L1_Y8, L1_Z8, L1_KO_KAI, L1_KHO_KHAI, L1_KHO_KHUAT, L1_KHO_KHWAI, L1_KHO_KHON, L1_KHO_RAKHANG, L1_NGO_NGU, L1_CHO_CHAN, L1_CHO_CHING, L1_CHO_CHANG, L1_SO_SO, L1_CHO_CHOE, L1_YO_YING, L1_DO_CHADA, L1_TO_PATAK, L1_THO_THAN, L1_THO_NANGMONTHO, L1_THO_PHUTHAO, L1_NO_NEN, L1_DO_DEK, L1_TO_TAO, L1_THO_THUNG, L1_THO_THAHAN, L1_THO_THONG, L1_NO_NU, L1_BO_BAIMAI, L1_PO_PLA, L1_PHO_PHUNG, L1_FO_FA, L1_PHO_PHAN, L1_FO_FAN, L1_PHO_SAMPHAO, L1_MO_MA, L1_YO_YAK, L1_RO_RUA, L1_RU, L1_LO_LING, L1_LU, L1_WO_WAEN, L1_SO_SALA, L1_SO_RUSI, L1_SO_SUA, L1_HO_HIP, L1_LO_CHULA, L1_O_ANG, L1_HO_NOKHUK, L1_NKHIT, L1_SARA_A, L1_MAI_HAN_AKAT, L1_SARA_AA, L1_SARA_AM, L1_SARA_I, L1_SARA_II, L1_SARA_UE, L1_SARA_UEE, L1_SARA_U, L1_SARA_UU, L1_SARA_E, L1_SARA_AE, L1_SARA_O, L1_SARA_AI_MAIMUAN, L1_SARA_AI_MAIMALAI }; /* level 2 symbols & order */ enum l2_symbols { L2_BLANK = TOT_LEVELS, L2_THAII, L2_YAMAK, L2_PINTHU, L2_GARAN, L2_TYKHU, L2_TONE1, L2_TONE2, L2_TONE3, L2_TONE4 }; /* level 3 symbols & order */ enum l3_symbols { L3_BLANK = TOT_LEVELS, L3_SPACE, L3_NB_SACE, L3_LOW_LINE, L3_HYPHEN, L3_COMMA, L3_SEMICOLON, L3_COLON, L3_EXCLAMATION, L3_QUESTION, L3_SOLIDUS, L3_FULL_STOP, L3_PAIYAN_NOI, L3_MAI_YAMOK, L3_GRAVE, L3_CIRCUMFLEX, L3_TILDE, L3_APOSTROPHE, L3_QUOTATION, L3_L_PARANTHESIS, L3_L_BRACKET, L3_L_BRACE, L3_R_BRACE, L3_R_BRACKET, L3_R_PARENTHESIS, L3_AT, L3_BAHT, L3_DOLLAR, L3_FONGMAN, L3_ANGKHANKHU, L3_KHOMUT, L3_ASTERISK, L3_BK_SOLIDUS, L3_AMPERSAND, L3_NUMBER, L3_PERCENT, L3_PLUS, L3_LESS_THAN, L3_EQUAL, L3_GREATER_THAN, L3_V_LINE }; /* level 4 symbols & order */ enum l4_symbols { L4_BLANK = TOT_LEVELS, L4_MIN, L4_CAP, L4_EXT }; enum level_symbols { L_UPRUPR = TOT_LEVELS, L_UPPER, L_MIDDLE, L_LOWER }; #define _is(c) (t_ctype[(c)][LAST_LEVEL]) #define _level 8 #define _consnt 16 #define _ldvowel 32 #define _fllwvowel 64 #define _uprvowel 128 #define _lwrvowel 256 #define _tone 512 #define _diacrt1 1024 #define _diacrt2 2048 #define _combine 4096 #define _stone 8192 #define _tdig 16384 #define _rearvowel (_fllwvowel | _uprvowel | _lwrvowel) #define _diacrt (_diacrt1 | _diacrt2) #define levelof(c) ( _is(c) & _level ) #define isthai(c) ( (c) >= 128 ) #define istalpha(c) ( _is(c) & (_consnt|_ldvowel|_rearvowel|\ _tone|_diacrt1|_diacrt2) ) #define isconsnt(c) ( _is(c) & _consnt ) #define isldvowel(c) ( _is(c) & _ldvowel ) #define isfllwvowel(c) ( _is(c) & _fllwvowel ) #define ismidvowel(c) ( _is(c) & (_ldvowel|_fllwvowel) ) #define isuprvowel(c) ( _is(c) & _uprvowel ) #define islwrvowel(c) ( _is(c) & _lwrvowel ) #define isuprlwrvowel(c) ( _is(c) & (_lwrvowel | _uprvowel)) #define isrearvowel(c) ( _is(c) & _rearvowel ) #define isvowel(c) ( _is(c) & (_ldvowel|_rearvowel) ) #define istone(c) ( _is(c) & _tone ) #define isunldable(c) ( _is(c) & (_rearvowel|_tone|_diacrt1|_diacrt2) ) #define iscombinable(c) ( _is(c) & _combine ) #define istdigit(c) ( _is(c) & _tdig ) #define isstone(c) ( _is(c) & _stone ) #define isdiacrt1(c) ( _is(c) & _diacrt1) #define isdiacrt2(c) ( _is(c) & _diacrt2) #define isdiacrt(c) ( _is(c) & _diacrt) /* Function prototype called by sql/field.cc */ void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length); #endif server/private/sql_alloc.h000064400000003304151031265040011643 0ustar00#ifndef SQL_ALLOC_INCLUDED #define SQL_ALLOC_INCLUDED /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. Copyright (c) 2017, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include /* alloc_root, MEM_ROOT, TRASH */ /* MariaDB standard class memory allocator */ class Sql_alloc { public: static void *operator new(size_t size) throw () { return thd_alloc(_current_thd(), size); } static void *operator new[](size_t size) throw () { return thd_alloc(_current_thd(), size); } static void *operator new[](size_t size, MEM_ROOT *mem_root) throw () { return alloc_root(mem_root, size); } static void *operator new(size_t size, MEM_ROOT *mem_root) throw() { return alloc_root(mem_root, size); } static void operator delete(void *ptr, size_t size) { TRASH_FREE(ptr, size); } static void operator delete(void *, MEM_ROOT *){} static void operator delete[](void *, MEM_ROOT *) { /* never called */ } static void operator delete[](void *ptr, size_t size) { TRASH_FREE(ptr, size); } }; #endif /* SQL_ALLOC_INCLUDED */ server/private/wsrep_types.h000064400000001745151031265040012265 0ustar00/* Copyright 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Wsrep typedefs to better conform to coding style. */ #ifndef WSREP_TYPES_H #define WSREP_TYPES_H #include "wsrep/seqno.hpp" #include "wsrep/view.hpp" typedef wsrep::id Wsrep_id; typedef wsrep::seqno Wsrep_seqno; typedef wsrep::view Wsrep_view; #endif /* WSREP_TYPES_H */ server/private/sql_bootstrap.h000064400000003424151031265040012571 0ustar00/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_BOOTSTRAP_H #define SQL_BOOTSTRAP_H /** The maximum size of a bootstrap query. Increase this size if parsing a longer query during bootstrap is necessary. The longest query in use depends on the documentation content, see the file fill_help_tables.sql */ #define MAX_BOOTSTRAP_QUERY_SIZE 60000 /** The maximum size of a bootstrap query, expressed in a single line. Do not increase this size, use the multiline syntax instead. */ #define MAX_BOOTSTRAP_LINE_SIZE 20000 #define MAX_BOOTSTRAP_ERROR_LEN 256 #define READ_BOOTSTRAP_SUCCESS 0 #define READ_BOOTSTRAP_EOF 1 #define READ_BOOTSTRAP_ERROR 2 #define READ_BOOTSTRAP_QUERY_SIZE 3 typedef void *fgets_input_t; typedef char * (*fgets_fn_t)(char *, size_t, fgets_input_t, int *error); #ifdef __cplusplus extern "C" { #endif int read_bootstrap_query(char *query, int *query_length, fgets_input_t input, fgets_fn_t fgets_fn, int preserve_delimiter, int *error); #ifdef __cplusplus } #endif #endif server/private/threadpool_winsockets.h000064400000004362151031265040014311 0ustar00/* Copyright (C) 2020 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #pragma once #include #include struct st_vio; struct win_aiosocket { /** OVERLAPPED is needed by all Windows AIO*/ OVERLAPPED m_overlapped{}; /** Handle to pipe, or socket */ HANDLE m_handle{}; /** Whether the m_handle refers to pipe*/ bool m_is_pipe{}; /* Read buffer handling */ /** Pointer to buffer of size READ_BUFSIZ. Can be NULL.*/ char *m_buf_ptr{}; /** Offset to current buffer position*/ size_t m_buf_off{}; /** Size of valid data in the buffer*/ size_t m_buf_datalen{}; /* Vio handling */ /** Pointer to original vio->vio_read/vio->has_data function */ size_t (*m_orig_vio_read)(st_vio *, unsigned char *, size_t){}; char (*m_orig_vio_has_data)(st_vio *){}; /** Begins asynchronnous reading from socket/pipe. On IO completion, pre-read some bytes into internal buffer */ DWORD begin_read(); /** Update number of bytes returned, and IO error status Should be called right after IO is completed GetQueuedCompletionStatus() , or threadpool IO completion callback would return nbytes and the error. Sets the valid data length in the read buffer. */ void end_read(ULONG nbytes, DWORD err); /** Override VIO routines with ours, accounting for one-shot buffering. */ void init(st_vio *vio); /** Return number of unread bytes.*/ size_t buffer_remaining(); /* Frees the read buffer.*/ ~win_aiosocket(); }; /* Functions related to IO buffers caches.*/ extern void init_win_aio_buffers(unsigned int n_buffers); extern void destroy_win_aio_buffers(); server/private/my_tree.h000064400000007627151031265040011352 0ustar00/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _tree_h #define _tree_h #ifdef __cplusplus extern "C" { #endif #include "my_base.h" /* get 'enum ha_rkey_function' */ #include "my_alloc.h" /* MEM_ROOT */ /* Worst case tree is half full. This gives use 2^(MAX_TREE_HEIGHT/2) leafs */ #define MAX_TREE_HEIGHT 64 #define ELEMENT_KEY(tree,element)\ (tree->offset_to_key ? (void*)((uchar*) element+tree->offset_to_key) :\ *((void**) (element+1))) #define tree_set_pointer(element,ptr) *((uchar **) (element+1))=((uchar*) (ptr)) /* A tree with its flag set to TREE_ONLY_DUPS behaves differently on inserting an element that is not in the tree: the element is not added at all, but instead tree_insert() returns a special address TREE_ELEMENT_UNIQUE as an indication that the function has not failed due to lack of memory. */ #define TREE_ELEMENT_UNIQUE ((TREE_ELEMENT *) 1) #define TREE_NO_DUPS 1 #define TREE_ONLY_DUPS 2 typedef enum { left_root_right, right_root_left } TREE_WALK; typedef uint32 element_count; typedef int (*tree_walk_action)(void *,element_count,void *); typedef enum { free_init, free_free, free_end } TREE_FREE; typedef int (*tree_element_free)(void*, TREE_FREE, void *); typedef struct st_tree_element { struct st_tree_element *left,*right; uint32 count:31, colour:1; /* black is marked as 1 */ } TREE_ELEMENT; #define ELEMENT_CHILD(element, offs) (*(TREE_ELEMENT**)((char*)element + offs)) typedef struct st_tree { TREE_ELEMENT *root; TREE_ELEMENT **parents[MAX_TREE_HEIGHT]; uint offset_to_key,elements_in_tree,size_of_element; size_t memory_limit, allocated; qsort_cmp2 compare; void *custom_arg; MEM_ROOT mem_root; my_bool with_delete; tree_element_free free; myf my_flags; uint flag; } TREE; /* Functions on whole tree */ void init_tree(TREE *tree, size_t default_alloc_size, size_t memory_limit, int size, qsort_cmp2 compare, tree_element_free free_element, void *custom_arg, myf my_flags); int delete_tree(TREE*, my_bool abort); int reset_tree(TREE*); /* similar to delete tree, except we do not my_free() blocks in mem_root */ #define is_tree_inited(tree) ((tree)->root != 0) /* Functions on leafs */ TREE_ELEMENT *tree_insert(TREE *tree,void *key, uint key_size, void *custom_arg); void *tree_search(TREE *tree, void *key, void *custom_arg); int tree_walk(TREE *tree,tree_walk_action action, void *argument, TREE_WALK visit); int tree_delete(TREE *tree, void *key, uint key_size, void *custom_arg); void *tree_search_key(TREE *tree, const void *key, TREE_ELEMENT **parents, TREE_ELEMENT ***last_pos, enum ha_rkey_function flag, void *custom_arg); void *tree_search_edge(TREE *tree, TREE_ELEMENT **parents, TREE_ELEMENT ***last_pos, int child_offs); void *tree_search_next(TREE *tree, TREE_ELEMENT ***last_pos, int l_offs, int r_offs); ha_rows tree_record_pos(TREE *tree, const void *key, enum ha_rkey_function search_flag, void *custom_arg); #define reset_free_element(tree) (tree)->free= 0 #define TREE_ELEMENT_EXTRA_SIZE (sizeof(TREE_ELEMENT) + sizeof(void*)) #ifdef __cplusplus } #endif #endif server/private/sql_explain.h000064400000070534151031265040012222 0ustar00/* Copyright (c) 2013 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* == EXPLAIN/ANALYZE architecture == === [SHOW] EXPLAIN data === Query optimization produces two data structures: 1. execution data structures themselves (eg. JOINs, JOIN_TAB, etc, etc) 2. Explain data structures. #2 are self contained set of data structures that has sufficient info to produce output of SHOW EXPLAIN, EXPLAIN [FORMAT=JSON], or ANALYZE [FORMAT=JSON], without accessing the execution data structures. (the only exception is that Explain data structures keep Item* pointers, and we require that one might call item->print(QT_EXPLAIN) when printing FORMAT=JSON output) === ANALYZE data === EXPLAIN data structures have embedded ANALYZE data structures. These are objects that are used to track how the parts of query plan were executed: how many times each part of query plan was invoked, how many rows were read/returned, etc. Each execution data structure keeps a direct pointer to its ANALYZE data structure. It is needed so that execution code can quickly increment the counters. (note that this increases the set of data that is frequently accessed during the execution. What is the impact of this?) Since ANALYZE/EXPLAIN data structures are separated from execution data structures, it is easy to have them survive until the end of the query, where we can return ANALYZE [FORMAT=JSON] output to the user, or print it into the slow query log. */ #ifndef SQL_EXPLAIN_INCLUDED #define SQL_EXPLAIN_INCLUDED class String_list: public List { public: const char *append_str(MEM_ROOT *mem_root, const char *str); }; class Json_writer; /************************************************************************************** Data structures for producing EXPLAIN outputs. These structures - Can be produced inexpensively from query plan. - Store sufficient information to produce tabular EXPLAIN output (the goal is to be able to produce JSON also) *************************************************************************************/ const uint FAKE_SELECT_LEX_ID= UINT_MAX; class Explain_query; /* A node can be either a SELECT, or a UNION. */ class Explain_node : public Sql_alloc { public: Explain_node(MEM_ROOT *root) : cache_tracker(NULL), subq_materialization(NULL), connection_type(EXPLAIN_NODE_OTHER), children(root) {} /* A type specifying what kind of node this is */ enum explain_node_type { EXPLAIN_UNION, EXPLAIN_SELECT, EXPLAIN_BASIC_JOIN, EXPLAIN_UPDATE, EXPLAIN_DELETE, EXPLAIN_INSERT }; /* How this node is connected */ enum explain_connection_type { EXPLAIN_NODE_OTHER, EXPLAIN_NODE_DERIVED, /* Materialized derived table */ EXPLAIN_NODE_NON_MERGED_SJ /* aka JTBM semi-join */ }; virtual enum explain_node_type get_type()= 0; virtual uint get_select_id()= 0; /** expression cache statistics */ Expression_cache_tracker* cache_tracker; /** If not NULL, this node is a SELECT (or UNION) in a materialized IN-subquery. */ Explain_subq_materialization* subq_materialization; /* How this node is connected to its parent. (NOTE: EXPLAIN_NODE_NON_MERGED_SJ is set very late currently) */ enum explain_connection_type connection_type; protected: /* A node may have children nodes. When a node's explain structure is created, children nodes may not yet have QPFs. This is why we store ids. */ Dynamic_array children; public: void add_child(int select_no) { children.append(select_no); } virtual int print_explain(Explain_query *query, select_result_sink *output, uint8 explain_flags, bool is_analyze)=0; virtual void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze)= 0; int print_explain_for_children(Explain_query *query, select_result_sink *output, uint8 explain_flags, bool is_analyze); void print_explain_json_for_children(Explain_query *query, Json_writer *writer, bool is_analyze); bool print_explain_json_cache(Json_writer *writer, bool is_analyze); bool print_explain_json_subq_materialization(Json_writer *writer, bool is_analyze); virtual ~Explain_node() = default; }; class Explain_table_access; /* A basic join. This is only used for SJ-Materialization nests. Basic join doesn't have ORDER/GROUP/DISTINCT operations. It also cannot be degenerate. It has its own select_id. */ class Explain_basic_join : public Explain_node { public: enum explain_node_type get_type() override { return EXPLAIN_BASIC_JOIN; } Explain_basic_join(MEM_ROOT *root) : Explain_node(root), join_tabs(NULL) {} ~Explain_basic_join(); bool add_table(Explain_table_access *tab, Explain_query *query); uint get_select_id() override { return select_id; } uint select_id; int print_explain(Explain_query *query, select_result_sink *output, uint8 explain_flags, bool is_analyze) override; void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze) override; void print_explain_json_interns(Explain_query *query, Json_writer *writer, bool is_analyze); /* A flat array of Explain structs for tables. */ Explain_table_access** join_tabs; uint n_join_tabs; }; class Explain_aggr_node; /* EXPLAIN structure for a SELECT. A select can be: 1. A degenerate case. In this case, message!=NULL, and it contains a description of what kind of degenerate case it is (e.g. "Impossible WHERE"). 2. a non-degenrate join. In this case, join_tabs describes the join. In the non-degenerate case, a SELECT may have a GROUP BY/ORDER BY operation. In both cases, the select may have children nodes. class Explain_node provides a way get node's children. */ class Explain_select : public Explain_basic_join { public: enum explain_node_type get_type() override { return EXPLAIN_SELECT; } Explain_select(MEM_ROOT *root, bool is_analyze) : Explain_basic_join(root), #ifndef DBUG_OFF select_lex(NULL), #endif linkage(UNSPECIFIED_TYPE), is_lateral(false), message(NULL), having(NULL), having_value(Item::COND_UNDEF), using_temporary(false), using_filesort(false), time_tracker(is_analyze), aggr_tree(NULL) {} void add_linkage(Json_writer *writer); public: #ifndef DBUG_OFF SELECT_LEX *select_lex; #endif const char *select_type; enum sub_select_type linkage; bool is_lateral; /* If message != NULL, this is a degenerate join plan, and all subsequent members have no info */ const char *message; /* Expensive constant condition */ Item *exec_const_cond; Item *outer_ref_cond; Item *pseudo_bits_cond; /* HAVING condition */ Item *having; Item::cond_result having_value; /* Global join attributes. In tabular form, they are printed on the first row */ bool using_temporary; bool using_filesort; /* ANALYZE members */ Time_and_counter_tracker time_tracker; /* Part of query plan describing sorting, temp.table usage, and duplicate removal */ Explain_aggr_node* aggr_tree; int print_explain(Explain_query *query, select_result_sink *output, uint8 explain_flags, bool is_analyze) override; void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze) override; Table_access_tracker *get_using_temporary_read_tracker() { return &using_temporary_read_tracker; } private: Table_access_tracker using_temporary_read_tracker; }; ///////////////////////////////////////////////////////////////////////////// // EXPLAIN structures for ORDER/GROUP operations. ///////////////////////////////////////////////////////////////////////////// typedef enum { AGGR_OP_TEMP_TABLE, AGGR_OP_FILESORT, //AGGR_OP_READ_SORTED_FILE, // need this? AGGR_OP_REMOVE_DUPLICATES, AGGR_OP_WINDOW_FUNCS //AGGR_OP_JOIN // Need this? } enum_explain_aggr_node_type; class Explain_aggr_node : public Sql_alloc { public: virtual enum_explain_aggr_node_type get_type()= 0; virtual ~Explain_aggr_node() = default; Explain_aggr_node *child; }; class Explain_aggr_filesort : public Explain_aggr_node { List sort_items; List sort_directions; public: enum_explain_aggr_node_type get_type() override { return AGGR_OP_FILESORT; } Filesort_tracker tracker; Explain_aggr_filesort(MEM_ROOT *mem_root, bool is_analyze, Filesort *filesort); void print_json_members(Json_writer *writer, bool is_analyze); }; class Explain_aggr_tmp_table : public Explain_aggr_node { public: enum_explain_aggr_node_type get_type() override { return AGGR_OP_TEMP_TABLE; } }; class Explain_aggr_remove_dups : public Explain_aggr_node { public: enum_explain_aggr_node_type get_type() override { return AGGR_OP_REMOVE_DUPLICATES; } }; class Explain_aggr_window_funcs : public Explain_aggr_node { List sorts; public: enum_explain_aggr_node_type get_type() override { return AGGR_OP_WINDOW_FUNCS; } void print_json_members(Json_writer *writer, bool is_analyze); friend class Window_funcs_computation; }; ///////////////////////////////////////////////////////////////////////////// extern const char *unit_operation_text[4]; extern const char *pushed_derived_text; extern const char *pushed_select_text; /* Explain structure for a UNION. A UNION may or may not have "Using filesort". */ class Explain_union : public Explain_node { public: Explain_union(MEM_ROOT *root, bool is_analyze) : Explain_node(root), union_members(PSI_INSTRUMENT_MEM), is_recursive_cte(false), fake_select_lex_explain(root, is_analyze) {} enum explain_node_type get_type() override { return EXPLAIN_UNION; } unit_common_op operation; uint get_select_id() override { DBUG_ASSERT(union_members.elements() > 0); return union_members.at(0); } /* Members of the UNION. Note: these are different from UNION's "children". Example: (select * from t1) union (select * from t2) order by (select col1 from t3 ...) here - select-from-t1 and select-from-t2 are "union members", - select-from-t3 is the only "child". */ Dynamic_array union_members; void add_select(int select_no) { union_members.append(select_no); } int print_explain(Explain_query *query, select_result_sink *output, uint8 explain_flags, bool is_analyze) override; void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze) override; const char *fake_select_type; bool using_filesort; bool using_tmp; bool is_recursive_cte; /* Explain data structure for "fake_select_lex" (i.e. for the degenerate SELECT that reads UNION result). It doesn't have a query plan, but we still need execution tracker, etc. */ Explain_select fake_select_lex_explain; Table_access_tracker *get_fake_select_lex_tracker() { return &fake_select_lex_tracker; } Table_access_tracker *get_tmptable_read_tracker() { return &tmptable_read_tracker; } private: uint make_union_table_name(char *buf); Table_access_tracker fake_select_lex_tracker; /* This one is for reading after ORDER BY */ Table_access_tracker tmptable_read_tracker; }; class Explain_update; class Explain_delete; class Explain_insert; /* Explain structure for a query (i.e. a statement). This should be able to survive when the query plan was deleted. Currently, we do not intend for it survive until after query's MEM_ROOT is freed. It does surivive freeing of query's items. For reference, the process of post-query cleanup is as follows: >dispatch_command | >mysql_parse | | ... | | lex_end() | | ... | | >THD::cleanup_after_query | | | ... | | | free_items() | | | ... | | dispatch_command That is, the order of actions is: - free query's Items - write to slow query log - free query's MEM_ROOT */ class Explain_query : public Sql_alloc { public: Explain_query(THD *thd, MEM_ROOT *root); ~Explain_query(); /* Add a new node */ void add_node(Explain_node *node); void add_insert_plan(Explain_insert *insert_plan_arg); void add_upd_del_plan(Explain_update *upd_del_plan_arg); /* This will return a select, or a union */ Explain_node *get_node(uint select_id); /* This will return a select (even if there is a union with this id) */ Explain_select *get_select(uint select_id); Explain_union *get_union(uint select_id); /* Produce a tabular EXPLAIN output */ int print_explain(select_result_sink *output, uint8 explain_flags, bool is_analyze); /* Send tabular EXPLAIN to the client */ int send_explain(THD *thd, bool extended); /* Return tabular EXPLAIN output as a text string */ bool print_explain_str(THD *thd, String *out_str, bool is_analyze); void print_explain_json(select_result_sink *output, bool is_analyze); /* If true, at least part of EXPLAIN can be printed */ bool have_query_plan() { return insert_plan || upd_del_plan|| get_node(1) != NULL; } void query_plan_ready(); MEM_ROOT *mem_root; Explain_update *get_upd_del_plan() { return upd_del_plan; } private: /* Explain_delete inherits from Explain_update */ Explain_update *upd_del_plan; /* Query "plan" for INSERTs */ Explain_insert *insert_plan; Dynamic_array unions; Dynamic_array selects; THD *thd; // for APC start/stop bool apc_enabled; /* Debugging aid: count how many times add_node() was called. Ideally, it should be one, we currently allow O(1) query plan saves for each select or union. The goal is not to have O(#rows_in_some_table), which is unacceptable. */ longlong operations; }; /* Some of the tags have matching text. See extra_tag_text for text names, and Explain_table_access::append_tag_name() for code to convert from tag form to text form. */ enum explain_extra_tag { ET_none= 0, /* not-a-tag */ ET_USING_INDEX_CONDITION, ET_USING_INDEX_CONDITION_BKA, ET_USING, /* For quick selects of various kinds */ ET_RANGE_CHECKED_FOR_EACH_RECORD, ET_USING_WHERE_WITH_PUSHED_CONDITION, ET_USING_WHERE, ET_NOT_EXISTS, ET_USING_INDEX, ET_FULL_SCAN_ON_NULL_KEY, ET_SKIP_OPEN_TABLE, ET_OPEN_FRM_ONLY, ET_OPEN_FULL_TABLE, ET_SCANNED_0_DATABASES, ET_SCANNED_1_DATABASE, ET_SCANNED_ALL_DATABASES, ET_USING_INDEX_FOR_GROUP_BY, ET_USING_MRR, // does not print "Using mrr". ET_DISTINCT, ET_LOOSESCAN, ET_START_TEMPORARY, ET_END_TEMPORARY, ET_FIRST_MATCH, ET_USING_JOIN_BUFFER, ET_CONST_ROW_NOT_FOUND, ET_UNIQUE_ROW_NOT_FOUND, ET_IMPOSSIBLE_ON_CONDITION, ET_TABLE_FUNCTION, ET_total }; /* Explain data structure describing join buffering use. */ class EXPLAIN_BKA_TYPE { public: EXPLAIN_BKA_TYPE() : join_alg(NULL) {} size_t join_buffer_size; bool incremental; /* NULL if no join buferring used. Other values: BNL, BNLH, BKA, BKAH. */ const char *join_alg; /* Information about MRR usage. */ StringBuffer<64> mrr_type; bool is_using_jbuf() { return (join_alg != NULL); } }; /* Data about how an index is used by some access method */ class Explain_index_use : public Sql_alloc { char *key_name; uint key_len; char *filter_name; uint filter_len; public: String_list key_parts_list; Explain_index_use() { clear(); } void clear() { key_name= NULL; key_len= (uint)-1; filter_name= NULL; filter_len= (uint)-1; } bool set(MEM_ROOT *root, KEY *key_name, uint key_len_arg); bool set_pseudo_key(MEM_ROOT *root, const char *key_name); inline const char *get_key_name() const { return key_name; } inline uint get_key_len() const { return key_len; } //inline const char *get_filter_name() const { return filter_name; } }; /* Query Plan data structure for Rowid filter. */ class Explain_rowid_filter : public Sql_alloc { public: /* Quick select used to collect the rowids into filter */ Explain_quick_select *quick; /* How many rows the above quick select is expected to return */ ha_rows rows; /* Expected selectivity for the filter */ double selectivity; /* Tracker with the information about how rowid filter is executed */ Rowid_filter_tracker *tracker; void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze); /* TODO: Here should be ANALYZE members: - r_rows for the quick select - An object that tracked the table access time - real selectivity of the filter. */ }; /* QPF for quick range selects, as well as index_merge select */ class Explain_quick_select : public Sql_alloc { public: Explain_quick_select(int quick_type_arg) : quick_type(quick_type_arg) {} const int quick_type; bool is_basic() { return (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE || quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC || quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX); } /* This is used when quick_type == QUICK_SELECT_I::QS_TYPE_RANGE */ Explain_index_use range; /* Used in all other cases */ List children; void print_extra(String *str); void print_key(String *str); void print_key_len(String *str); void print_json(Json_writer *writer); void print_extra_recursive(String *str); private: const char *get_name_by_type(); }; /* Data structure for "range checked for each record". It's a set of keys, tabular explain prints hex bitmap, json prints key names. */ typedef const char* NAME; class Explain_range_checked_fer : public Sql_alloc { public: String_list key_set; key_map keys_map; private: ha_rows full_scan, index_merge; ha_rows *keys_stat; NAME *keys_stat_names; uint keys; public: Explain_range_checked_fer() :Sql_alloc(), full_scan(0), index_merge(0), keys_stat(0), keys_stat_names(0), keys(0) {} int append_possible_keys_stat(MEM_ROOT *alloc, TABLE *table, key_map possible_keys); void collect_data(QUICK_SELECT_I *quick); void print_json(Json_writer *writer, bool is_analyze); }; /* EXPLAIN data structure for a single JOIN_TAB. */ class Explain_table_access : public Sql_alloc { public: Explain_table_access(MEM_ROOT *root, bool timed) : derived_select_number(0), non_merged_sjm_number(0), extra_tags(root), range_checked_fer(NULL), full_scan_on_null_key(false), start_dups_weedout(false), end_dups_weedout(false), where_cond(NULL), cache_cond(NULL), pushed_index_cond(NULL), sjm_nest(NULL), pre_join_sort(NULL), handler_for_stats(NULL), jbuf_unpack_tracker(timed), rowid_filter(NULL) {} ~Explain_table_access() { delete sjm_nest; } void push_extra(enum explain_extra_tag extra_tag); /* Internals */ /* id and 'select_type' are cared-of by the parent Explain_select */ StringBuffer<32> table_name; StringBuffer<32> used_partitions; String_list used_partitions_list; // valid with ET_USING_MRR StringBuffer<32> mrr_type; StringBuffer<32> firstmatch_table_name; /* Non-zero number means this is a derived table. The number can be used to find the query plan for the derived table */ int derived_select_number; /* TODO: join with the previous member. */ int non_merged_sjm_number; enum join_type type; bool used_partitions_set; /* Empty means "NULL" will be printed */ String_list possible_keys; bool rows_set; /* not set means 'NULL' should be printed */ bool filtered_set; /* not set means 'NULL' should be printed */ // Valid if ET_USING_INDEX_FOR_GROUP_BY is present bool loose_scan_is_scanning; /* Index use: key name and length. Note: that when one is accessing I_S tables, those may show use of non-existant indexes. key.key_name == NULL means 'NULL' will be shown in tabular output. key.key_len == (uint)-1 means 'NULL' will be shown in tabular output. */ Explain_index_use key; /* when type==JT_HASH_NEXT, 'key' stores the hash join pseudo-key. hash_next_key stores the table's key. */ Explain_index_use hash_next_key; String_list ref_list; ha_rows rows; double filtered; /* Contents of the 'Extra' column. Some are converted into strings, some have parameters, values for which are stored below. */ Dynamic_array extra_tags; // Valid if ET_USING tag is present Explain_quick_select *quick_info; /* Non-NULL value means this tab uses "range checked for each record" */ Explain_range_checked_fer *range_checked_fer; bool full_scan_on_null_key; // valid with ET_USING_JOIN_BUFFER EXPLAIN_BKA_TYPE bka_type; bool start_dups_weedout; bool end_dups_weedout; /* Note: lifespan of WHERE condition is less than lifespan of this object. The below two are valid if tags include "ET_USING_WHERE". (TODO: indexsubquery may put ET_USING_WHERE without setting where_cond?) */ Item *where_cond; Item *cache_cond; /* This is either pushed index condition, or BKA's index condition. (the latter refers to columns of other tables and so can only be checked by BKA code). Examine extra_tags to tell which one it is. */ Item *pushed_index_cond; Explain_basic_join *sjm_nest; /* This describes a possible filesort() call that is done before doing the join operation. */ Explain_aggr_filesort *pre_join_sort; /* ANALYZE members */ /* Tracker for reading the table */ Table_access_tracker tracker; Exec_time_tracker op_tracker; Gap_time_tracker extra_time_tracker; /* Handler object to get the handler_stats from. Notes: This pointer is only valid until notify_tables_are_closed() is called. After that, the tables may be freed or reused, together with their handler_stats objects. notify_tables_are_closed() disables printing of FORMAT=JSON output. r_engine_stats is only printed in FORMAT=JSON output, so we're fine. We do not store pointers to temporary (aka "work") tables here. Temporary tables may be freed (e.g. by JOIN::cleanup()) or re-created during query execution (when HEAP table is converted into Aria). */ handler *handler_for_stats; /* When using join buffer: Track the reads from join buffer */ Table_access_tracker jbuf_tracker; /* When using join buffer: time spent unpacking rows from the join buffer */ Time_and_counter_tracker jbuf_unpack_tracker; /* When using join buffer: time spent after unpacking rows from the join buffer. This will capture the time spent checking the Join Condition: the condition that depends on this table and preceding tables. */ Gap_time_tracker jbuf_extra_time_tracker; /* When using join buffer: Track the number of incoming record combinations */ Counter_tracker jbuf_loops_tracker; Explain_rowid_filter *rowid_filter; int print_explain(select_result_sink *output, uint8 explain_flags, bool is_analyze, uint select_id, const char *select_type, bool using_temporary, bool using_filesort); void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze); private: void append_tag_name(String *str, enum explain_extra_tag tag); void fill_key_str(String *key_str, bool is_json) const; void fill_key_len_str(String *key_len_str, bool is_json) const; double get_r_filtered(); void tag_to_json(Json_writer *writer, enum explain_extra_tag tag); }; /* EXPLAIN structure for single-table UPDATE. This is similar to Explain_table_access, except that it is more restrictive. Also, it can have UPDATE operation options, but currently there aren't any. Explain_delete inherits from this. */ class Explain_update : public Explain_node { public: Explain_update(MEM_ROOT *root, bool is_analyze) : Explain_node(root), filesort_tracker(NULL), command_tracker(is_analyze), handler_for_stats(NULL) {} enum explain_node_type get_type() override { return EXPLAIN_UPDATE; } uint get_select_id() override { return 1; /* always root */ } const char *select_type; StringBuffer<32> used_partitions; String_list used_partitions_list; bool used_partitions_set; bool impossible_where; bool no_partitions; StringBuffer<64> table_name; enum join_type jtype; String_list possible_keys; /* Used key when doing a full index scan (possibly with limit) */ Explain_index_use key; /* MRR that's used with quick select. This should probably belong to the quick select */ StringBuffer<64> mrr_type; Explain_quick_select *quick_info; bool using_where; Item *where_cond; ha_rows rows; bool using_io_buffer; /* Tracker for doing reads when filling the buffer */ Table_access_tracker buf_tracker; bool is_using_filesort() { return filesort_tracker? true: false; } /* Non-null value of filesort_tracker means "using filesort" if we are using filesort, then table_tracker is for the io done inside filesort. 'tracker' is for tracking post-filesort reads. */ Filesort_tracker *filesort_tracker; /* ANALYZE members and methods */ Table_access_tracker tracker; /* This tracks execution of the whole command */ Time_and_counter_tracker command_tracker; /* TODO: This tracks time to read rows from the table */ Exec_time_tracker table_tracker; /* The same as Explain_table_access::handler_for_stats */ handler *handler_for_stats; int print_explain(Explain_query *query, select_result_sink *output, uint8 explain_flags, bool is_analyze) override; void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze) override; }; /* EXPLAIN data structure for an INSERT. At the moment this doesn't do much as we don't really have any query plans for INSERT statements. */ class Explain_insert : public Explain_node { public: Explain_insert(MEM_ROOT *root) : Explain_node(root) {} StringBuffer<64> table_name; enum explain_node_type get_type() override { return EXPLAIN_INSERT; } uint get_select_id() override { return 1; /* always root */ } int print_explain(Explain_query *query, select_result_sink *output, uint8 explain_flags, bool is_analyze) override; void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze) override; }; /* EXPLAIN data of a single-table DELETE. */ class Explain_delete: public Explain_update { public: Explain_delete(MEM_ROOT *root, bool is_analyze) : Explain_update(root, is_analyze) {} /* TRUE means we're going to call handler->delete_all_rows() and not read any rows. */ bool deleting_all_rows; enum explain_node_type get_type() override { return EXPLAIN_DELETE; } uint get_select_id() override { return 1; /* always root */ } int print_explain(Explain_query *query, select_result_sink *output, uint8 explain_flags, bool is_analyze) override; void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze) override; }; /* EXPLAIN data structure for subquery materialization. All decisions are made at execution time so here we just store the tracker that has all the info. */ class Explain_subq_materialization : public Sql_alloc { public: Explain_subq_materialization(MEM_ROOT *mem_root) : tracker(mem_root) {} Subq_materialization_tracker *get_tracker() { return &tracker; } void print_explain_json(Json_writer *writer, bool is_analyze); private: Subq_materialization_tracker tracker; }; #endif //SQL_EXPLAIN_INCLUDED server/private/wsrep_client_service.h000064400000005000151031265040014103 0ustar00/* Copyright 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** @file wsrep_client_service.h This file provides declaratios for client service implementation. See wsrep/client_service.hpp for interface documentation. */ #ifndef WSREP_CLIENT_SERVICE_H #define WSREP_CLIENT_SERVICE_H /* wsrep-lib */ #include "wsrep/client_service.hpp" #include "wsrep/client_state.hpp" #include "wsrep/exception.hpp" /* not_implemented_error, remove when finished */ class THD; class Wsrep_client_state; class Wsrep_high_priority_context; class Wsrep_client_service : public wsrep::client_service { public: Wsrep_client_service(THD*, Wsrep_client_state&); bool interrupted(wsrep::unique_lock&) const override; void reset_globals() override; void store_globals() override; int prepare_data_for_replication() override; void cleanup_transaction() override; bool statement_allowed_for_streaming() const override; size_t bytes_generated() const override; int prepare_fragment_for_replication(wsrep::mutable_buffer&, size_t&) override; int remove_fragments() override; void emergency_shutdown() override { throw wsrep::not_implemented_error(); } void will_replay() override; void signal_replayed() override; enum wsrep::provider::status replay() override; enum wsrep::provider::status replay_unordered() override; void wait_for_replayers(wsrep::unique_lock&) override; enum wsrep::provider::status commit_by_xid() override; bool is_explicit_xa() override { return false; } bool is_prepared_xa() override { return false; } bool is_xa_rollback() override { return false; } void debug_sync(const char*) override; void debug_crash(const char*) override; int bf_rollback() override; private: friend class Wsrep_server_service; THD* m_thd; Wsrep_client_state& m_client_state; }; #endif /* WSREP_CLIENT_SERVICE_H */ server/private/ddl_log.h000064400000030615151031265040011303 0ustar00/* Copyright (c) 2000, 2019, Oracle and/or its affiliates. Copyright (c) 2010, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* External interfaces to ddl log functions */ #ifndef DDL_LOG_INCLUDED #define DDL_LOG_INCLUDED enum ddl_log_entry_code { /* DDL_LOG_UNKOWN Here mainly to detect blocks that are all zero DDL_LOG_EXECUTE_CODE: This is a code that indicates that this is a log entry to be executed, from this entry a linked list of log entries can be found and executed. DDL_LOG_ENTRY_CODE: An entry to be executed in a linked list from an execute log entry. DDL_LOG_IGNORE_ENTRY_CODE: An entry that is to be ignored */ DDL_LOG_UNKNOWN= 0, DDL_LOG_EXECUTE_CODE= 1, DDL_LOG_ENTRY_CODE= 2, DDL_LOG_IGNORE_ENTRY_CODE= 3, DDL_LOG_ENTRY_CODE_LAST= 4 }; /* When adding things below, also add an entry to ddl_log_action_names and ddl_log_entry_phases in ddl_log.cc */ enum ddl_log_action_code { /* The type of action that a DDL_LOG_ENTRY_CODE entry is to perform. */ DDL_LOG_UNKNOWN_ACTION= 0, /* Delete a .frm file or a table in the partition engine */ DDL_LOG_DELETE_ACTION= 1, /* Rename a .frm fire a table in the partition engine */ DDL_LOG_RENAME_ACTION= 2, /* Rename an entity after removing the previous entry with the new name, that is replace this entry. */ DDL_LOG_REPLACE_ACTION= 3, /* Exchange two entities by renaming them a -> tmp, b -> a, tmp -> b */ DDL_LOG_EXCHANGE_ACTION= 4, /* log do_rename(): Rename of .frm file, table, stat_tables and triggers */ DDL_LOG_RENAME_TABLE_ACTION= 5, DDL_LOG_RENAME_VIEW_ACTION= 6, DDL_LOG_DROP_INIT_ACTION= 7, DDL_LOG_DROP_TABLE_ACTION= 8, DDL_LOG_DROP_VIEW_ACTION= 9, DDL_LOG_DROP_TRIGGER_ACTION= 10, DDL_LOG_DROP_DB_ACTION=11, DDL_LOG_CREATE_TABLE_ACTION=12, DDL_LOG_CREATE_VIEW_ACTION=13, DDL_LOG_DELETE_TMP_FILE_ACTION=14, DDL_LOG_CREATE_TRIGGER_ACTION=15, DDL_LOG_ALTER_TABLE_ACTION=16, DDL_LOG_STORE_QUERY_ACTION=17, DDL_LOG_LAST_ACTION /* End marker */ }; /* Number of phases for each ddl_log_action_code */ extern const uchar ddl_log_entry_phases[DDL_LOG_LAST_ACTION]; enum enum_ddl_log_exchange_phase { EXCH_PHASE_NAME_TO_TEMP= 0, EXCH_PHASE_FROM_TO_NAME= 1, EXCH_PHASE_TEMP_TO_FROM= 2, EXCH_PHASE_END }; enum enum_ddl_log_rename_table_phase { DDL_RENAME_PHASE_TRIGGER= 0, DDL_RENAME_PHASE_STAT, DDL_RENAME_PHASE_TABLE, DDL_RENAME_PHASE_END }; enum enum_ddl_log_drop_table_phase { DDL_DROP_PHASE_TABLE=0, DDL_DROP_PHASE_TRIGGER, DDL_DROP_PHASE_BINLOG, DDL_DROP_PHASE_RESET, /* Reset found list of dropped tables */ DDL_DROP_PHASE_END }; enum enum_ddl_log_drop_db_phase { DDL_DROP_DB_PHASE_INIT=0, DDL_DROP_DB_PHASE_LOG, DDL_DROP_DB_PHASE_END }; enum enum_ddl_log_create_table_phase { DDL_CREATE_TABLE_PHASE_INIT=0, DDL_CREATE_TABLE_PHASE_LOG, DDL_CREATE_TABLE_PHASE_END }; enum enum_ddl_log_create_view_phase { DDL_CREATE_VIEW_PHASE_NO_OLD_VIEW, DDL_CREATE_VIEW_PHASE_DELETE_VIEW_COPY, DDL_CREATE_VIEW_PHASE_OLD_VIEW_COPIED, DDL_CREATE_VIEW_PHASE_END }; enum enum_ddl_log_create_trigger_phase { DDL_CREATE_TRIGGER_PHASE_NO_OLD_TRIGGER, DDL_CREATE_TRIGGER_PHASE_DELETE_COPY, DDL_CREATE_TRIGGER_PHASE_OLD_COPIED, DDL_CREATE_TRIGGER_PHASE_END }; enum enum_ddl_log_alter_table_phase { DDL_ALTER_TABLE_PHASE_INIT, DDL_ALTER_TABLE_PHASE_RENAME_FAILED, DDL_ALTER_TABLE_PHASE_INPLACE_COPIED, DDL_ALTER_TABLE_PHASE_INPLACE, DDL_ALTER_TABLE_PHASE_PREPARE_INPLACE, DDL_ALTER_TABLE_PHASE_CREATED, DDL_ALTER_TABLE_PHASE_COPIED, DDL_ALTER_TABLE_PHASE_OLD_RENAMED, DDL_ALTER_TABLE_PHASE_UPDATE_TRIGGERS, DDL_ALTER_TABLE_PHASE_UPDATE_STATS, DDL_ALTER_TABLE_PHASE_UPDATE_BINARY_LOG, DDL_ALTER_TABLE_PHASE_END }; /* Flags stored in DDL_LOG_ENTRY.flags The flag values can be reused for different commands */ #define DDL_LOG_FLAG_ALTER_RENAME (1 << 0) #define DDL_LOG_FLAG_ALTER_ENGINE_CHANGED (1 << 1) #define DDL_LOG_FLAG_ONLY_FRM (1 << 2) #define DDL_LOG_FLAG_UPDATE_STAT (1 << 3) /* Set when using ALTER TABLE on a partitioned table and the table engine is not changed */ #define DDL_LOG_FLAG_ALTER_PARTITION (1 << 4) /* Setting ddl_log_entry.phase to this has the same effect as setting the phase to the maximum phase (..PHASE_END) for an entry. */ #define DDL_LOG_FINAL_PHASE ((uchar) 0xff) typedef struct st_ddl_log_entry { LEX_CSTRING name; LEX_CSTRING from_name; LEX_CSTRING handler_name; LEX_CSTRING db; LEX_CSTRING from_db; LEX_CSTRING from_handler_name; LEX_CSTRING tmp_name; /* frm file or temporary file name */ LEX_CSTRING extra_name; /* Backup table name */ uchar uuid[MY_UUID_SIZE]; // UUID for new frm file ulonglong xid; // Xid stored in the binary log /* unique_id can be used to store a unique number to check current state. Currently it is used to store new size of frm file, link to another ddl log entry or store an a uniq version for a storage engine in alter table. For execute entries this is reused as an execute counter to ensure we don't repeat an entry too many times if executing the entry fails. */ ulonglong unique_id; uint next_entry; uint entry_pos; // Set by write_dll_log_entry() uint16 flags; // Flags unique for each command enum ddl_log_entry_code entry_type; // Set automatically enum ddl_log_action_code action_type; /* Most actions have only one phase. REPLACE does however have two phases. The first phase removes the file with the new name if there was one there before and the second phase renames the old name to the new name. */ uchar phase; // set automatically } DDL_LOG_ENTRY; typedef struct st_ddl_log_memory_entry { uint entry_pos; struct st_ddl_log_memory_entry *next_log_entry; struct st_ddl_log_memory_entry *prev_log_entry; struct st_ddl_log_memory_entry *next_active_log_entry; } DDL_LOG_MEMORY_ENTRY; /* State of the ddl log during execution of a DDL. A ddl log state has one execute entry (main entry pointing to the first action entry) and many 'action entries' linked in a list in the order they should be executed. One recovery the log is parsed and all execute entries will be executed. All entries are stored as separate blocks in the ddl recovery file. */ typedef struct st_ddl_log_state { /* List of ddl log entries */ DDL_LOG_MEMORY_ENTRY *list; /* One execute entry per list */ DDL_LOG_MEMORY_ENTRY *execute_entry; /* Entry used for PHASE updates. Normally same as first in 'list', but in case of a query log event, this points to the main event. */ DDL_LOG_MEMORY_ENTRY *main_entry; uint16 flags; /* Cache for flags */ bool is_active() { return list != 0; } } DDL_LOG_STATE; /* These functions are for recovery */ bool ddl_log_initialize(); void ddl_log_release(); bool ddl_log_close_binlogged_events(HASH *xids); int ddl_log_execute_recovery(); /* functions for updating the ddl log */ bool ddl_log_write_entry(DDL_LOG_ENTRY *ddl_log_entry, DDL_LOG_MEMORY_ENTRY **active_entry); bool ddl_log_write_execute_entry(uint first_entry, DDL_LOG_MEMORY_ENTRY **active_entry); bool ddl_log_disable_execute_entry(DDL_LOG_MEMORY_ENTRY **active_entry); void ddl_log_complete(DDL_LOG_STATE *ddl_log_state); bool ddl_log_revert(THD *thd, DDL_LOG_STATE *ddl_log_state); bool ddl_log_update_phase(DDL_LOG_STATE *entry, uchar phase); bool ddl_log_add_flag(DDL_LOG_STATE *entry, uint16 flag); bool ddl_log_update_unique_id(DDL_LOG_STATE *state, ulonglong id); bool ddl_log_update_xid(DDL_LOG_STATE *state, ulonglong xid); bool ddl_log_disable_entry(DDL_LOG_STATE *state); bool ddl_log_increment_phase(uint entry_pos); void ddl_log_release_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry); bool ddl_log_sync(); bool ddl_log_execute_entry(THD *thd, uint first_entry); void ddl_log_release_entries(DDL_LOG_STATE *ddl_log_state); bool ddl_log_rename_table(THD *thd, DDL_LOG_STATE *ddl_state, handlerton *hton, const LEX_CSTRING *org_db, const LEX_CSTRING *org_alias, const LEX_CSTRING *new_db, const LEX_CSTRING *new_alias); bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *org_db, const LEX_CSTRING *org_alias, const LEX_CSTRING *new_db, const LEX_CSTRING *new_alias); bool ddl_log_drop_table_init(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *db, const LEX_CSTRING *comment); bool ddl_log_drop_view_init(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *db); bool ddl_log_drop_table(THD *thd, DDL_LOG_STATE *ddl_state, handlerton *hton, const LEX_CSTRING *path, const LEX_CSTRING *db, const LEX_CSTRING *table); bool ddl_log_drop_view(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *path, const LEX_CSTRING *db, const LEX_CSTRING *table); bool ddl_log_drop_trigger(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *db, const LEX_CSTRING *table, const LEX_CSTRING *trigger_name, const LEX_CSTRING *query); bool ddl_log_drop_view(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *path, const LEX_CSTRING *db, const LEX_CSTRING *table); bool ddl_log_drop_view(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *db); bool ddl_log_drop_db(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *db, const LEX_CSTRING *path); bool ddl_log_create_table(THD *thd, DDL_LOG_STATE *ddl_state, handlerton *hton, const LEX_CSTRING *path, const LEX_CSTRING *db, const LEX_CSTRING *table, bool only_frm); bool ddl_log_create_view(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *path, enum_ddl_log_create_view_phase phase); bool ddl_log_delete_tmp_file(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *path, DDL_LOG_STATE *depending_state); bool ddl_log_create_trigger(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *db, const LEX_CSTRING *table, const LEX_CSTRING *trigger_name, enum_ddl_log_create_trigger_phase phase); bool ddl_log_alter_table(THD *thd, DDL_LOG_STATE *ddl_state, handlerton *org_hton, const LEX_CSTRING *db, const LEX_CSTRING *table, handlerton *new_hton, handlerton *partition_underlying_hton, const LEX_CSTRING *new_db, const LEX_CSTRING *new_table, const LEX_CSTRING *frm_path, const LEX_CSTRING *backup_table_name, const LEX_CUSTRING *version, ulonglong table_version, bool is_renamed); bool ddl_log_store_query(THD *thd, DDL_LOG_STATE *ddl_log_state, const char *query, size_t length); extern mysql_mutex_t LOCK_gdl; #endif /* DDL_LOG_INCLUDED */ server/private/pfs_memory_provider.h000064400000003132151031265040013763 0ustar00/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef PFS_MEMORY_PROVIDER_H #define PFS_MEMORY_PROVIDER_H /** @file include/pfs_memory_provider.h Performance schema instrumentation (declarations). */ #ifdef HAVE_PSI_MEMORY_INTERFACE #ifdef MYSQL_SERVER #ifndef EMBEDDED_LIBRARY #ifndef MYSQL_DYNAMIC_PLUGIN #include "mysql/psi/psi.h" #define PSI_MEMORY_CALL(M) pfs_ ## M ## _v1 C_MODE_START void pfs_register_memory_v1 (const char *category, struct PSI_memory_info_v1 *info, int count); PSI_memory_key pfs_memory_alloc_v1 (PSI_memory_key key, size_t size, PSI_thread **owner); PSI_memory_key pfs_memory_realloc_v1 (PSI_memory_key key, size_t old_size, size_t new_size, PSI_thread **owner); void pfs_memory_free_v1 (PSI_memory_key key, size_t size, PSI_thread *owner); C_MODE_END #endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_SERVER */ #endif /* HAVE_PSI_MEMORY_INTERFACE */ #endif server/private/sql_connect.h000064400000007767151031265040012223 0ustar00/* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_CONNECT_INCLUDED #define SQL_CONNECT_INCLUDED #include /* pthread_handler_t */ #include "mysql_com.h" /* enum_server_command */ #include "structs.h" #include #include #include "violite.h" /* Object to hold connect information to be given to the newly created thread */ struct scheduler_functions; class CONNECT : public ilink { public: MYSQL_SOCKET sock; #ifdef _WIN32 HANDLE pipe; CONNECT(HANDLE pipe_arg): pipe(pipe_arg), vio_type(VIO_TYPE_NAMEDPIPE), scheduler(thread_scheduler), thread_id(0), prior_thr_create_utime(0) { count++; } #endif enum enum_vio_type vio_type; scheduler_functions *scheduler; my_thread_id thread_id; /* Own variables */ ulonglong prior_thr_create_utime; static Atomic_counter count; CONNECT(MYSQL_SOCKET sock_arg, enum enum_vio_type vio_type_arg, scheduler_functions *scheduler_arg): sock(sock_arg), vio_type(vio_type_arg), scheduler(scheduler_arg), thread_id(0), prior_thr_create_utime(0) { count++; } ~CONNECT() { count--; DBUG_ASSERT(vio_type == VIO_CLOSED); } void close_and_delete(uint err); void close_with_error(uint sql_errno, const char *message, uint close_error); THD *create_thd(THD *thd); }; class THD; typedef struct user_conn USER_CONN; void init_max_user_conn(void); void init_global_user_stats(void); void init_global_table_stats(void); void init_global_index_stats(void); void init_global_client_stats(void); void free_max_user_conn(void); void free_global_user_stats(void); void free_global_table_stats(void); void free_global_index_stats(void); void free_global_client_stats(void); pthread_handler_t handle_one_connection(void *arg); void do_handle_one_connection(CONNECT *connect, bool put_in_cache); bool init_new_connection_handler_thread(); void reset_mqh(LEX_USER *lu, bool get_them); bool check_mqh(THD *thd, uint check_command); void time_out_user_resource_limits(THD *thd, USER_CONN *uc); #ifndef NO_EMBEDDED_ACCESS_CHECKS void decrease_user_connections(USER_CONN *uc); #else #define decrease_user_connections(X) do { } while(0) /* nothing */ #endif bool thd_init_client_charset(THD *thd, uint cs_number); void setup_connection_thread_globals(THD *thd); bool thd_prepare_connection(THD *thd); bool thd_is_connection_alive(THD *thd); int thd_set_peer_addr(THD *thd, sockaddr_storage *addr, const char *ip, uint port, bool check_proxy_networks, uint *host_errors); bool login_connection(THD *thd); void prepare_new_connection_state(THD* thd); void end_connection(THD *thd); void update_global_user_stats(THD* thd, bool create_user, time_t now); int get_or_create_user_conn(THD *thd, const char *user, const char *host, const USER_RESOURCES *mqh); int check_for_max_user_connections(THD *thd, USER_CONN *uc); extern HASH global_user_stats; extern HASH global_client_stats; extern HASH global_table_stats; extern HASH global_index_stats; extern mysql_mutex_t LOCK_global_user_client_stats; extern mysql_mutex_t LOCK_global_table_stats; extern mysql_mutex_t LOCK_global_index_stats; extern mysql_mutex_t LOCK_stats; #endif /* SQL_CONNECT_INCLUDED */ server/private/protocol.h000064400000030312151031265040011532 0ustar00#ifndef PROTOCOL_INCLUDED #define PROTOCOL_INCLUDED /* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_error.h" #include "my_decimal.h" /* my_decimal */ #include "sql_type.h" class i_string; class Field; class Send_field; class THD; class Item_param; struct TABLE_LIST; typedef struct st_mysql_field MYSQL_FIELD; typedef struct st_mysql_rows MYSQL_ROWS; class Protocol { protected: String *packet; /* Used by net_store_data() for charset conversions */ String *convert; uint field_pos; #ifndef DBUG_OFF const Type_handler **field_handlers; bool valid_handler(uint pos, protocol_send_type_t type) const { return field_handlers == 0 || field_handlers[field_pos]->protocol_send_type() == type; } #endif uint field_count; virtual bool net_store_data(const uchar *from, size_t length); virtual bool net_store_data_cs(const uchar *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); virtual bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *, bool); virtual bool net_send_error_packet(THD *, uint, const char *, const char *); #ifdef EMBEDDED_LIBRARY char **next_field; MYSQL_FIELD *next_mysql_field; MEM_ROOT *alloc; #endif bool needs_conversion(CHARSET_INFO *fromcs, CHARSET_INFO *tocs) const { // 'tocs' is set 0 when client issues SET character_set_results=NULL return tocs && !my_charset_same(fromcs, tocs) && fromcs != &my_charset_bin && tocs != &my_charset_bin; } /* The following two are low-level functions that are invoked from higher-level store_xxx() funcs. The data is stored into this->packet. */ bool store_string_aux(const char *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); virtual bool send_ok(uint server_status, uint statement_warn_count, ulonglong affected_rows, ulonglong last_insert_id, const char *message); virtual bool send_eof(uint server_status, uint statement_warn_count); virtual bool send_error(uint sql_errno, const char *err_msg, const char *sql_state); CHARSET_INFO *character_set_results() const; public: THD *thd; Protocol(THD *thd_arg) { init(thd_arg); } virtual ~Protocol() = default; void init(THD* thd_arg); enum { SEND_NUM_ROWS= 1, SEND_EOF= 2, SEND_FORCE_COLUMN_INFO= 4 }; virtual bool send_result_set_metadata(List *list, uint flags); bool send_list_fields(List *list, const TABLE_LIST *table_list); bool send_result_set_row(List *row_items); bool store(I_List *str_list); bool store_string_or_null(const char *from, CHARSET_INFO *cs); bool store_warning(const char *from, size_t length); String *storage_packet() { return packet; } inline void free() { packet->free(); } virtual bool write(); inline bool store(int from) { return store_long((longlong) from); } inline bool store(uint32 from) { return store_long((longlong) from); } inline bool store(longlong from) { return store_longlong((longlong) from, 0); } inline bool store(ulonglong from) { return store_longlong((longlong) from, 1); } inline bool store(String *str) { return store((char*) str->ptr(), str->length(), str->charset()); } inline bool store(const LEX_CSTRING *from, CHARSET_INFO *cs) { return store(from->str, from->length, cs); } virtual bool prepare_for_send(uint num_columns) { field_count= num_columns; return 0; } virtual bool flush(); virtual void end_partial_result_set(THD *thd); virtual void prepare_for_resend()=0; virtual bool store_null()=0; virtual bool store_tiny(longlong from)=0; virtual bool store_short(longlong from)=0; virtual bool store_long(longlong from)=0; virtual bool store_longlong(longlong from, bool unsigned_flag)=0; virtual bool store_decimal(const my_decimal *)=0; virtual bool store_str(const char *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0; virtual bool store_float(float from, uint32 decimals)=0; virtual bool store_double(double from, uint32 decimals)=0; virtual bool store_datetime(MYSQL_TIME *time, int decimals)=0; virtual bool store_date(MYSQL_TIME *time)=0; virtual bool store_time(MYSQL_TIME *time, int decimals)=0; virtual bool store(Field *field)=0; // Various useful wrappers for the virtual store*() methods. // Backward wrapper for store_str() bool store(const char *from, size_t length, CHARSET_INFO *cs) { return store_str(from, length, cs, character_set_results()); } bool store_lex_cstring(const LEX_CSTRING &s, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { return store_str(s.str, (uint) s.length, fromcs, tocs); } bool store_binary_string(const char *str, size_t length) { return store_str(str, (uint) length, &my_charset_bin, &my_charset_bin); } bool store_ident(const LEX_CSTRING &s) { return store_lex_cstring(s, system_charset_info, character_set_results()); } // End of wrappers virtual bool send_out_parameters(List *sp_params)=0; #ifdef EMBEDDED_LIBRARY bool begin_dataset(); bool begin_dataset(THD *thd, uint numfields); virtual void remove_last_row() {} #else void remove_last_row() {} #endif enum enum_protocol_type { /* Before adding a new type, please make sure there is enough storage for it in Query_cache_query_flags. */ PROTOCOL_TEXT= 0, PROTOCOL_BINARY= 1, PROTOCOL_LOCAL= 2, PROTOCOL_DISCARD= 3 /* Should be last, not used by Query_cache */ }; virtual enum enum_protocol_type type()= 0; virtual bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count); bool net_send_error(THD *thd, uint sql_errno, const char *err, const char* sqlstate); void end_statement(); }; /** Class used for the old (MySQL 4.0 protocol). */ class Protocol_text :public Protocol { StringBuffer buffer; bool store_numeric_string_aux(const char *from, size_t length); public: Protocol_text(THD *thd_arg, ulong prealloc= 0) :Protocol(thd_arg) { if (prealloc) packet->alloc(prealloc); } void prepare_for_resend() override; bool store_null() override; bool store_tiny(longlong from) override; bool store_short(longlong from) override; bool store_long(longlong from) override; bool store_longlong(longlong from, bool unsigned_flag) override; bool store_decimal(const my_decimal *) override; bool store_str(const char *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) override; bool store_datetime(MYSQL_TIME *time, int decimals) override; bool store_date(MYSQL_TIME *time) override; bool store_time(MYSQL_TIME *time, int decimals) override; bool store_float(float nr, uint32 decimals) override; bool store_double(double from, uint32 decimals) override; bool store(Field *field) override; bool send_out_parameters(List *sp_params) override; bool store_numeric_zerofill_str(const char *from, size_t length, protocol_send_type_t send_type); #ifdef EMBEDDED_LIBRARY void remove_last_row() override; #endif bool store_field_metadata(const THD *thd, const Send_field &field, CHARSET_INFO *charset_for_protocol, uint pos); bool store_item_metadata(THD *thd, Item *item, uint pos); bool store_field_metadata_for_list_fields(const THD *thd, Field *field, const TABLE_LIST *table_list, uint pos); enum enum_protocol_type type() override { return PROTOCOL_TEXT; }; }; class Protocol_binary final :public Protocol { private: uint bit_fields; public: Protocol_binary(THD *thd_arg) :Protocol(thd_arg) {} bool prepare_for_send(uint num_columns) override; void prepare_for_resend() override; #ifdef EMBEDDED_LIBRARY bool write() override; bool net_store_data(const uchar *from, size_t length) override; bool net_store_data_cs(const uchar *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) override; #endif bool store_null() override; bool store_tiny(longlong from) override; bool store_short(longlong from) override; bool store_long(longlong from) override; bool store_longlong(longlong from, bool unsigned_flag) override; bool store_decimal(const my_decimal *) override; bool store_str(const char *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) override; bool store_datetime(MYSQL_TIME *time, int decimals) override; bool store_date(MYSQL_TIME *time) override; bool store_time(MYSQL_TIME *time, int decimals) override; bool store_float(float nr, uint32 decimals) override; bool store_double(double from, uint32 decimals) override; bool store(Field *field) override; bool send_out_parameters(List *sp_params) override; enum enum_protocol_type type() override { return PROTOCOL_BINARY; }; }; /* A helper for "ANALYZE $stmt" which looks a real network procotol but doesn't write results to the network. At first glance, class select_send looks like a more appropriate place to implement the "write nothing" hook. This is not true, because - we need to evaluate the value of every item, and do it the way select_send does it (i.e. call item->val_int() or val_real() or...) - select_send::send_data() has some other code, like telling the storage engine that the row can be unlocked. We want to keep that also. as a result, "ANALYZE $stmt" uses a select_send_analyze which still uses select_send::send_data() & co., and also uses Protocol_discard object. */ class Protocol_discard final : public Protocol { public: Protocol_discard(THD *thd_arg) : Protocol(thd_arg) {} bool write() override { return 0; } bool send_result_set_metadata(List *, uint) override { return 0; } bool send_eof(uint, uint) override { return 0; } void prepare_for_resend() override { IF_DBUG(field_pos= 0,); } bool send_out_parameters(List *sp_params) override { return false; } /* Provide dummy overrides for any storage methods so that we avoid allocating and copying of data */ bool store_null() override { return false; } bool store_tiny(longlong) override { return false; } bool store_short(longlong) override { return false; } bool store_long(longlong) override { return false; } bool store_longlong(longlong, bool) override { return false; } bool store_decimal(const my_decimal *) override { return false; } bool store_str(const char *, size_t, CHARSET_INFO *, CHARSET_INFO *) override { return false; } bool store_datetime(MYSQL_TIME *, int) override { return false; } bool store_date(MYSQL_TIME *) override { return false; } bool store_time(MYSQL_TIME *, int) override { return false; } bool store_float(float, uint32) override { return false; } bool store_double(double, uint32) override { return false; } bool store(Field *) override { return false; } enum enum_protocol_type type() override { return PROTOCOL_DISCARD; }; }; void send_warning(THD *thd, uint sql_errno, const char *err=0); void net_send_progress_packet(THD *thd); uchar *net_store_data(uchar *to,const uchar *from, size_t length); uchar *net_store_data(uchar *to,int32 from); uchar *net_store_data(uchar *to,longlong from); #endif /* PROTOCOL_INCLUDED */ server/private/field_comp.h000064400000002226151031265040011775 0ustar00#ifndef FIELD_COMP_H_INCLUDED #define FIELD_COMP_H_INCLUDED /* Copyright (C) 2017 MariaDB Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #define MAX_COMPRESSION_METHODS 16 struct Compression_method { const char *name; uint (*compress)(THD *thd, char *to, const char *from, uint length); int (*uncompress)(String *to, const uchar *from, uint from_length, uint field_length); }; extern Compression_method compression_methods[MAX_COMPRESSION_METHODS]; #define zlib_compression_method (&compression_methods[8]) #endif server/private/rpl_record_old.h000064400000002577151031265040012676 0ustar00/* Copyright (c) 2007, 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef RPL_RECORD_OLD_H #define RPL_RECORD_OLD_H #include "log_event.h" /* Log_event_type */ #ifndef MYSQL_CLIENT size_t pack_row_old(TABLE *table, MY_BITMAP const* cols, uchar *row_data, const uchar *record); #ifdef HAVE_REPLICATION int unpack_row_old(rpl_group_info *rgi, TABLE *table, uint const colcnt, uchar *record, uchar const *row, uchar const *row_buffer_end, MY_BITMAP const *cols, uchar const **row_end, ulong *master_reclength, MY_BITMAP* const rw_set, Log_event_type const event_type); #endif #endif #endif server/private/sql_cache.h000064400000052254151031265040011624 0ustar00/* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _SQL_CACHE_H #define _SQL_CACHE_H #include "hash.h" #include "my_base.h" /* ha_rows */ class MY_LOCALE; struct TABLE_LIST; class Time_zone; struct LEX; struct TABLE; typedef struct st_changed_table_list CHANGED_TABLE_LIST; /* Query cache */ /* Can't create new free memory block if unused memory in block less then QUERY_CACHE_MIN_ALLOCATION_UNIT. if QUERY_CACHE_MIN_ALLOCATION_UNIT == 0 then QUERY_CACHE_MIN_ALLOCATION_UNIT choosed automatically */ #define QUERY_CACHE_MIN_ALLOCATION_UNIT 512 /* inittial size of hashes */ #define QUERY_CACHE_DEF_QUERY_HASH_SIZE 1024 #define QUERY_CACHE_DEF_TABLE_HASH_SIZE 1024 /* minimal result data size when data allocated */ #define QUERY_CACHE_MIN_RESULT_DATA_SIZE (1024*4) /* start estimation of first result block size only when number of queries bigger then: */ #define QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER 3 /* memory bins size spacing (see at Query_cache::init_cache (sql_cache.cc)) */ #define QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 4 #define QUERY_CACHE_MEM_BIN_STEP_PWR2 2 #define QUERY_CACHE_MEM_BIN_PARTS_INC 1 #define QUERY_CACHE_MEM_BIN_PARTS_MUL 1.2 #define QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2 3 /* how many free blocks check when finding most suitable before other 'end' of list of free blocks */ #define QUERY_CACHE_MEM_BIN_TRY 5 /* packing parameters */ #define QUERY_CACHE_PACK_ITERATION 2 #define QUERY_CACHE_PACK_LIMIT (512*1024L) #define TABLE_COUNTER_TYPE uint struct Query_cache_block; struct Query_cache_block_table; struct Query_cache_table; struct Query_cache_query; struct Query_cache_result; class Query_cache; struct Query_cache_tls; struct LEX; class THD; typedef my_bool (*qc_engine_callback)(THD *thd, const char *table_key, uint key_length, ulonglong *engine_data); /** This class represents a node in the linked chain of queries belonging to one table. @note The root of this linked list is not a query-type block, but the table- type block which all queries has in common. */ struct Query_cache_block_table { Query_cache_block_table() = default; /* Remove gcc warning */ /** This node holds a position in a static table list belonging to the associated query (base 0). */ TABLE_COUNTER_TYPE n; /** Pointers to the next and previous node, linking all queries with a common table. */ Query_cache_block_table *next, *prev; /** A pointer to the table-type block which all linked queries has in common. */ Query_cache_table *parent; /** A method to calculate the address of the query cache block owning this node. The purpose of this calculation is to make it easier to move the query cache block without having to modify all the pointer addresses. */ inline Query_cache_block *block(); }; struct Query_cache_block { Query_cache_block() = default; /* Remove gcc warning */ enum block_type {FREE, QUERY, RESULT, RES_CONT, RES_BEG, RES_INCOMPLETE, TABLE, INCOMPLETE}; size_t length; // length of all block size_t used; // length of data /* Not used **pprev, **prev because really needed access to pervious block: *pprev to join free blocks *prev to access to opposite side of list in cyclic sorted list */ Query_cache_block *pnext,*pprev, // physical next/previous block *next,*prev; // logical next/previous block block_type type; TABLE_COUNTER_TYPE n_tables; // number of tables in query inline bool is_free(void) { return type == FREE; } void init(size_t length); void destroy(); uint headers_len() const; uchar* data(void) const; Query_cache_query *query(); Query_cache_table *table(); Query_cache_result *result(); Query_cache_block_table *table(TABLE_COUNTER_TYPE n); }; struct Query_cache_query { ulonglong limit_found_rows; mysql_rwlock_t lock; Query_cache_block *res; Query_cache_tls *wri; size_t len; unsigned int last_pkt_nr; uint8 tbls_type; uint8 ready; ulonglong hit_count; Query_cache_query() = default; /* Remove gcc warning */ inline void init_n_lock(); void unlock_n_destroy(); inline ulonglong found_rows() { return limit_found_rows; } inline void found_rows(ulonglong rows) { limit_found_rows= rows; } inline Query_cache_block *result() { return res; } inline void result(Query_cache_block *p) { res= p; } inline Query_cache_tls *writer() { return wri; } inline void writer(Query_cache_tls *p) { wri= p; } inline uint8 tables_type() { return tbls_type; } inline void tables_type(uint8 type) { tbls_type= type; } inline size_t length() { return len; } inline size_t add(size_t packet_len) { return(len+= packet_len); } inline void length(size_t length_arg) { len= length_arg; } inline uchar* query() { return (((uchar*)this) + ALIGN_SIZE(sizeof(Query_cache_query))); } /** following used to check if result ready in plugin without locking rw_lock of the query. */ inline void set_results_ready() { ready= 1; } inline bool is_results_ready() { return ready; } inline void increment_hits() { hit_count++; } inline ulonglong hits() { return hit_count; } void lock_writing(); void lock_reading(); bool try_lock_writing(); void unlock_writing(); void unlock_reading(); }; struct Query_cache_table { Query_cache_table() = default; /* Remove gcc warning */ char *tbl; uint32 key_len; uint8 suffix_len; /* For partitioned tables */ uint8 table_type; /* unique for every engine reference */ qc_engine_callback callback_func; /* data need by some engines */ ulonglong engine_data_buff; /** The number of queries depending of this table. */ int32 m_cached_query_count; /** If table included in the table hash to be found by other queries */ my_bool hashed; inline char *db() { return (char *) data(); } inline char *table() { return tbl; } inline void table(char *table_arg) { tbl= table_arg; } inline uint32 key_length() { return key_len; } inline void key_length(uint32 len) { key_len= len; } inline uint8 suffix_length() { return suffix_len; } inline void suffix_length(uint8 len) { suffix_len= len; } inline uint8 type() { return table_type; } inline void type(uint8 t) { table_type= t; } inline qc_engine_callback callback() { return callback_func; } inline void callback(qc_engine_callback fn){ callback_func= fn; } inline ulonglong engine_data() { return engine_data_buff; } inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; } inline my_bool is_hashed() { return hashed; } inline void set_hashed(my_bool hash) { hashed= hash; } inline uchar* data() { return (uchar*)(((uchar*)this)+ ALIGN_SIZE(sizeof(Query_cache_table))); } }; struct Query_cache_result { Query_cache_result() = default; /* Remove gcc warning */ Query_cache_block *query; inline uchar* data() { return (uchar*)(((uchar*) this)+ ALIGN_SIZE(sizeof(Query_cache_result))); } /* data_continue (if not whole packet contained by this block) */ inline Query_cache_block *parent() { return query; } inline void parent (Query_cache_block *p) { query=p; } }; extern "C" { const uchar *query_cache_query_get_key(const void *record, size_t *length, my_bool); const uchar *query_cache_table_get_key(const void *record, size_t *length, my_bool); } extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename); struct Query_cache_memory_bin { Query_cache_memory_bin() = default; /* Remove gcc warning */ #ifndef DBUG_OFF size_t size; #endif uint number; Query_cache_block *free_blocks; inline void init(size_t size_arg) { #ifndef DBUG_OFF size = size_arg; #endif number = 0; free_blocks = 0; } }; struct Query_cache_memory_bin_step { Query_cache_memory_bin_step() = default; /* Remove gcc warning */ size_t size; size_t increment; size_t idx; inline void init(size_t size_arg, size_t idx_arg, size_t increment_arg) { size = size_arg; idx = idx_arg; increment = increment_arg; } }; class Query_cache { public: /* Info */ size_t query_cache_size, query_cache_limit; /* statistics */ size_t free_memory, queries_in_cache, hits, inserts, refused, free_memory_blocks, total_blocks, lowmem_prunes; private: #ifndef DBUG_OFF my_thread_id m_cache_lock_thread_id; #endif mysql_cond_t COND_cache_status_changed; uint m_requests_in_progress; enum Cache_lock_status { UNLOCKED, LOCKED_NO_WAIT, LOCKED }; Cache_lock_status m_cache_lock_status; enum Cache_staus {OK, DISABLE_REQUEST, DISABLED}; Cache_staus m_cache_status; void free_query_internal(Query_cache_block *point); void invalidate_table_internal(uchar *key, size_t key_length); protected: /* The following mutex is locked when searching or changing global query, tables lists or hashes. When we are operating inside the query structure we locked an internal query block mutex. LOCK SEQUENCE (to prevent deadlocks): 1. structure_guard_mutex 2. query block (for operation inside query (query block/results)) Thread doing cache flush releases the mutex once it sets m_cache_lock_status flag, so other threads may bypass the cache as if it is disabled, not waiting for reset to finish. The exception is other threads that were going to do cache flush---they'll wait till the end of a flush operation. */ mysql_mutex_t structure_guard_mutex; size_t additional_data_size; uchar *cache; // cache memory Query_cache_block *first_block; // physical location block list Query_cache_block *queries_blocks; // query list (LIFO) Query_cache_block *tables_blocks; Query_cache_memory_bin *bins; // free block lists Query_cache_memory_bin_step *steps; // bins spacing info HASH queries, tables; /* options */ size_t min_allocation_unit, min_result_data_size; uint def_query_hash_size, def_table_hash_size; size_t mem_bin_num, mem_bin_steps; // See at init_cache & find_bin bool initialized; /* Exclude/include from cyclic double linked list */ static void double_linked_list_exclude(Query_cache_block *point, Query_cache_block **list_pointer); static void double_linked_list_simple_include(Query_cache_block *point, Query_cache_block ** list_pointer); static void double_linked_list_join(Query_cache_block *head_tail, Query_cache_block *tail_head); /* The following functions require that structure_guard_mutex is locked */ void flush_cache(); my_bool free_old_query(); void free_query(Query_cache_block *point); my_bool allocate_data_chain(Query_cache_block **result_block, size_t data_len, Query_cache_block *query_block, my_bool first_block); void invalidate_table(THD *thd, TABLE_LIST *table); void invalidate_table(THD *thd, TABLE *table); void invalidate_table(THD *thd, uchar *key, size_t key_length); void invalidate_table(THD *thd, Query_cache_block *table_block); void invalidate_query_block_list(Query_cache_block_table *list_root); TABLE_COUNTER_TYPE register_tables_from_list(THD *thd, TABLE_LIST *tables_used, TABLE_COUNTER_TYPE counter, Query_cache_block_table **block_table); my_bool register_all_tables(THD *thd, Query_cache_block *block, TABLE_LIST *tables_used, TABLE_COUNTER_TYPE tables); void unlink_table(Query_cache_block_table *node); Query_cache_block *get_free_block (size_t len, my_bool not_less, size_t min); void free_memory_block(Query_cache_block *point); void split_block(Query_cache_block *block, size_t len); Query_cache_block *join_free_blocks(Query_cache_block *first_block, Query_cache_block *block_in_list); my_bool append_next_free_block(Query_cache_block *block, size_t add_size); void exclude_from_free_memory_list(Query_cache_block *free_block); void insert_into_free_memory_list(Query_cache_block *new_block); my_bool move_by_type(uchar **border, Query_cache_block **before, size_t *gap, Query_cache_block *i); uint find_bin(size_t size); void move_to_query_list_end(Query_cache_block *block); void insert_into_free_memory_sorted_list(Query_cache_block *new_block, Query_cache_block **list); void pack_cache(); void relink(Query_cache_block *oblock, Query_cache_block *nblock, Query_cache_block *next, Query_cache_block *prev, Query_cache_block *pnext, Query_cache_block *pprev); my_bool join_results(size_t join_limit); /* Following function control structure_guard_mutex by themself or don't need structure_guard_mutex */ size_t init_cache(); void make_disabled(); void free_cache(); Query_cache_block *write_block_data(size_t data_len, uchar* data, size_t header_len, Query_cache_block::block_type type, TABLE_COUNTER_TYPE ntab = 0); my_bool append_result_data(Query_cache_block **result, size_t data_len, uchar* data, Query_cache_block *parent); my_bool write_result_data(Query_cache_block **result, size_t data_len, uchar* data, Query_cache_block *parent, Query_cache_block::block_type type=Query_cache_block::RESULT); inline size_t get_min_first_result_data_size(); inline size_t get_min_append_result_data_size(); Query_cache_block *allocate_block(size_t len, my_bool not_less, size_t min); /* If query is cacheable return number tables in query (query without tables not cached) */ TABLE_COUNTER_TYPE is_cacheable(THD *thd, LEX *lex, TABLE_LIST *tables_used, uint8 *tables_type); TABLE_COUNTER_TYPE process_and_count_tables(THD *thd, TABLE_LIST *tables_used, uint8 *tables_type); static my_bool ask_handler_allowance(THD *thd, TABLE_LIST *tables_used); public: Query_cache(size_t query_cache_limit = ULONG_MAX, size_t min_allocation_unit = QUERY_CACHE_MIN_ALLOCATION_UNIT, size_t min_result_data_size = QUERY_CACHE_MIN_RESULT_DATA_SIZE, uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE, uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE); inline bool is_disabled(void) { return m_cache_status != OK; } inline bool is_disable_in_progress(void) { return m_cache_status == DISABLE_REQUEST; } /* initialize cache (mutex) */ void init(); /* resize query cache (return real query size, 0 if disabled) */ size_t resize(size_t query_cache_size); /* set limit on result size */ inline void result_size_limit(size_t limit){query_cache_limit=limit;} /* set minimal result data allocation unit size */ size_t set_min_res_unit(size_t size); /* register query in cache */ void store_query(THD *thd, TABLE_LIST *used_tables); /* Check if the query is in the cache and if this is true send the data to client. */ int send_result_to_client(THD *thd, char *query, uint query_length); /* Remove all queries that uses any of the listed following tables */ void invalidate(THD *thd, TABLE_LIST *tables_used, my_bool using_transactions); void invalidate(THD *thd, CHANGED_TABLE_LIST *tables_used); void invalidate_locked_for_write(THD *thd, TABLE_LIST *tables_used); void invalidate(THD *thd, TABLE *table, my_bool using_transactions); void invalidate(THD *thd, const char *key, size_t key_length, my_bool using_transactions); /* Remove all queries that uses any of the tables in following database */ void invalidate(THD *thd, const char *db); /* Remove all queries that uses any of the listed following table */ void invalidate_by_MyISAM_filename(const char *filename); void flush(); void pack(THD *thd, size_t join_limit = QUERY_CACHE_PACK_LIMIT, uint iteration_limit = QUERY_CACHE_PACK_ITERATION); void destroy(); void insert(THD *thd, Query_cache_tls *query_cache_tls, const char *packet, size_t length, unsigned pkt_nr); my_bool insert_table(THD *thd, size_t key_len, const char *key, Query_cache_block_table *node, size_t db_length, uint8 suffix_length_arg, uint8 cache_type, qc_engine_callback callback, ulonglong engine_data, my_bool hash); void end_of_result(THD *thd); void abort(THD *thd, Query_cache_tls *query_cache_tls); /* The following functions are only used when debugging We don't protect these with ifndef DBUG_OFF to not have to recompile everything if we want to add checks of the cache at some places. */ void wreck(uint line, const char *message); void bins_dump(); void cache_dump(); void queries_dump(); void tables_dump(); my_bool check_integrity(bool not_locked); my_bool in_list(Query_cache_block * root, Query_cache_block * point, const char *name); my_bool in_table_list(Query_cache_block_table * root, Query_cache_block_table * point, const char *name); my_bool in_blocks(Query_cache_block * point); /* Table key generation */ static uint filename_2_table_key (char *key, const char *filename, uint32 *db_langth); enum Cache_try_lock_mode {WAIT, TIMEOUT, TRY}; bool try_lock(THD *thd, Cache_try_lock_mode mode= WAIT); void lock(THD *thd); void lock_and_suspend(void); void unlock(void); void disable_query_cache(THD *thd); }; #ifdef HAVE_QUERY_CACHE struct Query_cache_query_flags { unsigned int client_long_flag:1; unsigned int client_protocol_41:1; unsigned int client_extended_metadata:1; unsigned int client_depr_eof:1; unsigned int protocol_type:2; unsigned int more_results_exists:1; unsigned int in_trans:1; unsigned int autocommit:1; unsigned int pkt_nr; uint character_set_client_num; uint character_set_results_num; uint collation_connection_num; uint group_concat_max_len; ha_rows limit; Time_zone *time_zone; sql_mode_t sql_mode; ulonglong max_sort_length; size_t default_week_format; size_t div_precision_increment; MY_LOCALE *lc_time_names; }; #define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags) #define QUERY_CACHE_DB_LENGTH_SIZE 2 #include "sql_cache.h" #define query_cache_abort(A,B) query_cache.abort(A,B) #define query_cache_end_of_result(A) query_cache.end_of_result(A) #define query_cache_store_query(A, B) query_cache.store_query(A, B) #define query_cache_destroy() query_cache.destroy() #define query_cache_result_size_limit(A) query_cache.result_size_limit(A) #define query_cache_init() query_cache.init() #define query_cache_resize(A) query_cache.resize(A) #define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A) #define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C) #define query_cache_invalidate1(A, B) query_cache.invalidate(A, B) #define query_cache_send_result_to_client(A, B, C) \ query_cache.send_result_to_client(A, B, C) #define query_cache_invalidate_by_MyISAM_filename_ref \ &query_cache_invalidate_by_MyISAM_filename /* note the "maybe": it's a read without mutex */ #define query_cache_maybe_disabled(T) \ (T->variables.query_cache_type == 0 || query_cache.query_cache_size == 0) #define query_cache_is_cacheable_query(L) \ (((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query) #else #define QUERY_CACHE_FLAGS_SIZE 0 #define query_cache_store_query(A, B) do { } while(0) #define query_cache_destroy() do { } while(0) #define query_cache_result_size_limit(A) do { } while(0) #define query_cache_init() do { } while(0) #define query_cache_resize(A) do { } while(0) #define query_cache_set_min_res_unit(A) do { } while(0) #define query_cache_invalidate3(A, B, C) do { } while(0) #define query_cache_invalidate1(A,B) do { } while(0) #define query_cache_send_result_to_client(A, B, C) 0 #define query_cache_invalidate_by_MyISAM_filename_ref NULL #define query_cache_abort(A,B) do { } while(0) #define query_cache_end_of_result(A) do { } while(0) #define query_cache_maybe_disabled(T) 1 #define query_cache_is_cacheable_query(L) 0 #endif /*HAVE_QUERY_CACHE*/ extern MYSQL_PLUGIN_IMPORT Query_cache query_cache; #endif server/private/sql_parse.h000064400000020674151031265040011674 0ustar00/* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_PARSE_INCLUDED #define SQL_PARSE_INCLUDED #include "sql_acl.h" /* GLOBAL_ACLS */ class Comp_creator; class Item; class Object_creation_ctx; class Parser_state; struct TABLE_LIST; class THD; class Table_ident; struct LEX; enum enum_mysql_completiontype { ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7, COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6 }; extern "C" int path_starts_from_data_home_dir(const char *dir); int test_if_data_home_dir(const char *dir); int error_if_data_home_dir(const char *path, const char *what); my_bool net_allocate_new_packet(NET *net, void *thd, uint my_flags); bool multi_update_precheck(THD *thd, TABLE_LIST *tables); bool multi_delete_precheck(THD *thd, TABLE_LIST *tables); int mysql_multi_update_prepare(THD *thd); int mysql_multi_delete_prepare(THD *thd); int mysql_insert_select_prepare(THD *thd,select_result *sel_res); bool update_precheck(THD *thd, TABLE_LIST *tables); bool delete_precheck(THD *thd, TABLE_LIST *tables); bool insert_precheck(THD *thd, TABLE_LIST *tables); bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); bool check_fk_parent_table_access(THD *thd, HA_CREATE_INFO *create_info, Alter_info *alter_info, const char* create_db); bool parse_sql(THD *thd, Parser_state *parser_state, Object_creation_ctx *creation_ctx, bool do_pfs_digest=false); void free_items(Item *item); void cleanup_items(Item *item); Comp_creator *comp_eq_creator(bool invert); Comp_creator *comp_ge_creator(bool invert); Comp_creator *comp_gt_creator(bool invert); Comp_creator *comp_le_creator(bool invert); Comp_creator *comp_lt_creator(bool invert); Comp_creator *comp_ne_creator(bool invert); int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, enum enum_schema_tables schema_table_idx); void get_default_definer(THD *thd, LEX_USER *definer, bool role); LEX_USER *create_default_definer(THD *thd, bool role); LEX_USER *create_definer(THD *thd, LEX_CSTRING *user_name, LEX_CSTRING *host_name); LEX_USER *get_current_user(THD *thd, LEX_USER *user, bool lock=true); bool sp_process_definer(THD *thd); bool check_string_byte_length(const LEX_CSTRING *str, uint err_msg, size_t max_byte_length); bool check_string_char_length(const LEX_CSTRING *str, uint err_msg, size_t max_char_length, CHARSET_INFO *cs, bool no_error); bool check_ident_length(const LEX_CSTRING *ident); CHARSET_INFO* merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl); CHARSET_INFO *find_bin_collation(CHARSET_INFO *cs); bool check_host_name(LEX_CSTRING *str); bool check_identifier_name(LEX_CSTRING *str, uint max_char_length, uint err_code, const char *param_for_err_msg); bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length); bool sqlcom_can_generate_row_events(const THD *thd); bool stmt_causes_implicit_commit(THD *thd, uint mask); bool is_update_query(enum enum_sql_command command); bool is_log_table_write_query(enum enum_sql_command command); bool alloc_query(THD *thd, const char *packet, size_t packet_length); void mysql_init_select(LEX *lex); void mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state); bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel); void create_select_for_variable(THD *thd, LEX_CSTRING *var_name); void create_table_set_open_action_and_adjust_tables(LEX *lex); void mysql_init_multi_delete(LEX *lex); bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void create_table_set_open_action_and_adjust_tables(LEX *lex); int bootstrap(MYSQL_FILE *file); bool run_set_statement_if_requested(THD *thd, LEX *lex); int mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt=false); enum dispatch_command_return { DISPATCH_COMMAND_SUCCESS=0, DISPATCH_COMMAND_CLOSE_CONNECTION= 1, DISPATCH_COMMAND_WOULDBLOCK= 2 }; dispatch_command_return do_command(THD *thd, bool blocking = true); dispatch_command_return dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length, bool blocking = true); void log_slow_statement(THD *thd); bool append_file_to_dir(THD *thd, const char **filename_ptr, const LEX_CSTRING *table_name); void execute_init_command(THD *thd, LEX_STRING *init_command, mysql_rwlock_t *var_lock); bool add_to_list(THD *thd, SQL_I_List &list, Item *group, bool asc); void add_join_on(THD *thd, TABLE_LIST *b, Item *expr); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List *using_fields, SELECT_LEX *lex); bool add_proc_to_list(THD *thd, Item *item); bool push_new_name_resolution_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op); void init_update_queries(void); Item *normalize_cond(THD *thd, Item *cond); Item *negate_expression(THD *thd, Item *expr); bool check_stack_overrun(THD *thd, long margin, uchar *dummy); /* Variables */ extern const LEX_CSTRING any_db; extern uint sql_command_flags[]; extern uint server_command_flags[]; extern const LEX_CSTRING command_name[]; extern uint server_command_flags[]; /* Inline functions */ inline bool check_identifier_name(LEX_CSTRING *str, uint err_code) { return check_identifier_name(str, NAME_CHAR_LEN, err_code, ""); } inline bool check_identifier_name(LEX_CSTRING *str) { return check_identifier_name(str, NAME_CHAR_LEN, 0, ""); } #ifndef NO_EMBEDDED_ACCESS_CHECKS bool check_one_table_access(THD *thd, privilege_t privilege, TABLE_LIST *tables); bool check_single_table_access(THD *thd, privilege_t privilege, TABLE_LIST *tables, bool no_errors); bool check_routine_access(THD *thd, privilege_t want_access, const LEX_CSTRING *db, const LEX_CSTRING *name, const Sp_handler *sph, bool no_errors); bool check_some_access(THD *thd, privilege_t want_access, TABLE_LIST *table); bool check_some_routine_access(THD *thd, const char *db, const char *name, const Sp_handler *sph); bool check_table_access(THD *thd, privilege_t requirements,TABLE_LIST *tables, bool any_combination_of_privileges_will_do, uint number, bool no_errors); #else inline bool check_one_table_access(THD *thd, privilege_t privilege, TABLE_LIST *tables) { return false; } inline bool check_single_table_access(THD *thd, privilege_t privilege, TABLE_LIST *tables, bool no_errors) { return false; } inline bool check_routine_access(THD *thd, privilege_t want_access, const LEX_CSTRING *db, const LEX_CSTRING *name, const Sp_handler *sph, bool no_errors) { return false; } inline bool check_some_access(THD *thd, privilege_t want_access, TABLE_LIST *table) { table->grant.privilege= want_access; return false; } inline bool check_some_routine_access(THD *thd, const char *db, const char *name, const Sp_handler *sph) { return false; } inline bool check_table_access(THD *thd, privilege_t requirements,TABLE_LIST *tables, bool any_combination_of_privileges_will_do, uint number, bool no_errors) { return false; } #endif /*NO_EMBEDDED_ACCESS_CHECKS*/ #endif /* SQL_PARSE_INCLUDED */ server/private/lex_ident.h000064400000004112151031265040011643 0ustar00#ifndef LEX_IDENT_INCLUDED #define LEX_IDENT_INCLUDED /* Copyright (c) 2023, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *table_alias_charset; /* Identifiers for the database objects stored on disk, e.g. databases, tables, triggers. */ class Lex_ident_fs: public LEX_CSTRING { public: static CHARSET_INFO *charset_info() { return table_alias_charset; } public: Lex_ident_fs() :LEX_CSTRING({0,0}) { } Lex_ident_fs(const char *str, size_t length) :LEX_CSTRING({str, length}) { } explicit Lex_ident_fs(const LEX_CSTRING &str) :LEX_CSTRING(str) { } #if MYSQL_VERSION_ID<=110501 private: static bool is_valid_ident(const LEX_CSTRING &str) { // NULL identifier, or 0-terminated identifier return (str.str == NULL && str.length == 0) || str.str[str.length] == 0; } public: bool streq(const LEX_CSTRING &rhs) const { DBUG_ASSERT(is_valid_ident(*this)); DBUG_ASSERT(is_valid_ident(rhs)); return length == rhs.length && my_strcasecmp(charset_info(), str, rhs.str) == 0; } #else /* Starting from 11.5.1 streq() is inherited from the base. The above implementations of streq() and is_valid_ident() should be removed. */ #error Remove streq() above. #endif }; class Lex_ident_db: public Lex_ident_fs { public: using Lex_ident_fs::Lex_ident_fs; }; class Lex_ident_table: public Lex_ident_fs { public: using Lex_ident_fs::Lex_ident_fs; }; #endif // LEX_IDENT_INCLUDED server/private/sql_alter.h000064400000035655151031265040011676 0ustar00/* Copyright (c) 2010, 2014, Oracle and/or its affiliates. Copyright (c) 2013, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_ALTER_TABLE_H #define SQL_ALTER_TABLE_H class Alter_drop; class Alter_column; class Alter_rename_key; class Alter_index_ignorability; class Key; /** Data describing the table being created by CREATE TABLE or altered by ALTER TABLE. */ class Alter_info { public: enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; bool vers_prohibited(THD *thd) const; /** The different values of the ALGORITHM clause. Describes which algorithm to use when altering the table. */ enum enum_alter_table_algorithm { /* Use thd->variables.alter_algorithm for alter method. If this is also default then use the fastest possible ALTER TABLE method (INSTANT, NOCOPY, INPLACE, COPY) */ ALTER_TABLE_ALGORITHM_DEFAULT, // Copy if supported, error otherwise. ALTER_TABLE_ALGORITHM_COPY, // In-place if supported, error otherwise. ALTER_TABLE_ALGORITHM_INPLACE, // No Copy will refuse any operation which does rebuild. ALTER_TABLE_ALGORITHM_NOCOPY, // Instant should allow any operation that changes metadata only. ALTER_TABLE_ALGORITHM_INSTANT, // When there is no specification of algorithm during alter table. ALTER_TABLE_ALGORITHM_NONE }; /** The different values of the LOCK clause. Describes the level of concurrency during ALTER TABLE. */ enum enum_alter_table_lock { // Maximum supported level of concurency for the given operation. ALTER_TABLE_LOCK_DEFAULT, // Allow concurrent reads & writes. If not supported, give error. ALTER_TABLE_LOCK_NONE, // Allow concurrent reads only. If not supported, give error. ALTER_TABLE_LOCK_SHARED, // Block reads and writes. ALTER_TABLE_LOCK_EXCLUSIVE }; Lex_table_name db, table_name; // Columns and keys to be dropped. List drop_list; // Columns for ALTER_CHANGE_COLUMN_DEFAULT. List alter_list; // List of keys, used by both CREATE and ALTER TABLE. List key_list; // List of keys to be renamed. List alter_rename_key_list; // List of columns, used by both CREATE and ALTER TABLE. List create_list; // Indexes whose ignorability needs to be changed. List alter_index_ignorability_list; List check_constraint_list; // Type of ALTER TABLE operation. alter_table_operations flags; ulong partition_flags; // Enable or disable keys. enum_enable_or_disable keys_onoff; // Used only in add_stat_drop_index() TABLE *original_table; // List of partitions. List partition_names; // Number of partitions. uint num_parts; /* List of fields that we should delete statistics from */ List drop_stat_fields; struct DROP_INDEX_STAT_PARAMS { KEY *key; bool ext_prefixes_only; }; struct RENAME_COLUMN_STAT_PARAMS { Field *field; LEX_CSTRING *name; uint duplicate_counter; // For temporary names }; struct RENAME_INDEX_STAT_PARAMS { const KEY *key; const LEX_CSTRING *name; uint duplicate_counter; // For temporary names uint usage_count; // How many rename entries }; /* List of index that we should delete statistics from */ List drop_stat_indexes; List rename_stat_fields; List rename_stat_indexes; bool add_stat_drop_index(KEY *key, bool ext_prefixes_only, MEM_ROOT *mem_root) { DROP_INDEX_STAT_PARAMS *param; if (!(param= (DROP_INDEX_STAT_PARAMS*) alloc_root(mem_root, sizeof(*param)))) return true; param->key= key; param->ext_prefixes_only= ext_prefixes_only; return drop_stat_indexes.push_back(param, mem_root); } bool add_stat_drop_index(THD *thd, const LEX_CSTRING *key_name); bool add_stat_rename_index(const KEY *key, const LEX_CSTRING *name, MEM_ROOT *mem_root) { RENAME_INDEX_STAT_PARAMS *param; if (!(param= (RENAME_INDEX_STAT_PARAMS*) alloc_root(mem_root, sizeof(*param)))) return true; param->key= key; param->name= name; param->usage_count= 0; return rename_stat_indexes.push_back(param, mem_root); } bool add_stat_rename_field(Field *field, LEX_CSTRING *name, MEM_ROOT *mem_root) { RENAME_COLUMN_STAT_PARAMS *param; if (!(param= (RENAME_COLUMN_STAT_PARAMS*) alloc_root(mem_root, sizeof(*param)))) return true; param->field= field; param->name= name; param->duplicate_counter= 0; return rename_stat_fields.push_back(param, mem_root); } bool collect_renamed_fields(THD *thd); /* Delete/update statistics in EITS tables */ void apply_statistics_deletes_renames(THD *thd, TABLE *table); private: // Type of ALTER TABLE algorithm. enum_alter_table_algorithm requested_algorithm; public: // Type of ALTER TABLE lock. enum_alter_table_lock requested_lock; Alter_info() : flags(0), partition_flags(0), keys_onoff(LEAVE_AS_IS), original_table(0), num_parts(0), requested_algorithm(ALTER_TABLE_ALGORITHM_NONE), requested_lock(ALTER_TABLE_LOCK_DEFAULT) {} void reset() { drop_list.empty(); alter_list.empty(); key_list.empty(); alter_rename_key_list.empty(); create_list.empty(); alter_index_ignorability_list.empty(); check_constraint_list.empty(); drop_stat_fields.empty(); drop_stat_indexes.empty(); rename_stat_fields.empty(); rename_stat_indexes.empty(); flags= 0; partition_flags= 0; keys_onoff= LEAVE_AS_IS; num_parts= 0; partition_names.empty(); requested_algorithm= ALTER_TABLE_ALGORITHM_NONE; requested_lock= ALTER_TABLE_LOCK_DEFAULT; } /** Construct a copy of this object to be used for mysql_alter_table and mysql_create_table. Historically, these two functions modify their Alter_info arguments. This behaviour breaks re-execution of prepared statements and stored procedures and is compensated by always supplying a copy of Alter_info to these functions. @param rhs Alter_info to make copy of @param mem_root Mem_root for new Alter_info @note You need to use check the error in THD for out of memory condition after calling this function. */ Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root); /** Parses the given string and sets requested_algorithm if the string value matches a supported value. Supported values: INPLACE, COPY, DEFAULT @param str String containing the supplied value @retval false Supported value found, state updated @retval true Not supported value, no changes made */ bool set_requested_algorithm(const LEX_CSTRING *str); /** Parses the given string and sets requested_lock if the string value matches a supported value. Supported values: NONE, SHARED, EXCLUSIVE, DEFAULT @param str String containing the supplied value @retval false Supported value found, state updated @retval true Not supported value, no changes made */ bool set_requested_lock(const LEX_CSTRING *str); /** Set the requested algorithm to the given algorithm value @param algo_value algorithm to be set */ void set_requested_algorithm(enum_alter_table_algorithm algo_value); /** Returns the algorithm value in the format "algorithm=value" */ const char* algorithm_clause(THD *thd) const; /** Returns the lock value in the format "lock=value" */ const char* lock() const; /** Check whether the given result can be supported with the specified user alter algorithm. @param thd Thread handle @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data during in-place alter @retval false Supported operation @retval true Not supported value */ bool supports_algorithm(THD *thd, const Alter_inplace_info *ha_alter_info); /** Check whether the given result can be supported with the specified user lock type. @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data during in-place alter @retval false Supported lock type @retval true Not supported value */ bool supports_lock(THD *thd, const Alter_inplace_info *ha_alter_info); /** Return user requested algorithm. If user does not specify algorithm then return alter_algorithm variable value. */ enum_alter_table_algorithm algorithm(const THD *thd) const; uint check_vcol_field(Item_field *f) const; private: Alter_info &operator=(const Alter_info &rhs); // not implemented Alter_info(const Alter_info &rhs); // not implemented }; /** Runtime context for ALTER TABLE. */ class Alter_table_ctx { public: Alter_table_ctx(); Alter_table_ctx(THD *thd, TABLE_LIST *table_list, uint tables_opened_arg, const LEX_CSTRING *new_db_arg, const LEX_CSTRING *new_name_arg); /** @return true if the table is moved to another database, false otherwise. */ bool is_database_changed() const { return (new_db.str != db.str); }; /** @return true if the table is renamed, false otherwise. */ bool is_table_renamed() const { return (is_database_changed() || new_name.str != table_name.str); }; /** @return filename (including .frm) for the new table. */ const char *get_new_filename() const { DBUG_ASSERT(!tmp_table); return new_filename; } /** @return path to the original table. */ const char *get_path() const { DBUG_ASSERT(!tmp_table); return path; } /** @return path to the new table. */ const char *get_new_path() const { DBUG_ASSERT(!tmp_table); return new_path; } /** @return path to the temporary table created during ALTER TABLE. */ const char *get_tmp_path() const { return tmp_path; } const LEX_CSTRING get_tmp_cstring_path() const { LEX_CSTRING tmp= { tmp_path, strlen(tmp_path) }; return tmp; }; /** Mark ALTER TABLE as needing to produce foreign key error if it deletes a row from the table being changed. */ void set_fk_error_if_delete_row(FOREIGN_KEY_INFO *fk) { fk_error_if_delete_row= true; fk_error_id= fk->foreign_id->str; fk_error_table= fk->foreign_table->str; } void report_implicit_default_value_error(THD *thd, const TABLE_SHARE *) const; public: Create_field *implicit_default_value_error_field= nullptr; bool error_if_not_empty= false; uint tables_opened= 0; LEX_CSTRING db; LEX_CSTRING table_name; LEX_CSTRING storage_engine_name; LEX_CSTRING alias; LEX_CSTRING new_db; LEX_CSTRING new_name; LEX_CSTRING new_alias; LEX_CSTRING tmp_name; LEX_CSTRING tmp_storage_engine_name; LEX_CUSTRING tmp_id, id; char tmp_buff[80]; uchar id_buff[MY_UUID_SIZE]; char storage_engine_buff[NAME_LEN], tmp_storage_engine_buff[NAME_LEN]; bool storage_engine_partitioned; bool tmp_storage_engine_name_partitioned; /** Indicates that if a row is deleted during copying of data from old version of table to the new version ER_FK_CANNOT_DELETE_PARENT error should be emitted. */ bool fk_error_if_delete_row= false; /** Name of foreign key for the above error. */ const char *fk_error_id= nullptr; /** Name of table for the above error. */ const char *fk_error_table= nullptr; bool modified_primary_key= false; bool fast_alter_partition= false; /** Indicates that we are altering temporary table */ bool tmp_table= false; private: char new_filename[FN_REFLEN + 1]; char new_alias_buff[NAME_LEN + 1]; char tmp_name_buff[NAME_LEN + 1]; char path[FN_REFLEN + 1]; char new_path[FN_REFLEN + 1]; char tmp_path[FN_REFLEN + 1]; Alter_table_ctx &operator=(const Alter_table_ctx &rhs); // not implemented Alter_table_ctx(const Alter_table_ctx &rhs); // not implemented }; /** Sql_cmd_common_alter_table represents the common properties of the ALTER TABLE statements. @todo move Alter_info and other ALTER generic structures from Lex here. */ class Sql_cmd_common_alter_table : public Sql_cmd { protected: /** Constructor. */ Sql_cmd_common_alter_table() = default; virtual ~Sql_cmd_common_alter_table() = default; enum_sql_command sql_command_code() const override { return SQLCOM_ALTER_TABLE; } }; /** Sql_cmd_alter_table represents the generic ALTER TABLE statement. @todo move Alter_info and other ALTER specific structures from Lex here. */ class Sql_cmd_alter_table : public Sql_cmd_common_alter_table, public Storage_engine_name { public: /** Constructor, used to represent a ALTER TABLE statement. */ Sql_cmd_alter_table() = default; ~Sql_cmd_alter_table() = default; Storage_engine_name *option_storage_engine_name() override { return this; } bool execute(THD *thd) override; }; /** Sql_cmd_alter_sequence represents the ALTER SEQUENCE statement. */ class Sql_cmd_alter_sequence : public Sql_cmd, public DDL_options { public: /** Constructor, used to represent a ALTER TABLE statement. */ Sql_cmd_alter_sequence(const DDL_options &options) :DDL_options(options) {} ~Sql_cmd_alter_sequence() = default; enum_sql_command sql_command_code() const override { return SQLCOM_ALTER_SEQUENCE; } bool execute(THD *thd) override; }; /** Sql_cmd_alter_table_tablespace represents ALTER TABLE IMPORT/DISCARD TABLESPACE statements. */ class Sql_cmd_discard_import_tablespace : public Sql_cmd_common_alter_table { public: enum enum_tablespace_op_type { DISCARD_TABLESPACE, IMPORT_TABLESPACE }; Sql_cmd_discard_import_tablespace(enum_tablespace_op_type tablespace_op_arg) : m_tablespace_op(tablespace_op_arg) {} bool execute(THD *thd) override; private: const enum_tablespace_op_type m_tablespace_op; }; #endif server/private/sql_join_cache.h000064400000137035151031265040012644 0ustar00/* Copyright (c) 2011, 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file contains declarations for implementations of block based join algorithms */ #define JOIN_CACHE_INCREMENTAL_BIT 1 #define JOIN_CACHE_HASHED_BIT 2 #define JOIN_CACHE_BKA_BIT 4 /* Categories of data fields of variable length written into join cache buffers. The value of any of these fields is written into cache together with the prepended length of the value. */ #define CACHE_BLOB 1 /* blob field */ #define CACHE_STRIPPED 2 /* field stripped of trailing spaces */ #define CACHE_VARSTR1 3 /* short string value (length takes 1 byte) */ #define CACHE_VARSTR2 4 /* long string value (length takes 2 bytes) */ #define CACHE_ROWID 5 /* ROWID field */ /* The CACHE_FIELD structure used to describe fields of records that are written into a join cache buffer from record buffers and backward. */ typedef struct st_cache_field { uchar *str; /**< buffer from/to where the field is to be copied */ uint length; /**< maximal number of bytes to be copied from/to str */ /* Field object for the moved field (0 - for a flag field, see JOIN_CACHE::create_flag_fields). */ Field *field; uint type; /**< category of the of the copied field (CACHE_BLOB et al.) */ /* The number of the record offset value for the field in the sequence of offsets placed after the last field of the record. These offset values are used to access fields referred to from other caches. If the value is 0 then no offset for the field is saved in the trailing sequence of offsets. */ uint referenced_field_no; /* The remaining structure fields are used as containers for temp values */ uint blob_length; /**< length of the blob to be copied */ uint offset; /**< field offset to be saved in cache buffer */ } CACHE_FIELD; class JOIN_TAB_SCAN; class EXPLAIN_BKA_TYPE; /* JOIN_CACHE is the base class to support the implementations of - Block Nested Loop (BNL) Join Algorithm, - Block Nested Loop Hash (BNLH) Join Algorithm, - Batched Key Access (BKA) Join Algorithm. The first algorithm is supported by the derived class JOIN_CACHE_BNL, the second algorithm is supported by the derived class JOIN_CACHE_BNLH, while the third algorithm is implemented in two variant supported by the classes JOIN_CACHE_BKA and JOIN_CACHE_BKAH. These three algorithms have a lot in common. Each of them first accumulates the records of the left join operand in a join buffer and then searches for matching rows of the second operand for all accumulated records. For the first two algorithms this strategy saves on logical I/O operations: the entire set of records from the join buffer requires only one look-through of the records provided by the second operand. For the third algorithm the accumulation of records allows to optimize fetching rows of the second operand from disk for some engines (MyISAM, InnoDB), or to minimize the number of round-trips between the Server and the engine nodes. */ class JOIN_CACHE :public Sql_alloc { private: /* Size of the offset of a record from the cache */ uint size_of_rec_ofs; /* Size of the length of a record in the cache */ uint size_of_rec_len; /* Size of the offset of a field within a record in the cache */ uint size_of_fld_ofs; /* This structure is used only for explain, not for execution */ bool for_explain_only; protected: /* 3 functions below actually do not use the hidden parameter 'this' */ /* Calculate the number of bytes used to store an offset value */ uint offset_size(size_t len) { return (len < 256 ? 1 : len < 256*256 ? 2 : 4); } /* Get the offset value that takes ofs_sz bytes at the position ptr */ ulong get_offset(uint ofs_sz, uchar *ptr) { switch (ofs_sz) { case 1: return uint(*ptr); case 2: return uint2korr(ptr); case 4: return uint4korr(ptr); } return 0; } /* Set the offset value ofs that takes ofs_sz bytes at the position ptr */ void store_offset(uint ofs_sz, uchar *ptr, ulong ofs) { switch (ofs_sz) { case 1: *ptr= (uchar) ofs; return; case 2: int2store(ptr, (uint16) ofs); return; case 4: int4store(ptr, (uint32) ofs); return; } } size_t calc_avg_record_length(); /* The maximum total length of the fields stored for a record in the cache. For blob fields only the sizes of the blob lengths are taken into account. */ uint length; /* Representation of the executed multi-way join through which all needed context can be accessed. */ JOIN *join; /* JOIN_TAB of the first table that can have it's fields in the join cache. That is, tables in the [start_tab, tab) range can have their fields in the join cache. If a join tab in the range represents an SJM-nest, then all tables from the nest can have their fields in the join cache, too. */ JOIN_TAB *start_tab; /* The total number of flag and data fields that can appear in a record written into the cache. Fields with null values are always skipped to save space. */ uint fields; /* The total number of flag fields in a record put into the cache. They are used for table null bitmaps, table null row flags, and an optional match flag. Flag fields go before other fields in a cache record with the match flag field placed always at the very beginning of the record. */ uint flag_fields; /* The total number of blob fields that are written into the cache */ uint blobs; /* The total number of fields referenced from field descriptors for other join caches. These fields are used to construct key values. When BKA join algorithm is employed the constructed key values serve to access matching rows with index lookups. The key values are put into a hash table when the BNLH join algorithm is employed and when BKAH is used for the join operation. */ uint referenced_fields; /* The current number of already created data field descriptors. This number can be useful for implementations of the init methods. */ uint data_field_count; /* The current number of already created pointers to the data field descriptors. This number can be useful for implementations of the init methods. */ uint data_field_ptr_count; /* Array of the descriptors of fields containing 'fields' elements. These are all fields that are stored for a record in the cache. */ CACHE_FIELD *field_descr; /* Array of pointers to the blob descriptors that contains 'blobs' elements. */ CACHE_FIELD **blob_ptr; /* This flag indicates that records written into the join buffer contain a match flag field. This is set to true for the first inner table of an outer join or a semi-join. The flag must be set by the init method. Currently any implementation of the virtial init method calls the function JOIN_CACHE::calc_record_fields() to set this flag. */ bool with_match_flag; /* This flag indicates that any record is prepended with the length of the record which allows us to skip the record or part of it without reading. */ bool with_length; /* The maximal number of bytes used for a record representation in the cache excluding the space for blob data. For future derived classes this representation may contains some redundant info such as a key value associated with the record. */ uint pack_length; /* The value of pack_length incremented by the total size of all pointers of a record in the cache to the blob data. */ uint pack_length_with_blob_ptrs; /* The total size of the record base prefix. The base prefix of record may include the following components: - the length of the record - the link to a record in a previous buffer. Each record in the buffer are supplied with the same set of the components. */ uint base_prefix_length; /* The expected length of a record in the join buffer together with all prefixes and postfixes */ size_t avg_record_length; /* The expected size of the space per record in the auxiliary buffer */ size_t avg_aux_buffer_incr; /* Pointer to the beginning of the join buffer */ uchar *buff; /* Size of the entire memory allocated for the join buffer. Part of this memory may be reserved for the auxiliary buffer. */ size_t buff_size; /* The minimal join buffer size when join buffer still makes sense to use */ size_t min_buff_size; /* The maximum expected size if the join buffer to be used */ size_t max_buff_size; /* Size of the auxiliary buffer */ size_t aux_buff_size; /* The number of records put into the join buffer */ size_t records; /* The number of records in the fully refilled join buffer of the minimal size equal to min_buff_size */ size_t min_records; /* Pointer to the current position in the join buffer. This member is used both when writing to buffer and when reading from it. */ uchar *pos; /* Pointer to the first free position in the join buffer, right after the last record into it. */ uchar *end_pos; /* Pointer to the beginning of the first field of the current read/write record from the join buffer. The value is adjusted by the get_record/put_record functions. */ uchar *curr_rec_pos; /* Pointer to the beginning of the first field of the last record from the join buffer. */ uchar *last_rec_pos; /* Flag is set if the blob data for the last record in the join buffer is in record buffers rather than in the join cache. */ bool last_rec_blob_data_is_in_rec_buff; /* Pointer to the position to the current record link. Record links are used only with linked caches. Record links allow to set connections between parts of one join record that are stored in different join buffers. In the simplest case a record link is just a pointer to the beginning of the record stored in the buffer. In a more general case a link could be a reference to an array of pointers to records in the buffer. */ uchar *curr_rec_link; /* This flag is set to TRUE if join_tab is the first inner table of an outer join and the latest record written to the join buffer is detected to be null complemented after checking on conditions over the outer tables for this outer join operation */ bool last_written_is_null_compl; /* The number of fields put in the join buffer of the join cache that are used in building keys to access the table join_tab */ uint local_key_arg_fields; /* The total number of the fields in the previous caches that are used in building keys to access the table join_tab */ uint external_key_arg_fields; /* This flag indicates that the key values will be read directly from the join buffer. It will save us building key values in the key buffer. */ bool use_emb_key; /* The length of an embedded key value */ uint emb_key_length; /* This flag is used only when 'not exists' optimization can be applied */ bool not_exists_opt_is_applicable; /* This object provides the methods to iterate over records of the joined table join_tab when looking for join matches between records from join buffer and records from join_tab. BNL and BNLH join algorithms retrieve all records from join_tab, while BKA/BKAH algorithm iterates only over those records from join_tab that can be accessed by look-ups with join keys built from records in join buffer. */ JOIN_TAB_SCAN *join_tab_scan; void calc_record_fields(); void collect_info_on_key_args(); int alloc_fields(); void create_flag_fields(); void create_key_arg_fields(); void create_remaining_fields(); void set_constants(); int alloc_buffer(); /* Shall reallocate the join buffer */ virtual int realloc_buffer(); /* Check the possibility to read the access keys directly from join buffer */ bool check_emb_key_usage(); uint get_size_of_rec_offset() { return size_of_rec_ofs; } uint get_size_of_rec_length() { return size_of_rec_len; } uint get_size_of_fld_offset() { return size_of_fld_ofs; } uchar *get_rec_ref(uchar *ptr) { return buff+get_offset(size_of_rec_ofs, ptr-size_of_rec_ofs); } ulong get_rec_length(uchar *ptr) { return (ulong) get_offset(size_of_rec_len, ptr); } ulong get_fld_offset(uchar *ptr) { return (ulong) get_offset(size_of_fld_ofs, ptr); } void store_rec_ref(uchar *ptr, uchar* ref) { store_offset(size_of_rec_ofs, ptr-size_of_rec_ofs, (ulong) (ref-buff)); } void store_rec_length(uchar *ptr, ulong len) { store_offset(size_of_rec_len, ptr, len); } void store_fld_offset(uchar *ptr, ulong ofs) { store_offset(size_of_fld_ofs, ptr, ofs); } /* Write record fields and their required offsets into the join buffer */ uint write_record_data(uchar *link, bool *is_full); /* Get the total length of all prefixes of a record in the join buffer */ virtual uint get_prefix_length() { return base_prefix_length; } /* Get maximum total length of all affixes of a record in the join buffer */ virtual uint get_record_max_affix_length(); /* Shall get maximum size of the additional space per record used for record keys */ virtual uint get_max_key_addon_space_per_record() { return 0; } /* This method must determine for how much the auxiliary buffer should be incremented when a new record is added to the join buffer. If no auxiliary buffer is needed the function should return 0. */ virtual uint aux_buffer_incr(size_t recno); /* Shall calculate how much space is remaining in the join buffer */ virtual size_t rem_space() { return MY_MAX(buff_size-(end_pos-buff)-aux_buff_size,0); } /* Shall calculate how much space is taken by allocation of the key for a record in the join buffer */ virtual uint extra_key_length() { return 0; } /* Read all flag and data fields of a record from the join buffer */ uint read_all_record_fields(); /* Read all flag fields of a record from the join buffer */ uint read_flag_fields(); /* Read a data record field from the join buffer */ uint read_record_field(CACHE_FIELD *copy, bool last_record); /* Read a referenced field from the join buffer */ bool read_referenced_field(CACHE_FIELD *copy, uchar *rec_ptr, uint *len); /* Shall skip record from the join buffer if its match flag is set to MATCH_FOUND */ virtual bool skip_if_matched(); /* Shall skip record from the join buffer if its match flag commands to do so */ virtual bool skip_if_not_needed_match(); /* True if rec_ptr points to the record whose blob data stay in record buffers */ bool blob_data_is_in_rec_buff(uchar *rec_ptr) { return rec_ptr == last_rec_pos && last_rec_blob_data_is_in_rec_buff; } /* Find matches from the next table for records from the join buffer */ virtual enum_nested_loop_state join_matching_records(bool skip_last); /* Shall set an auxiliary buffer up (currently used only by BKA joins) */ virtual int setup_aux_buffer(HANDLER_BUFFER &aux_buff) { DBUG_ASSERT(0); return 0; } /* Shall get the number of ranges in the cache buffer passed to the MRR interface */ virtual uint get_number_of_ranges_for_mrr() { return 0; }; /* Shall prepare to look for records from the join cache buffer that would match the record of the joined table read into the record buffer */ virtual bool prepare_look_for_matches(bool skip_last)= 0; /* Shall return a pointer to the record from join buffer that is checked as the next candidate for a match with the current record from join_tab. Each implementation of this virtual function should bare in mind that the record position it returns shall be exactly the position passed as the parameter to the implementations of the virtual functions skip_next_candidate_for_match and read_next_candidate_for_match. */ virtual uchar *get_next_candidate_for_match()= 0; /* Shall check whether the given record from the join buffer has its match flag settings commands to skip the record in the buffer. */ virtual bool skip_next_candidate_for_match(uchar *rec_ptr)= 0; /* Shall read the given record from the join buffer into the the corresponding record buffer */ virtual void read_next_candidate_for_match(uchar *rec_ptr)= 0; /* Shall return the location of the association label returned by the multi_read_range_next function for the current record loaded into join_tab's record buffer */ virtual uchar **get_curr_association_ptr() { return 0; }; /* Add null complements for unmatched outer records from the join buffer */ virtual enum_nested_loop_state join_null_complements(bool skip_last); /* Restore the fields of the last record from the join buffer */ virtual void restore_last_record(); /* Set match flag for a record in join buffer if it has not been set yet */ bool set_match_flag_if_none(JOIN_TAB *first_inner, uchar *rec_ptr); enum_nested_loop_state generate_full_extensions(uchar *rec_ptr); /* Check matching to a partial join record from the join buffer */ bool check_match(uchar *rec_ptr); /* This constructor creates an unlinked join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. */ JOIN_CACHE(JOIN *j, JOIN_TAB *tab) { join= j; join_tab= tab; prev_cache= next_cache= 0; buff= 0; min_buff_size= max_buff_size= 0; // Caches not_exists_opt_is_applicable= false; } /* This constructor creates a linked join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. The parameter 'prev' specifies the previous cache object to which this cache is linked. */ JOIN_CACHE(JOIN *j, JOIN_TAB *tab, JOIN_CACHE *prev) { join= j; join_tab= tab; next_cache= 0; prev_cache= prev; buff= 0; min_buff_size= max_buff_size= 0; // Caches if (prev) prev->next_cache= this; } public: /* The enumeration type Join_algorithm includes a mnemonic constant for each join algorithm that employs join buffers */ enum Join_algorithm { BNL_JOIN_ALG, /* Block Nested Loop Join algorithm */ BNLH_JOIN_ALG, /* Block Nested Loop Hash Join algorithm */ BKA_JOIN_ALG, /* Batched Key Access Join algorithm */ BKAH_JOIN_ALG /* Batched Key Access with Hash Table Join Algorithm */ }; /* The enumeration type Match_flag describes possible states of the match flag field stored for the records of the first inner tables of outer joins and semi-joins in the cases when the first match strategy is used for them. When a record with match flag field is written into the join buffer the state of the field usually is MATCH_NOT_FOUND unless this is a record of the first inner table of the outer join for which the on precondition (the condition from on expression over outer tables) has turned out not to be true. In the last case the state of the match flag is MATCH_IMPOSSIBLE. The state of the match flag field is changed to MATCH_FOUND as soon as the first full matching combination of inner tables of the outer join or the semi-join is discovered. */ enum Match_flag { MATCH_NOT_FOUND, MATCH_FOUND, MATCH_IMPOSSIBLE }; /* Table to be joined with the partial join records from the cache */ JOIN_TAB *join_tab; /* Pointer to the previous join cache if there is any */ JOIN_CACHE *prev_cache; /* Pointer to the next join cache if there is any */ JOIN_CACHE *next_cache; /* Shall initialize the join cache structure */ virtual int init(bool for_explain); /* Get the current size of the cache join buffer */ size_t get_join_buffer_size() { return buff_size; } /* Set the size of the cache join buffer to a new value */ void set_join_buffer_size(size_t sz) { buff_size= sz; } /* Get the minimum possible size of the cache join buffer */ size_t get_min_join_buffer_size(); /* Get the maximum possible size of the cache join buffer */ size_t get_max_join_buffer_size(bool optimize_buff_size, size_t min_buffer_size_arg); /* Shrink the size if the cache join buffer in a given ratio */ bool shrink_join_buffer_in_ratio(ulonglong n, ulonglong d); /* Shall return the type of the employed join algorithm */ virtual enum Join_algorithm get_join_alg()= 0; /* The function shall return TRUE only when there is a key access to the join table */ virtual bool is_key_access()= 0; /* Shall reset the join buffer for reading/writing */ virtual void reset(bool for_writing); /* This function shall add a record into the join buffer and return TRUE if it has been decided that it should be the last record in the buffer. */ virtual bool put_record(); /* This function shall read the next record into the join buffer and return TRUE if there is no more next records. */ virtual bool get_record(); /* This function shall read the record at the position rec_ptr in the join buffer */ virtual void get_record_by_pos(uchar *rec_ptr); /* Shall return the value of the match flag for the positioned record */ virtual enum Match_flag get_match_flag_by_pos(uchar *rec_ptr); /* Shall return the value of the match flag for the positioned record from the join buffer attached to the specified table */ virtual enum Match_flag get_match_flag_by_pos_from_join_buffer(uchar *rec_ptr, JOIN_TAB *tab); /* Shall return the position of the current record */ virtual uchar *get_curr_rec() { return curr_rec_pos; } /* Shall set the current record link */ virtual void set_curr_rec_link(uchar *link) { curr_rec_link= link; } /* Shall return the current record link */ virtual uchar *get_curr_rec_link() { return (curr_rec_link ? curr_rec_link : get_curr_rec()); } /* Join records from the join buffer with records from the next join table */ enum_nested_loop_state join_records(bool skip_last); /* Add a comment on the join algorithm employed by the join cache */ virtual bool save_explain_data(EXPLAIN_BKA_TYPE *explain); THD *thd(); virtual ~JOIN_CACHE() = default; void reset_join(JOIN *j) { join= j; } void free() { my_free(buff); buff= 0; } friend class JOIN_CACHE_HASHED; friend class JOIN_CACHE_BNL; friend class JOIN_CACHE_BKA; friend class JOIN_TAB_SCAN; friend class JOIN_TAB_SCAN_MRR; }; /* The class JOIN_CACHE_HASHED is the base class for the classes JOIN_CACHE_HASHED_BNL and JOIN_CACHE_HASHED_BKA. The first of them supports an implementation of Block Nested Loop Hash (BNLH) Join Algorithm, while the second is used for a variant of the BKA Join algorithm that performs only one lookup for any records from join buffer with the same key value. For a join cache of this class the records from the join buffer that have the same access key are linked into a chain attached to a key entry structure that either itself contains the key value, or, in the case when the keys are embedded, refers to its occurrence in one of the records from the chain. To build the chains with the same keys a hash table is employed. It is placed at the very end of the join buffer. The array of hash entries is allocated first at the very bottom of the join buffer, while key entries are placed before this array. A hash entry contains a header of the list of the key entries with the same hash value. Each key entry is a structure of the following type: struct st_join_cache_key_entry { union { uchar[] value; cache_ref *value_ref; // offset from the beginning of the buffer } hash_table_key; key_ref next_key; // offset backward from the beginning of hash table cache_ref *last_rec // offset from the beginning of the buffer } The references linking the records in a chain are always placed at the very beginning of the record info stored in the join buffer. The records are linked in a circular list. A new record is always added to the end of this list. The following picture represents a typical layout for the info stored in the join buffer of a join cache object of the JOIN_CACHE_HASHED class. buff V +----------------------------------------------------------------------------+ | |[*]record_1_1| | | ^ | | | | +--------------------------------------------------+ | | | |[*]record_2_1| | | | | ^ | V | | | | +------------------+ |[*]record_1_2| | | | +--------------------+-+ | | |+--+ +---------------------+ | | +-------------+ | || | | V | | | |||[*]record_3_1| |[*]record_1_3| |[*]record_2_2| | | ||^ ^ ^ | | ||+----------+ | | | | ||^ | |<---------------------------+-------------------+ | |++ | | ... mrr | buffer ... ... | | | | | | | | | +-----+--------+ | +-----|-------+ | | V | | | V | | | ||key_3|[/]|[*]| | | |key_2|[/]|[*]| | | | +-+---|-----------------------+ | | | V | | | | | | |key_1|[*]|[*]| | | ... |[*]| ... |[*]| ... | | +----------------------------------------------------------------------------+ ^ ^ ^ | i-th entry j-th entry hash table i-th hash entry: circular record chain for key_1: record_1_1 record_1_2 record_1_3 (points to record_1_1) circular record chain for key_3: record_3_1 (points to itself) j-th hash entry: circular record chain for key_2: record_2_1 record_2_2 (points to record_2_1) */ class JOIN_CACHE_HASHED: public JOIN_CACHE { typedef uint (JOIN_CACHE_HASHED::*Hash_func) (uchar *key, uint key_len); typedef bool (JOIN_CACHE_HASHED::*Hash_cmp_func) (uchar *key1, uchar *key2, uint key_len); private: /* Size of the offset of a key entry in the hash table */ uint size_of_key_ofs; /* Length of the key entry in the hash table. A key entry either contains the key value, or it contains a reference to the key value if use_emb_key flag is set for the cache. */ uint key_entry_length; /* The beginning of the hash table in the join buffer */ uchar *hash_table; /* Number of hash entries in the hash table */ uint hash_entries; /* The position of the currently retrieved key entry in the hash table */ uchar *curr_key_entry; /* The offset of the data fields from the beginning of the record fields */ uint data_fields_offset; inline uint get_hash_idx_simple(uchar *key, uint key_len); inline uint get_hash_idx_complex(uchar *key, uint key_len); inline bool equal_keys_simple(uchar *key1, uchar *key2, uint key_len); inline bool equal_keys_complex(uchar *key1, uchar *key2, uint key_len); int init_hash_table(); void cleanup_hash_table(); protected: /* Index info on the TABLE_REF object used by the hash join to look for matching records */ KEY *ref_key_info; /* Number of the key parts the TABLE_REF object used by the hash join to look for matching records */ uint ref_used_key_parts; /* The hash function used in the hash table, usually set by the init() method */ Hash_func hash_func; /* The function to check whether two key entries in the hash table are equal or not, usually set by the init() method */ Hash_cmp_func hash_cmp_func; /* Length of a key value. It is assumed that all key values have the same length. */ uint key_length; /* Buffer to store key values for probing */ uchar *key_buff; /* Number of key entries in the hash table (number of distinct keys) */ uint key_entries; /* The position of the last key entry in the hash table */ uchar *last_key_entry; /* The offset of the record fields from the beginning of the record representation. The record representation starts with a reference to the next record in the key record chain followed by the length of the trailing record data followed by a reference to the record segment in the previous cache, if any, followed by the record fields. */ uint rec_fields_offset; uint get_size_of_key_offset() { return size_of_key_ofs; } /* Get the position of the next_key_ptr field pointed to by a linking reference stored at the position key_ref_ptr. This reference is actually the offset backward from the beginning of hash table. */ uchar *get_next_key_ref(uchar *key_ref_ptr) { return hash_table-get_offset(size_of_key_ofs, key_ref_ptr); } /* Store the linking reference to the next_key_ptr field at the position key_ref_ptr. The position of the next_key_ptr field is pointed to by ref. The stored reference is actually the offset backward from the beginning of the hash table. */ void store_next_key_ref(uchar *key_ref_ptr, uchar *ref) { store_offset(size_of_key_ofs, key_ref_ptr, (ulong) (hash_table-ref)); } /* Check whether the reference to the next_key_ptr field at the position key_ref_ptr contains a nil value. */ bool is_null_key_ref(uchar *key_ref_ptr) { ulong nil= 0; return memcmp(key_ref_ptr, &nil, size_of_key_ofs ) == 0; } /* Set the reference to the next_key_ptr field at the position key_ref_ptr equal to nil. */ void store_null_key_ref(uchar *key_ref_ptr) { ulong nil= 0; store_offset(size_of_key_ofs, key_ref_ptr, nil); } uchar *get_next_rec_ref(uchar *ref_ptr) { return buff+get_offset(get_size_of_rec_offset(), ref_ptr); } void store_next_rec_ref(uchar *ref_ptr, uchar *ref) { store_offset(get_size_of_rec_offset(), ref_ptr, (ulong) (ref-buff)); } /* Get the position of the embedded key value for the current record pointed to by get_curr_rec(). */ uchar *get_curr_emb_key() { return get_curr_rec()+data_fields_offset; } /* Get the position of the embedded key value pointed to by a reference stored at ref_ptr. The stored reference is actually the offset from the beginning of the join buffer. */ uchar *get_emb_key(uchar *ref_ptr) { return buff+get_offset(get_size_of_rec_offset(), ref_ptr); } /* Store the reference to an embedded key at the position key_ref_ptr. The position of the embedded key is pointed to by ref. The stored reference is actually the offset from the beginning of the join buffer. */ void store_emb_key_ref(uchar *ref_ptr, uchar *ref) { store_offset(get_size_of_rec_offset(), ref_ptr, (ulong) (ref-buff)); } /* Get the total length of all prefixes of a record in hashed join buffer */ uint get_prefix_length() override { return base_prefix_length + get_size_of_rec_offset(); } /* Get maximum size of the additional space per record used for the hash table with record keys */ uint get_max_key_addon_space_per_record() override; /* Calculate how much space in the buffer would not be occupied by records, key entries and additional memory for the MMR buffer. */ size_t rem_space() override { return MY_MAX(last_key_entry-end_pos-aux_buff_size,0); } /* Calculate how much space is taken by allocation of the key entry for a record in the join buffer */ uint extra_key_length() override { return key_entry_length; } /* Skip record from a hashed join buffer if its match flag is set to MATCH_FOUND */ bool skip_if_matched() override; /* Skip record from a hashed join buffer if its match flag setting commands to do so */ bool skip_if_not_needed_match() override; /* Search for a key in the hash table of the join buffer */ bool key_search(uchar *key, uint key_len, uchar **key_ref_ptr); /* Reallocate the join buffer of a hashed join cache */ int realloc_buffer() override; /* This constructor creates an unlinked hashed join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. */ JOIN_CACHE_HASHED(JOIN *j, JOIN_TAB *tab) :JOIN_CACHE(j, tab) {} /* This constructor creates a linked hashed join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. The parameter 'prev' specifies the previous cache object to which this cache is linked. */ JOIN_CACHE_HASHED(JOIN *j, JOIN_TAB *tab, JOIN_CACHE *prev) :JOIN_CACHE(j, tab, prev) {} public: /* Initialize a hashed join cache */ int init(bool for_explain) override; /* Reset the buffer of a hashed join cache for reading/writing */ void reset(bool for_writing) override; /* Add a record into the buffer of a hashed join cache */ bool put_record() override; /* Read the next record from the buffer of a hashed join cache */ bool get_record() override; /* Shall check whether all records in a key chain have their match flags set on */ virtual bool check_all_match_flags_for_key(uchar *key_chain_ptr); uint get_next_key(uchar **key); /* Get the head of the record chain attached to the current key entry */ uchar *get_curr_key_chain() { return get_next_rec_ref(curr_key_entry+key_entry_length- get_size_of_rec_offset()); } }; /* The class JOIN_TAB_SCAN is a companion class for the classes JOIN_CACHE_BNL and JOIN_CACHE_BNLH. Actually the class implements the iterator over the table joinded by BNL/BNLH join algorithm. The virtual functions open, next and close are called for any iteration over the table. The function open is called to initiate the process of the iteration. The function next shall read the next record from the joined table. The record is read into the record buffer of the joined table. The record is to be matched with records from the join cache buffer. The function close shall perform the finalizing actions for the iteration. */ class JOIN_TAB_SCAN: public Sql_alloc { private: /* TRUE if this is the first record from the joined table to iterate over */ bool is_first_record; protected: /* The joined table to be iterated over */ JOIN_TAB *join_tab; /* The join cache used to join the table join_tab */ JOIN_CACHE *cache; /* Representation of the executed multi-way join through which all needed context can be accessed. */ JOIN *join; public: JOIN_TAB_SCAN(JOIN *j, JOIN_TAB *tab) { join= j; join_tab= tab; cache= join_tab->cache; } virtual ~JOIN_TAB_SCAN() = default; /* Shall calculate the increment of the auxiliary buffer for a record write if such a buffer is used by the table scan object */ virtual uint aux_buffer_incr(size_t recno) { return 0; } /* Initiate the process of iteration over the joined table */ virtual int open(); /* Shall read the next candidate for matches with records from the join buffer. */ virtual int next(); /* Perform the finalizing actions for the process of iteration over the joined_table. */ virtual void close(); }; /* The class JOIN_CACHE_BNL is used when the BNL join algorithm is employed to perform a join operation */ class JOIN_CACHE_BNL :public JOIN_CACHE { private: /* The number of the records in the join buffer that have to be checked yet for a match with the current record of join_tab read into the record buffer. */ uint rem_records; protected: bool prepare_look_for_matches(bool skip_last) override; uchar *get_next_candidate_for_match() override; bool skip_next_candidate_for_match(uchar *rec_ptr) override; void read_next_candidate_for_match(uchar *rec_ptr) override; public: /* This constructor creates an unlinked BNL join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. */ JOIN_CACHE_BNL(JOIN *j, JOIN_TAB *tab) :JOIN_CACHE(j, tab) {} /* This constructor creates a linked BNL join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. The parameter 'prev' specifies the previous cache object to which this cache is linked. */ JOIN_CACHE_BNL(JOIN *j, JOIN_TAB *tab, JOIN_CACHE *prev) :JOIN_CACHE(j, tab, prev) {} /* Initialize the BNL cache */ int init(bool for_explain) override; enum Join_algorithm get_join_alg() override { return BNL_JOIN_ALG; } bool is_key_access() override { return FALSE; } }; /* The class JOIN_CACHE_BNLH is used when the BNLH join algorithm is employed to perform a join operation */ class JOIN_CACHE_BNLH :public JOIN_CACHE_HASHED { protected: /* The pointer to the last record from the circular list of the records that match the join key built out of the record in the join buffer for the join_tab table */ uchar *last_matching_rec_ref_ptr; /* The pointer to the next current record from the circular list of the records that match the join key built out of the record in the join buffer for the join_tab table. This pointer is used by the class method get_next_candidate_for_match to iterate over records from the circular list. */ uchar *next_matching_rec_ref_ptr; /* Get the chain of records from buffer matching the current candidate record for join */ uchar *get_matching_chain_by_join_key(); bool prepare_look_for_matches(bool skip_last) override; uchar *get_next_candidate_for_match() override; bool skip_next_candidate_for_match(uchar *rec_ptr) override; void read_next_candidate_for_match(uchar *rec_ptr) override; public: /* This constructor creates an unlinked BNLH join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. */ JOIN_CACHE_BNLH(JOIN *j, JOIN_TAB *tab) : JOIN_CACHE_HASHED(j, tab) {} /* This constructor creates a linked BNLH join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. The parameter 'prev' specifies the previous cache object to which this cache is linked. */ JOIN_CACHE_BNLH(JOIN *j, JOIN_TAB *tab, JOIN_CACHE *prev) : JOIN_CACHE_HASHED(j, tab, prev) {} /* Initialize the BNLH cache */ int init(bool for_explain) override; enum Join_algorithm get_join_alg() override { return BNLH_JOIN_ALG; } bool is_key_access() override { return TRUE; } }; /* The class JOIN_TAB_SCAN_MRR is a companion class for the classes JOIN_CACHE_BKA and JOIN_CACHE_BKAH. Actually the class implements the iterator over the records from join_tab selected by BKA/BKAH join algorithm as the candidates to be joined. The virtual functions open, next and close are called for any iteration over join_tab record candidates. The function open is called to initiate the process of the iteration. The function next shall read the next record from the set of the record candidates. The record is read into the record buffer of the joined table. The function close shall perform the finalizing actions for the iteration. */ class JOIN_TAB_SCAN_MRR: public JOIN_TAB_SCAN { /* Interface object to generate key ranges for MRR */ RANGE_SEQ_IF range_seq_funcs; /* Number of ranges to be processed by the MRR interface */ uint ranges; /* Flag to to be passed to the MRR interface */ uint mrr_mode; /* MRR buffer assotiated with this join cache */ HANDLER_BUFFER mrr_buff; /* Shall initialize the MRR buffer */ virtual void init_mrr_buff() { cache->setup_aux_buffer(mrr_buff); } public: JOIN_TAB_SCAN_MRR(JOIN *j, JOIN_TAB *tab, uint flags, RANGE_SEQ_IF rs_funcs) :JOIN_TAB_SCAN(j, tab), range_seq_funcs(rs_funcs), mrr_mode(flags) {} uint aux_buffer_incr(size_t recno) override; int open() override; int next() override; friend class JOIN_CACHE_BKA; /* it needs to add an mrr_mode flag after JOIN_CACHE::init() call */ }; /* The class JOIN_CACHE_BKA is used when the BKA join algorithm is employed to perform a join operation */ class JOIN_CACHE_BKA :public JOIN_CACHE { private: /* Flag to to be passed to the companion JOIN_TAB_SCAN_MRR object */ uint mrr_mode; /* This value is set to 1 by the class prepare_look_for_matches method and back to 0 by the class get_next_candidate_for_match method */ uint rem_records; /* This field contains the current association label set by a call of the multi_range_read_next handler function. See the function JOIN_CACHE_BKA::get_curr_key_association() */ uchar *curr_association; protected: /* Get the number of ranges in the cache buffer passed to the MRR interface. For each record its own range is passed. */ uint get_number_of_ranges_for_mrr() override { return (uint)records; } /* Setup the MRR buffer as the space between the last record put into the join buffer and the very end of the join buffer */ int setup_aux_buffer(HANDLER_BUFFER &aux_buff) override { aux_buff.buffer= end_pos; aux_buff.buffer_end= buff+buff_size; return 0; } bool prepare_look_for_matches(bool skip_last) override; uchar *get_next_candidate_for_match() override; bool skip_next_candidate_for_match(uchar *rec_ptr) override; void read_next_candidate_for_match(uchar *rec_ptr) override; public: /* This constructor creates an unlinked BKA join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. The MRR mode initially is set to 'flags'. */ JOIN_CACHE_BKA(JOIN *j, JOIN_TAB *tab, uint flags) :JOIN_CACHE(j, tab), mrr_mode(flags) {} /* This constructor creates a linked BKA join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. The parameter 'prev' specifies the previous cache object to which this cache is linked. The MRR mode initially is set to 'flags'. */ JOIN_CACHE_BKA(JOIN *j, JOIN_TAB *tab, uint flags, JOIN_CACHE *prev) :JOIN_CACHE(j, tab, prev), mrr_mode(flags) {} JOIN_CACHE_BKA(JOIN_CACHE_BKA *bka) :JOIN_CACHE(bka->join, bka->join_tab, bka->prev_cache), mrr_mode(bka->mrr_mode) {} uchar **get_curr_association_ptr() override { return &curr_association; } /* Initialize the BKA cache */ int init(bool for_explain) override; enum Join_algorithm get_join_alg() override { return BKA_JOIN_ALG; } bool is_key_access() override { return TRUE; } /* Get the key built over the next record from the join buffer */ uint get_next_key(uchar **key); /* Check index condition of the joined table for a record from BKA cache */ bool skip_index_tuple(range_id_t range_info); bool save_explain_data(EXPLAIN_BKA_TYPE *explain) override; }; /* The class JOIN_CACHE_BKAH is used when the BKAH join algorithm is employed to perform a join operation */ class JOIN_CACHE_BKAH :public JOIN_CACHE_BNLH { private: /* Flag to to be passed to the companion JOIN_TAB_SCAN_MRR object */ uint mrr_mode; /* This flag is set to TRUE if the implementation of the MRR interface cannot handle range association labels and does not return them to the caller of the multi_range_read_next handler function. E.g. the implementation of the MRR inteface for the Falcon engine could not return association labels to the caller of multi_range_read_next. The flag is set by JOIN_CACHE_BKA::init() and is not ever changed. */ bool no_association; /* This field contains the association label returned by the multi_range_read_next function. See the function JOIN_CACHE_BKAH::get_curr_key_association() */ uchar *curr_matching_chain; protected: uint get_number_of_ranges_for_mrr() override { return key_entries; } /* Initialize the MRR buffer allocating some space within the join buffer. The entire space between the last record put into the join buffer and the last key entry added to the hash table is used for the MRR buffer. */ int setup_aux_buffer(HANDLER_BUFFER &aux_buff) override { aux_buff.buffer= end_pos; aux_buff.buffer_end= last_key_entry; return 0; } bool prepare_look_for_matches(bool skip_last) override; /* The implementations of the methods - get_next_candidate_for_match - skip_recurrent_candidate_for_match - read_next_candidate_for_match are inherited from the JOIN_CACHE_BNLH class */ public: /* This constructor creates an unlinked BKAH join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. The MRR mode initially is set to 'flags'. */ JOIN_CACHE_BKAH(JOIN *j, JOIN_TAB *tab, uint flags) :JOIN_CACHE_BNLH(j, tab), mrr_mode(flags) {} /* This constructor creates a linked BKAH join cache. The cache is to be used to join table 'tab' to the result of joining the previous tables specified by the 'j' parameter. The parameter 'prev' specifies the previous cache object to which this cache is linked. The MRR mode initially is set to 'flags'. */ JOIN_CACHE_BKAH(JOIN *j, JOIN_TAB *tab, uint flags, JOIN_CACHE *prev) :JOIN_CACHE_BNLH(j, tab, prev), mrr_mode(flags) {} JOIN_CACHE_BKAH(JOIN_CACHE_BKAH *bkah) :JOIN_CACHE_BNLH(bkah->join, bkah->join_tab, bkah->prev_cache), mrr_mode(bkah->mrr_mode) {} uchar **get_curr_association_ptr() override { return &curr_matching_chain; } /* Initialize the BKAH cache */ int init(bool for_explain) override; enum Join_algorithm get_join_alg() override { return BKAH_JOIN_ALG; } /* Check index condition of the joined table for a record from BKAH cache */ bool skip_index_tuple(range_id_t range_info); bool save_explain_data(EXPLAIN_BKA_TYPE *explain) override; }; server/private/sql_load.h000064400000002374151031265040011476 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_LOAD_INCLUDED #define SQL_LOAD_INCLUDED #include "sql_list.h" /* List */ class Item; #include "sql_class.h" /* enum_duplicates */ class sql_exchange; int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, List &fields_vars, List &set_fields, List &set_values_list, enum enum_duplicates handle_duplicates, bool ignore, bool local_file); #endif /* SQL_LOAD_INCLUDED */ server/private/sql_profile.h000064400000017210151031265040012212 0ustar00/* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _SQL_PROFILE_H #define _SQL_PROFILE_H class Item; struct TABLE_LIST; class THD; class ST_FIELD_INFO; typedef struct st_schema_table ST_SCHEMA_TABLE; namespace Show { extern ST_FIELD_INFO query_profile_statistics_info[]; } // namespace Show int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond); int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table); #define PROFILE_NONE (uint)0 #define PROFILE_CPU (uint)(1<<0) #define PROFILE_MEMORY (uint)(1<<1) #define PROFILE_BLOCK_IO (uint)(1<<2) #define PROFILE_CONTEXT (uint)(1<<3) #define PROFILE_PAGE_FAULTS (uint)(1<<4) #define PROFILE_IPC (uint)(1<<5) #define PROFILE_SWAPS (uint)(1<<6) #define PROFILE_SOURCE (uint)(1<<16) #define PROFILE_ALL (uint)(~0) #if defined(ENABLED_PROFILING) #include "sql_priv.h" #include "unireg.h" #ifdef _WIN32 #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif extern PSI_memory_key key_memory_queue_item; class PROF_MEASUREMENT; class QUERY_PROFILE; class PROFILING; /** Implements a persistent FIFO using server List method names. Not thread-safe. Intended to be used on thread-local data only. */ template class Queue { private: struct queue_item { T *payload; struct queue_item *next, *previous; }; struct queue_item *first, *last; public: Queue() { elements= 0; first= last= NULL; } void empty() { struct queue_item *i, *after_i; for (i= first; i != NULL; i= after_i) { after_i= i->next; my_free(i); } elements= 0; } ulong elements; /* The count of items in the Queue */ void push_back(T *payload) { struct queue_item *new_item; new_item= (struct queue_item *) my_malloc(key_memory_queue_item, sizeof(struct queue_item), MYF(0)); if (!new_item) return; new_item->payload= payload; if (first == NULL) first= new_item; if (last != NULL) { DBUG_ASSERT(last->next == NULL); last->next= new_item; } new_item->previous= last; new_item->next= NULL; last= new_item; elements++; } T *pop() { struct queue_item *old_item= first; T *ret= NULL; if (first == NULL) { DBUG_PRINT("warning", ("tried to pop nonexistent item from Queue")); return NULL; } ret= old_item->payload; if (first->next != NULL) first->next->previous= NULL; else last= NULL; first= first->next; my_free(old_item); elements--; return ret; } bool is_empty() { DBUG_ASSERT(((elements > 0) && (first != NULL)) || ((elements == 0) || (first == NULL))); return (elements == 0); } void *new_iterator() { return first; } void *iterator_next(void *current) { return ((struct queue_item *) current)->next; } T *iterator_value(void *current) { return ((struct queue_item *) current)->payload; } }; /** A single entry in a single profile. */ class PROF_MEASUREMENT { private: friend class QUERY_PROFILE; friend class PROFILING; QUERY_PROFILE *profile; char *status; #ifdef HAVE_GETRUSAGE struct rusage rusage; #elif defined(_WIN32) FILETIME ftKernel, ftUser; IO_COUNTERS io_count; PROCESS_MEMORY_COUNTERS mem_count; #endif char *function; char *file; unsigned int line; ulong m_seq; double time_usecs; char *allocated_status_memory; void set_label(const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg); void clean_up(); PROF_MEASUREMENT(); PROF_MEASUREMENT(QUERY_PROFILE *profile_arg, const char *status_arg); PROF_MEASUREMENT(QUERY_PROFILE *profile_arg, const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg); ~PROF_MEASUREMENT(); void collect(); }; /** The full profile for a single query, and includes multiple PROF_MEASUREMENT objects. */ class QUERY_PROFILE { private: friend class PROFILING; PROFILING *profiling; query_id_t profiling_query_id; /* Session-specific id. */ char *query_source; double m_start_time_usecs; double m_end_time_usecs; ulong m_seq_counter; Queue entries; QUERY_PROFILE(PROFILING *profiling_arg, const char *status_arg); ~QUERY_PROFILE(); void set_query_source(char *query_source_arg, size_t query_length_arg); /* Add a profile status change to the current profile. */ void new_status(const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg); /* Reset the contents of this profile entry. */ void reset(); /* Show this profile. This is called by PROFILING. */ bool show(uint options); }; /** Profiling state for a single THD; contains multiple QUERY_PROFILE objects. */ class PROFILING { private: friend class PROF_MEASUREMENT; friend class QUERY_PROFILE; /* Not the system query_id, but a counter unique to profiling. */ query_id_t profile_id_counter; THD *thd; bool keeping; bool enabled; QUERY_PROFILE *current; QUERY_PROFILE *last; Queue history; query_id_t next_profile_id() { return(profile_id_counter++); } public: PROFILING(); ~PROFILING(); /** At a point in execution where we know the query source, save the text of it in the query profile. This must be called exactly once per descrete statement. */ void set_query_source(char *query_source_arg, size_t query_length_arg) { if (unlikely(current)) current->set_query_source(query_source_arg, query_length_arg); } /** Prepare to start processing a new query. It is an error to do this if there's a query already in process; nesting is not supported. @param initial_state (optional) name of period before first state change */ void start_new_query(const char *initial_state= "Starting") { DBUG_ASSERT(!current); if (unlikely(enabled)) { QUERY_PROFILE *new_profile= new QUERY_PROFILE(this, initial_state); if (new_profile) current= new_profile; } } void discard_current_query(); void finish_current_query() { if (unlikely(current)) finish_current_query_impl(); } void finish_current_query_impl(); void status_change(const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg) { if (unlikely(current)) current->new_status(status_arg, function_arg, file_arg, line_arg); } inline void set_thd(THD *thd_arg) { thd= thd_arg; reset(); } /* SHOW PROFILES */ bool show_profiles(); /* ... from INFORMATION_SCHEMA.PROFILING ... */ int fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond); void reset(); void restart(); }; # endif /* ENABLED_PROFILING */ #endif /* _SQL_PROFILE_H */ server/private/innodb_priv.h000064400000002447151031265040012212 0ustar00/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef INNODB_PRIV_INCLUDED #define INNODB_PRIV_INCLUDED /** @file Declaring server-internal functions that are used by InnoDB. */ #include #include /* strconvert */ class THD; int get_quote_char_for_identifier(THD *thd, const char *name, size_t length); bool schema_table_store_record(THD *thd, TABLE *table); void localtime_to_TIME(MYSQL_TIME *to, struct tm *from); void sql_print_error(const char *format, ...); #define thd_binlog_pos(X, Y, Z) mysql_bin_log_commit_pos(X, Z, Y) #endif /* INNODB_PRIV_INCLUDED */ server/private/sql_type_int.h000064400000023421151031265040012406 0ustar00/* Copyright (c) 2018, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_TYPE_INT_INCLUDED #define SQL_TYPE_INT_INCLUDED #include "my_bit.h" // my_count_bits() class Null_flag { protected: bool m_is_null; public: bool is_null() const { return m_is_null; } Null_flag(bool is_null) :m_is_null(is_null) { } }; class Longlong { protected: longlong m_value; public: longlong value() const { return m_value; } Longlong(longlong nr) :m_value(nr) { } ulonglong abs() { if (m_value == LONGLONG_MIN) // avoid undefined behavior return ((ulonglong) LONGLONG_MAX) + 1; return m_value < 0 ? -m_value : m_value; } }; class Longlong_null: public Longlong, public Null_flag { public: Longlong_null(longlong nr, bool is_null) :Longlong(nr), Null_flag(is_null) { } explicit Longlong_null() :Longlong(0), Null_flag(true) { } explicit Longlong_null(longlong nr) :Longlong(nr), Null_flag(false) { } Longlong_null operator|(const Longlong_null &other) const { if (is_null() || other.is_null()) return Longlong_null(); return Longlong_null(value() | other.value()); } Longlong_null operator&(const Longlong_null &other) const { if (is_null() || other.is_null()) return Longlong_null(); return Longlong_null(value() & other.value()); } Longlong_null operator^(const Longlong_null &other) const { if (is_null() || other.is_null()) return Longlong_null(); return Longlong_null((longlong) (value() ^ other.value())); } Longlong_null operator~() const { if (is_null()) return *this; return Longlong_null((longlong) ~ (ulonglong) value()); } Longlong_null operator<<(const Longlong_null &llshift) const { ulonglong res; uint shift; if (is_null() || llshift.is_null()) return Longlong_null(); shift= (uint) llshift.value(); res= 0; if (shift < sizeof(longlong) * 8) res= ((ulonglong) value()) << shift; return Longlong_null((longlong) res); } Longlong_null operator>>(const Longlong_null &llshift) const { ulonglong res; uint shift; if (is_null() || llshift.is_null()) return Longlong_null(); shift= (uint) llshift.value(); res= 0; if (shift < sizeof(longlong) * 8) res= ((ulonglong) value()) >> shift; return Longlong_null(res); } Longlong_null bit_count() const { if (is_null()) return *this; return Longlong_null((longlong) my_count_bits((ulonglong) value())); } }; class ULonglong { protected: ulonglong m_value; public: ulonglong value() const { return m_value; } explicit ULonglong(ulonglong nr) :m_value(nr) { } static bool test_if_sum_overflows_ull(ulonglong arg1, ulonglong arg2) { return ULONGLONG_MAX - arg1 < arg2; } Longlong_null operator-() const { if (m_value > (ulonglong) LONGLONG_MAX) // Avoid undefined behaviour { return m_value == (ulonglong) LONGLONG_MAX + 1 ? Longlong_null(LONGLONG_MIN, false) : Longlong_null(0, true); } return Longlong_null(-(longlong) m_value, false); } // Convert to Longlong_null with the range check Longlong_null to_longlong_null() const { if (m_value > (ulonglong) LONGLONG_MAX) return Longlong_null(0, true); return Longlong_null((longlong) m_value, false); } }; class ULonglong_null: public ULonglong, public Null_flag { public: ULonglong_null(ulonglong nr, bool is_null) :ULonglong(nr), Null_flag(is_null) { } /* Multiply two ulonglong values. Let a = a1 * 2^32 + a0 and b = b1 * 2^32 + b0. Then a * b = (a1 * 2^32 + a0) * (b1 * 2^32 + b0) = a1 * b1 * 2^64 + + (a1 * b0 + a0 * b1) * 2^32 + a0 * b0; We can determine if the above sum overflows the ulonglong range by sequentially checking the following conditions: 1. If both a1 and b1 are non-zero. 2. Otherwise, if (a1 * b0 + a0 * b1) is greater than ULONG_MAX. 3. Otherwise, if (a1 * b0 + a0 * b1) * 2^32 + a0 * b0 is greater than ULONGLONG_MAX. */ static ULonglong_null ullmul(ulonglong a, ulonglong b) { ulong a1= (ulong)(a >> 32); ulong b1= (ulong)(b >> 32); if (a1 && b1) return ULonglong_null(0, true); ulong a0= (ulong)(0xFFFFFFFFUL & a); ulong b0= (ulong)(0xFFFFFFFFUL & b); ulonglong res1= (ulonglong) a1 * b0 + (ulonglong) a0 * b1; if (res1 > 0xFFFFFFFFUL) return ULonglong_null(0, true); res1= res1 << 32; ulonglong res0= (ulonglong) a0 * b0; if (test_if_sum_overflows_ull(res1, res0)) return ULonglong_null(0, true); return ULonglong_null(res1 + res0, false); } }; // A longlong/ulonglong hybrid. Good to store results of val_int(). class Longlong_hybrid: public Longlong { protected: bool m_unsigned; int cmp_signed(const Longlong_hybrid& other) const { return m_value < other.m_value ? -1 : m_value == other.m_value ? 0 : 1; } int cmp_unsigned(const Longlong_hybrid& other) const { return (ulonglong) m_value < (ulonglong) other.m_value ? -1 : m_value == other.m_value ? 0 : 1; } public: Longlong_hybrid(longlong nr, bool unsigned_flag) :Longlong(nr), m_unsigned(unsigned_flag) { } bool is_unsigned() const { return m_unsigned; } bool is_unsigned_outside_of_signed_range() const { return m_unsigned && ((ulonglong) m_value) > (ulonglong) LONGLONG_MAX; } bool neg() const { return m_value < 0 && !m_unsigned; } ulonglong abs() const { if (m_unsigned) return (ulonglong) m_value; return Longlong(m_value).abs(); } /* Convert to an unsigned number: - Negative numbers are converted to 0. - Positive numbers bigger than upper_bound are converted to upper_bound. - Other numbers are returned as is. */ ulonglong to_ulonglong(ulonglong upper_bound) const { return neg() ? 0 : (ulonglong) m_value > upper_bound ? upper_bound : (ulonglong) m_value; } uint to_uint(uint upper_bound) const { return (uint) to_ulonglong(upper_bound); } Longlong_null val_int_signed() const { if (m_unsigned) return ULonglong((ulonglong) m_value).to_longlong_null(); return Longlong_null(m_value, false); } Longlong_null val_int_unsigned() const { if (!m_unsigned && m_value < 0) return Longlong_null(0, true); return Longlong_null(m_value, false); } /* Return in Item compatible val_int() format: - signed numbers as a straight longlong value - unsigned numbers as a ulonglong value reinterpreted to longlong */ Longlong_null val_int(bool want_unsigned_value) const { return want_unsigned_value ? val_int_unsigned() : val_int_signed(); } int cmp(const Longlong_hybrid& other) const { if (m_unsigned == other.m_unsigned) return m_unsigned ? cmp_unsigned(other) : cmp_signed(other); if (is_unsigned_outside_of_signed_range()) return 1; if (other.is_unsigned_outside_of_signed_range()) return -1; /* The unsigned argument is in the range 0..LONGLONG_MAX. The signed argument is in the range LONGLONG_MIN..LONGLONG_MAX. Safe to compare as signed. */ return cmp_signed(other); } bool operator==(const Longlong_hybrid &nr) const { return cmp(nr) == 0; } bool operator==(ulonglong nr) const { return cmp(Longlong_hybrid((longlong) nr, true)) == 0; } bool operator==(uint nr) const { return cmp(Longlong_hybrid((longlong) nr, true)) == 0; } bool operator==(longlong nr) const { return cmp(Longlong_hybrid(nr, false)) == 0; } bool operator==(int nr) const { return cmp(Longlong_hybrid(nr, false)) == 0; } }; class Longlong_hybrid_null: public Longlong_hybrid, public Null_flag { public: Longlong_hybrid_null(const Longlong_null &nr, bool unsigned_flag) :Longlong_hybrid(nr.value(), unsigned_flag), Null_flag(nr.is_null()) { } }; /* Stores the absolute value of a number, and the sign. Value range: -ULONGLONG_MAX .. +ULONGLONG_MAX. Provides a wider range for negative numbers than Longlong_hybrid does. Usefull to store intermediate results of an expression whose value is further needed to be negated. For example, these methods: - Item_func_mul::int_op() - Item_func_int_div::val_int() - Item_func_mod::int_op() calculate the result of absolute values of the arguments, then optionally negate the result. */ class ULonglong_hybrid: public ULonglong { bool m_neg; public: ULonglong_hybrid(ulonglong value, bool neg) :ULonglong(value), m_neg(neg) { if (m_neg && !m_value) m_neg= false; // convert -0 to +0 } Longlong_null val_int_unsigned() const { return m_neg ? Longlong_null(0, true) : Longlong_null((longlong) m_value, false); } Longlong_null val_int_signed() const { return m_neg ? -ULonglong(m_value) : ULonglong::to_longlong_null(); } /* Return in Item compatible val_int() format: - signed numbers as a straight longlong value - unsigned numbers as a ulonglong value reinterpreted to longlong */ Longlong_null val_int(bool want_unsigned_value) const { return want_unsigned_value ? val_int_unsigned() : val_int_signed(); } }; #endif // SQL_TYPE_INT_INCLUDED server/private/sql_sort.h000064400000052717151031265040011554 0ustar00#ifndef SQL_SORT_INCLUDED #define SQL_SORT_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_base.h" /* ha_rows */ #include #include "queues.h" #include "sql_string.h" #include "sql_class.h" class Field; struct TABLE; /* Defines used by filesort and uniques */ #define MERGEBUFF 7 #define MERGEBUFF2 15 /* The structure SORT_ADDON_FIELD describes a fixed layout for field values appended to sorted values in records to be sorted in the sort buffer. Only fixed layout is supported now. Null bit maps for the appended values is placed before the values themselves. Offsets are from the last sorted field, that is from the record referefence, which is still last component of sorted records. It is preserved for backward compatiblility. The structure is used tp store values of the additional fields in the sort buffer. It is used also when these values are read from a temporary file/buffer. As the reading procedures are beyond the scope of the 'filesort' code the values have to be retrieved via the callback function 'unpack_addon_fields'. */ typedef struct st_sort_addon_field { /* Sort addon packed field */ Field *field; /* Original field */ uint offset; /* Offset from the last sorted field */ uint null_offset; /* Offset to to null bit from the last sorted field */ uint length; /* Length in the sort buffer */ uint8 null_bit; /* Null bit mask for the field */ } SORT_ADDON_FIELD; struct BUFFPEK_COMPARE_CONTEXT { qsort_cmp2 key_compare; void *key_compare_arg; }; /** Descriptor for a merge chunk to be sort-merged. A merge chunk is a sequence of pre-sorted records, written to a temporary file. A Merge_chunk instance describes where this chunk is stored in the file, and where it is located when it is in memory. It is a POD because - we read/write them from/to files. We have accessors (getters/setters) for all struct members. */ struct Merge_chunk { public: my_off_t file_position() const { return m_file_position; } void set_file_position(my_off_t val) { m_file_position= val; } void advance_file_position(my_off_t val) { m_file_position+= val; } uchar *buffer_start() { return m_buffer_start; } const uchar *buffer_end() const { return m_buffer_end; } void set_buffer(uchar *start, uchar *end) { m_buffer_start= start; m_buffer_end= end; } void set_buffer_start(uchar *start) { m_buffer_start= start; } void set_buffer_end(uchar *end) { DBUG_ASSERT(m_buffer_end == NULL || end <= m_buffer_end); m_buffer_end= end; } void init_current_key() { m_current_key= m_buffer_start; } uchar *current_key() { return m_current_key; } void advance_current_key(uint val) { m_current_key+= val; } void decrement_rowcount(ha_rows val) { m_rowcount-= val; } void set_rowcount(ha_rows val) { m_rowcount= val; } ha_rows rowcount() const { return m_rowcount; } ha_rows mem_count() const { return m_mem_count; } void set_mem_count(ha_rows val) { m_mem_count= val; } ha_rows decrement_mem_count() { return --m_mem_count; } ha_rows max_keys() const { return m_max_keys; } void set_max_keys(ha_rows val) { m_max_keys= val; } size_t buffer_size() const { return m_buffer_end - m_buffer_start; } /** Tries to merge *this with *mc, returns true if successful. The assumption is that *this is no longer in use, and the space it has been allocated can be handed over to a buffer which is adjacent to it. */ bool merge_freed_buff(Merge_chunk *mc) const { if (mc->m_buffer_end == m_buffer_start) { mc->m_buffer_end= m_buffer_end; mc->m_max_keys+= m_max_keys; return true; } else if (mc->m_buffer_start == m_buffer_end) { mc->m_buffer_start= m_buffer_start; mc->m_max_keys+= m_max_keys; return true; } return false; } /// The current key for this chunk uchar *m_current_key= nullptr; /// Current position in the file to be sorted. my_off_t m_file_position= 0; /// Start of main-memory buffer for this chunk. uchar *m_buffer_start= nullptr; /// End of main-memory buffer for this chunk. uchar *m_buffer_end= nullptr; /// Number of unread rows in this chunk. ha_rows m_rowcount= 0; /// Number of rows in the main-memory buffer. ha_rows m_mem_count= 0; /// If we have fixed-size rows: max number of rows in buffer. ha_rows m_max_keys= 0; }; typedef Bounds_checked_array Addon_fields_array; typedef Bounds_checked_array Sort_keys_array; /** This class wraps information about usage of addon fields. An Addon_fields object is used both during packing of data in the filesort buffer, and later during unpacking in 'Filesort_info::unpack_addon_fields'. @see documentation for the Sort_addon_field struct. @see documentation for get_addon_fields() */ class Addon_fields { public: Addon_fields(Addon_fields_array arr) : m_field_descriptors(arr), m_addon_buf(), m_addon_buf_length(), m_using_packed_addons(false) { DBUG_ASSERT(!arr.is_null()); } SORT_ADDON_FIELD *begin() { return m_field_descriptors.begin(); } SORT_ADDON_FIELD *end() { return m_field_descriptors.end(); } /// rr_unpack_from_tempfile needs an extra buffer when unpacking. uchar *allocate_addon_buf(uint sz) { m_addon_buf= (uchar *)my_malloc(PSI_INSTRUMENT_ME, sz, MYF(MY_WME | MY_THREAD_SPECIFIC)); if (m_addon_buf) m_addon_buf_length= sz; return m_addon_buf; } void free_addon_buff() { my_free(m_addon_buf); m_addon_buf= NULL; m_addon_buf_length= 0; } uchar *get_addon_buf() { return m_addon_buf; } uint get_addon_buf_length() const { return m_addon_buf_length; } void set_using_packed_addons(bool val) { m_using_packed_addons= val; } bool using_packed_addons() const { return m_using_packed_addons; } static bool can_pack_addon_fields(uint record_length) { return (record_length <= (0xFFFF)); } /** @returns Total number of bytes used for packed addon fields. the size of the length field + size of null bits + sum of field sizes. */ static uint read_addon_length(uchar *p) { return size_of_length_field + uint2korr(p); } /** Stores the number of bytes used for packed addon fields. */ static void store_addon_length(uchar *p, uint sz) { // We actually store the length of everything *after* the length field. int2store(p, sz - size_of_length_field); } static const uint size_of_length_field= 2; private: Addon_fields_array m_field_descriptors; uchar *m_addon_buf; ///< Buffer for unpacking addon fields. uint m_addon_buf_length; ///< Length of the buffer. bool m_using_packed_addons; ///< Are we packing the addon fields? }; /** This class wraps information about usage of sort keys. A Sort_keys object is used both during packing of data in the filesort buffer, and later during unpacking in 'Filesort_info::unpack_addon_fields'. @see SORT_FIELD struct. */ class Sort_keys :public Sql_alloc, public Sort_keys_array { public: Sort_keys(SORT_FIELD* arr, size_t count): Sort_keys_array(arr, count), m_using_packed_sortkeys(false), size_of_packable_fields(0), sort_length_with_original_values(0), sort_length_with_memcmp_values(0), parameters_computed(false) { DBUG_ASSERT(!is_null()); } bool using_packed_sortkeys() const { return m_using_packed_sortkeys; } void set_using_packed_sortkeys(bool val) { m_using_packed_sortkeys= val; } void set_size_of_packable_fields(uint len) { size_of_packable_fields= len; } uint get_size_of_packable_fields() { return size_of_packable_fields; } void set_sort_length_with_original_values(uint len) { sort_length_with_original_values= len; } uint get_sort_length_with_original_values() { return sort_length_with_original_values; } void set_sort_length_with_memcmp_values(uint len) { sort_length_with_memcmp_values= len; } uint get_sort_length_with_memcmp_values() { return sort_length_with_memcmp_values; } static void store_sortkey_length(uchar *p, uint sz) { int4store(p, sz - size_of_length_field); } static uint read_sortkey_length(uchar *p) { return size_of_length_field + uint4korr(p); } void increment_size_of_packable_fields(uint len) { size_of_packable_fields+= len; } void increment_original_sort_length(uint len) { sort_length_with_original_values+= len; } bool is_parameters_computed() { return parameters_computed; } void set_parameters_computed(bool val) { parameters_computed= val; } static const uint size_of_length_field= 4; private: bool m_using_packed_sortkeys; // Are we packing sort keys uint size_of_packable_fields; // Total length bytes for packable columns /* The sort length for all the keyparts storing the original values */ uint sort_length_with_original_values; /* The sort length for all the keyparts storing the mem-comparable images */ uint sort_length_with_memcmp_values; /* TRUE parameters(like sort_length_* , size_of_packable_field) are computed FALSE otherwise. */ bool parameters_computed; }; /** PACKED SORT KEYS Description In this optimization where we would like the pack the values of the sort key inside the sort buffer for each record. Contents: 1. Background 1.1 Implementation details 2. Solution : Packed Sort Keys 2.1 Packed key format 2.2 Which format to use 3. Special cases 3.1 Handling very long strings 3.2 Handling for long binary strings 3.3 Handling very long strings with Packed sort keys 4. Sort key columns in addon_fields 1. Background Before this optimization of using packed sort keys, filesort() sorted the data using mem-comparable keys. That is, if we wanted to sort by ORDER BY col1, col2, ... colN then the filesort code would for each row generate one "Sort Key" and then sort the rows by their Sort Keys. The Sort Keys are mem-comparable (that is, are compared by memcmp()) and they are of FIXED SIZE. The sort key has the same length regardless of what value it represents. This causes INEFFICIENT MEMORY USAGE. 1.1 Implementation details make_sortkey() is the function that produces a sort key from a record. The function treats Field and Item objects differently. class Field has: a) void make_sort_key(uchar *buff, uint length); make_sort_key is a non-virtual function which handles encoding of SQL null values. b) virtual void sort_string(uchar *buff,uint length)=0; sort_string produces mem-comparable image of the field value for each datatype. For Items, Type_handler has a virtual function: virtual void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const= 0; which various datatypes overload. 2. SOLUTION: PACKED SORT KEYS Note that one can have mem-comparable keys are that are not fixed-size. MyRocks uses such encoding for example. However for this optimization it was decided to store the original (non-mem-comparable) values instead and use a datatype-aware key comparison function. 2.1 Packed key format The keys are stored in a new variable-size data format called "packed". The format is as follows: ....... format for a n-part sort key is the length of the whole key. Each packed value is encoded as follows: // This is a an SQL NULL [] // this a non-NULL value null_byte is present if the field/item is NULLable. SQL NULL is encoded as just one NULL-indicator byte. The value itself is omitted. The format of the packed_value depends on the datatype. For "non-packable" datatypes it is just their mem-comparable form, as before. The "packable" datatypes are currently variable-length strings and the packed format for them is (for binary blobs, see a note below): 2.2 Which format to use The advantage of Packed Key Format is potential space savings for variable-length fields. The disadvantages are: a) It may actually take more space, because of sort_key_length and length fields. b) The comparison function is more expensive. Currently the logic is: use Packed Key Format if we would save 128 or more bytes when constructing a sort key from values that have empty string for each packable component. 3. SPECIAL CASES 3.1 HANDLING VERY LONG STRINGS the size of sort key part was limited by @@max_sort_length variable. It is defined as: The number of bytes to use when sorting data values. The server uses only the first max_sort_length bytes of each value and ignores the rest. 3.2 HANDLING VERY LONG BINARY STRINGS Long binary strings receive special treatment. A sort key for the long binary string is truncated at max_sort_length bytes like described above, but then a "suffix" is appended which contains the total length of the value before the truncation. 3.3 HANDLING VERY LONG STRINGS WITH PACKED SORT KEY Truncating multi-byte string at N bytes is not safe because one can cut in the middle of a character. One is tempted to solve this by discarding the partial character but that's also not a good idea as in some collations multiple characters may produce one weight (this is called "contraction"). This combination of circumstances: The string value is very long, so truncation is necessary The collation is "complex", so truncation is dangerous is deemed to be relatively rare so it was decided to just use the non-packed sort keys in this case. 4. SORT KEY COLUMNS IN ADDON FIELDS Currently, each sort key column is actually stored twice 1. as part of the sort key 2. in the addon_fields This made total sense when sort key stored the mem-comparable image (from which one cannot restore the original value in general case). But since we now store the original value, we could also remove it from the addon_fields and further save space. This is still a limitation and needs to be fixed later @see Sort_keys **/ /** The sort record format may use one of two formats for the non-sorted part of the record: 1. Use the rowid || | / / ref_length / 2. Use "addon fields" |||...| / / addon_length / The packed format for "addon fields" ||||...| / / addon_length / The key may use one of the two formats: A. fixed-size mem-comparable form. The record is always sort_length bytes long. B. "PackedKeyFormat" - the records are variable-size. Fields are fixed-size, specially encoded with Field::make_sort_key() so we can do byte-by-byte compare. Contains the *actual* packed length (after packing) of everything after the sort keys. The size of the length field is 2 bytes, which should cover most use cases: addon data <= 65535 bytes. This is the same as max record size in MySQL. One bit for each nullable field, indicating whether the field is null or not. May have size zero if no fields are nullable. Are stored with field->pack(), and retrieved with field->unpack(). Addon fields within a record are stored consecutively, with no "holes" or padding. They will have zero size for NULL values. */ class Sort_param { public: uint rec_length; // Length of sorted records. uint sort_length; // Length of sorted columns. uint ref_length; // Length of record ref. uint addon_length; // Length of addon_fields uint res_length; // Length of records in final sorted file/buffer. uint max_keys_per_buffer; // Max keys / buffer. uint min_dupl_count; ha_rows max_rows; // Select limit, or HA_POS_ERROR if unlimited. ha_rows examined_rows; // Number of examined rows. TABLE *sort_form; // For quicker make_sortkey. /** ORDER BY list with some precalculated info for filesort. Array is created and owned by a Filesort instance. */ Bounds_checked_array local_sortorder; Addon_fields *addon_fields; // Descriptors for companion fields. Sort_keys *sort_keys; ha_rows *accepted_rows; /* For ROWNUM */ bool using_pq; bool set_all_read_bits; uchar *unique_buff; bool not_killable; String tmp_buffer; // The fields below are used only by Unique class. qsort_cmp2 compare; BUFFPEK_COMPARE_CONTEXT cmp_context; Sort_param() { memset(reinterpret_cast(this), 0, sizeof(*this)); tmp_buffer.set_thread_specific(); /* Fix memset() clearing the charset. TODO: The constructor should be eventually rewritten not to use memset(). */ tmp_buffer.set_charset(&my_charset_bin); } void init_for_filesort(uint sortlen, TABLE *table, ha_rows maxrows, Filesort *filesort); void (*unpack)(TABLE *); /// Enables the packing of addons if possible. void try_to_pack_addons(ulong max_length_for_sort_data); /// Are we packing the "addon fields"? bool using_packed_addons() const { DBUG_ASSERT(m_using_packed_addons == (addon_fields != NULL && addon_fields->using_packed_addons())); return m_using_packed_addons; } bool using_packed_sortkeys() const { DBUG_ASSERT(m_using_packed_sortkeys == (sort_keys != NULL && sort_keys->using_packed_sortkeys())); return m_using_packed_sortkeys; } /// Are we using "addon fields"? bool using_addon_fields() const { return addon_fields != NULL; } uint32 get_result_length(uchar *plen) { if (!m_using_packed_addons) return res_length; return Addon_fields::read_addon_length(plen); } uint32 get_addon_length(uchar *plen) { if (using_packed_addons()) return Addon_fields::read_addon_length(plen); else return addon_length; } uint32 get_sort_length(uchar *plen) { if (using_packed_sortkeys()) return Sort_keys::read_sortkey_length(plen) + /* when addon fields are not present, then the sort_length also includes the res_length. For packed keys here we add the res_length */ (using_addon_fields() ? 0: res_length); else return sort_length; } uint get_record_length(uchar *plen) { if (m_packed_format) { uint sort_len= get_sort_length(plen); return sort_len + get_addon_length(plen + sort_len); } else return rec_length; } /** Getter for record length and result length. @param record_start Pointer to record. @param [out] recl Store record length here. @param [out] resl Store result length here. */ void get_rec_and_res_len(uchar *record_start, uint *recl, uint *resl) { if (m_packed_format) { uint sort_len= get_sort_length(record_start); uint addon_len= get_addon_length(record_start + sort_len); *recl= sort_len + addon_len; *resl= using_addon_fields() ? addon_len : res_length; } else { *recl= rec_length; *resl= res_length; } } void try_to_pack_sortkeys(); qsort_cmp2 get_compare_function() const { return using_packed_sortkeys() ? get_packed_keys_compare_ptr() : get_ptr_compare(sort_length); } void* get_compare_argument(size_t *sort_len) const { return using_packed_sortkeys() ? (void*) this : (void*) sort_len; } bool is_packed_format() const { return m_packed_format; } private: uint m_packable_length; bool m_using_packed_addons; ///< caches the value of using_packed_addons() /* caches the value of using_packed_sortkeys() */ bool m_using_packed_sortkeys; bool m_packed_format; }; typedef Bounds_checked_array Sort_buffer; int merge_many_buff(Sort_param *param, Sort_buffer sort_buffer, Merge_chunk *buffpek, uint *maxbuffer, IO_CACHE *t_file); ulong read_to_buffer(IO_CACHE *fromfile, Merge_chunk *buffpek, Sort_param *param, bool packing_format); bool merge_buffers(Sort_param *param,IO_CACHE *from_file, IO_CACHE *to_file, Sort_buffer sort_buffer, Merge_chunk *lastbuff, Merge_chunk *Fb, Merge_chunk *Tb, int flag); int merge_index(Sort_param *param, Sort_buffer sort_buffer, Merge_chunk *buffpek, uint maxbuffer, IO_CACHE *tempfile, IO_CACHE *outfile); void reuse_freed_buff(QUEUE *queue, Merge_chunk *reuse, uint key_length); #endif /* SQL_SORT_INCLUDED */ server/private/datadict.h000064400000003244151031265040011452 0ustar00#ifndef DATADICT_INCLUDED #define DATADICT_INCLUDED /* Copyright (c) 2010, Oracle and/or its affiliates. Copyright (c) 2017 MariaDB corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "handler.h" /* Data dictionary API. */ enum Table_type { TABLE_TYPE_UNKNOWN, TABLE_TYPE_NORMAL, /* Normal table */ TABLE_TYPE_SEQUENCE, TABLE_TYPE_VIEW }; /* Take extra care when using dd_frm_type() - it only checks the .frm file, and it won't work for any engine that supports discovery. Prefer to use ha_table_exists() instead. To check whether it's an frm of a view, use dd_frm_is_view(). */ enum Table_type dd_frm_type(THD *thd, char *path, LEX_CSTRING *engine_name, LEX_CSTRING *partition_engine_name, LEX_CUSTRING *table_version); static inline bool dd_frm_is_view(THD *thd, char *path) { return dd_frm_type(thd, path, NULL, NULL, NULL) == TABLE_TYPE_VIEW; } bool dd_recreate_table(THD *thd, const char *db, const char *table_name); #endif // DATADICT_INCLUDED server/private/vers_string.h000064400000004746151031265040012252 0ustar00/* Copyright (c) 2018, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef VERS_STRING_INCLUDED #define VERS_STRING_INCLUDED #include "lex_string.h" /* LEX_CSTRING with comparison semantics. */ // db and table names: case sensitive (or insensitive) in table_alias_charset struct Compare_table_names { int operator()(const LEX_CSTRING& a, const LEX_CSTRING& b) const { DBUG_ASSERT(a.str[a.length] == 0); DBUG_ASSERT(b.str[b.length] == 0); return table_alias_charset->strnncoll(a.str, a.length, b.str, b.length); } }; // column names and other identifiers: case insensitive in system_charset_info struct Compare_identifiers { int operator()(const LEX_CSTRING& a, const LEX_CSTRING& b) const { DBUG_ASSERT(a.str != NULL); DBUG_ASSERT(b.str != NULL); DBUG_ASSERT(a.str[a.length] == 0); DBUG_ASSERT(b.str[b.length] == 0); return my_strcasecmp(system_charset_info, a.str, b.str); } }; template struct Lex_cstring_with_compare : public Lex_cstring { public: Lex_cstring_with_compare() = default; Lex_cstring_with_compare(const char *_str, size_t _len) : Lex_cstring(_str, _len) { } Lex_cstring_with_compare(const LEX_STRING src) : Lex_cstring(src.str, src.length) { } Lex_cstring_with_compare(const LEX_CSTRING src) : Lex_cstring(src.str, src.length) { } Lex_cstring_with_compare(const char *_str) : Lex_cstring(_str, strlen(_str)) { } bool streq(const Lex_cstring_with_compare& b) const { return Lex_cstring::length == b.length && 0 == Compare()(*this, b); } operator const char* () const { return str; } operator bool () const { return str != NULL; } }; typedef Lex_cstring_with_compare Lex_ident; typedef Lex_cstring_with_compare Lex_table_name; #endif // VERS_STRING_INCLUDED server/private/wsrep_thd.h000064400000025630151031265040011677 0ustar00/* Copyright (C) 2013-2023 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA. */ #ifndef WSREP_THD_H #define WSREP_THD_H #include #include "mysql/service_wsrep.h" #include "wsrep/client_state.hpp" #include "sql_class.h" #include "wsrep_utils.h" #include class Wsrep_thd_queue { public: Wsrep_thd_queue(THD* t) : thd(t) { mysql_mutex_init(key_LOCK_wsrep_thd_queue, &LOCK_wsrep_thd_queue, MY_MUTEX_INIT_FAST); mysql_cond_init(key_COND_wsrep_thd_queue, &COND_wsrep_thd_queue, NULL); } ~Wsrep_thd_queue() { mysql_mutex_destroy(&LOCK_wsrep_thd_queue); mysql_cond_destroy(&COND_wsrep_thd_queue); } bool push_back(THD* thd) { DBUG_ASSERT(thd); wsp::auto_lock lock(&LOCK_wsrep_thd_queue); std::deque::iterator it = queue.begin(); while (it != queue.end()) { if (*it == thd) { return true; } it++; } queue.push_back(thd); mysql_cond_signal(&COND_wsrep_thd_queue); return false; } THD* pop_front() { wsp::auto_lock lock(&LOCK_wsrep_thd_queue); while (queue.empty()) { if (thd->killed != NOT_KILLED) return NULL; thd->mysys_var->current_mutex= &LOCK_wsrep_thd_queue; thd->mysys_var->current_cond= &COND_wsrep_thd_queue; mysql_cond_wait(&COND_wsrep_thd_queue, &LOCK_wsrep_thd_queue); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; } THD* ret= queue.front(); queue.pop_front(); return ret; } private: THD* thd; std::deque queue; mysql_mutex_t LOCK_wsrep_thd_queue; mysql_cond_t COND_wsrep_thd_queue; }; int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, void *, system_status_var *, enum enum_var_type scope); bool wsrep_create_appliers(long threads, bool mutex_protected=false); void wsrep_create_rollbacker(); bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd); /* Abort transaction for victim_thd. This function is called from MDL BF abort codepath. */ void wsrep_abort_thd(THD *bf_thd, THD *victim_thd, my_bool signal) __attribute__((nonnull(1,2))); /** Kill wsrep connection with kill_signal. Object thd is not guaranteed to exist anymore when this function returns. Asserts that the caller holds victim_thd->LOCK_thd_kill, victim_thd->LOCK_thd_data. @param thd THD object for connection that executes the KILL. @param victim_thd THD object for connection to be killed. @param kill_signal Kill signal. @return Zero if the kill was successful, otherwise non-zero error code. */ uint wsrep_kill_thd(THD *thd, THD *victim_thd, killed_state kill_signal); /* Backup kill status for commit. */ void wsrep_backup_kill_for_commit(THD *); /* Restore KILL status after commit. */ void wsrep_restore_kill_after_commit(THD *); /* Helper methods to deal with thread local storage. The purpose of these methods is to hide the details of thread local storage handling when operating with wsrep storage access and streaming applier THDs With one-thread-per-connection thread handling thread specific variables are allocated when the thread is started and deallocated before thread exits (my_thread_init(), my_thread_end()). However, with pool-of-threads thread handling new thread specific variables are allocated for each THD separately (see threadpool_add_connection()), and the variables in thread local storage are assigned from currently active thread (see thread_attach()). This must be taken into account when storing/resetting thread local storage and when creating streaming applier THDs. */ /** Create new variables for thread local storage. With one-thread-per-connection thread handling this is a no op, with pool-of-threads new variables are created via my_thread_init(). It is assumed that the caller has called wsrep_reset_threadvars() to clear the thread local storage before this call. @return Zero in case of success, non-zero otherwise. */ int wsrep_create_threadvars(); /** Delete variables which were created by wsrep_create_threadvars(). The caller must store variables into thread local storage before this call via wsrep_store_threadvars(). */ void wsrep_delete_threadvars(); /** Assign variables from current thread local storage into THD. This should be called for THDs whose lifetime is limited to single thread execution or which may share the operation context with some parent THD (e.g. storage access) and thus don't require separately allocated globals. With one-thread-per-connection thread handling this is a no-op, with pool-of-threads the variables which are currently stored into thread local storage are assigned to THD. */ void wsrep_assign_from_threadvars(THD *); /** Helper struct to save variables from thread local storage. */ struct Wsrep_threadvars { THD* cur_thd; st_my_thread_var* mysys_var; }; /** Save variables from thread local storage into Wsrep_threadvars struct. */ Wsrep_threadvars wsrep_save_threadvars(); /** Restore variables into thread local storage from Wsrep_threadvars struct. */ void wsrep_restore_threadvars(const Wsrep_threadvars&); /** Store variables into thread local storage. */ void wsrep_store_threadvars(THD *); /** Reset thread local storage. */ void wsrep_reset_threadvars(THD *); /** Helper functions to override error status In many contexts it is desirable to mask the original error status set for THD or it is necessary to change OK status to error. This function implements the common logic for the most of the cases. Rules: * If the diagnostics are has OK or EOF status, override it unconditionally * If the error is either ER_ERROR_DURING_COMMIT or ER_LOCK_DEADLOCK it is usually the correct error status to be returned to client, so don't override those by default */ static inline void wsrep_override_error(THD *thd, uint error, const char *format= 0, ...) { Diagnostics_area *da= thd->get_stmt_da(); if (da->is_ok() || da->is_eof() || !da->is_set() || (da->is_error() && da->sql_errno() != error && da->sql_errno() != ER_ERROR_DURING_COMMIT && da->sql_errno() != ER_LOCK_DEADLOCK)) { da->reset_diagnostics_area(); va_list args; va_start(args, format); if (!format) format= ER_THD(thd, error); my_printv_error(error, format, MYF(0), args); va_end(args); } } static inline void wsrep_override_error(THD* thd, wsrep::client_error ce, enum wsrep::provider::status status) { DBUG_ASSERT(ce != wsrep::e_success); switch (ce) { case wsrep::e_error_during_commit: if (status == wsrep::provider::error_size_exceeded) wsrep_override_error(thd, ER_UNKNOWN_ERROR, "Maximum writeset size exceeded"); else /* TODO: Figure out better error number */ if (status) wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, "Error while appending streaming replication fragment" "(provider status: %s)", wsrep::provider::to_string(status).c_str()); else wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, "Error while appending streaming replication fragment"); break; case wsrep::e_deadlock_error: switch (thd->lex->sql_command) { case SQLCOM_XA_END: case SQLCOM_XA_PREPARE: wsrep_override_error(thd, ER_XA_RBDEADLOCK); break; default: wsrep_override_error(thd, ER_LOCK_DEADLOCK); break; } break; case wsrep::e_interrupted_error: wsrep_override_error(thd, ER_QUERY_INTERRUPTED); break; case wsrep::e_size_exceeded_error: wsrep_override_error(thd, ER_UNKNOWN_ERROR, "Maximum writeset size exceeded"); break; case wsrep::e_append_fragment_error: /* TODO: Figure out better error number */ if (status) wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, "Error while appending streaming replication fragment" "(provider status: %s)", wsrep::provider::to_string(status).c_str()); else wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, "Error while appending streaming replication fragment"); break; case wsrep::e_not_supported_error: wsrep_override_error(thd, ER_NOT_SUPPORTED_YET); break; case wsrep::e_timeout_error: wsrep_override_error(thd, ER_LOCK_WAIT_TIMEOUT); break; default: wsrep_override_error(thd, ER_UNKNOWN_ERROR); } } /** Helper function to log THD wsrep context. @param thd Pointer to THD @param message Optional message @param function Function where the call was made from */ static inline void wsrep_log_thd(const THD *thd, const char *message, const char *function) { WSREP_DEBUG("%s %s\n" " thd: %llu thd_ptr: %p client_mode: %s client_state: %s trx_state: %s\n" " next_trx_id: %lld trx_id: %lld seqno: %lld\n" " is_streaming: %d fragments: %zu\n" " sql_errno: %u message: %s\n" #define WSREP_THD_LOG_QUERIES #ifdef WSREP_THD_LOG_QUERIES " command: %d query: %.72s" #endif /* WSREP_OBSERVER_LOG_QUERIES */ , function, message ? message : "", thd->thread_id, thd, wsrep_thd_client_mode_str(thd), wsrep_thd_client_state_str(thd), wsrep_thd_transaction_state_str(thd), (long long)thd->wsrep_next_trx_id(), (long long)thd->wsrep_trx_id(), (long long)wsrep_thd_trx_seqno(thd), thd->wsrep_trx().is_streaming(), thd->wsrep_sr().fragments().size(), (thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0), (thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->message() : "") #ifdef WSREP_THD_LOG_QUERIES , thd->lex->sql_command, wsrep_thd_query(thd) #endif /* WSREP_OBSERVER_LOG_QUERIES */ ); } #define WSREP_LOG_THD(thd_, message_) wsrep_log_thd(thd_, message_, __FUNCTION__) #endif /* WSREP_THD_H */ server/private/maria.h000064400000013360151031265040010766 0ustar00/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. Copyright (c) 2009, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file should be included when using maria functions */ #ifndef _maria_h #define _maria_h #include #include #include "my_compare.h" #include "ft_global.h" #include #ifdef __cplusplus extern "C" { #endif #define MARIA_UNIQUE_HASH_LENGTH 4 extern my_bool maria_delay_key_write; uint maria_max_key_length(void); #define maria_max_key_segments() HA_MAX_KEY_SEG struct st_maria_bit_buff; struct st_maria_page; struct st_maria_s_param; struct st_maria_share; typedef struct st_maria_decode_tree MARIA_DECODE_TREE; typedef struct st_maria_handler MARIA_HA; typedef struct st_maria_key MARIA_KEY; typedef ulonglong MARIA_RECORD_POS; typedef struct st_maria_keydef /* Key definition with open & info */ { struct st_maria_share *share; /* Pointer to base (set in open) */ mysql_rwlock_t root_lock; /* locking of tree */ uint16 keysegs; /* Number of key-segment */ uint16 flag; /* NOSAME, PACK_USED */ uint8 key_alg; /* BTREE, RTREE */ uint8 key_nr; /* key number (auto) */ uint16 block_length; /* Length of keyblock (auto) */ uint16 underflow_block_length; /* When to execute underflow */ uint16 keylength; /* Tot length of keyparts (auto) */ uint16 minlength; /* min length of (packed) key (auto) */ uint16 maxlength; /* max length of (packed) key (auto) */ uint16 max_store_length; /* Size to store key + overhead */ uint32 write_comp_flag; /* compare flag for write key (auto) */ uint32 version; /* For concurrent read/write */ uint32 ftkey_nr; /* full-text index number */ HA_KEYSEG *seg, *end; struct st_mysql_ftparser *parser; /* Fulltext [pre]parser */ int (*bin_search)(const MARIA_KEY *key, const struct st_maria_page *page, uint32 comp_flag, uchar **ret_pos, uchar *buff, my_bool *was_last_key); uint (*get_key)(MARIA_KEY *key, uint page_flag, uint nod_flag, uchar **page); uchar *(*skip_key)(MARIA_KEY *key, uint page_flag, uint nod_flag, uchar *page); int (*pack_key)(const MARIA_KEY *key, uint nod_flag, uchar *next_key, uchar *org_key, uchar *prev_key, struct st_maria_s_param *s_temp); void (*store_key)(struct st_maria_keydef *keyinfo, uchar *key_pos, struct st_maria_s_param *s_temp); my_bool (*ck_insert)(MARIA_HA *inf, MARIA_KEY *key); my_bool (*ck_delete)(MARIA_HA *inf, MARIA_KEY *klen); MARIA_KEY *(*make_key)(MARIA_HA *info, MARIA_KEY *int_key, uint keynr, uchar *key, const uchar *record, MARIA_RECORD_POS filepos, ulonglong trid); } MARIA_KEYDEF; typedef struct st_maria_unique_def /* Segment definition of unique */ { uint16 keysegs; /* Number of key-segment */ uint8 key; /* Mapped to which key */ uint8 null_are_equal; HA_KEYSEG *seg, *end; } MARIA_UNIQUEDEF; /* Note that null markers should always be first in a row ! When creating a column, one should only specify: type, length, null_bit and null_pos */ typedef struct st_maria_columndef /* column information */ { enum en_fieldtype type; uint32 offset; /* Offset to position in row */ uint16 length; /* length of field */ uint16 column_nr; /* Intern variable (size of total storage area for the row) */ uint16 fill_length; uint16 null_pos; /* Position for null marker */ uint16 empty_pos; /* Position for empty marker */ uint8 null_bit; /* If column may be NULL */ /* Intern. Set if column should be zero packed (part of empty_bits) */ uint8 empty_bit; #ifndef NOT_PACKED_DATABASES void(*unpack)(struct st_maria_columndef *rec, struct st_maria_bit_buff *buff, uchar *start, uchar *end); enum en_fieldtype base_type; uint space_length_bits, pack_type; MARIA_DECODE_TREE *huff_tree; #endif } MARIA_COLUMNDEF; typedef struct st_maria_create_info { const char *index_file_name, *data_file_name; /* If using symlinks */ ha_rows max_rows; ha_rows reloc_rows; ulonglong auto_increment; ulonglong data_file_length; ulonglong key_file_length; ulong s3_block_size; /* Size of null bitmap at start of row */ uint null_bytes; uint old_options; uint compression_algorithm; enum data_file_type org_data_file_type; uint16 language; my_bool with_auto_increment, transactional, encrypted; } MARIA_CREATE_INFO; extern int maria_create(const char *name, enum data_file_type record_type, uint keys, MARIA_KEYDEF *keydef, uint columns, MARIA_COLUMNDEF *columndef, uint uniques, MARIA_UNIQUEDEF *uniquedef, MARIA_CREATE_INFO *create_info, uint flags); #ifdef __cplusplus } #endif #endif server/private/item_sum.h000064400000215137151031265040011525 0ustar00#ifndef ITEM_SUM_INCLUDED #define ITEM_SUM_INCLUDED /* Copyright (c) 2000, 2013 Oracle and/or its affiliates. Copyright (c) 2008, 2023, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* classes for sum functions */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include #include "sql_udf.h" /* udf_handler */ class Item_sum; class Aggregator_distinct; class Aggregator_simple; /** The abstract base class for the Aggregator_* classes. It implements the data collection functions (setup/add/clear) as either pass-through to the real functionality or as collectors into an Unique (for distinct) structure. Note that update_field/reset_field are not in that class, because they're simply not called when GROUP BY/DISTINCT can be handled with help of index on grouped fields (quick_group = 0); */ class Aggregator : public Sql_alloc { friend class Item_sum; friend class Item_sum_sum; friend class Item_sum_count; friend class Item_sum_avg; /* All members are protected as this class is not usable outside of an Item_sum descendant. */ protected: /* the aggregate function class to act on */ Item_sum *item_sum; public: Aggregator (Item_sum *arg): item_sum(arg) {} virtual ~Aggregator () = default; /* Keep gcc happy */ enum Aggregator_type { SIMPLE_AGGREGATOR, DISTINCT_AGGREGATOR }; virtual Aggregator_type Aggrtype() = 0; /** Called before adding the first row. Allocates and sets up the internal aggregation structures used, e.g. the Unique instance used to calculate distinct. */ virtual bool setup(THD *) = 0; /** Called when we need to wipe out all the data from the aggregator : all the values acumulated and all the state. Cleans up the internal structures and resets them to their initial state. */ virtual void clear() = 0; /** Called when there's a new value to be aggregated. Updates the internal state of the aggregator to reflect the new value. */ virtual bool add() = 0; /** Called when there are no more data and the final value is to be retrieved. Finalises the state of the aggregator, so the final result can be retrieved. */ virtual void endup() = 0; /** Decimal value of being-aggregated argument */ virtual my_decimal *arg_val_decimal(my_decimal * value) = 0; /** Floating point value of being-aggregated argument */ virtual double arg_val_real() = 0; /** NULLness of being-aggregated argument. @param use_null_value Optimization: to determine if the argument is NULL we must, in the general case, call is_null() on it, which itself might call val_*() on it, which might be costly. If you just have called arg_val*(), you can pass use_null_value=true; this way, arg_is_null() might avoid is_null() and instead do a cheap read of the Item's null_value (updated by arg_val*()). */ virtual bool arg_is_null(bool use_null_value) = 0; }; class st_select_lex; class Window_spec; /** Class Item_sum is the base class used for special expressions that SQL calls 'set functions'. These expressions are formed with the help of aggregate functions such as SUM, MAX, GROUP_CONCAT etc. GENERAL NOTES A set function cannot be used in certain positions where expressions are accepted. There are some quite explicable restrictions for the usage of set functions. In the query: SELECT AVG(b) FROM t1 WHERE SUM(b) > 20 GROUP by a the usage of the set function AVG(b) is legal, while the usage of SUM(b) is illegal. A WHERE condition must contain expressions that can be evaluated for each row of the table. Yet the expression SUM(b) can be evaluated only for each group of rows with the same value of column a. In the query: SELECT AVG(b) FROM t1 WHERE c > 30 GROUP BY a HAVING SUM(b) > 20 both set function expressions AVG(b) and SUM(b) are legal. We can say that in a query without nested selects an occurrence of a set function in an expression of the SELECT list or/and in the HAVING clause is legal, while in the WHERE clause it's illegal. The general rule to detect whether a set function is legal in a query with nested subqueries is much more complicated. Consider the the following query: SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a > ALL (SELECT t2.c FROM t2 WHERE SUM(t1.b) < t2.c). The set function SUM(b) is used here in the WHERE clause of the subquery. Nevertheless it is legal since it is under the HAVING clause of the query to which this function relates. The expression SUM(t1.b) is evaluated for each group defined in the main query, not for groups of the subquery. The problem of finding the query where to aggregate a particular set function is not so simple as it seems to be. In the query: SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a > ALL(SELECT t2.c FROM t2 GROUP BY t2.c HAVING SUM(t1.a) < t2.c) the set function can be evaluated for both outer and inner selects. If we evaluate SUM(t1.a) for the outer query then we get the value of t1.a multiplied by the cardinality of a group in table t1. In this case in each correlated subquery SUM(t1.a) is used as a constant. But we also can evaluate SUM(t1.a) for the inner query. In this case t1.a will be a constant for each correlated subquery and summation is performed for each group of table t2. (Here it makes sense to remind that the query SELECT c FROM t GROUP BY a HAVING SUM(1) < a is quite legal in our SQL). So depending on what query we assign the set function to we can get different result sets. The general rule to detect the query where a set function is to be evaluated can be formulated as follows. Consider a set function S(E) where E is an expression with occurrences of column references C1, ..., CN. Resolve these column references against subqueries that contain the set function S(E). Let Q be the innermost subquery of those subqueries. (It should be noted here that S(E) in no way can be evaluated in the subquery embedding the subquery Q, otherwise S(E) would refer to at least one unbound column reference) If S(E) is used in a construct of Q where set functions are allowed then we evaluate S(E) in Q. Otherwise we look for a innermost subquery containing S(E) of those where usage of S(E) is allowed. Let's demonstrate how this rule is applied to the following queries. 1. SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a > ALL(SELECT t2.b FROM t2 GROUP BY t2.b HAVING t2.b > ALL(SELECT t3.c FROM t3 GROUP BY t3.c HAVING SUM(t1.a+t2.b) < t3.c)) For this query the set function SUM(t1.a+t2.b) depends on t1.a and t2.b with t1.a defined in the outermost query, and t2.b defined for its subquery. The set function is in the HAVING clause of the subquery and can be evaluated in this subquery. 2. SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a > ALL(SELECT t2.b FROM t2 WHERE t2.b > ALL (SELECT t3.c FROM t3 GROUP BY t3.c HAVING SUM(t1.a+t2.b) < t3.c)) Here the set function SUM(t1.a+t2.b)is in the WHERE clause of the second subquery - the most upper subquery where t1.a and t2.b are defined. If we evaluate the function in this subquery we violate the context rules. So we evaluate the function in the third subquery (over table t3) where it is used under the HAVING clause. 3. SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a > ALL(SELECT t2.b FROM t2 WHERE t2.b > ALL (SELECT t3.c FROM t3 WHERE SUM(t1.a+t2.b) < t3.c)) In this query evaluation of SUM(t1.a+t2.b) is not legal neither in the second nor in the third subqueries. So this query is invalid. Mostly set functions cannot be nested. In the query SELECT t1.a from t1 GROUP BY t1.a HAVING AVG(SUM(t1.b)) > 20 the expression SUM(b) is not acceptable, though it is under a HAVING clause. Yet it is acceptable in the query: SELECT t.1 FROM t1 GROUP BY t1.a HAVING SUM(t1.b) > 20. An argument of a set function does not have to be a reference to a table column as we saw it in examples above. This can be a more complex expression SELECT t1.a FROM t1 GROUP BY t1.a HAVING SUM(t1.b+1) > 20. The expression SUM(t1.b+1) has a very clear semantics in this context: we sum up the values of t1.b+1 where t1.b varies for all values within a group of rows that contain the same t1.a value. A set function for an outer query yields a constant within a subquery. So the semantics of the query SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c HAVING AVG(t2.c+SUM(t1.b)) > 20) is still clear. For a group of the rows with the same t1.a values we calculate the value of SUM(t1.b). This value 's' is substituted in the the subquery: SELECT t2.c FROM t2 GROUP BY t2.c HAVING AVG(t2.c+s) than returns some result set. By the same reason the following query with a subquery SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a IN (SELECT t2.c FROM t2 GROUP BY t2.c HAVING AVG(SUM(t1.b)) > 20) is also acceptable. IMPLEMENTATION NOTES Three methods were added to the class to check the constraints specified in the previous section. These methods utilize several new members. The field 'nest_level' contains the number of the level for the subquery containing the set function. The main SELECT is of level 0, its subqueries are of levels 1, the subqueries of the latter are of level 2 and so on. The field 'aggr_level' is to contain the nest level of the subquery where the set function is aggregated. The field 'max_arg_level' is for the maximum of the nest levels of the unbound column references occurred in the set function. A column reference is unbound within a set function if it is not bound by any subquery used as a subexpression in this function. A column reference is bound by a subquery if it is a reference to the column by which the aggregation of some set function that is used in the subquery is calculated. For the set function used in the query SELECT t1.a FROM t1 GROUP BY t1.a HAVING t1.a > ALL(SELECT t2.b FROM t2 GROUP BY t2.b HAVING t2.b > ALL(SELECT t3.c FROM t3 GROUP BY t3.c HAVING SUM(t1.a+t2.b) < t3.c)) the value of max_arg_level is equal to 1 since t1.a is bound in the main query, and t2.b is bound by the first subquery whose nest level is 1. Obviously a set function cannot be aggregated in the subquery whose nest level is less than max_arg_level. (Yet it can be aggregated in the subqueries whose nest level is greater than max_arg_level.) In the query SELECT t.a FROM t1 HAVING AVG(t1.a+(SELECT MIN(t2.c) FROM t2)) the value of the max_arg_level for the AVG set function is 0 since the reference t2.c is bound in the subquery. The field 'max_sum_func_level' is to contain the maximum of the nest levels of the set functions that are used as subexpressions of the arguments of the given set function, but not aggregated in any subquery within this set function. A nested set function s1 can be used within set function s0 only if s1.max_sum_func_level < s0.max_sum_func_level. Set function s1 is considered as nested for set function s0 if s1 is not calculated in any subquery within s0. A set function that is used as a subexpression in an argument of another set function refers to the latter via the field 'in_sum_func'. The condition imposed on the usage of set functions are checked when we traverse query subexpressions with the help of the recursive method fix_fields. When we apply this method to an object of the class Item_sum, first, on the descent, we call the method init_sum_func_check that initialize members used at checking. Then, on the ascent, we call the method check_sum_func that validates the set function usage and reports an error if it is illegal. The method register_sum_func serves to link the items for the set functions that are aggregated in the embedding (sub)queries. Circular chains of such functions are attached to the corresponding st_select_lex structures through the field inner_sum_func_list. Exploiting the fact that the members mentioned above are used in one recursive function we could have allocated them on the thread stack. Yet we don't do it now. We assume that the nesting level of subquries does not exceed 127. TODO: to catch queries where the limit is exceeded to make the code clean here. @note The implementation takes into account the used strategy: - Items resolved at optimization phase return 0 from Item_sum::used_tables(). - Items that depend on the number of join output records, but not columns of any particular table (like COUNT(*)), returm 0 from Item_sum::used_tables(), but still return false from Item_sum::const_item(). */ class Item_sum :public Item_func_or_sum { friend class Aggregator_distinct; friend class Aggregator_simple; protected: /** Aggregator class instance. Not set initially. Allocated only after it is determined if the incoming data are already distinct. */ Aggregator *aggr; private: /** Used in making ROLLUP. Set for the ROLLUP copies of the original Item_sum and passed to create_tmp_field() to cause it to work over the temp table buffer that is referenced by Item_result_field::result_field. */ bool force_copy_fields; /** Indicates how the aggregate function was specified by the parser : 1 if it was written as AGGREGATE(DISTINCT), 0 if it was AGGREGATE() */ bool with_distinct; /* TRUE if this is aggregate function of a window function */ bool window_func_sum_expr_flag; public: bool has_force_copy_fields() const { return force_copy_fields; } bool has_with_distinct() const { return with_distinct; } enum Sumfunctype { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC, AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_FUNC, VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC, ROW_NUMBER_FUNC, RANK_FUNC, DENSE_RANK_FUNC, PERCENT_RANK_FUNC, CUME_DIST_FUNC, NTILE_FUNC, FIRST_VALUE_FUNC, LAST_VALUE_FUNC, NTH_VALUE_FUNC, LEAD_FUNC, LAG_FUNC, PERCENTILE_CONT_FUNC, PERCENTILE_DISC_FUNC, SP_AGGREGATE_FUNC, JSON_ARRAYAGG_FUNC, JSON_OBJECTAGG_FUNC }; Item **ref_by; /* pointer to a ref to the object used to register it */ Item_sum *next; /* next in the circular chain of registered objects */ Item_sum *in_sum_func; /* embedding set function if any */ st_select_lex * aggr_sel; /* select where the function is aggregated */ int8 nest_level; /* number of the nesting level of the set function */ int8 aggr_level; /* nesting level of the aggregating subquery */ int8 max_arg_level; /* max level of unbound column references */ int8 max_sum_func_level;/* max level of aggregation for embedded functions */ /* true (the default value) means this aggregate function can be computed with TemporaryTableWithPartialSums algorithm (see end_update()). false means this aggregate function needs OrderedGroupBy algorithm (see end_write_group()). */ bool quick_group; /* This list is used by the check for mixing non aggregated fields and sum functions in the ONLY_FULL_GROUP_BY_MODE. We save all outer fields directly or indirectly used under this function it as it's unclear at the moment of fixing outer field whether it's aggregated or not. */ List outer_fields; protected: /* Copy of the arguments list to hold the original set of arguments. Used in EXPLAIN EXTENDED instead of the current argument list because the current argument list can be altered by usage of temporary tables. */ Item **orig_args, *tmp_orig_args[2]; static size_t ram_limitation(THD *thd); public: // Methods used by ColumnStore Item **get_orig_args() const { return orig_args; } public: void mark_as_sum_func(); Item_sum(THD *thd): Item_func_or_sum(thd), quick_group(1) { mark_as_sum_func(); init_aggregator(); } Item_sum(THD *thd, Item *a): Item_func_or_sum(thd, a), quick_group(1), orig_args(tmp_orig_args) { mark_as_sum_func(); init_aggregator(); } Item_sum(THD *thd, Item *a, Item *b): Item_func_or_sum(thd, a, b), quick_group(1), orig_args(tmp_orig_args) { mark_as_sum_func(); init_aggregator(); } Item_sum(THD *thd, List &list); //Copy constructor, need to perform subselects with temporary tables Item_sum(THD *thd, Item_sum *item); enum Type type() const override { return SUM_FUNC_ITEM; } virtual enum Sumfunctype sum_func () const=0; bool is_aggr_sum_func() { switch (sum_func()) { case COUNT_FUNC: case COUNT_DISTINCT_FUNC: case SUM_FUNC: case SUM_DISTINCT_FUNC: case AVG_FUNC: case AVG_DISTINCT_FUNC: case MIN_FUNC: case MAX_FUNC: case STD_FUNC: case VARIANCE_FUNC: case SUM_BIT_FUNC: case UDF_SUM_FUNC: case GROUP_CONCAT_FUNC: case JSON_ARRAYAGG_FUNC: return true; default: return false; } } /** Resets the aggregate value to its default and aggregates the current value of its attribute(s). */ inline bool reset_and_add() { aggregator_clear(); return aggregator_add(); }; /* Called when new group is started and results are being saved in a temporary table. Similarly to reset_and_add() it resets the value to its default and aggregates the value of its attribute(s), but must also store it in result_field. This set of methods (result_item(), reset_field, update_field()) of Item_sum is used only if quick_group is not null. Otherwise copy_or_same() is used to obtain a copy of this item. */ virtual void reset_field()=0; /* Called for each new value in the group, when temporary table is in use. Similar to add(), but uses temporary table field to obtain current value, Updated value is then saved in the field. */ virtual void update_field()=0; bool fix_length_and_dec() override { set_maybe_null(); null_value=1; return FALSE; } virtual Item *result_item(THD *thd, Field *field); void update_used_tables() override; COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) override { /* Item_sum (and derivants) of the original WHERE/HAVING clauses should already be replaced to Item_aggregate_ref by the time when build_equal_items() is called. See Item::split_sum_func2(). */ DBUG_ASSERT(0); return Item::build_equal_items(thd, inherited, link_item_fields, cond_equal_ref); } bool is_null() override { return null_value; } /** make_const() Called if we've managed to calculate the value of this Item in opt_sum_query(), hence it can be considered constant at all subsequent steps. */ void make_const () { used_tables_cache= 0; const_item_cache= true; } void reset_forced_const() { const_item_cache= false; } bool const_during_execution() const override { return false; } void print(String *str, enum_query_type query_type) override; void fix_num_length_and_dec(); /** Mark an aggregate as having no rows. This function is called by the execution engine to assign 'NO ROWS FOUND' value to an aggregate item, when the underlying result set has no rows. Such value, in a general case, may be different from the default value of the item after 'clear()': e.g. a numeric item may be initialized to 0 by clear() and to NULL by no_rows_in_result(). */ void no_rows_in_result() override { set_aggregator(current_thd, with_distinct ? Aggregator::DISTINCT_AGGREGATOR : Aggregator::SIMPLE_AGGREGATOR); aggregator_clear(); } virtual void make_unique() { force_copy_fields= TRUE; } virtual Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table); Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { return create_tmp_field(root, param->group(), table); } bool collect_outer_ref_processor(void *param) override; bool init_sum_func_check(THD *thd); bool check_sum_func(THD *thd, Item **ref); bool register_sum_func(THD *thd, Item **ref); st_select_lex *depended_from() { return (nest_level == aggr_level ? 0 : aggr_sel); } Item *get_arg(uint i) const { return args[i]; } Item *set_arg(uint i, THD *thd, Item *new_val); uint get_arg_count() const { return arg_count; } virtual Item **get_args() { return fixed() ? orig_args : args; } /* Initialization of distinct related members */ void init_aggregator() { aggr= NULL; with_distinct= FALSE; force_copy_fields= FALSE; } /** Called to initialize the aggregator. */ inline bool aggregator_setup(THD *thd) { return aggr->setup(thd); }; /** Called to cleanup the aggregator. */ inline void aggregator_clear() { aggr->clear(); } /** Called to add value to the aggregator. */ inline bool aggregator_add() { return aggr->add(); }; /* stores the declared DISTINCT flag (from the parser) */ void set_distinct(bool distinct) { with_distinct= distinct; quick_group= with_distinct ? 0 : 1; } /* Set the type of aggregation : DISTINCT or not. May be called multiple times. */ int set_aggregator(THD *thd, Aggregator::Aggregator_type aggregator); virtual void clear()= 0; virtual bool add()= 0; virtual bool setup(THD *thd) { return false; } virtual bool supports_removal() const { return false; } virtual void remove() { DBUG_ASSERT(0); } void cleanup() override; bool check_vcol_func_processor(void *arg) override; virtual void setup_window_func(THD *thd, Window_spec *window_spec) {} void mark_as_window_func_sum_expr() { window_func_sum_expr_flag= true; } bool is_window_func_sum_expr() { return window_func_sum_expr_flag; } virtual void setup_caches(THD *thd) {}; virtual void set_partition_row_count(ulonglong count) { DBUG_ASSERT(0); } /* While most Item_sum descendants employ standard aggregators configured through Item_sum::set_aggregator() call, there are exceptions like Item_func_group_concat, which implements its own custom aggregators for deduplication values. This function distinguishes between the use of standard and custom aggregators by the object */ virtual bool uses_non_standard_aggregator_for_distinct() const { return false; } }; class Unique; /** The distinct aggregator. Implements AGGFN (DISTINCT ..) Collects all the data into an Unique (similarly to what Item_sum does currently when with_distinct=true) and then (if applicable) iterates over the list of unique values and pumps them back into its object */ class Aggregator_distinct : public Aggregator { friend class Item_sum_sum; /* flag to prevent consecutive runs of endup(). Normally in endup there are expensive calculations (like walking the distinct tree for example) which we must do only once if there are no data changes. We can re-use the data for the second and subsequent val_xxx() calls. endup_done set to TRUE also means that the calculated values for the aggregate functions are correct and don't need recalculation. */ bool endup_done; /* Used depending on the type of the aggregate function and the presence of blob columns in it: - For COUNT(DISTINCT) and no blob fields this points to a real temporary table. It's used as a hash table. - For AVG/SUM(DISTINCT) or COUNT(DISTINCT) with blob fields only the in-memory data structure of a temporary table is constructed. It's used by the Field classes to transform data into row format. */ TABLE *table; /* An array of field lengths on row allocated and used only for COUNT(DISTINCT) with multiple columns and no blobs. Used in Aggregator_distinct::composite_key_cmp (called from Unique to compare nodes */ uint32 *field_lengths; /* Used in conjunction with 'table' to support the access to Field classes for COUNT(DISTINCT). Needed by copy_fields()/copy_funcs(). */ TMP_TABLE_PARAM *tmp_table_param; /* If there are no blobs in the COUNT(DISTINCT) arguments, we can use a tree, which is faster than heap table. In that case, we still use the table to help get things set up, but we insert nothing in it. For AVG/SUM(DISTINCT) we always use this tree (as it takes a single argument) to get the distinct rows. */ Unique *tree; /* The length of the temp table row. Must be a member of the class as it gets passed down to simple_raw_key_cmp () as a compare function argument to Unique. simple_raw_key_cmp () is used as a fast comparison function when the entire row can be binary compared. */ uint tree_key_length; /* Set to true if the result is known to be always NULL. If set deactivates creation and usage of the temporary table (in the 'table' member) and the Unique instance (in the 'tree' member) as well as the calculation of the final value on the first call to Item_[sum|avg|count]::val_xxx(). */ bool always_null; /** When feeding back the data in endup() from Unique/temp table back to Item_sum::add() methods we must read the data from Unique (and not recalculate the functions that are given as arguments to the aggregate function. This flag is to tell the arg_*() methods to take the data from the Unique instead of calling the relevant val_..() method. */ bool use_distinct_values; public: Aggregator_distinct (Item_sum *sum) : Aggregator(sum), table(NULL), tmp_table_param(NULL), tree(NULL), always_null(false), use_distinct_values(false) {} virtual ~Aggregator_distinct (); Aggregator_type Aggrtype() override { return DISTINCT_AGGREGATOR; } bool setup(THD *) override; void clear() override; bool add() override; void endup() override; my_decimal *arg_val_decimal(my_decimal * value) override; double arg_val_real() override; bool arg_is_null(bool use_null_value) override; bool unique_walk_function(void *element); bool unique_walk_function_for_count(void *element); static int composite_key_cmp(void *arg, const void *key1, const void *key2); }; /** The pass-through aggregator. Implements AGGFN (DISTINCT ..) by knowing it gets distinct data on input. So it just pumps them back to the Item_sum descendant class. */ class Aggregator_simple : public Aggregator { public: Aggregator_simple (Item_sum *sum) : Aggregator(sum) {} Aggregator_type Aggrtype() override { return Aggregator::SIMPLE_AGGREGATOR; } bool setup(THD * thd) override { return item_sum->setup(thd); } void clear() override { item_sum->clear(); } bool add() override { return item_sum->add(); } void endup() override {}; my_decimal *arg_val_decimal(my_decimal * value) override; double arg_val_real() override; bool arg_is_null(bool use_null_value) override; }; class Item_sum_num :public Item_sum { public: Item_sum_num(THD *thd): Item_sum(thd) {} Item_sum_num(THD *thd, Item *item_par): Item_sum(thd, item_par) {} Item_sum_num(THD *thd, Item *a, Item* b): Item_sum(thd, a, b) {} Item_sum_num(THD *thd, List &list): Item_sum(thd, list) {} Item_sum_num(THD *thd, Item_sum_num *item): Item_sum(thd, item) {} bool fix_fields(THD *, Item **) override; }; class Item_sum_double :public Item_sum_num { public: Item_sum_double(THD *thd): Item_sum_num(thd) {} Item_sum_double(THD *thd, Item *item_par): Item_sum_num(thd, item_par) {} Item_sum_double(THD *thd, List &list): Item_sum_num(thd, list) {} Item_sum_double(THD *thd, Item_sum_double *item) :Item_sum_num(thd, item) {} longlong val_int() override { return val_int_from_real(); } String *val_str(String*str) override { return val_string_from_real(str); } my_decimal *val_decimal(my_decimal *to) override { return val_decimal_from_real(to); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_real(thd, ltime, fuzzydate); } const Type_handler *type_handler() const override { return &type_handler_double; } }; class Item_sum_int :public Item_sum_num { public: Item_sum_int(THD *thd): Item_sum_num(thd) {} Item_sum_int(THD *thd, Item *item_par): Item_sum_num(thd, item_par) {} Item_sum_int(THD *thd, List &list): Item_sum_num(thd, list) {} Item_sum_int(THD *thd, Item_sum_int *item) :Item_sum_num(thd, item) {} double val_real() override { DBUG_ASSERT(fixed()); return (double) val_int(); } String *val_str(String*str) override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_int(thd, ltime, fuzzydate); } bool fix_length_and_dec() override { decimals=0; max_length=21; base_flags&= ~item_base_t::MAYBE_NULL; null_value=0; return false; } }; class Item_sum_sum :public Item_sum_num, public Type_handler_hybrid_field_type { protected: bool direct_added; bool direct_reseted_field; bool direct_sum_is_null; double direct_sum_real; double sum; my_decimal direct_sum_decimal; my_decimal dec_buffs[2]; uint curr_dec_buff; bool fix_length_and_dec() override; public: Item_sum_sum(THD *thd, Item *item_par, bool distinct): Item_sum_num(thd, item_par), direct_added(FALSE), direct_reseted_field(FALSE) { set_distinct(distinct); } Item_sum_sum(THD *thd, Item_sum_sum *item); enum Sumfunctype sum_func() const override { return has_with_distinct() ? SUM_DISTINCT_FUNC : SUM_FUNC; } void cleanup() override; void direct_add(my_decimal *add_sum_decimal); void direct_add(double add_sum_real, bool add_sum_is_null); void clear() override; bool add() override; double val_real() override; longlong val_int() override; String *val_str(String*str) override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } void fix_length_and_dec_double(); void fix_length_and_dec_decimal(); void reset_field() override; void update_field() override; void no_rows_in_result() override {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name_distinct= { STRING_WITH_LEN("sum(distinct ")}; static LEX_CSTRING name_normal= { STRING_WITH_LEN("sum(") }; return has_with_distinct() ? name_distinct : name_normal; } Item *copy_or_same(THD* thd) override; void remove() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } bool supports_removal() const override { return true; } private: void add_helper(bool perform_removal); ulonglong count; }; class Item_sum_count :public Item_sum_int { bool direct_counted; bool direct_reseted_field; longlong direct_count; longlong count; friend class Aggregator_distinct; void clear() override; bool add() override; void cleanup() override; void remove() override; public: Item_sum_count(THD *thd, Item *item_par): Item_sum_int(thd, item_par), direct_counted(FALSE), direct_reseted_field(FALSE), count(0) {} /** Constructs an instance for COUNT(DISTINCT) @param list a list of the arguments to the aggregate function This constructor is called by the parser only for COUNT (DISTINCT). */ Item_sum_count(THD *thd, List &list): Item_sum_int(thd, list), direct_counted(FALSE), direct_reseted_field(FALSE), count(0) { set_distinct(TRUE); } Item_sum_count(THD *thd, Item_sum_count *item): Item_sum_int(thd, item), direct_counted(FALSE), direct_reseted_field(FALSE), count(item->count) {} enum Sumfunctype sum_func () const override { return has_with_distinct() ? COUNT_DISTINCT_FUNC : COUNT_FUNC; } void no_rows_in_result() override { count=0; } void make_const(longlong count_arg) { count=count_arg; Item_sum::make_const(); } const Type_handler *type_handler() const override { return &type_handler_slonglong; } longlong val_int() override; void reset_field() override; void update_field() override; void direct_add(longlong add_count); LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name_distinct= { STRING_WITH_LEN("count(distinct ")}; static LEX_CSTRING name_normal= { STRING_WITH_LEN("count(") }; return has_with_distinct() ? name_distinct : name_normal; } Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } bool supports_removal() const override { return true; } }; class Item_sum_avg :public Item_sum_sum { public: // TODO-cvicentiu given that Item_sum_sum now uses a counter of its own, in // order to implement remove(), it is possible to remove this member. ulonglong count; uint prec_increment; uint f_precision, f_scale, dec_bin_size; Item_sum_avg(THD *thd, Item *item_par, bool distinct): Item_sum_sum(thd, item_par, distinct), count(0) {} Item_sum_avg(THD *thd, Item_sum_avg *item) :Item_sum_sum(thd, item), count(item->count), prec_increment(item->prec_increment) {} void fix_length_and_dec_double(); void fix_length_and_dec_decimal(); bool fix_length_and_dec() override; enum Sumfunctype sum_func () const override { return has_with_distinct() ? AVG_DISTINCT_FUNC : AVG_FUNC; } void clear() override; bool add() override; void remove() override; double val_real() override; // In SPs we might force the "wrong" type with select into a declare variable longlong val_int() override { return val_int_from_real(); } my_decimal *val_decimal(my_decimal *) override; String *val_str(String *str) override; void reset_field() override; void update_field() override; Item *result_item(THD *thd, Field *field) override; void no_rows_in_result() override {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name_distinct= { STRING_WITH_LEN("avg(distinct ")}; static LEX_CSTRING name_normal= { STRING_WITH_LEN("avg(") }; return has_with_distinct() ? name_distinct : name_normal; } Item *copy_or_same(THD* thd) override; Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table) override; void cleanup() override { count= 0; Item_sum_sum::cleanup(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } bool supports_removal() const override { return true; } }; /* variance(a) = = sum (ai - avg(a))^2 / count(a) ) = sum (ai^2 - 2*ai*avg(a) + avg(a)^2) / count(a) = (sum(ai^2) - sum(2*ai*avg(a)) + sum(avg(a)^2))/count(a) = = (sum(ai^2) - 2*avg(a)*sum(a) + count(a)*avg(a)^2)/count(a) = = (sum(ai^2) - 2*sum(a)*sum(a)/count(a) + count(a)*sum(a)^2/count(a)^2 )/count(a) = = (sum(ai^2) - 2*sum(a)^2/count(a) + sum(a)^2/count(a) )/count(a) = = (sum(ai^2) - sum(a)^2/count(a))/count(a) But, this falls prey to catastrophic cancellation. Instead, use the recurrence formulas M_{1} = x_{1}, ~ M_{k} = M_{k-1} + (x_{k} - M_{k-1}) / k newline S_{1} = 0, ~ S_{k} = S_{k-1} + (x_{k} - M_{k-1}) times (x_{k} - M_{k}) newline for 2 <= k <= n newline ital variance = S_{n} / (n-1) */ class Stddev { double m_m; double m_s; ulonglong m_count; public: Stddev() :m_m(0), m_s(0), m_count(0) { } Stddev(double nr) :m_m(nr), m_s(0.0), m_count(1) { } Stddev(const uchar *); void to_binary(uchar *) const; void recurrence_next(double nr); double result(bool is_simple_variance); ulonglong count() const { return m_count; } static uint32 binary_size() { return (uint32) (sizeof(double) * 2 + sizeof(ulonglong)); }; }; class Item_sum_variance :public Item_sum_double { Stddev m_stddev; bool fix_length_and_dec() override; public: uint sample; uint prec_increment; Item_sum_variance(THD *thd, Item *item_par, uint sample_arg): Item_sum_double(thd, item_par), sample(sample_arg) {} Item_sum_variance(THD *thd, Item_sum_variance *item); Sumfunctype sum_func () const override { return VARIANCE_FUNC; } void fix_length_and_dec_double(); void fix_length_and_dec_decimal(); void clear() override final; bool add() override final; double val_real() override; void reset_field() override final; void update_field() override final; Item *result_item(THD *thd, Field *field) override; void no_rows_in_result() override final {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name_sample= { STRING_WITH_LEN("var_samp(")}; static LEX_CSTRING name_normal= { STRING_WITH_LEN("variance(") }; return sample ? name_sample : name_normal; } Item *copy_or_same(THD* thd) override; Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table) override final; void cleanup() override final { m_stddev= Stddev(); Item_sum_double::cleanup(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* standard_deviation(a) = sqrt(variance(a)) */ class Item_sum_std final :public Item_sum_variance { public: Item_sum_std(THD *thd, Item *item_par, uint sample_arg): Item_sum_variance(thd, item_par, sample_arg) {} Item_sum_std(THD *thd, Item_sum_std *item) :Item_sum_variance(thd, item) {} enum Sumfunctype sum_func () const override final { return STD_FUNC; } double val_real() override final; Item *result_item(THD *thd, Field *field) override final; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING std_name= {STRING_WITH_LEN("std(") }; static LEX_CSTRING stddev_samp_name= {STRING_WITH_LEN("stddev_samp(") }; return sample ? stddev_samp_name : std_name; } Item *copy_or_same(THD* thd) override final; Item *do_get_copy(THD *thd) const override final { return get_item_copy(thd, this); } }; class Item_sum_hybrid : public Item_sum, public Type_handler_hybrid_field_type { public: Item_sum_hybrid(THD *thd, Item *item_par): Item_sum(thd, item_par), Type_handler_hybrid_field_type(&type_handler_slonglong) { collation.set(&my_charset_bin); } Item_sum_hybrid(THD *thd, Item *a, Item *b): Item_sum(thd, a, b), Type_handler_hybrid_field_type(&type_handler_slonglong) { collation.set(&my_charset_bin); } Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) :Item_sum(thd, item), Type_handler_hybrid_field_type(item) { } const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } bool fix_length_and_dec_generic(); bool fix_length_and_dec_numeric(const Type_handler *h); bool fix_length_and_dec_sint_ge0(); bool fix_length_and_dec_string(); }; // This class is a string or number function depending on num_func class Arg_comparator; class Item_cache; class Item_sum_min_max :public Item_sum_hybrid { protected: bool direct_added; Item *direct_item; Item_cache *value, *arg_cache; Arg_comparator *cmp; int cmp_sign; bool was_values; // Set if we have found at least one row (for max/min only) bool was_null_value; public: Item_sum_min_max(THD *thd, Item *item_par,int sign): Item_sum_hybrid(thd, item_par), direct_added(FALSE), value(0), arg_cache(0), cmp(0), cmp_sign(sign), was_values(TRUE) { collation.set(&my_charset_bin); } Item_sum_min_max(THD *thd, Item_sum_min_max *item) :Item_sum_hybrid(thd, item), direct_added(FALSE), value(item->value), arg_cache(0), cmp_sign(item->cmp_sign), was_values(item->was_values) { } bool fix_fields(THD *, Item **) override; bool fix_length_and_dec() override; void setup_hybrid(THD *thd, Item *item, Item *value_arg); void clear() override; void direct_add(Item *item); double val_real() override; longlong val_int() override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; void reset_field() override; String *val_str(String *) override; bool val_native(THD *thd, Native *) override; const Type_handler *real_type_handler() const override { return get_arg(0)->real_type_handler(); } const TYPELIB *get_typelib() const override { return args[0]->get_typelib(); } void update_field() override; void min_max_update_str_field(); void min_max_update_real_field(); void min_max_update_int_field(); void min_max_update_decimal_field(); void min_max_update_native_field(); void cleanup() override; bool any_value() { return was_values; } void no_rows_in_result() override; void restore_to_before_no_rows_in_result() override; Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table) override; void setup_caches(THD *thd) override { setup_hybrid(thd, arguments()[0], NULL); } }; class Item_sum_min final :public Item_sum_min_max { public: Item_sum_min(THD *thd, Item *item_par): Item_sum_min_max(thd, item_par, 1) {} Item_sum_min(THD *thd, Item_sum_min *item) :Item_sum_min_max(thd, item) {} enum Sumfunctype sum_func () const override {return MIN_FUNC;} bool add() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING sum_name= {STRING_WITH_LEN("min(") }; return sum_name; } Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_sum_max final :public Item_sum_min_max { public: Item_sum_max(THD *thd, Item *item_par): Item_sum_min_max(thd, item_par, -1) {} Item_sum_max(THD *thd, Item_sum_max *item) :Item_sum_min_max(thd, item) {} enum Sumfunctype sum_func() const override {return MAX_FUNC;} bool add() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING sum_name= {STRING_WITH_LEN("max(") }; return sum_name; } Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_sum_bit :public Item_sum_int { public: Item_sum_bit(THD *thd, Item *item_par, ulonglong reset_arg): Item_sum_int(thd, item_par), reset_bits(reset_arg), bits(reset_arg), as_window_function(FALSE), num_values_added(0) {} Item_sum_bit(THD *thd, Item_sum_bit *item): Item_sum_int(thd, item), reset_bits(item->reset_bits), bits(item->bits), as_window_function(item->as_window_function), num_values_added(item->num_values_added) { if (as_window_function) memcpy(bit_counters, item->bit_counters, sizeof(bit_counters)); } enum Sumfunctype sum_func () const override { return SUM_BIT_FUNC;} void clear() override; longlong val_int() override; void reset_field() override; void update_field() override; const Type_handler *type_handler() const override { return &type_handler_ulonglong; } bool fix_length_and_dec() override { if (args[0]->check_type_can_return_int(func_name_cstring())) return true; decimals= 0; max_length=21; unsigned_flag= 1; base_flags&= ~item_base_t::MAYBE_NULL; null_value= 0; return FALSE; } void cleanup() override { bits= reset_bits; if (as_window_function) clear_as_window(); Item_sum_int::cleanup(); } void setup_window_func(THD *, Window_spec *) override { as_window_function= TRUE; clear_as_window(); } void remove() override { if (as_window_function) { remove_as_window(args[0]->val_int()); return; } // Unless we're counting bits, we can not remove anything. DBUG_ASSERT(0); } bool supports_removal() const override { return true; } protected: enum bit_counters { NUM_BIT_COUNTERS= 64 }; ulonglong reset_bits,bits; /* Marks whether the function is to be computed as a window function. */ bool as_window_function; // When used as an aggregate window function, we need to store // this additional information. ulonglong num_values_added; ulonglong bit_counters[NUM_BIT_COUNTERS]; bool add_as_window(ulonglong value); bool remove_as_window(ulonglong value); bool clear_as_window(); virtual void set_bits_from_counters()= 0; }; class Item_sum_or final :public Item_sum_bit { public: Item_sum_or(THD *thd, Item *item_par): Item_sum_bit(thd, item_par, 0) {} Item_sum_or(THD *thd, Item_sum_or *item) :Item_sum_bit(thd, item) {} bool add() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING sum_name= {STRING_WITH_LEN("bit_or(") }; return sum_name; } Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } private: void set_bits_from_counters() override; }; class Item_sum_and final :public Item_sum_bit { public: Item_sum_and(THD *thd, Item *item_par): Item_sum_bit(thd, item_par, ULONGLONG_MAX) {} Item_sum_and(THD *thd, Item_sum_and *item) :Item_sum_bit(thd, item) {} bool add() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING sum_min_name= {STRING_WITH_LEN("bit_and(") }; return sum_min_name; } Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } private: void set_bits_from_counters() override; }; class Item_sum_xor final :public Item_sum_bit { public: Item_sum_xor(THD *thd, Item *item_par): Item_sum_bit(thd, item_par, 0) {} Item_sum_xor(THD *thd, Item_sum_xor *item) :Item_sum_bit(thd, item) {} bool add() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING sum_min_name= {STRING_WITH_LEN("bit_xor(") }; return sum_min_name; } Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } private: void set_bits_from_counters() override; }; class sp_head; class sp_name; class Query_arena; struct st_sp_security_context; /* Item_sum_sp handles STORED AGGREGATE FUNCTIONS Each Item_sum_sp represents a custom aggregate function. Inside the function's body, we require at least one occurrence of FETCH GROUP NEXT ROW instruction. This cursor is what makes custom stored aggregates possible. During computation the function's add method is called. This in turn performs an execution of the function. The function will execute from the current function context (and instruction), if one exists, or from the start if not. See Item_sp for more details. Upon encounter of FETCH GROUP NEXT ROW instruction, the function will pause execution. We assume that the user has performed the necessary additions for a row, between two encounters of FETCH GROUP NEXT ROW. Example: create aggregate function f1(x INT) returns int begin declare continue handler for not found return s; declare s int default 0 loop fetch group next row; set s = s + x; end loop; end The function will always stop after an encounter of FETCH GROUP NEXT ROW, except (!) on first encounter, as the value for the first row in the group is already set in the argument x. This behaviour is done so when a user writes a function, he should "logically" include FETCH GROUP NEXT ROW before any "add" instructions in the stored function. This means however that internally, the first occurrence doesn't stop the function. See the implementation of FETCH GROUP NEXT ROW for details as to how it happens. Either way, one should assume that after calling "Item_sum_sp::add()" that the values for that particular row have been added to the aggregation. To produce values for val_xxx methods we need an extra syntactic construct. We require a continue handler when "no more rows are available". val_xxx methods force a function return by executing the function again, while setting a server flag that no more rows have been found. This implies that val_xxx methods should only be called once per group however. Example: DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN ret_val; */ class Item_sum_sp :public Item_sum, public Item_sp { private: bool execute(); public: Item_sum_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name, sp_head *sp); Item_sum_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name, sp_head *sp, List &list); Item_sum_sp(THD *thd, Item_sum_sp *item); enum Sumfunctype sum_func () const override { return SP_AGGREGATE_FUNC; } Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) override { return create_table_field_from_handler(root, table); } bool fix_length_and_dec() override; bool fix_fields(THD *thd, Item **ref) override; LEX_CSTRING func_name_cstring() const override; const Type_handler *type_handler() const override; bool add() override; /* val_xx functions */ longlong val_int() override { if(execute()) return 0; return sp_result_field->val_int(); } double val_real() override { if(execute()) return 0.0; return sp_result_field->val_real(); } my_decimal *val_decimal(my_decimal *dec_buf) override { if(execute()) return NULL; return sp_result_field->val_decimal(dec_buf); } bool val_native(THD *thd, Native *to) override { return (null_value= execute()) || sp_result_field->val_native(to); } String *val_str(String *str) override { String buf; char buff[20]; buf.set(buff, 20, str->charset()); buf.length(0); if (execute()) return NULL; /* result_field will set buf pointing to internal buffer of the resul_field. Due to this it will change any time when SP is executed. In order to prevent occasional corruption of returned value, we make here a copy. */ sp_result_field->val_str(&buf); str->copy(buf); return str; } void reset_field() override{DBUG_ASSERT(0);} void update_field() override{DBUG_ASSERT(0);} void clear() override; void cleanup() override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return execute() || sp_result_field->get_date(ltime, fuzzydate); } inline Field *get_sp_result_field() { return sp_result_field; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *copy_or_same(THD *thd) override; }; /* Items to get the value of a stored sum function */ class Item_sum_field :public Item { protected: Field *field; public: Item_sum_field(THD *thd, Item_sum *item) :Item(thd), field(item->result_field) { name= item->name; set_maybe_null(); decimals= item->decimals; max_length= item->max_length; unsigned_flag= item->unsigned_flag; } table_map used_tables() const override { return (table_map) 1L; } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { return create_tmp_field_ex_simple(root, table, src, param); } void save_in_result_field(bool no_conversions) override { DBUG_ASSERT(0); } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(name.str, arg, VCOL_IMPOSSIBLE); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } }; class Item_avg_field :public Item_sum_field { protected: uint prec_increment; public: Item_avg_field(THD *thd, Item_sum_avg *item) :Item_sum_field(thd, item), prec_increment(item->prec_increment) { } enum Type type() const override { return FIELD_AVG_ITEM; } bool is_null() override { update_null_value(); return null_value; } }; class Item_avg_field_double :public Item_avg_field { public: Item_avg_field_double(THD *thd, Item_sum_avg *item) :Item_avg_field(thd, item) { } const Type_handler *type_handler() const override { return &type_handler_double; } longlong val_int() override { return val_int_from_real(); } my_decimal *val_decimal(my_decimal *dec) override { return val_decimal_from_real(dec); } String *val_str(String *str) override { return val_string_from_real(str); } double val_real() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_avg_field_decimal :public Item_avg_field { uint f_precision, f_scale, dec_bin_size; public: Item_avg_field_decimal(THD *thd, Item_sum_avg *item) :Item_avg_field(thd, item), f_precision(item->f_precision), f_scale(item->f_scale), dec_bin_size(item->dec_bin_size) { } const Type_handler *type_handler() const override { return &type_handler_newdecimal; } double val_real() override { return VDec(this).to_double(); } longlong val_int() override { return VDec(this).to_longlong(unsigned_flag); } String *val_str(String *str) override { return VDec(this).to_string_round(str, decimals); } my_decimal *val_decimal(my_decimal *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_variance_field :public Item_sum_field { uint sample; public: Item_variance_field(THD *thd, Item_sum_variance *item) :Item_sum_field(thd, item), sample(item->sample) { } enum Type type() const override {return FIELD_VARIANCE_ITEM; } double val_real() override; longlong val_int() override { return val_int_from_real(); } String *val_str(String *str) override { return val_string_from_real(str); } my_decimal *val_decimal(my_decimal *dec_buf) override { return val_decimal_from_real(dec_buf); } bool is_null() override { update_null_value(); return null_value; } const Type_handler *type_handler() const override { return &type_handler_double; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_std_field :public Item_variance_field { public: Item_std_field(THD *thd, Item_sum_std *item) :Item_variance_field(thd, item) { } enum Type type() const override { return FIELD_STD_ITEM; } double val_real() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /* User defined aggregates */ #ifdef HAVE_DLOPEN class Item_udf_sum : public Item_sum { protected: udf_handler udf; public: Item_udf_sum(THD *thd, udf_func *udf_arg): Item_sum(thd), udf(udf_arg) { quick_group=0; } Item_udf_sum(THD *thd, udf_func *udf_arg, List &list): Item_sum(thd, list), udf(udf_arg) { quick_group=0;} Item_udf_sum(THD *thd, Item_udf_sum *item) :Item_sum(thd, item), udf(item->udf) { udf.not_original= TRUE; } LEX_CSTRING func_name_cstring() const override { const char *tmp= udf.name(); return {tmp, strlen(tmp) }; } bool fix_fields(THD *thd, Item **ref) override { DBUG_ASSERT(fixed() == 0); if (init_sum_func_check(thd)) return TRUE; base_flags|= item_base_t::FIXED; /* We set const_item_cache to false in constructors. It can be later changed to "true", in a Item_sum::make_const() call. No make_const() calls should have happened so far. */ DBUG_ASSERT(!const_item_cache); if (udf.fix_fields(thd, this, this->arg_count, this->args)) return TRUE; /** The above call for udf.fix_fields() updates the Used_tables_and_const_cache part of "this" as if it was a regular non-aggregate UDF function and can change both const_item_cache and used_tables_cache members. - The used_tables_cache will be re-calculated in update_used_tables() which is called from check_sum_func() below. So we don't care about its current value. - The const_item_cache must stay "false" until a Item_sum::make_const() call happens, if ever. So we need to reset const_item_cache back to "false" here. */ const_item_cache= false; memcpy (orig_args, args, sizeof (Item *) * arg_count); return check_sum_func(thd, ref); } enum Sumfunctype sum_func () const override { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } void clear() override; bool add() override; bool supports_removal() const override; void remove() override; void reset_field() override {}; void update_field() override {} void cleanup() override; void print(String *str, enum_query_type query_type) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } }; class Item_sum_udf_float :public Item_udf_sum { public: Item_sum_udf_float(THD *thd, udf_func *udf_arg): Item_udf_sum(thd, udf_arg) {} Item_sum_udf_float(THD *thd, udf_func *udf_arg, List &list): Item_udf_sum(thd, udf_arg, list) {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_udf_sum(thd, item) {} longlong val_int() override { return val_int_from_real(); } double val_real() override; String *val_str(String*str) override; my_decimal *val_decimal(my_decimal *) override; const Type_handler *type_handler() const override { return &type_handler_double; } bool fix_length_and_dec() override { fix_num_length_and_dec(); return FALSE; } Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_sum_udf_int :public Item_udf_sum { public: Item_sum_udf_int(THD *thd, udf_func *udf_arg): Item_udf_sum(thd, udf_arg) {} Item_sum_udf_int(THD *thd, udf_func *udf_arg, List &list): Item_udf_sum(thd, udf_arg, list) {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_udf_sum(thd, item) {} longlong val_int() override; double val_real() override { DBUG_ASSERT(fixed()); return (double) Item_sum_udf_int::val_int(); } String *val_str(String*str) override; my_decimal *val_decimal(my_decimal *) override; const Type_handler *type_handler() const override { if (unsigned_flag) return &type_handler_ulonglong; return &type_handler_slonglong; } bool fix_length_and_dec() override { decimals=0; max_length=21; return FALSE; } Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_sum_udf_str :public Item_udf_sum { public: Item_sum_udf_str(THD *thd, udf_func *udf_arg): Item_udf_sum(thd, udf_arg) {} Item_sum_udf_str(THD *thd, udf_func *udf_arg, List &list): Item_udf_sum(thd, udf_arg, list) {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) :Item_udf_sum(thd, item) {} String *val_str(String *) override; double val_real() override { int err_not_used; char *end_not_used; String *res; res=val_str(&str_value); return res ? res->charset()->strntod((char*) res->ptr(),res->length(), &end_not_used, &err_not_used) : 0.0; } longlong val_int() override { int err_not_used; char *end; String *res; CHARSET_INFO *cs; if (!(res= val_str(&str_value))) return 0; /* Null value */ cs= res->charset(); end= (char*) res->ptr()+res->length(); return cs->strtoll10(res->ptr(), &end, &err_not_used); } my_decimal *val_decimal(my_decimal *dec) override; const Type_handler *type_handler() const override { return string_type_handler(); } bool fix_length_and_dec() override; Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_sum_udf_decimal :public Item_udf_sum { public: Item_sum_udf_decimal(THD *thd, udf_func *udf_arg): Item_udf_sum(thd, udf_arg) {} Item_sum_udf_decimal(THD *thd, udf_func *udf_arg, List &list): Item_udf_sum(thd, udf_arg, list) {} Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item) :Item_udf_sum(thd, item) {} String *val_str(String *str) override { return VDec(this).to_string_round(str, decimals); } double val_real() override { return VDec(this).to_double(); } longlong val_int() override { return VDec(this).to_longlong(unsigned_flag); } my_decimal *val_decimal(my_decimal *) override; const Type_handler *type_handler() const override { return &type_handler_newdecimal; } bool fix_length_and_dec() override { fix_num_length_and_dec(); return FALSE; } Item *copy_or_same(THD* thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #else /* Dummy functions to get yy_*.cc files compiled */ class Item_sum_udf_float :public Item_sum_double { public: Item_sum_udf_float(THD *thd, udf_func *udf_arg): Item_sum_double(thd) {} Item_sum_udf_float(THD *thd, udf_func *udf_arg, List &list): Item_sum_double(thd) {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_sum_double(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val_real() { DBUG_ASSERT(fixed()); return 0.0; } void clear() {} bool add() { return 0; } void reset_field() { DBUG_ASSERT(0); }; void update_field() {} }; class Item_sum_udf_int :public Item_sum_double { public: Item_sum_udf_int(THD *thd, udf_func *udf_arg): Item_sum_double(thd) {} Item_sum_udf_int(THD *thd, udf_func *udf_arg, List &list): Item_sum_double(thd) {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_sum_double(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } longlong val_int() { DBUG_ASSERT(fixed()); return 0; } double val_real() { DBUG_ASSERT(fixed()); return 0; } void clear() {} bool add() { return 0; } void reset_field() { DBUG_ASSERT(0); }; void update_field() {} }; class Item_sum_udf_decimal :public Item_sum_double { public: Item_sum_udf_decimal(THD *thd, udf_func *udf_arg): Item_sum_double(thd) {} Item_sum_udf_decimal(THD *thd, udf_func *udf_arg, List &list): Item_sum_double(thd) {} Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item) :Item_sum_double(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val_real() { DBUG_ASSERT(fixed()); return 0.0; } my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed()); return 0; } void clear() {} bool add() { return 0; } void reset_field() { DBUG_ASSERT(0); }; void update_field() {} }; class Item_sum_udf_str :public Item_sum_double { public: Item_sum_udf_str(THD *thd, udf_func *udf_arg): Item_sum_double(thd) {} Item_sum_udf_str(THD *thd, udf_func *udf_arg, List &list): Item_sum_double(thd) {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) :Item_sum_double(thd, item) {} String *val_str(String *) { DBUG_ASSERT(fixed()); null_value=1; return 0; } double val_real() { DBUG_ASSERT(fixed()); null_value=1; return 0.0; } longlong val_int() { DBUG_ASSERT(fixed()); null_value=1; return 0; } bool fix_length_and_dec() override { base_flags|= item_base_t::MAYBE_NULL; max_length=0; return FALSE; } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } void clear() {} bool add() { return 0; } void reset_field() { DBUG_ASSERT(0); }; void update_field() {} }; #endif /* HAVE_DLOPEN */ C_MODE_START int group_concat_key_cmp_with_distinct(void *arg, const void *key1, const void *key2); int group_concat_key_cmp_with_distinct_with_nulls(void *arg, const void *key1, const void *key2); int group_concat_key_cmp_with_order(void *arg, const void *key1, const void *key2); int group_concat_key_cmp_with_order_with_nulls(void *arg, const void *key1, const void *key2); int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), void* item_arg); C_MODE_END class Item_func_group_concat : public Item_sum { protected: TMP_TABLE_PARAM *tmp_table_param; String result; String *separator; TREE tree_base; TREE *tree; size_t tree_len; Item **ref_pointer_array; /** If DISTINCT is used with this GROUP_CONCAT, this member is used to filter out duplicates. @see Item_func_group_concat::setup @see Item_func_group_concat::add @see Item_func_group_concat::clear */ Unique *unique_filter; TABLE *table; ORDER **order; Name_resolution_context *context; /** The number of ORDER BY items. */ uint arg_count_order; /** The number of selected items, aka the expr list. */ uint arg_count_field; uint row_count; bool distinct; bool warning_for_row; bool always_null; bool force_copy_fields; /** True if entire result of GROUP_CONCAT has been written to output buffer. */ bool result_finalized; /** Limits the rows in the result */ Item *row_limit; /** Skips a particular number of rows in from the result*/ Item *offset_limit; bool limit_clause; /* copy of the offset limit */ ulonglong copy_offset_limit; /*copy of the row limit */ ulonglong copy_row_limit; /* Following is 0 normal object and pointer to original one for copy (to correctly free resources) */ Item_func_group_concat *original; /* Used by Item_func_group_concat and Item_func_json_arrayagg. The latter needs null values but the former doesn't. */ bool add(bool exclude_nulls); friend int group_concat_key_cmp_with_distinct(void *arg, const void *key1, const void *key2); friend int group_concat_key_cmp_with_distinct_with_nulls(void *arg, const void *key1, const void *key2); friend int group_concat_key_cmp_with_order(void *arg, const void *key1, const void *key2); friend int group_concat_key_cmp_with_order_with_nulls(void *arg, const void *key1, const void *key2); friend int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), void* item_arg); bool repack_tree(THD *thd); /* Says whether the function should skip NULL arguments or add them to the result. Redefined in JSON_ARRAYAGG. */ virtual bool skip_nulls() const { return true; } virtual String *get_str_from_item(Item *i, String *tmp) { return i->val_str(tmp); } virtual String *get_str_from_field(Item *i, Field *f, String *tmp, const uchar *key, size_t offset) { return f->val_str(tmp, key + offset); } virtual void cut_max_length(String *result, uint old_length, uint max_length) const; bool uses_non_standard_aggregator_for_distinct() const override { return distinct; } public: // Methods used by ColumnStore bool get_distinct() const { return distinct; } uint get_count_field() const { return arg_count_field; } uint get_order_field() const { return arg_count_order; } const String* get_separator() const { return separator; } ORDER** get_order() const { return order; } public: Item_func_group_concat(THD *thd, Name_resolution_context *context_arg, bool is_distinct, List *is_select, const SQL_I_List &is_order, String *is_separator, bool limit_clause, Item *row_limit, Item *offset_limit); Item_func_group_concat(THD *thd, Item_func_group_concat *item); ~Item_func_group_concat(); void cleanup() override; enum Sumfunctype sum_func () const override {return GROUP_CONCAT_FUNC;} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING sum_name= {STRING_WITH_LEN("group_concat(") }; return sum_name; } const Type_handler *type_handler() const override { if (too_big_for_varchar()) return &type_handler_blob; return &type_handler_varchar; } void clear() override; bool add() override { return add(skip_nulls()); } void reset_field() override { DBUG_ASSERT(0); } // not used void update_field() override { DBUG_ASSERT(0); } // not used bool fix_fields(THD *,Item **) override; bool setup(THD *thd) override; void make_unique() override; double val_real() override { int error; const char *end; String *res; if (!(res= val_str(&str_value))) return 0.0; end= res->ptr() + res->length(); return (my_strtod(res->ptr(), (char**) &end, &error)); } longlong val_int() override { String *res; char *end_ptr; int error; if (!(res= val_str(&str_value))) return (longlong) 0; end_ptr= (char*) res->ptr()+ res->length(); return my_strtoll10(res->ptr(), &end_ptr, &error); } my_decimal *val_decimal(my_decimal *decimal_value) override { return val_decimal_from_string(decimal_value); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_string(thd, ltime, fuzzydate); } String *val_str(String *str) override; Item *copy_or_same(THD* thd) override; void no_rows_in_result() override {} void print(String *str, enum_query_type query_type) override; bool change_context_processor(void *cntx) override { context= (Name_resolution_context *)cntx; return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } qsort_cmp2 get_comparator_function_for_distinct(); qsort_cmp2 get_comparator_function_for_order_by(); uchar* get_record_pointer(); uint get_null_bytes(); }; #endif /* ITEM_SUM_INCLUDED */ server/private/des_key_file.h000064400000002324151031265040012315 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef DES_KEY_FILE_INCLUDED #define DES_KEY_FILE_INCLUDED #ifdef HAVE_des #include #include "violite.h" /* DES_cblock, DES_key_schedule */ struct st_des_keyblock { DES_cblock key1, key2, key3; }; struct st_des_keyschedule { DES_key_schedule ks1, ks2, ks3; }; extern struct st_des_keyschedule des_keyschedule[10]; extern uint des_default_key; bool load_des_key_file(const char *file_name); #endif /* HAVE_des */ #endif /* DES_KEY_FILE_INCLUDED */ server/private/sp.h000064400000054074151031265040010326 0ustar00/* -*- C++ -*- */ /* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2009, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _SP_H_ #define _SP_H_ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_string.h" // LEX_STRING #include "sql_cmd.h" #include "mdl.h" class Field; class Open_tables_backup; class Open_tables_state; class Query_arena; class Query_tables_list; class Sroutine_hash_entry; class THD; class sp_cache; class sp_head; class sp_package; class sp_pcontext; class sp_name; class Database_qualified_name; struct st_sp_chistics; class Stored_program_creation_ctx; struct LEX; struct TABLE; struct TABLE_LIST; typedef struct st_hash HASH; template class SQL_I_List; /* Values for the type enum. This reflects the order of the enum declaration in the CREATE TABLE command. See also storage/perfschema/my_thread.h */ enum enum_sp_type { SP_TYPE_FUNCTION=1, SP_TYPE_PROCEDURE=2, SP_TYPE_PACKAGE=3, SP_TYPE_PACKAGE_BODY=4, SP_TYPE_TRIGGER=5, SP_TYPE_EVENT=6, }; class Sp_handler { bool sp_resolve_package_routine_explicit(THD *thd, sp_head *caller, sp_name *name, const Sp_handler **pkg_routine_hndlr, Database_qualified_name *pkgname) const; bool sp_resolve_package_routine_implicit(THD *thd, sp_head *caller, sp_name *name, const Sp_handler **pkg_routine_hndlr, Database_qualified_name *pkgname) const; protected: int db_find_routine_aux(THD *thd, const Database_qualified_name *name, TABLE *table) const; int db_find_routine(THD *thd, const Database_qualified_name *name, sp_head **sphp) const; int db_find_and_cache_routine(THD *thd, const Database_qualified_name *name, sp_head **sp) const; int db_load_routine(THD *thd, const Database_qualified_name *name, sp_head **sphp, sql_mode_t sql_mode, const LEX_CSTRING ¶ms, const LEX_CSTRING &returns, const LEX_CSTRING &body, const st_sp_chistics &chistics, const AUTHID &definer, longlong created, longlong modified, sp_package *parent, Stored_program_creation_ctx *creation_ctx) const; int sp_drop_routine_internal(THD *thd, const Database_qualified_name *name, TABLE *table) const; sp_head *sp_clone_and_link_routine(THD *thd, const Database_qualified_name *name, sp_head *sp) const; int sp_cache_package_routine(THD *thd, const LEX_CSTRING &pkgname_cstr, const Database_qualified_name *name, sp_head **sp) const; int sp_cache_package_routine(THD *thd, const Database_qualified_name *name, sp_head **sp) const; sp_head *sp_find_package_routine(THD *thd, const LEX_CSTRING pkgname_str, const Database_qualified_name *name, bool cache_only) const; sp_head *sp_find_package_routine(THD *thd, const Database_qualified_name *name, bool cache_only) const; public: // TODO: make it private or protected virtual int sp_find_and_drop_routine(THD *thd, TABLE *table, const Database_qualified_name *name) const; public: virtual ~Sp_handler() = default; static const Sp_handler *handler(enum enum_sql_command cmd); static const Sp_handler *handler(enum_sp_type type); static const Sp_handler *handler(MDL_key::enum_mdl_namespace ns); /* Return a handler only those SP objects that store definitions in the mysql.proc system table */ static const Sp_handler *handler_mysql_proc(enum_sp_type type) { const Sp_handler *sph= handler(type); return sph ? sph->sp_handler_mysql_proc() : NULL; } static bool eq_routine_name(const LEX_CSTRING &name1, const LEX_CSTRING &name2) { return system_charset_info->strnncoll(name1.str, name1.length, name2.str, name2.length) == 0; } const char *type_str() const { return type_lex_cstring().str; } virtual const char *show_create_routine_col1_caption() const { DBUG_ASSERT(0); return ""; } virtual const char *show_create_routine_col3_caption() const { DBUG_ASSERT(0); return ""; } virtual const Sp_handler *package_routine_handler() const { return this; } virtual enum_sp_type type() const= 0; virtual LEX_CSTRING type_lex_cstring() const= 0; virtual LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const { static LEX_CSTRING m_empty_body= {STRING_WITH_LEN("???")}; DBUG_ASSERT(0); return m_empty_body; } virtual MDL_key::enum_mdl_namespace get_mdl_type() const= 0; virtual const Sp_handler *sp_handler_mysql_proc() const { return this; } virtual sp_cache **get_cache(THD *) const { return NULL; } #ifndef NO_EMBEDDED_ACCESS_CHECKS virtual HASH *get_priv_hash() const { return NULL; } #endif virtual ulong recursion_depth(THD *thd) const { return 0; } /** Return appropriate error about recursion limit reaching @param thd Thread handle @param sp SP routine @remark For functions and triggers we return error about prohibited recursion. For stored procedures we return about reaching recursion limit. */ virtual void recursion_level_error(THD *thd, const sp_head *sp) const { my_error(ER_SP_NO_RECURSION, MYF(0)); } virtual bool add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont, Item *item, LEX *lex) const; virtual bool add_instr_preturn(THD *thd, sp_head *sp, sp_pcontext *spcont) const; void add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena, const Database_qualified_name *name) const; bool sp_resolve_package_routine(THD *thd, sp_head *caller, sp_name *name, const Sp_handler **pkg_routine_handler, Database_qualified_name *pkgname) const; virtual sp_head *sp_find_routine(THD *thd, const Database_qualified_name *name, bool cache_only) const; virtual int sp_cache_routine(THD *thd, const Database_qualified_name *name, sp_head **sp) const; int sp_cache_routine_reentrant(THD *thd, const Database_qualified_name *nm, sp_head **sp) const; bool sp_exist_routines(THD *thd, TABLE_LIST *procs) const; bool sp_show_create_routine(THD *thd, const Database_qualified_name *name) const; bool sp_create_routine(THD *thd, const sp_head *sp) const; int sp_update_routine(THD *thd, const Database_qualified_name *name, const st_sp_chistics *chistics) const; int sp_drop_routine(THD *thd, const Database_qualified_name *name) const; sp_head *sp_load_for_information_schema(THD *thd, TABLE *proc_table, const LEX_CSTRING &db, const LEX_CSTRING &name, const LEX_CSTRING ¶ms, const LEX_CSTRING &returns, sql_mode_t sql_mode, bool *free_sp_head) const; /* Make a SHOW CREATE statement. @retval true on error @retval false on success */ virtual bool show_create_sp(THD *thd, String *buf, const LEX_CSTRING &db, const LEX_CSTRING &name, const LEX_CSTRING ¶ms, const LEX_CSTRING &returns, const LEX_CSTRING &body, const st_sp_chistics &chistics, const AUTHID &definer, const DDL_options_st ddl_options, sql_mode_t sql_mode) const; }; class Sp_handler_procedure: public Sp_handler { public: enum_sp_type type() const override { return SP_TYPE_PROCEDURE; } LEX_CSTRING type_lex_cstring() const override { static LEX_CSTRING m_type_str= { STRING_WITH_LEN("PROCEDURE")}; return m_type_str; } LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const override; const char *show_create_routine_col1_caption() const override { return "Procedure"; } const char *show_create_routine_col3_caption() const override { return "Create Procedure"; } MDL_key::enum_mdl_namespace get_mdl_type() const override { return MDL_key::PROCEDURE; } const Sp_handler *package_routine_handler() const override; sp_cache **get_cache(THD *) const override; #ifndef NO_EMBEDDED_ACCESS_CHECKS HASH *get_priv_hash() const override; #endif ulong recursion_depth(THD *thd) const override; void recursion_level_error(THD *thd, const sp_head *sp) const override; bool add_instr_preturn(THD *thd, sp_head *sp, sp_pcontext *spcont) const override; }; class Sp_handler_package_procedure: public Sp_handler_procedure { public: int sp_cache_routine(THD *thd, const Database_qualified_name *name, sp_head **sp) const override { return sp_cache_package_routine(thd, name, sp); } sp_head *sp_find_routine(THD *thd, const Database_qualified_name *name, bool cache_only) const override { return sp_find_package_routine(thd, name, cache_only); } }; class Sp_handler_function: public Sp_handler { public: enum_sp_type type() const override { return SP_TYPE_FUNCTION; } LEX_CSTRING type_lex_cstring() const override { static LEX_CSTRING m_type_str= { STRING_WITH_LEN("FUNCTION")}; return m_type_str; } LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const override; const char *show_create_routine_col1_caption() const override { return "Function"; } const char *show_create_routine_col3_caption() const override { return "Create Function"; } MDL_key::enum_mdl_namespace get_mdl_type() const override { return MDL_key::FUNCTION; } const Sp_handler *package_routine_handler() const override; sp_cache **get_cache(THD *) const override; #ifndef NO_EMBEDDED_ACCESS_CHECKS HASH *get_priv_hash() const override; #endif bool add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont, Item *item, LEX *lex) const override; }; class Sp_handler_package_function: public Sp_handler_function { public: int sp_cache_routine(THD *thd, const Database_qualified_name *name, sp_head **sp) const override { return sp_cache_package_routine(thd, name, sp); } sp_head *sp_find_routine(THD *thd, const Database_qualified_name *name, bool cache_only) const override { return sp_find_package_routine(thd, name, cache_only); } }; class Sp_handler_package: public Sp_handler { public: bool show_create_sp(THD *thd, String *buf, const LEX_CSTRING &db, const LEX_CSTRING &name, const LEX_CSTRING ¶ms, const LEX_CSTRING &returns, const LEX_CSTRING &body, const st_sp_chistics &chistics, const AUTHID &definer, const DDL_options_st ddl_options, sql_mode_t sql_mode) const override; }; class Sp_handler_package_spec: public Sp_handler_package { public: // TODO: make it private or protected int sp_find_and_drop_routine(THD *thd, TABLE *table, const Database_qualified_name *name) const override; public: enum_sp_type type() const override { return SP_TYPE_PACKAGE; } LEX_CSTRING type_lex_cstring() const override { static LEX_CSTRING m_type_str= {STRING_WITH_LEN("PACKAGE")}; return m_type_str; } LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const override { static LEX_CSTRING m_empty_body= {STRING_WITH_LEN("BEGIN END")}; return m_empty_body; } const char *show_create_routine_col1_caption() const override { return "Package"; } const char *show_create_routine_col3_caption() const override { return "Create Package"; } MDL_key::enum_mdl_namespace get_mdl_type() const override { return MDL_key::PACKAGE_BODY; } sp_cache **get_cache(THD *) const override; #ifndef NO_EMBEDDED_ACCESS_CHECKS HASH *get_priv_hash() const override; #endif }; class Sp_handler_package_body: public Sp_handler_package { public: enum_sp_type type() const override { return SP_TYPE_PACKAGE_BODY; } LEX_CSTRING type_lex_cstring() const override { static LEX_CSTRING m_type_str= {STRING_WITH_LEN("PACKAGE BODY")}; return m_type_str; } LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const override { static LEX_CSTRING m_empty_body= {STRING_WITH_LEN("BEGIN END")}; return m_empty_body; } const char *show_create_routine_col1_caption() const override { return "Package body"; } const char *show_create_routine_col3_caption() const override { return "Create Package Body"; } MDL_key::enum_mdl_namespace get_mdl_type() const override { return MDL_key::PACKAGE_BODY; } sp_cache **get_cache(THD *) const override; #ifndef NO_EMBEDDED_ACCESS_CHECKS HASH *get_priv_hash() const override; #endif }; class Sp_handler_trigger: public Sp_handler { public: enum_sp_type type() const override { return SP_TYPE_TRIGGER; } LEX_CSTRING type_lex_cstring() const override { static LEX_CSTRING m_type_str= { STRING_WITH_LEN("TRIGGER")}; return m_type_str; } MDL_key::enum_mdl_namespace get_mdl_type() const override { DBUG_ASSERT(0); return MDL_key::TRIGGER; } const Sp_handler *sp_handler_mysql_proc() const override { return NULL; } }; extern MYSQL_PLUGIN_IMPORT Sp_handler_function sp_handler_function; extern MYSQL_PLUGIN_IMPORT Sp_handler_procedure sp_handler_procedure; extern MYSQL_PLUGIN_IMPORT Sp_handler_package_spec sp_handler_package_spec; extern MYSQL_PLUGIN_IMPORT Sp_handler_package_body sp_handler_package_body; extern MYSQL_PLUGIN_IMPORT Sp_handler_package_function sp_handler_package_function; extern MYSQL_PLUGIN_IMPORT Sp_handler_package_procedure sp_handler_package_procedure; extern MYSQL_PLUGIN_IMPORT Sp_handler_trigger sp_handler_trigger; inline const Sp_handler *Sp_handler::handler(enum_sql_command cmd) { switch (cmd) { case SQLCOM_CREATE_PROCEDURE: case SQLCOM_ALTER_PROCEDURE: case SQLCOM_DROP_PROCEDURE: case SQLCOM_SHOW_PROC_CODE: case SQLCOM_SHOW_CREATE_PROC: case SQLCOM_SHOW_STATUS_PROC: return &sp_handler_procedure; case SQLCOM_CREATE_SPFUNCTION: case SQLCOM_ALTER_FUNCTION: case SQLCOM_DROP_FUNCTION: case SQLCOM_SHOW_FUNC_CODE: case SQLCOM_SHOW_CREATE_FUNC: case SQLCOM_SHOW_STATUS_FUNC: return &sp_handler_function; case SQLCOM_CREATE_PACKAGE: case SQLCOM_DROP_PACKAGE: case SQLCOM_SHOW_CREATE_PACKAGE: case SQLCOM_SHOW_STATUS_PACKAGE: return &sp_handler_package_spec; case SQLCOM_CREATE_PACKAGE_BODY: case SQLCOM_DROP_PACKAGE_BODY: case SQLCOM_SHOW_CREATE_PACKAGE_BODY: case SQLCOM_SHOW_STATUS_PACKAGE_BODY: case SQLCOM_SHOW_PACKAGE_BODY_CODE: return &sp_handler_package_body; default: break; } return NULL; } inline const Sp_handler *Sp_handler::handler(enum_sp_type type) { switch (type) { case SP_TYPE_PROCEDURE: return &sp_handler_procedure; case SP_TYPE_FUNCTION: return &sp_handler_function; case SP_TYPE_PACKAGE: return &sp_handler_package_spec; case SP_TYPE_PACKAGE_BODY: return &sp_handler_package_body; case SP_TYPE_TRIGGER: return &sp_handler_trigger; case SP_TYPE_EVENT: break; } return NULL; } inline const Sp_handler *Sp_handler::handler(MDL_key::enum_mdl_namespace type) { switch (type) { case MDL_key::FUNCTION: return &sp_handler_function; case MDL_key::PROCEDURE: return &sp_handler_procedure; case MDL_key::PACKAGE_BODY: return &sp_handler_package_body; case MDL_key::BACKUP: case MDL_key::SCHEMA: case MDL_key::TABLE: case MDL_key::TRIGGER: case MDL_key::EVENT: case MDL_key::USER_LOCK: case MDL_key::NAMESPACE_END: break; } return NULL; } /* Tells what SP_DEFAULT_ACCESS should be mapped to */ #define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL // Return codes from sp_create_*, sp_drop_*, and sp_show_*: #define SP_OK 0 #define SP_KEY_NOT_FOUND -1 #define SP_OPEN_TABLE_FAILED -2 #define SP_WRITE_ROW_FAILED -3 #define SP_DELETE_ROW_FAILED -4 #define SP_GET_FIELD_FAILED -5 #define SP_PARSE_ERROR -6 #define SP_INTERNAL_ERROR -7 #define SP_NO_DB_ERROR -8 #define SP_BAD_IDENTIFIER -9 #define SP_BODY_TOO_LONG -10 #define SP_FLD_STORE_FAILED -11 /* DB storage of Stored PROCEDUREs and FUNCTIONs */ enum { MYSQL_PROC_FIELD_DB = 0, MYSQL_PROC_FIELD_NAME, MYSQL_PROC_MYSQL_TYPE, MYSQL_PROC_FIELD_SPECIFIC_NAME, MYSQL_PROC_FIELD_LANGUAGE, MYSQL_PROC_FIELD_ACCESS, MYSQL_PROC_FIELD_DETERMINISTIC, MYSQL_PROC_FIELD_SECURITY_TYPE, MYSQL_PROC_FIELD_PARAM_LIST, MYSQL_PROC_FIELD_RETURNS, MYSQL_PROC_FIELD_BODY, MYSQL_PROC_FIELD_DEFINER, MYSQL_PROC_FIELD_CREATED, MYSQL_PROC_FIELD_MODIFIED, MYSQL_PROC_FIELD_SQL_MODE, MYSQL_PROC_FIELD_COMMENT, MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT, MYSQL_PROC_FIELD_COLLATION_CONNECTION, MYSQL_PROC_FIELD_DB_COLLATION, MYSQL_PROC_FIELD_BODY_UTF8, MYSQL_PROC_FIELD_AGGREGATE, MYSQL_PROC_FIELD_COUNT }; /* Drop all routines in database 'db' */ int sp_drop_db_routines(THD *thd, const char *db); /** Acquires exclusive metadata lock on all stored routines in the given database. @param thd Thread handler @param db Database name @retval false Success @retval true Failure */ bool lock_db_routines(THD *thd, const char *db); /** Structure that represents element in the set of stored routines used by statement or routine. */ class Sroutine_hash_entry { public: /** Metadata lock request for routine. MDL_key in this request is also used as a key for set. */ MDL_request mdl_request; /** Next element in list linking all routines in set. See also comments for LEX::sroutine/sroutine_list and sp_head::m_sroutines. */ Sroutine_hash_entry *next; /** Uppermost view which directly or indirectly uses this routine. 0 if routine is not used in view. Note that it also can be 0 if statement uses routine both via view and directly. */ TABLE_LIST *belong_to_view; /** This is for prepared statement validation purposes. A statement looks up and pre-loads all its stored functions at prepare. Later on, if a function is gone from the cache, execute may fail. Remember the version of sp_head at prepare to be able to invalidate the prepared statement at execute if it changes. */ ulong m_sp_cache_version; const Sp_handler *m_handler; int sp_cache_routine(THD *thd, sp_head **sp) const; }; bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena, const MDL_key *key, const Sp_handler *handler, TABLE_LIST *belong_to_view); void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx); bool sp_update_sp_used_routines(HASH *dst, HASH *src); void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx, HASH *src, TABLE_LIST *belong_to_view); void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx, SQL_I_List *src, TABLE_LIST *belong_to_view); extern "C" const uchar *sp_sroutine_key(const void *ptr, size_t *plen, my_bool); /* Routines which allow open/lock and close mysql.proc table even when we already have some tables open and locked. */ TABLE *open_proc_table_for_read(THD *thd); bool load_charset(THD *thd, MEM_ROOT *mem_root, Field *field, CHARSET_INFO *dflt_cs, CHARSET_INFO **cs); bool load_collation(THD *thd,MEM_ROOT *mem_root, Field *field, CHARSET_INFO *dflt_cl, CHARSET_INFO **cl); void sp_returns_type(THD *thd, String &result, const sp_head *sp); #endif /* _SP_H_ */ server/private/my_handler_errors.h000064400000011422151031265040013410 0ustar00#ifndef MYSYS_MY_HANDLER_ERRORS_INCLUDED #define MYSYS_MY_HANDLER_ERRORS_INCLUDED /* Copyright (c) 2008, 2013, Oracle and/or its affiliates. Copyright (c) 2011, 2013, SkySQL Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Errors a handler can give you */ static const char *handler_error_messages[]= { /* 120 */ "Didn't find the key on read or update", "Duplicate key on write or update", "Internal (unspecified) error in handler", "Someone has changed the row since it was read (even though the table was locked to prevent it)", "Wrong index given to a function", "Undefined handler error 125", "Index is corrupted", "Table file is corrupted", "Out of memory in engine", "Undefined handler error 129", /* 130 */ "Incorrect file format", "Command not supported by the engine", "Old database file", "No record read before update", "Record was already deleted (or record file crashed)", "No more room in record file", "No more room in index file", "No more records (read after end of file)", "Unsupported extension used for table", "Too big row", /* 140 */ "Wrong create options", "Duplicate unique key on write or update", "Unknown character set used in table", "Conflicting table definitions in sub-tables of MERGE table", "Table is crashed and last repair failed", "Table was marked as crashed and should be repaired", "Lock timed out; Retry transaction", "Lock table is full; Restart program with a larger lock table", "Updates are not allowed under a read only transactions", "Lock deadlock; Retry transaction", /* 150 */ "Foreign key constraint is incorrectly formed", "Cannot add a child row", "Cannot delete a parent row", "No savepoint with that name", "Non unique key block size", "The table does not exist in the storage engine", "The table already existed in the storage engine", "Could not connect to the storage engine", "Unexpected null pointer found when using spatial index", "The table changed in the storage engine", /* 160 */ "There's no partition in the table for the given value", "Row-based binary logging of row failed", "Index needed in foreign key constraint", "Upholding foreign key constraints would lead to a duplicate key error in some other table", "Table needs to be upgraded before it can be used", "Table is read only", "Failed to get next auto increment value", "Failed to set row auto increment value", "Unknown (generic) error from engine", "Record was not updated. New values were the same as original values", /* 170 */ "It is not possible to log this statement", "The event was corrupt, leading to illegal data being read", "The table is of a new format not supported by this version", "The event could not be processed. No other handler error happened", "Fatal error during initialization of handler", "File too short; Expected more data in file", "Read page with wrong checksum", "Too many active concurrent transactions", "Record not matching the given partition set", "Index column length exceeds limit", /* 180 */ "Index corrupted", "Undo record too big", "Invalid InnoDB FTS Doc ID", "Table is being used in foreign key check", "Tablespace already exists", "Too many columns", "Row in wrong partition", "Row is not visible by the current transaction", "Operation was interrupted by end user (probably kill command?)", "Disk full", /* 190 */ "Incompatible key or row definition between the MariaDB .frm file and the information in the storage engine. You may have retry or dump and restore the table to fix this", "Too many words in a FTS phrase or proximity search", "Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.", "Foreign key cascade delete/update exceeds max depth", "Tablespace is missing for a table", "Sequence has been run out", "Sequence values are conflicting", "Error during commit", "Cannot select partitions", "Cannot initialize encryption. Check that all encryption parameters have been set", "Transaction was aborted", }; #endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */ server/private/log_event_data_type.h000064400000003542151031265040013712 0ustar00/* Copyright (c) 2024, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef LOG_EVENT_DATA_TYPE_H #define LOG_EVENT_DATA_TYPE_H class Log_event_data_type { public: enum { CHUNK_SIGNED= 0, CHUNK_UNSIGNED= 1, CHUNK_DATA_TYPE_NAME= 2 }; protected: LEX_CSTRING m_data_type_name; Item_result m_type; uint m_charset_number; bool m_is_unsigned; public: Log_event_data_type() :m_data_type_name({NULL,0}), m_type(STRING_RESULT), m_charset_number(my_charset_bin.number), m_is_unsigned(false) { } Log_event_data_type(const LEX_CSTRING &data_type_name_arg, Item_result type_arg, uint charset_number_arg, bool is_unsigned_arg) :m_data_type_name(data_type_name_arg), m_type(type_arg), m_charset_number(charset_number_arg), m_is_unsigned(is_unsigned_arg) { } const LEX_CSTRING & data_type_name() const { return m_data_type_name; } Item_result type() const { return m_type; } uint charset_number() const { return m_charset_number; } bool is_unsigned() const { return m_is_unsigned; } bool unpack_optional_attributes(const char *str, const char *end); }; #endif // LOG_EVENT_DATA_TYPE_H server/private/log_event_old.h000064400000046566151031265040012533 0ustar00/* Copyright (c) 2007, 2013, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef LOG_EVENT_OLD_H #define LOG_EVENT_OLD_H /* Need to include this file at the proper position of log_event.h */ /** @file @brief This file contains classes handling old formats of row-based binlog events. */ /* Around 2007-10-31, I made these classes completely separated from the new classes (before, there was a complex class hierarchy involving multiple inheritance; see BUG#31581), by simply copying and pasting the entire contents of Rows_log_event into Old_rows_log_event and the entire contents of {Write|Update|Delete}_rows_log_event into {Write|Update|Delete}_rows_log_event_old. For clarity, I will keep the comments marking which code was cut-and-pasted for some time. With the classes collapsed into one, there is probably some redundancy (maybe some methods can be simplified and/or removed), but we keep them this way for now. /Sven */ /* These classes are based on the v1 RowsHeaderLen */ #undef ROWS_HEADER_LEN #define ROWS_HEADER_LEN ROWS_HEADER_LEN_V1 /** @class Old_rows_log_event Base class for the three types of row-based events {Write|Update|Delete}_row_log_event_old, with event type codes PRE_GA_{WRITE|UPDATE|DELETE}_ROWS_EVENT. These events are never created any more, except when reading a relay log created by an old server. */ class Old_rows_log_event : public Log_event { /********** BEGIN CUT & PASTE FROM Rows_log_event **********/ public: /** Enumeration of the errors that can be returned. */ enum enum_error { ERR_OPEN_FAILURE = -1, /**< Failure to open table */ ERR_OK = 0, /**< No error */ ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */ ERR_OUT_OF_MEM = 2, /**< Out of memory */ ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */ ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */ }; /* These definitions allow you to combine the flags into an appropriate flag set using the normal bitwise operators. The implicit conversion from an enum-constant to an integer is accepted by the compiler, which is then used to set the real set of flags. */ enum enum_flag { /* Last event of a statement */ STMT_END_F = (1U << 0), /* Value of the OPTION_NO_FOREIGN_KEY_CHECKS flag in thd->options */ NO_FOREIGN_KEY_CHECKS_F = (1U << 1), /* Value of the OPTION_RELAXED_UNIQUE_CHECKS flag in thd->options */ RELAXED_UNIQUE_CHECKS_F = (1U << 2), /** Indicates that rows in this event are complete, that is contain values for all columns of the table. */ COMPLETE_ROWS_F = (1U << 3) }; typedef uint16 flag_set; /* Special constants representing sets of flags */ enum { RLE_NO_FLAGS = 0U }; virtual ~Old_rows_log_event(); void set_flags(flag_set flags_arg) { m_flags |= flags_arg; } void clear_flags(flag_set flags_arg) { m_flags &= ~flags_arg; } flag_set get_flags(flag_set flags_arg) const { return m_flags & flags_arg; } #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) void pack_info(Protocol *protocol) override; #endif #ifdef MYSQL_CLIENT /* not for direct call, each derived has its own ::print() */ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override= 0; #endif #ifndef MYSQL_CLIENT int add_row_data(uchar *data, size_t length) { return do_add_row_data(data,length); } #endif /* Member functions to implement superclass interface */ int get_data_size() override; MY_BITMAP const *get_cols() const { return &m_cols; } size_t get_width() const { return m_width; } ulonglong get_table_id() const { return m_table_id; } #ifndef MYSQL_CLIENT bool write_data_header() override; bool write_data_body() override; const char *get_db() override { return m_table->s->db.str; } #ifdef HAVE_REPLICATION bool is_part_of_group() override { return 1; } #endif #endif /* Check that malloc() succeeded in allocating memory for the rows buffer and the COLS vector. Checking that an Update_rows_log_event_old is valid is done in the Update_rows_log_event_old::is_valid() function. */ bool is_valid() const override { return m_rows_buf && m_cols.bitmap; } uint m_row_count; /* The number of rows added to the event */ protected: /* The constructors are protected since you're supposed to inherit this class, not create instances of this class. */ #ifndef MYSQL_CLIENT Old_rows_log_event(THD*, TABLE*, ulonglong table_id, MY_BITMAP const *cols, bool is_transactional); #endif Old_rows_log_event(const uchar *row_data, uint event_len, Log_event_type event_type, const Format_description_log_event *description_event); #ifdef MYSQL_CLIENT bool print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name); #endif #ifndef MYSQL_CLIENT virtual int do_add_row_data(uchar *data, size_t length); #endif #ifndef MYSQL_CLIENT TABLE *m_table; /* The table the rows belong to */ #endif ulonglong m_table_id; /* Table ID */ MY_BITMAP m_cols; /* Bitmap denoting columns available */ ulong m_width; /* The width of the columns bitmap */ ulong m_master_reclength; /* Length of record on master side */ /* Bit buffers in the same memory as the class */ my_bitmap_map m_bitbuf[128/(sizeof(my_bitmap_map)*8)]; my_bitmap_map m_bitbuf_ai[128/(sizeof(my_bitmap_map)*8)]; uchar *m_rows_buf; /* The rows in packed format */ uchar *m_rows_cur; /* One-after the end of the data */ uchar *m_rows_end; /* One-after the end of the allocated space */ flag_set m_flags; /* Flags for row-level events */ /* helper functions */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) const uchar *m_curr_row; /* Start of the row being processed */ const uchar *m_curr_row_end; /* One-after the end of the current row */ uchar *m_key; /* Buffer to keep key value during searches */ int find_row(rpl_group_info *); int write_row(rpl_group_info *, const bool); // Unpack the current row into m_table->record[0] int unpack_current_row(rpl_group_info *rgi) { DBUG_ASSERT(m_table); ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); return ::unpack_row(rgi, m_table, m_width, m_curr_row, &m_cols, &m_curr_row_end, &m_master_reclength, m_rows_end); } #endif private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; /* Primitive to prepare for a sequence of row executions. DESCRIPTION Before doing a sequence of do_prepare_row() and do_exec_row() calls, this member function should be called to prepare for the entire sequence. Typically, this member function will allocate space for any buffers that are needed for the two member functions mentioned above. RETURN VALUE The member function will return 0 if all went OK, or a non-zero error code otherwise. */ virtual int do_before_row_operations(const Slave_reporting_capability *const log) = 0; /* Primitive to clean up after a sequence of row executions. DESCRIPTION After doing a sequence of do_prepare_row() and do_exec_row(), this member function should be called to clean up and release any allocated buffers. The error argument, if non-zero, indicates an error which happened during row processing before this function was called. In this case, even if function is successful, it should return the error code given in the argument. */ virtual int do_after_row_operations(const Slave_reporting_capability *const log, int error) = 0; /* Primitive to do the actual execution necessary for a row. DESCRIPTION The member function will do the actual execution needed to handle a row. The row is located at m_curr_row. When the function returns, m_curr_row_end should point at the next row (one byte after the end of the current row). RETURN VALUE 0 if execution succeeded, 1 if execution failed. */ virtual int do_exec_row(rpl_group_info *rgi) = 0; #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ /********** END OF CUT & PASTE FROM Rows_log_event **********/ protected: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) int do_apply_event(Old_rows_log_event*, rpl_group_info *rgi); /* Primitive to prepare for a sequence of row executions. DESCRIPTION Before doing a sequence of do_prepare_row() and do_exec_row() calls, this member function should be called to prepare for the entire sequence. Typically, this member function will allocate space for any buffers that are needed for the two member functions mentioned above. RETURN VALUE The member function will return 0 if all went OK, or a non-zero error code otherwise. */ virtual int do_before_row_operations(TABLE *table) = 0; /* Primitive to clean up after a sequence of row executions. DESCRIPTION After doing a sequence of do_prepare_row() and do_exec_row(), this member function should be called to clean up and release any allocated buffers. */ virtual int do_after_row_operations(TABLE *table, int error) = 0; /* Primitive to prepare for handling one row in a row-level event. DESCRIPTION The member function prepares for execution of operations needed for one row in a row-level event by reading up data from the buffer containing the row. No specific interpretation of the data is normally done here, since SQL thread specific data is not available: that data is made available for the do_exec function. A pointer to the start of the next row, or NULL if the preparation failed. Currently, preparation cannot fail, but don't rely on this behavior. RETURN VALUE Error code, if something went wrong, 0 otherwise. */ virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*, uchar const *row_start, uchar const **row_end) = 0; /* Primitive to do the actual execution necessary for a row. DESCRIPTION The member function will do the actual execution needed to handle a row. RETURN VALUE 0 if execution succeeded, 1 if execution failed. */ virtual int do_exec_row(TABLE *table) = 0; #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ }; /** @class Write_rows_log_event_old Old class for binlog events that write new rows to a table (event type code PRE_GA_WRITE_ROWS_EVENT). Such events are never produced by this version of the server, but they may be read from a relay log created by an old server. New servers create events of class Write_rows_log_event (event type code WRITE_ROWS_EVENT) instead. */ class Write_rows_log_event_old : public Old_rows_log_event { /********** BEGIN CUT & PASTE FROM Write_rows_log_event **********/ public: #if !defined(MYSQL_CLIENT) Write_rows_log_event_old(THD*, TABLE*, ulonglong table_id, MY_BITMAP const *cols, bool is_transactional); #endif #ifdef HAVE_REPLICATION Write_rows_log_event_old(const uchar *buf, uint event_len, const Format_description_log_event *description_event); #endif #if !defined(MYSQL_CLIENT) static bool binlog_row_logging_function(THD *thd, TABLE *table, bool is_transactional, const uchar *before_record __attribute__((unused)), const uchar *after_record) { return thd->binlog_write_row(table, is_transactional, after_record); } #endif private: #ifdef MYSQL_CLIENT bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) int do_before_row_operations(const Slave_reporting_capability *const) override; int do_after_row_operations(const Slave_reporting_capability *const,int) override; int do_exec_row(rpl_group_info *) override; #endif /********** END OF CUT & PASTE FROM Write_rows_log_event **********/ public: enum { /* Support interface to THD::binlog_prepare_pending_rows_event */ TYPE_CODE = PRE_GA_WRITE_ROWS_EVENT }; private: Log_event_type get_type_code() override { return (Log_event_type)TYPE_CODE; } #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() int do_apply_event(rpl_group_info *rgi) override { return Old_rows_log_event::do_apply_event(this, rgi); } // primitives for old version of do_apply_event() int do_before_row_operations(TABLE *table) override; int do_after_row_operations(TABLE *table, int error) override; virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*, uchar const *row_start, uchar const **row_end) override; int do_exec_row(TABLE *table) override; #endif }; /** @class Update_rows_log_event_old Old class for binlog events that modify existing rows to a table (event type code PRE_GA_UPDATE_ROWS_EVENT). Such events are never produced by this version of the server, but they may be read from a relay log created by an old server. New servers create events of class Update_rows_log_event (event type code UPDATE_ROWS_EVENT) instead. */ class Update_rows_log_event_old : public Old_rows_log_event { /********** BEGIN CUT & PASTE FROM Update_rows_log_event **********/ public: #ifndef MYSQL_CLIENT Update_rows_log_event_old(THD*, TABLE*, ulonglong table_id, MY_BITMAP const *cols, bool is_transactional); #endif #ifdef HAVE_REPLICATION Update_rows_log_event_old(const uchar *buf, uint event_len, const Format_description_log_event *description_event); #endif #if !defined(MYSQL_CLIENT) static bool binlog_row_logging_function(THD *thd, TABLE *table, bool is_transactional, MY_BITMAP *cols, uint fields, const uchar *before_record, const uchar *after_record) { return thd->binlog_update_row(table, is_transactional, before_record, after_record); } #endif protected: #ifdef MYSQL_CLIENT bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) int do_before_row_operations(const Slave_reporting_capability *const) override; int do_after_row_operations(const Slave_reporting_capability *const,int) override; int do_exec_row(rpl_group_info *) override; #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ /********** END OF CUT & PASTE FROM Update_rows_log_event **********/ uchar *m_after_image, *m_memory; public: enum { /* Support interface to THD::binlog_prepare_pending_rows_event */ TYPE_CODE = PRE_GA_UPDATE_ROWS_EVENT }; private: Log_event_type get_type_code() override { return (Log_event_type)TYPE_CODE; } #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() int do_apply_event(rpl_group_info *rgi) override { return Old_rows_log_event::do_apply_event(this, rgi); } // primitives for old version of do_apply_event() int do_before_row_operations(TABLE *table) override; int do_after_row_operations(TABLE *table, int error) override; virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*, uchar const *row_start, uchar const **row_end) override; int do_exec_row(TABLE *table) override; #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ }; /** @class Delete_rows_log_event_old Old class for binlog events that delete existing rows from a table (event type code PRE_GA_DELETE_ROWS_EVENT). Such events are never produced by this version of the server, but they may be read from a relay log created by an old server. New servers create events of class Delete_rows_log_event (event type code DELETE_ROWS_EVENT) instead. */ class Delete_rows_log_event_old : public Old_rows_log_event { /********** BEGIN CUT & PASTE FROM Update_rows_log_event **********/ public: #ifndef MYSQL_CLIENT Delete_rows_log_event_old(THD*, TABLE*, ulonglong, MY_BITMAP const *cols, bool is_transactional); #endif #ifdef HAVE_REPLICATION Delete_rows_log_event_old(const uchar *buf, uint event_len, const Format_description_log_event *description_event); #endif #if !defined(MYSQL_CLIENT) static bool binlog_row_logging_function(THD *thd, TABLE *table, bool is_transactional, MY_BITMAP *cols, uint fields, const uchar *before_record, const uchar *after_record __attribute__((unused))) { return thd->binlog_delete_row(table, is_transactional, before_record); } #endif protected: #ifdef MYSQL_CLIENT bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) int do_before_row_operations(const Slave_reporting_capability *const) override; int do_after_row_operations(const Slave_reporting_capability *const,int) override; int do_exec_row(rpl_group_info *) override; #endif /********** END CUT & PASTE FROM Delete_rows_log_event **********/ uchar *m_after_image, *m_memory; public: enum { /* Support interface to THD::binlog_prepare_pending_rows_event */ TYPE_CODE = PRE_GA_DELETE_ROWS_EVENT }; private: Log_event_type get_type_code() override { return (Log_event_type)TYPE_CODE; } #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() int do_apply_event(rpl_group_info *rgi) override { return Old_rows_log_event::do_apply_event(this, rgi); } // primitives for old version of do_apply_event() int do_before_row_operations(TABLE *table) override; int do_after_row_operations(TABLE *table, int error) override; virtual int do_prepare_row(THD*, rpl_group_info*, TABLE*, uchar const *row_start, uchar const **row_end) override; int do_exec_row(TABLE *table) override; #endif }; #endif server/private/gcalc_tools.h000064400000027174151031265040012176 0ustar00/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. Copyright (C) 2011 Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef GCALC_TOOLS_INCLUDED #define GCALC_TOOLS_INCLUDED #include "gcalc_slicescan.h" #include "sql_string.h" /* The Gcalc_function class objects are used to check for a binary relation. The relation can be constructed with the prefix notation using predicates as op_not (as !A) op_union ( A || B || C... ) op_intersection ( A && B && C ... ) op_symdifference ( A+B+C+... == 1 ) op_difference ( A && !(B||C||..)) with the calls of the add_operation(operation, n_operands) method. The relation is calculated over a set of shapes, that in turn have to be added with the add_new_shape() method. All the 'shapes' can be set to 0 with clear_shapes() method and single value can be changed with the invert_state() method. Then the value of the relation can be calculated with the count() method. Frequently used method is find_function(Gcalc_scan_iterator it) that iterates through the 'it' until the relation becomes TRUE. */ class Gcalc_function { private: String shapes_buffer; String function_buffer; int *i_states; int *b_states; uint32 cur_object_id; uint n_shapes; int count_internal(const char *cur_func, uint set_type, const char **end); public: enum op_type { v_empty= 0x00000000, v_find_t= 0x01000000, v_find_f= 0x02000000, v_t_found= 0x03000000, v_f_found= 0x04000000, v_mask= 0x07000000, op_not= 0x80000000, op_shape= 0x00000000, op_union= 0x10000000, op_intersection= 0x20000000, op_symdifference= 0x30000000, op_difference= 0x40000000, op_repeat= 0x50000000, op_border= 0x60000000, op_internals= 0x70000000, op_false= 0x08000000, op_any= 0x78000000 /* The mask to get any of the operations */ }; enum shape_type { shape_point= 0, shape_line= 1, shape_polygon= 2, shape_hole= 3 }; enum count_result { result_false= 0, result_true= 1, result_unknown= 2 }; Gcalc_function() : n_shapes(0) {} gcalc_shape_info add_new_shape(uint32 shape_id, shape_type shape_kind); /* Adds the leaf operation that returns the shape value. Also adds the shape to the list of operands. */ int single_shape_op(shape_type shape_kind, gcalc_shape_info *si); void add_operation(uint operation, uint32 n_operands); void add_not_operation(op_type operation, uint32 n_operands); uint32 get_next_expression_pos() { return function_buffer.length(); } void add_operands_to_op(uint32 operation_pos, uint32 n_operands); int repeat_expression(uint32 exp_pos); void set_cur_obj(uint32 cur_obj) { cur_object_id= cur_obj; } int reserve_shape_buffer(uint n_shapes); int reserve_op_buffer(uint n_ops); uint get_nshapes() const { return n_shapes; } shape_type get_shape_kind(gcalc_shape_info si) const { return (shape_type) uint4korr(shapes_buffer.ptr() + (si*4)); } void set_states(int *shape_states) { i_states= shape_states; } int alloc_states(); void invert_i_state(gcalc_shape_info shape) { i_states[shape]^= 1; } void set_i_state(gcalc_shape_info shape) { i_states[shape]= 1; } void clear_i_state(gcalc_shape_info shape) { i_states[shape]= 0; } void set_b_state(gcalc_shape_info shape) { b_states[shape]= 1; } void clear_b_state(gcalc_shape_info shape) { b_states[shape]= 0; } int get_state(gcalc_shape_info shape) { return i_states[shape] | b_states[shape]; } int get_i_state(gcalc_shape_info shape) { return i_states[shape]; } int get_b_state(gcalc_shape_info shape) { return b_states[shape]; } int count() { return count_internal(function_buffer.ptr(), 0, 0); } int count_last() { return count_internal(function_buffer.ptr(), 1, 0); } void clear_i_states(); void clear_b_states(); void reset(); int check_function(Gcalc_scan_iterator &scan_it); }; /* Gcalc_operation_transporter class extends the Gcalc_shape_transporter. In addition to the parent's functionality, it fills the Gcalc_function object so it has the function that determines the proper shape. For example Multipolyline will be represented as an union of polylines. */ class Gcalc_operation_transporter : public Gcalc_shape_transporter { protected: Gcalc_function *m_fn; gcalc_shape_info m_si; public: Gcalc_operation_transporter(Gcalc_function *fn, Gcalc_heap *heap) : Gcalc_shape_transporter(heap), m_fn(fn) {} int single_point(double x, double y) override; int start_line() override; int complete_line() override; int start_poly() override; int complete_poly() override; int start_ring() override; int complete_ring() override; int add_point(double x, double y) override; int start_collection(int n_objects) override; int empty_shape() override; }; /* When we calculate the result of an spatial operation like Union or Intersection, we receive vertexes of the result one-by-one, and probably need to treat them in variative ways. So, the Gcalc_result_receiver class designed to get these vertexes and construct shapes/objects out of them. and to store the result in an appropriate format */ class Gcalc_result_receiver { String buffer; uint32 n_points; Gcalc_function::shape_type common_shapetype; bool collection_result; uint32 n_shapes; uint32 n_holes; Gcalc_function::shape_type cur_shape; uint32 shape_pos; double first_x, first_y, prev_x, prev_y; double shape_area; public: Gcalc_result_receiver() : n_points(0), common_shapetype(Gcalc_function::shape_point), collection_result(FALSE), n_shapes(0), n_holes(0), cur_shape(Gcalc_function::shape_point), shape_pos(0) {} int start_shape(Gcalc_function::shape_type shape); int add_point(double x, double y); int complete_shape(); int single_point(double x, double y); int done(); void reset(); const char *result() { return buffer.ptr(); } uint length() { return buffer.length(); } int get_nshapes() { return n_shapes; } int get_nholes() { return n_holes; } int get_result_typeid(); uint32 position() { return buffer.length(); } int move_hole(uint32 dest_position, uint32 source_position, uint32 *position_shift); }; /* Gcalc_operation_reducer class incapsulates the spatial operation functionality. It analyses the slices generated by the slicescan and calculates the shape of the result defined by some Gcalc_function. */ class Gcalc_operation_reducer : public Gcalc_dyn_list { public: enum modes { /* Numeric values important here - careful with changing */ default_mode= 0, prefer_big_with_holes= 1, polygon_selfintersections_allowed= 2, /* allowed in the result */ line_selfintersections_allowed= 4 /* allowed in the result */ }; Gcalc_operation_reducer(size_t blk_size=8192); Gcalc_operation_reducer(const Gcalc_operation_reducer &gor); void init(Gcalc_function *fn, modes mode= default_mode); Gcalc_operation_reducer(Gcalc_function *fn, modes mode= default_mode, size_t blk_size=8192); GCALC_DECL_TERMINATED_STATE(killed) int count_slice(Gcalc_scan_iterator *si); int count_all(Gcalc_heap *hp); int get_result(Gcalc_result_receiver *storage); void reset(); #ifndef GCALC_DBUG_OFF int n_res_points; #endif /*GCALC_DBUG_OFF*/ class res_point : public Gcalc_dyn_list::Item { public: int intersection_point; union { const Gcalc_heap::Info *pi; res_point *first_poly_node; }; union { res_point *outer_poly; uint32 poly_position; }; res_point *up; res_point *down; res_point *glue; Gcalc_function::shape_type type; Gcalc_dyn_list::Item **prev_hook; #ifndef GCALC_DBUG_OFF int point_n; #endif /*GCALC_DBUG_OFF*/ void set(const Gcalc_scan_iterator *si); res_point *get_next() { return (res_point *)next; } }; class active_thread : public Gcalc_dyn_list::Item { public: res_point *rp; res_point *thread_start; const Gcalc_heap::Info *p1, *p2; res_point *enabled() { return rp; } active_thread *get_next() { return (active_thread *)next; } }; class poly_instance : public Gcalc_dyn_list::Item { public: uint32 *after_poly_position; poly_instance *get_next() { return (poly_instance *)next; } }; class line : public Gcalc_dyn_list::Item { public: active_thread *t; int incoming; const Gcalc_scan_iterator::point *p; line *get_next() { return (line *)next; } }; class poly_border : public Gcalc_dyn_list::Item { public: active_thread *t; int incoming; int prev_state; const Gcalc_scan_iterator::point *p; poly_border *get_next() { return (poly_border *)next; } }; line *m_lines; Gcalc_dyn_list::Item **m_lines_hook; poly_border *m_poly_borders; Gcalc_dyn_list::Item **m_poly_borders_hook; line *new_line() { return (line *) new_item(); } poly_border *new_poly_border() { return (poly_border *) new_item(); } int add_line(int incoming, active_thread *t, const Gcalc_scan_iterator::point *p); int add_poly_border(int incoming, active_thread *t, int prev_state, const Gcalc_scan_iterator::point *p); protected: Gcalc_function *m_fn; Gcalc_dyn_list::Item **m_res_hook; res_point *m_result; int m_mode; res_point *result_heap; active_thread *m_first_active_thread; res_point *add_res_point(Gcalc_function::shape_type type); active_thread *new_active_thread() { return (active_thread *)new_item(); } poly_instance *new_poly() { return (poly_instance *) new_item(); } private: int start_line(active_thread *t, const Gcalc_scan_iterator::point *p, const Gcalc_scan_iterator *si); int end_line(active_thread *t, const Gcalc_scan_iterator *si); int connect_threads(int incoming_a, int incoming_b, active_thread *ta, active_thread *tb, const Gcalc_scan_iterator::point *pa, const Gcalc_scan_iterator::point *pb, active_thread *prev_range, const Gcalc_scan_iterator *si, Gcalc_function::shape_type s_t); int add_single_point(const Gcalc_scan_iterator *si); poly_border *get_pair_border(poly_border *b1); int continue_range(active_thread *t, const Gcalc_heap::Info *p, const Gcalc_heap::Info *p_next); int continue_i_range(active_thread *t, const Gcalc_heap::Info *ii); int end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p); int get_single_result(res_point *res, Gcalc_result_receiver *storage); int get_result_thread(res_point *cur, Gcalc_result_receiver *storage, int move_upward, res_point *first_poly_node); int get_polygon_result(res_point *cur, Gcalc_result_receiver *storage, res_point *first_poly_node); int get_line_result(res_point *cur, Gcalc_result_receiver *storage); void free_result(res_point *res); }; #endif /*GCALC_TOOLS_INCLUDED*/ server/private/my_user.h000064400000002146151031265040011360 0ustar00/* Copyright (c) 2005-2007 MySQL AB Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* This is a header for libraries containing functions used in both server and only some of clients (but not in libmysql)... */ #ifndef _my_user_h_ #define _my_user_h_ C_MODE_START int parse_user(const char *user_id_str, size_t user_id_len, char *user_name_str, size_t *user_name_len, char *host_name_str, size_t *host_name_len); C_MODE_END #endif /* _my_user_h_ */ server/private/my_default.h000064400000003530151031265040012024 0ustar00/* Copyright (C) 2013 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Definitions for mysys/my_default.c */ #ifndef MY_DEFAULT_INCLUDED #define MY_DEFAULT_INCLUDED C_MODE_START extern MYSQL_PLUGIN_IMPORT const char *my_defaults_extra_file; extern const char *my_defaults_group_suffix; extern MYSQL_PLUGIN_IMPORT const char *my_defaults_file; extern my_bool my_defaults_mark_files; extern int get_defaults_options(char **argv); extern int my_load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv, const char ***); extern int load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv); extern void free_defaults(char **argv); extern void my_print_default_files(const char *conf_file); extern void print_defaults(const char *conf_file, const char **groups); /** Simplify load_defaults() common use */ #define load_defaults_or_exit(A, B, C, D) switch (load_defaults(A, B, C, D)) { \ case 0: break; \ case 4: my_end(0); exit(0); \ default: my_end(0); exit(1); } C_MODE_END #endif /* MY_DEFAULT_INCLUDED */ server/private/sql_lifo_buffer.h000064400000022714151031265040013041 0ustar00/* Copyright (c) 2010, 2011, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @defgroup Bi-directional LIFO buffers used by DS-MRR implementation @{ */ class Forward_lifo_buffer; class Backward_lifo_buffer; /* A base class for in-memory buffer used by DS-MRR implementation. Common properties: - The buffer is last-in-first-out, i.e. elements that are written last are read first. - The buffer contains fixed-size elements. The elements are either atomic byte sequences or pairs of them. - The buffer resides in the memory provided by the user. It is possible to = dynamically (ie. between write operations) add ajacent memory space to the buffer = dynamically remove unused space from the buffer. The intent of this is to allow to have two buffers on adjacent memory space, one is being read from (and so its space shrinks), while the other is being written to (and so it needs more and more space). There are two concrete classes, Forward_lifo_buffer and Backward_lifo_buffer. */ class Lifo_buffer { protected: size_t size1; size_t size2; public: /** write() will put into buffer size1 bytes pointed by write_ptr1. If size2!=0, then they will be accompanied by size2 bytes pointed by write_ptr2. */ uchar *write_ptr1; uchar *write_ptr2; /** read() will do reading by storing pointers to read data into read_ptr1 or into (read_ptr1, read_ptr2), depending on whether the buffer was set to store single objects or pairs. */ uchar *read_ptr1; uchar *read_ptr2; protected: uchar *start; /**< points to start of buffer space */ uchar *end; /**< points to just beyond the end of buffer space */ public: enum enum_direction { BACKWARD=-1, /**< buffer is filled/read from bigger to smaller memory addresses */ FORWARD=1 /**< buffer is filled/read from smaller to bigger memory addresses */ }; virtual enum_direction type() = 0; /* Buffer space control functions */ /** Let the buffer store data in the given space. */ void set_buffer_space(uchar *start_arg, uchar *end_arg) { start= start_arg; end= end_arg; if (end != start) TRASH_ALLOC(start, size_t(end - start)); reset(); } /** Specify where write() should get the source data from, as well as source data size. */ void setup_writing(size_t len1, size_t len2) { size1= len1; size2= len2; } /** Specify where read() should store pointers to read data, as well as read data size. The sizes must match those passed to setup_writing(). */ void setup_reading(size_t len1, size_t len2) { DBUG_ASSERT(len1 == size1); DBUG_ASSERT(len2 == size2); } bool can_write() { return have_space_for(size1 + size2); } virtual void write() = 0; bool is_empty() { return used_size() == 0; } virtual bool read() = 0; void sort(qsort_cmp2 cmp_func, void *cmp_func_arg) { size_t elem_size= size1 + size2; size_t n_elements= used_size() / elem_size; my_qsort2(used_area(), n_elements, elem_size, cmp_func, cmp_func_arg); } virtual void reset() = 0; virtual uchar *end_of_space() = 0; protected: virtual size_t used_size() = 0; /* To be used only by iterator class: */ virtual uchar *get_pos()= 0; virtual bool read(uchar **position, uchar **ptr1, uchar **ptr2)= 0; friend class Lifo_buffer_iterator; public: virtual bool have_space_for(size_t bytes) = 0; virtual void remove_unused_space(uchar **unused_start, uchar **unused_end)=0; virtual uchar *used_area() = 0; virtual ~Lifo_buffer() = default; }; /** Forward LIFO buffer The buffer that is being written to from start to end and read in the reverse. 'pos' points to just beyond the end of used space. It is possible to grow/shink the buffer at the end bound used space unused space *==============*-----------------* ^ ^ ^ | | +--- end | +---- pos +--- start */ class Forward_lifo_buffer: public Lifo_buffer { uchar *pos; public: enum_direction type() override { return FORWARD; } size_t used_size() override { return (size_t)(pos - start); } void reset() override { pos= start; } uchar *end_of_space() override { return pos; } bool have_space_for(size_t bytes) override { return (pos + bytes < end); } void write() override { write_bytes(write_ptr1, size1); if (size2) write_bytes(write_ptr2, size2); } void write_bytes(const uchar *data, size_t bytes) { DBUG_ASSERT(have_space_for(bytes)); memcpy(pos, data, bytes); pos += bytes; } bool have_data(uchar *position, size_t bytes) { return ((position - start) >= (ptrdiff_t)bytes); } uchar *read_bytes(uchar **position, size_t bytes) { DBUG_ASSERT(have_data(*position, bytes)); *position= (*position) - bytes; return *position; } bool read() override { return read(&pos, &read_ptr1, &read_ptr2); } bool read(uchar **position, uchar **ptr1, uchar **ptr2) override { if (!have_data(*position, size1 + size2)) return TRUE; if (size2) *ptr2= read_bytes(position, size2); *ptr1= read_bytes(position, size1); return FALSE; } void remove_unused_space(uchar **unused_start, uchar **unused_end) override { DBUG_ASSERT(0); /* Don't need this yet */ } /** Add more space to the buffer. The caller is responsible that the space being added is adjacent to the end of the buffer. @param unused_start Start of space @param unused_end End of space */ void grow(uchar *unused_start, uchar *unused_end) { DBUG_ASSERT(unused_end >= unused_start); DBUG_ASSERT(end == unused_start); TRASH_ALLOC(unused_start, size_t(unused_end - unused_start)); end= unused_end; } /* Return pointer to start of the memory area that is occupied by the data */ uchar *used_area() override { return start; } friend class Lifo_buffer_iterator; uchar *get_pos() override { return pos; } }; /** Backward LIFO buffer The buffer that is being written to from start to end and read in the reverse. 'pos' points to the start of used space. It is possible to grow/shink the buffer at the start. unused space used space *--------------*=================* ^ ^ ^ | | +--- end | +---- pos +--- start */ class Backward_lifo_buffer: public Lifo_buffer { uchar *pos; public: enum_direction type() override { return BACKWARD; } size_t used_size() override { return (size_t)(end - pos); } void reset() override { pos= end; } uchar *end_of_space() override { return end; } bool have_space_for(size_t bytes) override { return (pos - bytes >= start); } void write() override { if (write_ptr2) write_bytes(write_ptr2, size2); write_bytes(write_ptr1, size1); } void write_bytes(const uchar *data, size_t bytes) { DBUG_ASSERT(have_space_for(bytes)); pos -= bytes; memcpy(pos, data, bytes); } bool read() override { return read(&pos, &read_ptr1, &read_ptr2); } bool read(uchar **position, uchar **ptr1, uchar **ptr2) override { if (!have_data(*position, size1 + size2)) return TRUE; *ptr1= read_bytes(position, size1); if (size2) *ptr2= read_bytes(position, size2); return FALSE; } bool have_data(uchar *position, size_t bytes) { return ((end - position) >= (ptrdiff_t)bytes); } uchar *read_bytes(uchar **position, size_t bytes) { DBUG_ASSERT(have_data(*position, bytes)); uchar *ret= *position; *position= *position + bytes; return ret; } /** Stop using/return the unused part of the space @param unused_start OUT Start of the unused space @param unused_end OUT End of the unused space */ void remove_unused_space(uchar **unused_start, uchar **unused_end) override { *unused_start= start; *unused_end= pos; start= pos; } void grow(uchar *unused_start, uchar *unused_end) { DBUG_ASSERT(0); /* Not used for backward buffers */ } /* Return pointer to start of the memory area that is occupied by the data */ uchar *used_area() override { return pos; } friend class Lifo_buffer_iterator; uchar *get_pos() override { return pos; } }; /** Iterator to walk over contents of the buffer without reading from it */ class Lifo_buffer_iterator { uchar *pos; Lifo_buffer *buf; public: /* The data is read to here */ uchar *read_ptr1; uchar *read_ptr2; void init(Lifo_buffer *buf_arg) { buf= buf_arg; pos= buf->get_pos(); } /* Read the next value. The calling convention is the same as buf->read() has. @retval FALSE - ok @retval TRUE - EOF, reached the end of the buffer */ bool read() { return buf->read(&pos, &read_ptr1, &read_ptr2); } }; server/private/sql_locale.h000064400000005215151031265040012013 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_LOCALE_INCLUDED #define SQL_LOCALE_INCLUDED typedef struct my_locale_errmsgs { const char *language; const char ***errmsgs; } MY_LOCALE_ERRMSGS; typedef struct st_typelib TYPELIB; class MY_LOCALE { public: uint number; const char *name; const char *description; const bool is_ascii; TYPELIB *month_names; TYPELIB *ab_month_names; TYPELIB *day_names; TYPELIB *ab_day_names; uint max_month_name_length; uint max_day_name_length; uint decimal_point; uint thousand_sep; const char *grouping; MY_LOCALE_ERRMSGS *errmsgs; MY_LOCALE(uint number_par, const char *name_par, const char *descr_par, bool is_ascii_par, TYPELIB *month_names_par, TYPELIB *ab_month_names_par, TYPELIB *day_names_par, TYPELIB *ab_day_names_par, uint max_month_name_length_par, uint max_day_name_length_par, uint decimal_point_par, uint thousand_sep_par, const char *grouping_par, MY_LOCALE_ERRMSGS *errmsgs_par) : number(number_par), name(name_par), description(descr_par), is_ascii(is_ascii_par), month_names(month_names_par), ab_month_names(ab_month_names_par), day_names(day_names_par), ab_day_names(ab_day_names_par), max_month_name_length(max_month_name_length_par), max_day_name_length(max_day_name_length_par), decimal_point(decimal_point_par), thousand_sep(thousand_sep_par), grouping(grouping_par), errmsgs(errmsgs_par) {} my_repertoire_t repertoire() const { return is_ascii ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_EXTENDED; } }; /* Exported variables */ extern MY_LOCALE my_locale_en_US; extern MYSQL_PLUGIN_IMPORT MY_LOCALE *my_locales[]; extern MY_LOCALE *my_default_lc_messages; extern MY_LOCALE *my_default_lc_time_names; /* Exported functions */ MY_LOCALE *my_locale_by_name(const char *name); MY_LOCALE *my_locale_by_number(uint number); void cleanup_errmsgs(void); #endif /* SQL_LOCALE_INCLUDED */ server/private/sql_type_real.h000064400000002351151031265040012536 0ustar00/* Copyright (c) 2019 MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_TYPE_REAL_INCLUDED #define SQL_TYPE_REAL_INCLUDED #include class Float { float m_value; public: Float(float nr) :m_value(nr) { DBUG_ASSERT(!std::isnan(nr)); DBUG_ASSERT(!std::isinf(nr)); } Float(double nr) :m_value((float) nr) { DBUG_ASSERT(!std::isnan(nr)); DBUG_ASSERT(!std::isinf(nr)); DBUG_ASSERT(nr <= FLT_MAX); DBUG_ASSERT(nr >= -FLT_MAX); } Float(const uchar *ptr) { float4get(m_value, ptr); } bool to_string(String *to, uint dec) const; }; #endif // SQL_TYPE_REAL_INCLUDED server/private/my_counter.h000064400000003271151031265040012061 0ustar00#ifndef MY_COUNTER_H_INCLUDED #define MY_COUNTER_H_INCLUDED /* Copyright (C) 2018 MariaDB Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include template class Atomic_counter { std::atomic m_counter; Type add(Type i) { return m_counter.fetch_add(i, std::memory_order_relaxed); } Type sub(Type i) { return m_counter.fetch_sub(i, std::memory_order_relaxed); } public: Atomic_counter(const Atomic_counter &rhs) { m_counter.store(rhs, std::memory_order_relaxed); } Atomic_counter(Type val): m_counter(val) {} Atomic_counter() = default; Type operator++(int) { return add(1); } Type operator--(int) { return sub(1); } Type operator++() { return add(1) + 1; } Type operator--() { return sub(1) - 1; } Type operator+=(const Type i) { return add(i) + i; } Type operator-=(const Type i) { return sub(i) - i; } operator Type() const { return m_counter.load(std::memory_order_relaxed); } Type operator=(const Type val) { m_counter.store(val, std::memory_order_relaxed); return val; } }; #endif /* MY_COUNTER_H_INCLUDED */ server/private/sql_plist.h000064400000017064151031265040011714 0ustar00#ifndef SQL_PLIST_H #define SQL_PLIST_H /* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ template class I_P_List_iterator; class I_P_List_null_counter; template class I_P_List_no_push_back; /** Intrusive parameterized list. Unlike I_List does not require its elements to be descendant of ilink class and therefore allows them to participate in several such lists simultaneously. Unlike List is doubly-linked list and thus supports efficient deletion of element without iterator. @param T Type of elements which will belong to list. @param B Class which via its methods specifies which members of T should be used for participating in this list. Here is typical layout of such class: struct B { static inline T **next_ptr(T *el) { return &el->next; } static inline T ***prev_ptr(T *el) { return &el->prev; } }; @param C Policy class specifying how counting of elements in the list should be done. Instance of this class is also used as a place where information about number of list elements is stored. @sa I_P_List_null_counter, I_P_List_counter @param I Policy class specifying whether I_P_List should support efficient push_back() operation. Instance of this class is used as place where we store information to support this operation. @sa I_P_List_no_push_back, I_P_List_fast_push_back. */ template > class I_P_List : public C, public I { T *m_first; /* Do not prohibit copying of I_P_List object to simplify their usage in backup/restore scenarios. Note that performing any operations on such is a bad idea. */ public: I_P_List() : I(&m_first), m_first(NULL) {}; /* empty() is used in many places in the code instead of a constructor, to initialize a bzero-ed I_P_List instance. */ inline void empty() { m_first= NULL; C::reset(); I::set_last(&m_first); } inline bool is_empty() const { return (m_first == NULL); } inline void push_front(T* a) { *B::next_ptr(a)= m_first; if (m_first) *B::prev_ptr(m_first)= B::next_ptr(a); else I::set_last(B::next_ptr(a)); m_first= a; *B::prev_ptr(a)= &m_first; C::inc(); } inline void push_back(T *a) { T **last= I::get_last(); *B::next_ptr(a)= *last; *last= a; *B::prev_ptr(a)= last; I::set_last(B::next_ptr(a)); C::inc(); } inline void insert_after(T *pos, T *a) { if (pos == NULL) push_front(a); else { *B::next_ptr(a)= *B::next_ptr(pos); *B::prev_ptr(a)= B::next_ptr(pos); *B::next_ptr(pos)= a; if (*B::next_ptr(a)) { T *old_next= *B::next_ptr(a); *B::prev_ptr(old_next)= B::next_ptr(a); } else I::set_last(B::next_ptr(a)); C::inc(); } } inline void remove(T *a) { T *next= *B::next_ptr(a); if (next) *B::prev_ptr(next)= *B::prev_ptr(a); else I::set_last(*B::prev_ptr(a)); **B::prev_ptr(a)= next; C::dec(); } inline T* front() { return m_first; } inline const T *front() const { return m_first; } inline T* pop_front() { T *result= front(); if (result) remove(result); return result; } void swap(I_P_List &rhs) { swap_variables(T *, m_first, rhs.m_first); I::swap(rhs); if (m_first) *B::prev_ptr(m_first)= &m_first; else I::set_last(&m_first); if (rhs.m_first) *B::prev_ptr(rhs.m_first)= &rhs.m_first; else I::set_last(&rhs.m_first); C::swap(rhs); } typedef B Adapter; typedef I_P_List Base; typedef I_P_List_iterator Iterator; typedef I_P_List_iterator Const_Iterator; #ifndef _lint friend class I_P_List_iterator; friend class I_P_List_iterator; #endif }; /** Iterator for I_P_List. */ template class I_P_List_iterator { const L *list; T *current; public: I_P_List_iterator(const L &a) : list(&a), current(a.m_first) {} I_P_List_iterator(const L &a, T* current_arg) : list(&a), current(current_arg) {} inline void init(const L &a) { list= &a; current= a.m_first; } /** Operator for it++ @note since we save next element pointer, caller may remove current element. Such modification doesn't invalidate iterator. */ inline T* operator++(int) { T *result= current; if (result) current= *L::Adapter::next_ptr(current); return result; } /* Operator for ++it */ inline T* operator++() { current= *L::Adapter::next_ptr(current); return current; } inline void rewind() { current= list->m_first; } }; /** Hook class which via its methods specifies which members of T should be used for participating in a intrusive list. */ template struct I_P_List_adapter { static inline T **next_ptr(T *el) { return &(el->*next); } static inline const T* const* next_ptr(const T *el) { return &(el->*next); } static inline T ***prev_ptr(T *el) { return &(el->*prev); } }; /** Element counting policy class for I_P_List to be used in cases when no element counting should be done. */ class I_P_List_null_counter { protected: void reset() {} void inc() {} void dec() {} void swap(I_P_List_null_counter &) {} }; /** Element counting policy class for I_P_List which provides basic element counting. */ class I_P_List_counter { uint m_counter; protected: I_P_List_counter() : m_counter (0) {} void reset() {m_counter= 0;} void inc() {m_counter++;} void dec() {m_counter--;} void swap(I_P_List_counter &rhs) { swap_variables(uint, m_counter, rhs.m_counter); } public: uint elements() const { return m_counter; } }; /** A null insertion policy class for I_P_List to be used in cases when push_back() operation is not necessary. */ template class I_P_List_no_push_back { protected: I_P_List_no_push_back(T **) {} void set_last(T **) {} /* T** get_last() const method is intentionally left unimplemented in order to prohibit usage of push_back() method in lists which use this policy. */ void swap(I_P_List_no_push_back &) {} }; /** An insertion policy class for I_P_List which can be used when fast push_back() operation is required. */ template class I_P_List_fast_push_back { T **m_last; protected: I_P_List_fast_push_back(T **a) : m_last(a) { }; void set_last(T **a) { m_last= a; } T** get_last() const { return m_last; } void swap(I_P_List_fast_push_back &rhs) { swap_variables(T**, m_last, rhs.m_last); } }; #endif server/private/sql_binlog.h000064400000001577151031265040012035 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_BINLOG_INCLUDED #define SQL_BINLOG_INCLUDED class THD; void mysql_client_binlog_statement(THD *thd); #endif /* SQL_BINLOG_INCLUDED */ server/private/my_alarm.h000064400000004575151031265040011506 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* File to include when we want to use alarm or a loop_counter to display some information when a program is running */ #ifndef _my_alarm_h #define _my_alarm_h #ifdef __cplusplus extern "C" { #endif extern int volatile my_have_got_alarm; extern ulong my_time_to_wait_for_lock; #if defined(HAVE_ALARM) && !defined(NO_ALARM_LOOP) #include #ifdef HAVE_SIGHANDLER_T #define sig_return sighandler_t #elif defined(SOLARIS) || defined(__sun) || defined(__APPLE__) || \ defined(_AIX) || \ defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ defined(__DragonFly__) typedef void (*sig_return)(int); /* Returns type from signal */ #else typedef void (*sig_return)(void); /* Returns type from signal */ #endif #define ALARM_VARIABLES uint alarm_old=0; \ sig_return alarm_signal=0 #define ALARM_INIT my_have_got_alarm=0 ; \ alarm_old=(uint) alarm(MY_HOW_OFTEN_TO_ALARM); \ alarm_signal=signal(SIGALRM,my_set_alarm_variable); #define ALARM_END (void) signal(SIGALRM,alarm_signal); \ (void) alarm(alarm_old); #define ALARM_TEST my_have_got_alarm #ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY #define ALARM_REINIT (void) alarm(MY_HOW_OFTEN_TO_ALARM); \ (void) signal(SIGALRM,my_set_alarm_variable);\ my_have_got_alarm=0; #else #define ALARM_REINIT (void) alarm((uint) MY_HOW_OFTEN_TO_ALARM); \ my_have_got_alarm=0; #endif /* SIGNAL_HANDLER_RESET_ON_DELIVERY */ #else #define ALARM_VARIABLES long alarm_pos=0,alarm_end_pos=MY_HOW_OFTEN_TO_WRITE-1 #define ALARM_INIT #define ALARM_END #define ALARM_TEST (alarm_pos++ >= alarm_end_pos) #define ALARM_REINIT (alarm_end_pos+=MY_HOW_OFTEN_TO_WRITE) #endif /* HAVE_ALARM */ #ifdef __cplusplus } #endif #endif server/private/key.h000064400000004124151031265040010463 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef KEY_INCLUDED #define KEY_INCLUDED class Field; class String; struct TABLE; typedef struct st_bitmap MY_BITMAP; typedef struct st_key KEY; typedef struct st_key_part_info KEY_PART_INFO; int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field, uint *key_length, uint *keypart); void key_copy(uchar *to_key, const uchar *from_record, const KEY *key_info, uint key_length, bool with_zerofill= FALSE); void key_restore(uchar *to_record, const uchar *from_key, KEY *key_info, uint key_length); bool key_cmp_if_same(TABLE *form,const uchar *key,uint index,uint key_length); void key_unpack(String *to, TABLE *table, KEY *key); void field_unpack(String *to, Field *field, const uchar *rec, uint max_length, bool prefix_key); bool is_key_used(TABLE *table, uint idx, const MY_BITMAP *fields); int key_cmp(KEY_PART_INFO *key_part, const uchar *key, uint key_length); ulong key_hashnr(KEY *key_info, uint used_key_parts, const uchar *key); bool key_buf_cmp(KEY *key_info, uint used_key_parts, const uchar *key1, const uchar *key2); extern "C" int key_rec_cmp(const KEY *const *key_info, const uchar *a, const uchar *b); int key_tuple_cmp(KEY_PART_INFO *part, const uchar *key1, const uchar *key2, uint tuple_length); #endif /* KEY_INCLUDED */ server/private/sql_acl.h000064400000033464151031265040011322 0ustar00#ifndef SQL_ACL_INCLUDED #define SQL_ACL_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2017, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "violite.h" /* SSL_type */ #include "sql_class.h" /* LEX_COLUMN */ #include "grant.h" #include "sql_cmd.h" /* Sql_cmd */ enum mysql_db_table_field { MYSQL_DB_FIELD_HOST = 0, MYSQL_DB_FIELD_DB, MYSQL_DB_FIELD_USER, MYSQL_DB_FIELD_SELECT_PRIV, MYSQL_DB_FIELD_INSERT_PRIV, MYSQL_DB_FIELD_UPDATE_PRIV, MYSQL_DB_FIELD_DELETE_PRIV, MYSQL_DB_FIELD_CREATE_PRIV, MYSQL_DB_FIELD_DROP_PRIV, MYSQL_DB_FIELD_GRANT_PRIV, MYSQL_DB_FIELD_REFERENCES_PRIV, MYSQL_DB_FIELD_INDEX_PRIV, MYSQL_DB_FIELD_ALTER_PRIV, MYSQL_DB_FIELD_CREATE_TMP_TABLE_PRIV, MYSQL_DB_FIELD_LOCK_TABLES_PRIV, MYSQL_DB_FIELD_CREATE_VIEW_PRIV, MYSQL_DB_FIELD_SHOW_VIEW_PRIV, MYSQL_DB_FIELD_CREATE_ROUTINE_PRIV, MYSQL_DB_FIELD_ALTER_ROUTINE_PRIV, MYSQL_DB_FIELD_EXECUTE_PRIV, MYSQL_DB_FIELD_EVENT_PRIV, MYSQL_DB_FIELD_TRIGGER_PRIV, MYSQL_DB_FIELD_DELETE_VERSIONING_ROWS_PRIV, MYSQL_DB_FIELD_COUNT }; extern const TABLE_FIELD_DEF mysql_db_table_def; extern bool mysql_user_table_is_in_short_password_format; extern LEX_CSTRING host_not_specified; extern LEX_CSTRING current_user; extern LEX_CSTRING current_role; extern LEX_CSTRING current_user_and_current_role; static inline int access_denied_error_code(int passwd_used) { #ifdef mysqld_error_find_printf_error_used return 0; #else return passwd_used == 2 ? ER_ACCESS_DENIED_NO_PASSWORD_ERROR : ER_ACCESS_DENIED_ERROR; #endif } /* prototypes */ bool hostname_requires_resolving(const char *hostname); bool acl_init(bool dont_read_acl_tables); bool acl_reload(THD *thd); void acl_free(bool end=0); privilege_t acl_get(const char *host, const char *ip, const char *user, const char *db, my_bool db_is_pattern); bool acl_authenticate(THD *thd, uint com_change_user_pkt_len); bool acl_getroot(Security_context *sctx, const char *user, const char *host, const char *ip, const char *db); bool acl_check_host(const char *host, const char *ip); bool check_change_password(THD *thd, LEX_USER *user); bool change_password(THD *thd, LEX_USER *user); bool mysql_grant_role(THD *thd, List &user_list, bool revoke); bool mysql_grant(THD *thd, const char *db, List &user_list, privilege_t rights, bool revoke, bool is_proxy); int mysql_table_grant(THD *thd, TABLE_LIST *table, List &user_list, List &column_list, privilege_t rights, bool revoke); bool mysql_routine_grant(THD *thd, TABLE_LIST *table, const Sp_handler *sph, List &user_list, privilege_t rights, bool revoke, bool write_to_binlog); bool grant_init(); void grant_free(void); bool grant_reload(THD *thd); bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables, bool any_combination_will_do, uint number, bool no_errors); bool check_grant_column (THD *thd, GRANT_INFO *grant, const char *db_name, const char *table_name, const char *name, size_t length, Security_context *sctx); bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref, const char *name, size_t length, Field *fld); bool check_grant_all_columns(THD *thd, privilege_t want_access, Field_iterator_table_ref *fields); bool check_grant_routine(THD *thd, privilege_t want_access, TABLE_LIST *procs, const Sp_handler *sph, bool no_error); bool check_grant_db(THD *thd,const char *db); bool check_global_access(THD *thd, const privilege_t want_access, bool no_errors= false); bool check_access(THD *thd, privilege_t want_access, const char *db, privilege_t *save_priv, GRANT_INTERNAL_INFO *grant_internal_info, bool dont_check_global_grants, bool no_errors); privilege_t get_table_grant(THD *thd, TABLE_LIST *table); privilege_t get_column_grant(THD *thd, GRANT_INFO *grant, const char *db_name, const char *table_name, const char *field_name); bool get_show_user(THD *thd, LEX_USER *lex_user, const char **username, const char **hostname, const char **rolename); void mysql_show_grants_get_fields(THD *thd, List *fields, const char *name, size_t length); bool mysql_show_grants(THD *thd, LEX_USER *user); bool mysql_show_create_user(THD *thd, LEX_USER *user); int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_applicable_roles(THD *thd, TABLE_LIST *tables, COND *cond); void get_privilege_desc(char *to, uint max_length, privilege_t access); void get_mqh(const char *user, const char *host, USER_CONN *uc); bool mysql_create_user(THD *thd, List &list, bool handle_as_role); bool mysql_drop_user(THD *thd, List &list, bool handle_as_role); bool mysql_rename_user(THD *thd, List &list); int mysql_alter_user(THD *thd, List &list); bool mysql_revoke_all(THD *thd, List &list); void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, const char *db, const char *table); bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, const Sp_handler *sph); bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, const Sp_handler *sph); bool check_routine_level_acl(THD *thd, const char *db, const char *name, const Sp_handler *sph); bool is_acl_user(const char *host, const char *user); int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr); /** Result of an access check for an internal schema or table. Internal ACL checks are always performed *before* using the grant tables. This mechanism enforces that the server implementation has full control on its internal tables. Depending on the internal check result, the server implementation can choose to: - always allow access, - always deny access, - delegate the decision to the database administrator, by using the grant tables. */ enum ACL_internal_access_result { /** Access granted for all the requested privileges, do not use the grant tables. */ ACL_INTERNAL_ACCESS_GRANTED, /** Access denied, do not use the grant tables. */ ACL_INTERNAL_ACCESS_DENIED, /** No decision yet, use the grant tables. */ ACL_INTERNAL_ACCESS_CHECK_GRANT }; /** Per internal table ACL access rules. This class is an interface. Per table(s) specific access rule should be implemented in a subclass. @sa ACL_internal_schema_access */ class ACL_internal_table_access { public: ACL_internal_table_access() = default; virtual ~ACL_internal_table_access() = default; /** Check access to an internal table. When a privilege is granted, this method add the requested privilege to save_priv. @param want_access the privileges requested @param [in, out] save_priv the privileges granted @return @retval ACL_INTERNAL_ACCESS_GRANTED All the requested privileges are granted, and saved in save_priv. @retval ACL_INTERNAL_ACCESS_DENIED At least one of the requested privileges was denied. @retval ACL_INTERNAL_ACCESS_CHECK_GRANT No requested privilege was denied, and grant should be checked for at least one privilege. Requested privileges that are granted, if any, are saved in save_priv. */ virtual ACL_internal_access_result check(privilege_t want_access, privilege_t *save_priv, bool any_combination_will_do) const= 0; }; /** Per internal schema ACL access rules. This class is an interface. Each per schema specific access rule should be implemented in a different subclass, and registered. Per schema access rules can control: - every schema privileges on schema.* - every table privileges on schema.table @sa ACL_internal_schema_registry */ class ACL_internal_schema_access { public: ACL_internal_schema_access() = default; virtual ~ACL_internal_schema_access() = default; /** Check access to an internal schema. @param want_access the privileges requested @param [in, out] save_priv the privileges granted @return @retval ACL_INTERNAL_ACCESS_GRANTED All the requested privileges are granted, and saved in save_priv. @retval ACL_INTERNAL_ACCESS_DENIED At least one of the requested privileges was denied. @retval ACL_INTERNAL_ACCESS_CHECK_GRANT No requested privilege was denied, and grant should be checked for at least one privilege. Requested privileges that are granted, if any, are saved in save_priv. */ virtual ACL_internal_access_result check(privilege_t want_access, privilege_t *save_priv) const= 0; /** Search for per table ACL access rules by table name. @param name the table name @return per table access rules, or NULL */ virtual const ACL_internal_table_access *lookup(const char *name) const= 0; }; /** A registry for per internal schema ACL. An 'internal schema' is a database schema maintained by the server implementation, such as 'performance_schema' and 'INFORMATION_SCHEMA'. */ class ACL_internal_schema_registry { public: static void register_schema(const LEX_CSTRING *name, const ACL_internal_schema_access *access); static const ACL_internal_schema_access *lookup(const char *name); }; const ACL_internal_schema_access * get_cached_schema_access(GRANT_INTERNAL_INFO *grant_internal_info, const char *schema_name); const ACL_internal_table_access * get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info, const char *schema_name, const char *table_name); bool acl_check_proxy_grant_access (THD *thd, const char *host, const char *user, bool with_grant); int acl_setrole(THD *thd, const char *rolename, privilege_t access); int acl_check_setrole(THD *thd, const char *rolename, privilege_t *access); int acl_check_set_default_role(THD *thd, const char *host, const char *user, const char *role); int acl_set_default_role(THD *thd, const char *host, const char *user, const char *rolename); extern SHOW_VAR acl_statistics[]; /* Check if a role is granted to a user/role. If hostname == NULL, search for a role as the starting grantee. */ bool check_role_is_granted(const char *username, const char *hostname, const char *rolename); #ifndef DBUG_OFF extern ulong role_global_merges, role_db_merges, role_table_merges, role_column_merges, role_routine_merges; #endif class Sql_cmd_grant: public Sql_cmd { protected: enum_sql_command m_command; #ifndef NO_EMBEDDED_ACCESS_CHECKS void warn_hostname_requires_resolving(THD *thd, List &list); bool user_list_reset_mqh(THD *thd, List &list); void grant_stage0(THD *thd); #endif public: Sql_cmd_grant(enum_sql_command command) :m_command(command) { } bool is_revoke() const { return m_command == SQLCOM_REVOKE; } enum_sql_command sql_command_code() const override { return m_command; } }; class Sql_cmd_grant_proxy: public Sql_cmd_grant { privilege_t m_grant_option; #ifndef NO_EMBEDDED_ACCESS_CHECKS bool check_access_proxy(THD *thd, List &list); #endif public: Sql_cmd_grant_proxy(enum_sql_command command, privilege_t grant_option) :Sql_cmd_grant(command), m_grant_option(grant_option) { } bool execute(THD *thd) override; }; class Sql_cmd_grant_object: public Sql_cmd_grant, public Grant_privilege { protected: #ifndef NO_EMBEDDED_ACCESS_CHECKS bool grant_stage0_exact_object(THD *thd, TABLE_LIST *table); #endif public: Sql_cmd_grant_object(enum_sql_command command, const Grant_privilege &grant) :Sql_cmd_grant(command), Grant_privilege(grant) { } }; class Sql_cmd_grant_table: public Sql_cmd_grant_object { #ifndef NO_EMBEDDED_ACCESS_CHECKS bool execute_table_mask(THD *thd); bool execute_exact_table(THD *thd, TABLE_LIST *table); #endif public: Sql_cmd_grant_table(enum_sql_command command, const Grant_privilege &grant) :Sql_cmd_grant_object(command, grant) { } bool execute(THD *thd) override; }; class Sql_cmd_grant_sp: public Sql_cmd_grant_object { const Sp_handler &m_sph; public: Sql_cmd_grant_sp(enum_sql_command command, const Grant_privilege &grant, const Sp_handler &sph) :Sql_cmd_grant_object(command, grant), m_sph(sph) { } bool execute(THD *thd) override; }; #endif /* SQL_ACL_INCLUDED */ server/private/wsrep_storage_service.h000064400000003421151031265040014276 0ustar00/* Copyright 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WSREP_STORAGE_SERVICE_H #define WSREP_STORAGE_SERVICE_H #include "wsrep/storage_service.hpp" #include "wsrep/client_state.hpp" class THD; class Wsrep_server_service; class Wsrep_storage_service : public wsrep::storage_service, public wsrep::high_priority_context { public: Wsrep_storage_service(THD*); ~Wsrep_storage_service(); int start_transaction(const wsrep::ws_handle&) override; void adopt_transaction(const wsrep::transaction&) override; int append_fragment(const wsrep::id&, wsrep::transaction_id, int flags, const wsrep::const_buffer&, const wsrep::xid&) override; int update_fragment_meta(const wsrep::ws_meta&) override; int remove_fragments() override; int commit(const wsrep::ws_handle&, const wsrep::ws_meta&) override; int rollback(const wsrep::ws_handle&, const wsrep::ws_meta&) override; void store_globals() override; void reset_globals() override; private: friend class Wsrep_server_service; THD* m_thd; }; #endif /* WSREP_STORAGE_SERVICE_H */ server/private/derived_handler.h000064400000004513151031265040013014 0ustar00/* Copyright (c) 2016, 2017 MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef DERIVED_HANDLER_INCLUDED #define DERIVED_HANDLER_INCLUDED #include "mariadb.h" #include "sql_priv.h" class TMP_TABLE_PARAM; typedef class st_select_lex_unit SELECT_LEX_UNIT; /** @class derived_handler This interface class is to be used for execution of queries that specify derived table by foreign engines */ class derived_handler { public: THD *thd; handlerton *ht; TABLE_LIST *derived; /* Temporary table where all results should be stored in record[0] The table has a field for every item from the select list of the specification of derived. */ TABLE *table; /* The parameters if the temporary table used at its creation */ TMP_TABLE_PARAM *tmp_table_param; SELECT_LEX_UNIT *unit; // Specifies the derived table SELECT_LEX *select; // The first select of the specification derived_handler(THD *thd_arg, handlerton *ht_arg) : thd(thd_arg), ht(ht_arg), derived(0),table(0), tmp_table_param(0), unit(0), select(0) {} virtual ~derived_handler() = default; /* Functions to scan data. All these returns 0 if ok, error code in case of error */ /* Initialize the process of producing rows of the derived table */ virtual int init_scan()= 0; /* Put the next produced row of the derived in table->record[0] and return 0. Return HA_ERR_END_OF_FILE if there are no more rows, return other error number in case of fatal error. */ virtual int next_row()= 0; /* End prodicing rows */ virtual int end_scan()=0; /* Report errors */ virtual void print_error(int error, myf errflag); void set_derived(TABLE_LIST *tbl); }; #endif /* DERIVED_HANDLER_INCLUDED */ server/private/event_db_repository.h000064400000007100151031265040013755 0ustar00#ifndef _EVENT_DB_REPOSITORY_H_ #define _EVENT_DB_REPOSITORY_H_ /* Copyright (c) 2006, 2011, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @addtogroup Event_Scheduler @{ @file event_db_repository.h Data Dictionary related operations of Event Scheduler. This is a private header file of Events module. Please do not include it directly. All public declarations of Events module should be stored in events.h and event_data_objects.h. */ enum enum_events_table_field { ET_FIELD_DB = 0, ET_FIELD_NAME, ET_FIELD_BODY, ET_FIELD_DEFINER, ET_FIELD_EXECUTE_AT, ET_FIELD_INTERVAL_EXPR, ET_FIELD_TRANSIENT_INTERVAL, ET_FIELD_CREATED, ET_FIELD_MODIFIED, ET_FIELD_LAST_EXECUTED, ET_FIELD_STARTS, ET_FIELD_ENDS, ET_FIELD_STATUS, ET_FIELD_ON_COMPLETION, ET_FIELD_SQL_MODE, ET_FIELD_COMMENT, ET_FIELD_ORIGINATOR, ET_FIELD_TIME_ZONE, ET_FIELD_CHARACTER_SET_CLIENT, ET_FIELD_COLLATION_CONNECTION, ET_FIELD_DB_COLLATION, ET_FIELD_BODY_UTF8, ET_FIELD_COUNT /* a cool trick to count the number of fields :) */ }; int events_table_index_read_for_db(THD *thd, TABLE *schema_table, TABLE *event_table); int events_table_scan_all(THD *thd, TABLE *schema_table, TABLE *event_table); class Event_basic; class Event_parse_data; class Event_db_repository { public: Event_db_repository() = default; bool create_event(THD *thd, Event_parse_data *parse_data, bool *event_already_exists); bool update_event(THD *thd, Event_parse_data *parse_data, LEX_CSTRING *new_dbname, LEX_CSTRING *new_name); bool drop_event(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *name, bool drop_if_exists); void drop_schema_events(THD *thd, const LEX_CSTRING *schema); bool find_named_event(const LEX_CSTRING *db, const LEX_CSTRING *name, TABLE *table); bool load_named_event(THD *thd, const LEX_CSTRING *dbname, const LEX_CSTRING *name, Event_basic *et); static bool open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table); bool fill_schema_events(THD *thd, TABLE_LIST *tables, const char *db); bool update_timing_fields_for_event(THD *thd, const LEX_CSTRING *event_db_name, const LEX_CSTRING *event_name, my_time_t last_executed, ulonglong status); public: static bool check_system_tables(THD *thd); private: bool index_read_for_db_for_i_s(THD *thd, TABLE *schema_table, TABLE *event_table, const char *db); bool table_scan_all_for_i_s(THD *thd, TABLE *schema_table, TABLE *event_table); private: /* Prevent use of these */ Event_db_repository(const Event_db_repository &); void operator=(Event_db_repository &); }; /** @} (End of group Event_Scheduler) */ #endif /* _EVENT_DB_REPOSITORY_H_ */ server/private/rpl_rli.h000064400000077752151031265040011357 0ustar00/* Copyright (c) 2005, 2017, Oracle and/or its affiliates. Copyright (c) 2009, 2017, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef RPL_RLI_H #define RPL_RLI_H #include "rpl_tblmap.h" #include "rpl_reporting.h" #include "rpl_utility.h" #include "log.h" /* LOG_INFO, MYSQL_BIN_LOG */ #include "sql_class.h" /* THD */ #include "log_event.h" #include "rpl_parallel.h" struct RPL_TABLE_LIST; class Master_info; class Rpl_filter; /**************************************************************************** Replication SQL Thread Relay_log_info contains: - the current relay log - the current relay log offset - master log name - master log sequence corresponding to the last update - misc information specific to the SQL thread Relay_log_info is initialized from the slave.info file if such exists. Otherwise, data members are intialized with defaults. The initialization is done with Relay_log_info::init() call. The format of slave.info file: relay_log_name relay_log_pos master_log_name master_log_pos To clean up, call end_relay_log_info() *****************************************************************************/ struct rpl_group_info; struct inuse_relaylog; class Relay_log_info : public Slave_reporting_capability { public: /** Flags for the state of reading the relay log. Note that these are bit masks. */ enum enum_state_flag { /** We are inside a group of events forming a statement */ IN_STMT=1, /** We have inside a transaction */ IN_TRANSACTION=2 }; /* The SQL thread owns one Relay_log_info, and each client that has executed a BINLOG statement owns one Relay_log_info. This function returns zero for the Relay_log_info object that belongs to the SQL thread and nonzero for Relay_log_info objects that belong to clients. */ inline bool belongs_to_client() { DBUG_ASSERT(sql_driver_thd); return !sql_driver_thd->slave_thread; } /* If true, events with the same server id should be replicated. This field is set on creation of a relay log info structure by copying the value of ::replicate_same_server_id and can be overridden if necessary. For example of when this is done, check sql_binlog.cc, where the BINLOG statement can be used to execute "raw" events. */ bool replicate_same_server_id; /*** The following variables can only be read when protect by data lock ****/ /* info_fd - file descriptor of the info file. set only during initialization or clean up - safe to read anytime cur_log_fd - file descriptor of the current read relay log */ File info_fd,cur_log_fd; /* Protected with internal locks. Must get data_lock when resetting the logs. */ MYSQL_BIN_LOG relay_log; LOG_INFO linfo; /* cur_log Pointer that either points at relay_log.get_log_file() or &rli->cache_buf, depending on whether the log is hot or there was the need to open a cold relay_log. cache_buf IO_CACHE used when opening cold relay logs. */ IO_CACHE cache_buf,*cur_log; /* Keeps track of the number of transactions that commits before fsyncing. The option --sync-relay-log-info determines how many transactions should commit before fsyncing. */ uint sync_counter; /* Identifies when the recovery process is going on. See sql/slave.cc:init_recovery for further details. */ bool is_relay_log_recovery; /* The following variables are safe to read any time */ /* IO_CACHE of the info file - set only during init or end */ IO_CACHE info_file; /* List of temporary tables used by this connection. This is updated when a temporary table is created or dropped by a replication thread. Not reset when replication ends, to allow one to access the tables when replication restarts. Protected by data_lock. */ All_tmp_tables_list *save_temporary_tables; /* standard lock acquisition order to avoid deadlocks: run_lock, data_lock, relay_log.LOCK_log, relay_log.LOCK_index */ mysql_mutex_t data_lock, run_lock; /* start_cond is broadcast when SQL thread is started stop_cond - when stopped data_cond - when data protected by data_lock changes */ mysql_cond_t start_cond, stop_cond, data_cond; /* parent Master_info structure */ Master_info *mi; /* List of active relay log files. (This can be more than one in case of parallel replication). */ inuse_relaylog *inuse_relaylog_list; inuse_relaylog *last_inuse_relaylog; /* Needed to deal properly with cur_log getting closed and re-opened with a different log under our feet */ uint32 cur_log_old_open_count; /* If on init_info() call error_on_rli_init_info is true that means that previous call to init_info() terminated with an error, RESET SLAVE must be executed and the problem fixed manually. */ bool error_on_rli_init_info; /* Let's call a group (of events) : - a transaction or - an autocommiting query + its associated events (INSERT_ID, TIMESTAMP...) We need these rli coordinates : - relay log name and position of the beginning of the group we currently are executing. Needed to know where we have to restart when replication has stopped in the middle of a group (which has been rolled back by the slave). - relay log name and position just after the event we have just executed. This event is part of the current group. Formerly we only had the immediately above coordinates, plus a 'pending' variable, but this dealt wrong with the case of a transaction starting on a relay log and finishing (commiting) on another relay log. Case which can happen when, for example, the relay log gets rotated because of max_binlog_size. Note: group_relay_log_name, group_relay_log_pos must only be written from the thread owning the Relay_log_info (SQL thread if !belongs_to_client(); client thread executing BINLOG statement if belongs_to_client()). */ char group_relay_log_name[FN_REFLEN]; ulonglong group_relay_log_pos; char event_relay_log_name[FN_REFLEN]; ulonglong event_relay_log_pos; ulonglong future_event_relay_log_pos; /* The master log name for current event. Only used in parallel replication. */ char future_event_master_log_name[FN_REFLEN]; /* Original log name and position of the group we're currently executing (whose coordinates are group_relay_log_name/pos in the relay log) in the master's binlog. These concern the *group*, because in the master's binlog the log_pos that comes with each event is the position of the beginning of the group. Note: group_master_log_name, group_master_log_pos must only be written from the thread owning the Relay_log_info (SQL thread if !belongs_to_client(); client thread executing BINLOG statement if belongs_to_client()). */ char group_master_log_name[FN_REFLEN]; volatile my_off_t group_master_log_pos; /* Handling of the relay_log_space_limit optional constraint. ignore_log_space_limit is used to resolve a deadlock between I/O and SQL threads, the SQL thread sets it to unblock the I/O thread and make it temporarily forget about the constraint. */ ulonglong log_space_limit; Atomic_counter log_space_total; bool ignore_log_space_limit; /* Used by the SQL thread to instructs the IO thread to rotate the logs when the SQL thread needs to purge to release some disk space. */ bool sql_force_rotate_relay; time_t last_master_timestamp; /* The SQL driver thread sets this true while it is waiting at the end of the relay log for more events to arrive. SHOW SLAVE STATUS uses this to report Seconds_Behind_Master as zero while the SQL thread is so waiting. */ bool sql_thread_caught_up; void clear_until_condition(); /** Reset the delay. This is used by RESET SLAVE to clear the delay. */ void clear_sql_delay() { sql_delay= 0; } /* Needed for problems when slave stops and we want to restart it skipping one or more events in the master log that have caused errors, and have been manually applied by DBA already. Must be ulong as it's referred to from set_var.cc */ volatile ulonglong slave_skip_counter; ulonglong max_relay_log_size; volatile ulong abort_pos_wait; /* Incremented on change master */ volatile ulong slave_run_id; /* Incremented on slave start */ mysql_mutex_t log_space_lock; mysql_cond_t log_space_cond; /* THD for the main sql thread, the one that starts threads to process slave requests. If there is only one thread, then this THD is also used for SQL processing. A kill sent to this THD will kill the replication. */ THD *sql_driver_thd; #ifndef DBUG_OFF int events_till_abort; #endif enum_gtid_skip_type gtid_skip_flag; /* inited changes its value within LOCK_active_mi-guarded critical sections at times of start_slave_threads() (0->1) and end_slave() (1->0). Readers may not acquire the mutex while they realize potential concurrency issue. If not set, the value of other members of the structure are undefined. */ volatile bool inited; volatile bool abort_slave; volatile bool stop_for_until; volatile uint slave_running; /* Condition and its parameters from START SLAVE UNTIL clause. UNTIL condition is tested with is_until_satisfied() method that is called by exec_relay_log_event(). is_until_satisfied() caches the result of the comparison of log names because log names don't change very often; this cache is invalidated by parts of code which change log names with notify_*_log_name_updated() methods. (They need to be called only if SQL thread is running). */ enum { UNTIL_NONE= 0, UNTIL_MASTER_POS, UNTIL_RELAY_POS, UNTIL_GTID } until_condition; char until_log_name[FN_REFLEN]; ulonglong until_log_pos; /* extension extracted from log_name and converted to int */ ulong until_log_name_extension; /* Cached result of comparison of until_log_name and current log name -2 means unitialised, -1,0,1 are comarison results */ enum { UNTIL_LOG_NAMES_CMP_UNKNOWN= -2, UNTIL_LOG_NAMES_CMP_LESS= -1, UNTIL_LOG_NAMES_CMP_EQUAL= 0, UNTIL_LOG_NAMES_CMP_GREATER= 1 } until_log_names_cmp_result; /* Condition for UNTIL master_gtid_pos. */ slave_connection_state until_gtid_pos; /* retried_trans is a cumulative counter: how many times the slave has retried a transaction (any) since slave started. Protected by data_lock. */ ulong retried_trans; /* Number of executed events for SLAVE STATUS. Protected by slave_executed_entries_lock */ Atomic_counter executed_entries; /* If the end of the hot relay log is made of master's events ignored by the slave I/O thread, these two keep track of the coords (in the master's binlog) of the last of these events seen by the slave I/O thread. If not, ign_master_log_name_end[0] == 0. As they are like a Rotate event read/written from/to the relay log, they are both protected by rli->relay_log.LOCK_log. */ char ign_master_log_name_end[FN_REFLEN]; ulonglong ign_master_log_pos_end; /* Similar for ignored GTID events. */ slave_connection_state ign_gtids; /* Indentifies where the SQL Thread should create temporary files for the LOAD DATA INFILE. This is used for security reasons. */ char slave_patternload_file[FN_REFLEN]; size_t slave_patternload_file_size; rpl_parallel parallel; /* The relay_log_state keeps track of the current binlog state of the execution of the relay log. This is used to know where to resume current GTID position if the slave thread is stopped and restarted. It is only accessed from the SQL thread, so it does not need any locking. */ rpl_binlog_state relay_log_state; /* The restart_gtid_state is used when the SQL thread restarts on a relay log in GTID mode. In multi-domain parallel replication, each domain may have a separat position, so some events in more progressed domains may need to be skipped. This keeps track of the domains that have not yet reached their starting event. */ slave_connection_state restart_gtid_pos; Relay_log_info(bool is_slave_recovery, const char* thread_name= "SQL"); ~Relay_log_info(); /* Invalidate cached until_log_name and group_relay_log_name comparison result. Should be called after any update of group_realy_log_name if there chances that sql_thread is running. */ inline void notify_group_relay_log_name_update() { if (until_condition==UNTIL_RELAY_POS) until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_UNKNOWN; } /* The same as previous but for group_master_log_name. */ inline void notify_group_master_log_name_update() { if (until_condition==UNTIL_MASTER_POS) until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_UNKNOWN; } void inc_group_relay_log_pos(ulonglong log_pos, rpl_group_info *rgi, bool skip_lock=0); int wait_for_pos(THD* thd, String* log_name, longlong log_pos, longlong timeout); void close_temporary_tables(); /* Check if UNTIL condition is satisfied. See slave.cc for more. */ bool is_until_satisfied(Log_event *ev); inline ulonglong until_pos() { DBUG_ASSERT(until_condition == UNTIL_MASTER_POS || until_condition == UNTIL_RELAY_POS); return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_pos : group_relay_log_pos); } inline char *until_name() { DBUG_ASSERT(until_condition == UNTIL_MASTER_POS || until_condition == UNTIL_RELAY_POS); return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_name : group_relay_log_name); } /** Helper function to do after statement completion. This function is called from an event to complete the group by either stepping the group position, if the "statement" is not inside a transaction; or increase the event position, if the "statement" is inside a transaction. @param event_log_pos Master log position of the event. The position is recorded in the relay log info and used to produce information for SHOW SLAVE STATUS. */ bool stmt_done(my_off_t event_log_pos, THD *thd, rpl_group_info *rgi); int alloc_inuse_relaylog(const char *name); void free_inuse_relaylog(inuse_relaylog *ir); void reset_inuse_relaylog(); int update_relay_log_state(rpl_gtid *gtid_list, uint32 count); /** Is the replication inside a group? The reader of the relay log is inside a group if either: - The IN_TRANSACTION flag is set, meaning we're inside a transaction - The IN_STMT flag is set, meaning we have read at least one row from a multi-event entry. This flag reflects the state of the log 'just now', ie after the last read event would be executed. This allow us to test if we can stop replication before reading the next entry. @retval true Replication thread is currently inside a group @retval false Replication thread is currently not inside a group */ bool is_in_group() const { return (m_flags & (IN_STMT | IN_TRANSACTION)); } /** Set the value of a replication state flag. @param flag Flag to set */ void set_flag(enum_state_flag flag) { m_flags|= flag; } /** Get the value of a replication state flag. @param flag Flag to get value of @return @c true if the flag was set, @c false otherwise. */ bool get_flag(enum_state_flag flag) { return m_flags & flag; } /** Clear the value of a replication state flag. @param flag Flag to clear */ void clear_flag(enum_state_flag flag) { m_flags&= ~flag; } bool flush(); /** Reads the relay_log.info file. */ int init(const char* info_filename); /** Indicate that a delay starts. This does not actually sleep; it only sets the state of this Relay_log_info object to delaying so that the correct state can be reported by SHOW SLAVE STATUS and SHOW PROCESSLIST. Requires rli->data_lock. @param delay_end The time when the delay shall end. */ void start_sql_delay(time_t delay_end) { mysql_mutex_assert_owner(&data_lock); sql_delay_end= delay_end; THD_STAGE_INFO(sql_driver_thd, stage_sql_thd_waiting_until_delay); } int32 get_sql_delay() { return sql_delay; } void set_sql_delay(int32 _sql_delay) { sql_delay= _sql_delay; } time_t get_sql_delay_end() { return sql_delay_end; } rpl_gtid last_seen_gtid; ulong last_trans_retry_count; private: /** Delay slave SQL thread by this amount, compared to master (in seconds). This is set with CHANGE MASTER TO MASTER_DELAY=X. Guarded by data_lock. Initialized by the client thread executing START SLAVE. Written by client threads executing CHANGE MASTER TO MASTER_DELAY=X. Read by SQL thread and by client threads executing SHOW SLAVE STATUS. Note: must not be written while the slave SQL thread is running, since the SQL thread reads it without a lock when executing Relay_log_info::flush(). */ int sql_delay; /** During a delay, specifies the point in time when the delay ends. This is used for the SQL_Remaining_Delay column in SHOW SLAVE STATUS. Guarded by data_lock. Written by the sql thread. Read by client threads executing SHOW SLAVE STATUS. This is calculated as: clock_time_for_event_on_master + clock_difference_between_master_and_slave + SQL_DELAY. */ time_t sql_delay_end; /* Before the MASTER_DELAY parameter was added (WL#344), relay_log.info had 4 lines. Now it has 5 lines. */ static const int LINES_IN_RELAY_LOG_INFO_WITH_DELAY= 5; /* Hint for when to stop event distribution by sql driver thread. The flag is set ON by a non-group event when this event is in the middle of a group (e.g a transaction group) so it's too early to refresh the current-relay-log vs until-log cached comparison result. And it is checked and to decide whether it's a right time to do so when the being processed group has been fully scheduled. */ bool until_relay_log_names_defer; /* Holds the state of the data in the relay log. We need this to ensure that we are not in the middle of a statement or inside BEGIN ... COMMIT when should rotate the relay log. */ uint32 m_flags; }; /* In parallel replication, if we need to re-try a transaction due to a deadlock or other temporary error, we may need to go back and re-read events out of an earlier relay log. This structure keeps track of the relaylogs that are potentially in use. Each rpl_group_info has a pointer to one of those, corresponding to the first GTID event. A pair of reference count keeps track of how long a relay log is potentially in use. When the `completed' flag is set, all events have been read out of the relay log, but the log might still be needed for retry in worker threads. As worker threads complete an event group, they increment atomically the `dequeued_count' with number of events queued. Thus, when completed is set and dequeued_count equals queued_count, the relay log file is finally done with and can be purged. By separating the queued and dequeued count, only the dequeued_count needs multi-thread synchronisation; the completed flag and queued_count fields are only accessed by the SQL driver thread and need no synchronisation. */ struct inuse_relaylog { inuse_relaylog *next; Relay_log_info *rli; /* relay_log_state holds the binlog state corresponding to the start of this relay log file. It is an array with relay_log_state_count elements. */ rpl_gtid *relay_log_state; uint32 relay_log_state_count; /* Number of events in this relay log queued for worker threads. */ Atomic_counter queued_count; /* Number of events completed by worker threads. */ Atomic_counter dequeued_count; /* Set when all events have been read from a relaylog. */ bool completed; char name[FN_REFLEN]; inuse_relaylog(Relay_log_info *rli_arg, rpl_gtid *relay_log_state_arg, uint32 relay_log_state_count_arg, const char *name_arg): next(0), rli(rli_arg), relay_log_state(relay_log_state_arg), relay_log_state_count(relay_log_state_count_arg), queued_count(0), dequeued_count(0), completed(false) { strmake_buf(name, name_arg); } }; /* This is data for various state needed to be kept for the processing of one event group (transaction) during replication. In single-threaded replication, there will be one global rpl_group_info and one global Relay_log_info per master connection. They will be linked together. In parallel replication, there will be one rpl_group_info object for each running sql thread, each having their own thd. All rpl_group_info will share the same Relay_log_info. */ struct rpl_group_info { rpl_group_info *next; /* For free list in rpl_parallel_thread */ Relay_log_info *rli; THD *thd; /* Current GTID being processed. The sub_id gives the binlog order within one domain_id. A zero sub_id means that there is no active GTID. */ uint64 gtid_sub_id; rpl_gtid current_gtid; uint64 commit_id; /* This is used to keep transaction commit order. We will signal this when we commit, and can register it to wait for the commit_orderer of the previous commit to signal us. */ wait_for_commit commit_orderer; /* If non-zero, the sub_id of a prior event group whose commit we have to wait for before committing ourselves. Then wait_commit_group_info points to the event group to wait for. Before using this, rpl_parallel_entry::last_committed_sub_id should be compared against wait_commit_sub_id. Only if last_committed_sub_id is smaller than wait_commit_sub_id must the wait be done (otherwise the waited-for transaction is already committed, so we would otherwise wait for the wrong commit). */ uint64 wait_commit_sub_id; rpl_group_info *wait_commit_group_info; /* This holds a pointer to a struct that keeps track of the need to wait for the previous batch of event groups to reach the commit stage, before this batch can start to execute. (When we execute in parallel the transactions that group committed together on the master, we still need to wait for any prior transactions to have reached the commit stage). The pointed-to gco is only valid for as long as gtid_sub_id < parallel_entry->last_committed_sub_id. After that, it can be freed by another thread. */ group_commit_orderer *gco; struct rpl_parallel_entry *parallel_entry; /* A container to hold on Intvar-, Rand-, Uservar- log-events in case the slave is configured with table filtering rules. The withhold events are executed when their parent Query destiny is determined for execution as well. */ Deferred_log_events *deferred_events; /* State of the container: true stands for IRU events gathering, false does for execution, either deferred or direct. */ bool deferred_events_collecting; Annotate_rows_log_event *m_annotate_event; RPL_TABLE_LIST *tables_to_lock; /* RBR: Tables to lock */ uint tables_to_lock_count; /* RBR: Count of tables to lock */ table_mapping m_table_map; /* RBR: Mapping table-id to table */ mysql_mutex_t sleep_lock; mysql_cond_t sleep_cond; /* trans_retries varies between 0 to slave_transaction_retries and counts how many times the slave has retried the present transaction; gets reset to 0 when the transaction finally succeeds. */ ulong trans_retries; /* Used to defer stopping the SQL thread to give it a chance to finish up the current group of events. The timestamp is set and reset in @c sql_slave_killed(). */ time_t last_event_start_time; char *event_relay_log_name; char event_relay_log_name_buf[FN_REFLEN]; ulonglong event_relay_log_pos; ulonglong future_event_relay_log_pos; /* The master log name for current event. Only used in parallel replication. */ char future_event_master_log_name[FN_REFLEN]; bool is_parallel_exec; /* When gtid_pending is true, we have not yet done record_gtid(). */ bool gtid_pending; int worker_error; /* Set true when we signalled that we reach the commit phase. Used to avoid counting one event group twice. */ bool did_mark_start_commit; /* Copy of flags2 from GTID event. */ uchar gtid_ev_flags2; enum { GTID_DUPLICATE_NULL=0, GTID_DUPLICATE_IGNORE=1, GTID_DUPLICATE_OWNER=2 }; /* When --gtid-ignore-duplicates, this is set to one of the above three values: GTID_DUPLICATE_NULL - Not using --gtid-ignore-duplicates. GTID_DUPLICATE_IGNORE - This gtid already applied, skip the event group. GTID_DUPLICATE_OWNER - We are the current owner of the domain, and must apply the event group and then release the domain. */ uint8 gtid_ignore_duplicate_state; /* Runtime state for printing a note when slave is taking too long while processing a row event. */ longlong row_stmt_start_timestamp; bool long_find_row_note_printed; /* Needs room for "Gtid D-S-N\x00". */ char gtid_info_buf[5+10+1+10+1+20+1]; /* The timestamp, from the master, of the commit event. Used to do delayed update of rli->last_master_timestamp, for getting reasonable values out of Seconds_Behind_Master in SHOW SLAVE STATUS. */ time_t last_master_timestamp; /* Information to be able to re-try an event group in case of a deadlock or other temporary error. */ inuse_relaylog *relay_log; uint64 retry_start_offset; uint64 retry_event_count; /* If `speculation' is != SPECULATE_NO, then we are optimistically running this transaction in parallel, even though it might not be safe (there may be a conflict with a prior event group). In this case, a conflict can cause other errors than deadlocks (like duplicate key for example). So in case of _any_ error, we need to roll back and retry the event group. */ enum enum_speculation { /* This transaction was group-committed together on the master with the other transactions with which it is replicated in parallel. */ SPECULATE_NO, /* We will optimistically try to run this transaction in parallel with other transactions, even though it is not known to be conflict free. If we get a conflict, we will detect it as a deadlock, roll back and retry. */ SPECULATE_OPTIMISTIC, /* This transaction got a conflict during speculative parallel apply, or it was marked on the master as likely to cause a conflict or unsafe to speculate. So it will wait for the prior transaction to commit before starting to replicate. */ SPECULATE_WAIT } speculation; enum enum_retry_killed { RETRY_KILL_NONE = 0, RETRY_KILL_PENDING, RETRY_KILL_KILLED }; uchar killed_for_retry; rpl_group_info(Relay_log_info *rli_); ~rpl_group_info(); void reinit(Relay_log_info *rli); /* Returns true if the argument event resides in the containter; more specifically, the checking is done against the last added event. */ bool is_deferred_event(Log_event * ev) { return deferred_events_collecting ? deferred_events->is_last(ev) : false; }; /* The general cleanup that slave applier may need at the end of query. */ inline void cleanup_after_query() { if (deferred_events) deferred_events->rewind(); }; /* The general cleanup that slave applier may need at the end of session. */ void cleanup_after_session() { if (deferred_events) { delete deferred_events; deferred_events= NULL; } }; /** Save pointer to Annotate_rows event and switch on the binlog_annotate_row_events for this sql thread. To be called when sql thread receives an Annotate_rows event. */ inline void set_annotate_event(Annotate_rows_log_event *event) { DBUG_ASSERT(m_annotate_event == NULL); m_annotate_event= event; this->thd->variables.binlog_annotate_row_events= 1; } /** Returns pointer to the saved Annotate_rows event or NULL if there is no saved event. */ inline Annotate_rows_log_event* get_annotate_event() { return m_annotate_event; } /** Delete saved Annotate_rows event (if any) and switch off the binlog_annotate_row_events for this sql thread. To be called when sql thread has applied the last (i.e. with STMT_END_F flag) rbr event. */ inline void free_annotate_event() { if (m_annotate_event) { this->thd->variables.binlog_annotate_row_events= 0; delete m_annotate_event; m_annotate_event= 0; } } bool get_table_data(TABLE *table_arg, table_def **tabledef_var, TABLE **conv_table_var) const { DBUG_ASSERT(tabledef_var && conv_table_var); for (TABLE_LIST *ptr= tables_to_lock ; ptr != NULL ; ptr= ptr->next_global) if (ptr->table == table_arg) { *tabledef_var= &static_cast(ptr)->m_tabledef; *conv_table_var= static_cast(ptr)->m_conv_table; DBUG_PRINT("debug", ("Fetching table data for table %s.%s:" " tabledef: %p, conv_table: %p", table_arg->s->db.str, table_arg->s->table_name.str, *tabledef_var, *conv_table_var)); return true; } return false; } void clear_tables_to_lock(); void cleanup_context(THD *, bool, bool keep_domain_owner= false); void slave_close_thread_tables(THD *); void mark_start_commit_no_lock(); void mark_start_commit(); char *gtid_info(); void unmark_start_commit(); longlong get_row_stmt_start_timestamp() { return row_stmt_start_timestamp; } void set_row_stmt_start_timestamp() { if (row_stmt_start_timestamp == 0) row_stmt_start_timestamp= microsecond_interval_timer(); } void reset_row_stmt_start_timestamp() { row_stmt_start_timestamp= 0; } void set_long_find_row_note_printed() { long_find_row_note_printed= true; } void unset_long_find_row_note_printed() { long_find_row_note_printed= false; } bool is_long_find_row_note_printed() { return long_find_row_note_printed; } inline void inc_event_relay_log_pos() { if (!is_parallel_exec) rli->event_relay_log_pos= future_event_relay_log_pos; } }; /* The class rpl_sql_thread_info is the THD::system_thread_info for an SQL thread; this is either the driver SQL thread or a worker thread for parallel replication. */ class rpl_sql_thread_info { public: char cached_charset[6]; Rpl_filter* rpl_filter; rpl_sql_thread_info(Rpl_filter *filter); /* Last charset (6 bytes) seen by slave SQL thread is cached here; it helps the thread save 3 get_charset() per Query_log_event if the charset is not changing from event to event (common situation). When the 6 bytes are equal to 0 is used to mean "cache is invalidated". */ void cached_charset_invalidate(); bool cached_charset_compare(char *charset) const; }; extern struct rpl_slave_state *rpl_global_gtid_slave_state; extern gtid_waiting rpl_global_gtid_waiting; int rpl_load_gtid_slave_state(THD *thd); int find_gtid_slave_pos_tables(THD *thd); int event_group_new_gtid(rpl_group_info *rgi, Gtid_log_event *gev); void delete_or_keep_event_post_apply(rpl_group_info *rgi, Log_event_type typ, Log_event *ev); #endif /* RPL_RLI_H */ server/private/sql_cte.h000064400000040225151031265040011327 0ustar00/* Copyright (c) 2016, 2017 MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_CTE_INCLUDED #define SQL_CTE_INCLUDED #include "sql_list.h" #include "sql_lex.h" #include "sql_select.h" class select_unit; struct st_unit_ctxt_elem; /** @class With_element_head @brief Head of the definition of a CTE table It contains the name of the CTE and it contains the position of the subchain of table references used in the definition in the global chain of table references used in the query where this definition is encountered. */ class With_element_head : public Sql_alloc { /* The name of the defined CTE */ LEX_CSTRING *query_name; public: /* The structure describing the subchain of the table references used in the specification of the defined CTE in the global chain of table references used in the query. The structure is fully defined only after the CTE definition has been parsed. */ TABLE_CHAIN tables_pos; With_element_head(LEX_CSTRING *name) : query_name(name) { tables_pos.set_start_pos(0); tables_pos.set_end_pos(0); } friend class With_element; }; /** @class With_element @brief Definition of a CTE table It contains a reference to the name of the table introduced by this with element, and a reference to the unit that specificies this table. Also it contains a reference to the with clause to which this element belongs to. */ class With_element : public Sql_alloc { private: With_clause *owner; // with clause this object belongs to With_element *next; // next element in the with clause uint number; // number of the element in the with clause (starting from 0) table_map elem_map; // The map where with only one 1 set in this->number /* The map base_dep_map has 1 in the i-th position if the query that specifies this with element contains a reference to the with element number i in the query FROM list. (In this case this with element depends directly on the i-th with element.) */ table_map base_dep_map; /* The map derived_dep_map has 1 in i-th position if this with element depends directly or indirectly from the i-th with element. */ table_map derived_dep_map; /* The map sq_dep_map has 1 in i-th position if there is a reference to this with element somewhere in subqueries of the specifications of the tables defined in the with clause containing this element; */ table_map sq_dep_map; table_map work_dep_map; // dependency map used for work /* Dependency map of with elements mutually recursive with this with element */ table_map mutually_recursive; /* Dependency map built only for the top level references i.e. for those that are encountered in from lists of the selects of the specification unit */ table_map top_level_dep_map; /* Points to a recursive reference in subqueries. Used only for specifications without recursive references on the top level. */ TABLE_LIST *sq_rec_ref; /* The next with element from the circular chain of the with elements mutually recursive with this with element. (If This element is simply recursive than next_mutually_recursive contains the pointer to itself. If it's not recursive than next_mutually_recursive is set to NULL.) */ With_element *next_mutually_recursive; /* Total number of references to this element in the FROM lists of the queries that are in the scope of the element (including subqueries and specifications of other with elements). */ uint references; /* true <=> this With_element is referred in the query in which the element is defined */ bool referenced; /* true <=> this With_element is needed for the execution of the query in which the element is defined */ bool is_used_in_query; /* Unparsed specification of the query that specifies this element. It's used to build clones of the specification if they are needed. */ LEX_CSTRING unparsed_spec; /* Offset of the specification in the input string */ my_ptrdiff_t unparsed_spec_offset; /* True if the with element is used a prepared statement */ bool stmt_prepare_mode; /* Return the map where 1 is set only in the position for this element */ table_map get_elem_map() { return (table_map) 1 << number; } public: /* Contains the name of the defined With element and the position of the subchain of the tables references used by its definition in the global chain of TABLE_LIST objects created for the whole query. */ With_element_head *head; /* Optional list of column names to name the columns of the table introduced by this with element. It is used in the case when the names are not inherited from the query that specified the table. Otherwise the list is always empty. */ List column_list; List *cycle_list; /* The query that specifies the table introduced by this with element */ st_select_lex_unit *spec; /* Set to true is recursion is used (directly or indirectly) for the definition of this element */ bool is_recursive; /* For a simple recursive CTE: the number of references to the CTE from outside of the CTE specification. For a CTE mutually recursive with other CTEs : the total number of references to all these CTEs outside of their specification. Each of these mutually recursive CTEs has the same value in this field. */ uint rec_outer_references; /* Any non-recursive select in the specification of a recursive with element is a called anchor. In the case mutually recursive elements the specification of some them may be without any anchor. Yet at least one of them must contain an anchor. All anchors of any recursivespecification are moved ahead before the prepare stage. */ /* Set to true if this is a recursive element with an anchor */ bool with_anchor; /* Set to the first recursive select of the unit specifying the element after all anchor have been moved to the head of the unit. */ st_select_lex *first_recursive; /* The number of the last performed iteration for recursive table (the number of the initial non-recursive step is 0, the number of the first iteration is 1). */ uint level; /* The pointer to the object used to materialize this with element if it's recursive. This object is built at the end of prepare stage and is used at the execution stage. */ select_union_recursive *rec_result; /* List of Item_subselects containing recursive references to this CTE */ SQL_I_List sq_with_rec_ref; /* List of derived tables containing recursive references to this CTE */ SQL_I_List derived_with_rec_ref; With_element(With_element_head *h, List list, st_select_lex_unit *unit) : next(NULL), base_dep_map(0), derived_dep_map(0), sq_dep_map(0), work_dep_map(0), mutually_recursive(0), top_level_dep_map(0), sq_rec_ref(NULL), next_mutually_recursive(NULL), references(0), referenced(false), is_used_in_query(false), head(h), column_list(list), cycle_list(0), spec(unit), is_recursive(false), rec_outer_references(0), with_anchor(false), level(0), rec_result(NULL) { unit->with_element= this; } LEX_CSTRING *get_name() { return head->query_name; } const char *get_name_str() { return get_name()->str; } void set_tables_start_pos(TABLE_LIST **pos) { head->tables_pos.set_start_pos(pos); } void set_tables_end_pos(TABLE_LIST **pos) { head->tables_pos.set_end_pos(pos); } bool check_dependencies_in_spec(); void check_dependencies_in_select(st_select_lex *sl, st_unit_ctxt_elem *ctxt, bool in_subq, table_map *dep_map); void check_dependencies_in_unit(st_select_lex_unit *unit, st_unit_ctxt_elem *ctxt, bool in_subq, table_map *dep_map); void check_dependencies_in_with_clause(With_clause *with_clause, st_unit_ctxt_elem *ctxt, bool in_subq, table_map *dep_map); void set_dependency_on(With_element *with_elem) { base_dep_map|= with_elem->get_elem_map(); } bool check_dependency_on(With_element *with_elem) { return base_dep_map & with_elem->get_elem_map(); } TABLE_LIST *find_first_sq_rec_ref_in_select(st_select_lex *sel); bool set_unparsed_spec(THD *thd, const char *spec_start, const char *spec_end, my_ptrdiff_t spec_offset); st_select_lex_unit *clone_parsed_spec(LEX *old_lex, TABLE_LIST *with_table); bool is_referenced() { return referenced; } bool is_hanging_recursive() { return is_recursive && !rec_outer_references; } void inc_references() { references++; } bool process_columns_of_derived_unit(THD *thd, st_select_lex_unit *unit); bool prepare_unreferenced(THD *thd); bool check_unrestricted_recursive(st_select_lex *sel, table_map &unrestricted, table_map &encountered); void print(THD *thd, String *str, enum_query_type query_type); With_clause *get_owner() { return owner; } bool contains_sq_with_recursive_reference() { return sq_dep_map & mutually_recursive; } bool no_rec_ref_on_top_level() { return !(top_level_dep_map & mutually_recursive); } table_map get_mutually_recursive() { return mutually_recursive; } With_element *get_next_mutually_recursive() { return next_mutually_recursive; } TABLE_LIST *get_sq_rec_ref() { return sq_rec_ref; } bool is_anchor(st_select_lex *sel); void move_anchors_ahead(); bool is_unrestricted(); bool is_with_prepared_anchor(); void mark_as_with_prepared_anchor(); bool is_cleaned(); void mark_as_cleaned(); void reset_recursive_for_exec(); void cleanup_stabilized(); void set_as_stabilized(); bool is_stabilized(); bool all_are_stabilized(); bool instantiate_tmp_tables(); void prepare_for_next_iteration(); void set_cycle_list(List *cycle_list_arg); friend class With_clause; friend bool LEX::resolve_references_to_cte(TABLE_LIST *tables, TABLE_LIST **tables_last, st_select_lex_unit *excl_spec); }; const uint max_number_of_elements_in_with_clause= sizeof(table_map)*8; /** @class With_clause @brief Set of with_elements It has a reference to the first with element from this with clause. This reference allows to navigate through all the elements of the with clause. It contains a reference to the unit to which this with clause is attached. It also contains a flag saying whether this with clause was specified as recursive. */ class With_clause : public Sql_alloc { private: st_select_lex_unit *owner; // the unit this with clause attached to /* The list of all with elements from this with clause */ SQL_I_List with_list; /* The with clause immediately containing this with clause if there is any, otherwise NULL. Now used only at parsing. */ With_clause *embedding_with_clause; /* The next with the clause of the chain of with clauses encountered in the current statement */ With_clause *next_with_clause; /* Set to true if dependencies between with elements have been checked */ bool dependencies_are_checked; /* The bitmap of all recursive with elements whose specifications are not complied with restrictions imposed by the SQL standards on recursive specifications. */ table_map unrestricted; /* The bitmap of all recursive with elements whose anchors has been already prepared. */ table_map with_prepared_anchor; table_map cleaned; /* The bitmap of all recursive with elements that has been already materialized */ table_map stabilized; public: /* If true the specifier RECURSIVE is present in the with clause */ bool with_recursive; With_clause(bool recursive_fl, With_clause *emb_with_clause) : owner(NULL), embedding_with_clause(emb_with_clause), next_with_clause(NULL), dependencies_are_checked(false), unrestricted(0), with_prepared_anchor(0), cleaned(0), stabilized(0), with_recursive(recursive_fl) { } bool add_with_element(With_element *elem); /* Add this with clause to the list of with clauses used in the statement */ void add_to_list(With_clause **ptr, With_clause ** &last_next) { if (embedding_with_clause) { /* An embedded with clause is always placed before the embedding one in the list of with clauses used in the query. */ while (*ptr != embedding_with_clause) ptr= &(*ptr)->next_with_clause; *ptr= this; next_with_clause= embedding_with_clause; } else { *last_next= this; last_next= &this->next_with_clause; } } st_select_lex_unit *get_owner() { return owner; } void set_owner(st_select_lex_unit *unit) { owner= unit; } void attach_to(st_select_lex *select_lex); With_clause *pop() { return embedding_with_clause; } bool check_dependencies(); bool check_anchors(); void move_anchors_ahead(); With_element *find_table_def(TABLE_LIST *table, With_element *barrier, st_select_lex_unit *excl_spec); With_element *find_table_def_in_with_clauses(TABLE_LIST *table); bool prepare_unreferenced_elements(THD *thd); void add_unrestricted(table_map map) { unrestricted|= map; } void print(THD *thd, String *str, enum_query_type query_type); friend class With_element; friend bool LEX::check_dependencies_in_with_clauses(); }; inline bool With_element::is_unrestricted() { return owner->unrestricted & get_elem_map(); } inline bool With_element::is_with_prepared_anchor() { return owner->with_prepared_anchor & get_elem_map(); } inline void With_element::mark_as_with_prepared_anchor() { owner->with_prepared_anchor|= mutually_recursive; } inline bool With_element::is_cleaned() { return owner->cleaned & get_elem_map(); } inline void With_element::mark_as_cleaned() { owner->cleaned|= get_elem_map(); } inline void With_element::reset_recursive_for_exec() { DBUG_ASSERT(is_recursive); level= 0; owner->with_prepared_anchor&= ~mutually_recursive; owner->cleaned&= ~get_elem_map(); cleanup_stabilized(); spec->columns_are_renamed= false; } inline void With_element::cleanup_stabilized() { owner->stabilized&= ~mutually_recursive; } inline void With_element::set_as_stabilized() { owner->stabilized|= get_elem_map(); } inline bool With_element::is_stabilized() { return owner->stabilized & get_elem_map(); } inline bool With_element::all_are_stabilized() { return (owner->stabilized & mutually_recursive) == mutually_recursive; } inline void With_element::prepare_for_next_iteration() { With_element *with_elem= this; while ((with_elem= with_elem->get_next_mutually_recursive()) != this) { TABLE *rec_table= with_elem->rec_result->first_rec_table_to_update; if (rec_table) rec_table->reginfo.join_tab->preread_init_done= false; } } inline void With_clause::attach_to(st_select_lex *select_lex) { for (With_element *with_elem= with_list.first; with_elem; with_elem= with_elem->next) { select_lex->register_unit(with_elem->spec, NULL); } } inline void st_select_lex::set_with_clause(With_clause *with_clause) { master_unit()->with_clause= with_clause; if (with_clause) with_clause->set_owner(master_unit()); } #endif /* SQL_CTE_INCLUDED */ server/private/filesort_utils.h000064400000020003151031265040012734 0ustar00/* Copyright (c) 2010, 2012 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef FILESORT_UTILS_INCLUDED #define FILESORT_UTILS_INCLUDED #include "my_base.h" #include "sql_array.h" class Sort_param; /* Calculate cost of merge sort @param num_rows Total number of rows. @param num_keys_per_buffer Number of keys per buffer. @param elem_size Size of each element. Calculates cost of merge sort by simulating call to merge_many_buff(). @retval Computed cost of merge sort in disk seeks. @note Declared here in order to be able to unit test it, since library dependencies have not been sorted out yet. See also comments get_merge_many_buffs_cost(). */ double get_merge_many_buffs_cost_fast(ha_rows num_rows, ha_rows num_keys_per_buffer, uint elem_size); /** A wrapper class around the buffer used by filesort(). The sort buffer is a contiguous chunk of memory, containing both records to be sorted, and pointers to said records: |rec 0|record 1 |rec 2| ............ |ptr to rec2|ptr to rec1|ptr to rec0| Records will be inserted "left-to-right". Records are not necessarily fixed-size, they can be packed and stored without any "gaps". Record pointers will be inserted "right-to-left", as a side-effect of inserting the actual records. We wrap the buffer in order to be able to do lazy initialization of the pointers: the buffer is often much larger than what we actually need. With this allocation scheme, and lazy initialization of the pointers, we are able to pack variable-sized records in the buffer, and thus possibly have space for more records than we initially estimated. The buffer must be kept available for multiple executions of the same sort operation, so we have explicit allocate and free functions, rather than doing alloc/free in CTOR/DTOR. */ class Filesort_buffer { public: Filesort_buffer() : m_next_rec_ptr(NULL), m_rawmem(NULL), m_record_pointers(NULL), m_sort_keys(NULL), m_num_records(0), m_record_length(0), m_sort_length(0), m_size_in_bytes(0), m_idx(0) {} /** Sort me... */ void sort_buffer(const Sort_param *param, uint count); /** Reverses the record pointer array, to avoid recording new results for non-deterministic mtr tests. */ void reverse_record_pointers() { if (m_idx < 2) // There is nothing to swap. return; uchar **keys= get_sort_keys(); const longlong count= m_idx - 1; for (longlong ix= 0; ix <= count/2; ++ix) { uchar *tmp= keys[count - ix]; keys[count - ix] = keys[ix]; keys[ix]= tmp; } } /** Initializes all the record pointers. */ void init_record_pointers() { init_next_record_pointer(); while (m_idx < m_num_records) (void) get_next_record_pointer(); reverse_record_pointers(); } /** Prepares the buffer for the next batch of records to process. */ void init_next_record_pointer() { m_idx= 0; m_next_rec_ptr= m_rawmem; m_sort_keys= NULL; } /** @returns the number of bytes currently in use for data. */ size_t space_used_for_data() const { return m_next_rec_ptr ? m_next_rec_ptr - m_rawmem : 0; } /** @returns the number of bytes left in the buffer. */ size_t spaceleft() const { DBUG_ASSERT(m_next_rec_ptr >= m_rawmem); const size_t spaceused= (m_next_rec_ptr - m_rawmem) + (static_cast(m_idx) * sizeof(uchar*)); return m_size_in_bytes - spaceused; } /** Is the buffer full? */ bool isfull() const { if (m_idx < m_num_records) return false; return spaceleft() < (m_record_length + sizeof(uchar*)); } /** Where should the next record be stored? */ uchar *get_next_record_pointer() { uchar *retval= m_next_rec_ptr; // Save the return value in the record pointer array. m_record_pointers[-m_idx]= m_next_rec_ptr; // Prepare for the subsequent request. m_idx++; m_next_rec_ptr+= m_record_length; return retval; } /** Adjusts for actual record length. get_next_record_pointer() above was pessimistic, and assumed that the record could not be packed. */ void adjust_next_record_pointer(uint val) { m_next_rec_ptr-= (m_record_length - val); } /// Returns total size: pointer array + record buffers. size_t sort_buffer_size() const { return m_size_in_bytes; } bool is_allocated() const { return m_rawmem; } /** Allocates the buffer, but does *not* initialize pointers. Total size = (num_records * record_length) + (num_records * sizeof(pointer)) space for records space for pointer to records Caller is responsible for raising an error if allocation fails. @param num_records Number of records. @param record_length (maximum) size of each record. @returns Pointer to allocated area, or NULL in case of out-of-memory. */ uchar *alloc_sort_buffer(uint num_records, uint record_length); /// Frees the buffer. void free_sort_buffer(); void reset() { m_rawmem= NULL; } /** Used to access the "right-to-left" array of record pointers as an ordinary "left-to-right" array, so that we can pass it directly on to std::sort(). */ uchar **get_sort_keys() { if (m_idx == 0) return NULL; return &m_record_pointers[1 - m_idx]; } /** Gets sorted record number ix. @see get_sort_keys() Only valid after buffer has been sorted! */ uchar *get_sorted_record(uint ix) { return m_sort_keys[ix]; } /** @returns The entire buffer, as a character array. This is for reusing the memory for merge buffers. */ Bounds_checked_array get_raw_buf() { return Bounds_checked_array(m_rawmem, m_size_in_bytes); } /** We need an assignment operator, see filesort(). This happens to have the same semantics as the one that would be generated by the compiler. Note that this is a shallow copy. We have two objects sharing the same array. */ Filesort_buffer &operator=(const Filesort_buffer &rhs) = default; uint get_sort_length() const { return m_sort_length; } void set_sort_length(uint val) { m_sort_length= val; } private: uchar *m_next_rec_ptr; /// The next record will be inserted here. uchar *m_rawmem; /// The raw memory buffer. uchar **m_record_pointers; /// The "right-to-left" array of record pointers. uchar **m_sort_keys; /// Caches the value of get_sort_keys() uint m_num_records; /// Saved value from alloc_sort_buffer() uint m_record_length; /// Saved value from alloc_sort_buffer() uint m_sort_length; /// The length of the sort key. size_t m_size_in_bytes; /// Size of raw buffer, in bytes. /** This is the index in the "right-to-left" array of the next record to be inserted into the buffer. It is signed, because we use it in signed expressions like: m_record_pointers[-m_idx]; It is longlong rather than int, to ensure that it covers UINT_MAX32 without any casting/warning. */ longlong m_idx; }; int compare_packed_sort_keys(void *sort_param, const void *a_ptr, const void *b_ptr); qsort_cmp2 get_packed_keys_compare_ptr(); #endif // FILESORT_UTILS_INCLUDED server/private/item_create.h000064400000026355151031265040012166 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. Copyright (c) 2008, 2022, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Functions to create an item. Used by sql/sql_yacc.yy */ #ifndef ITEM_CREATE_H #define ITEM_CREATE_H #include "item_func.h" // Cast_target typedef struct st_udf_func udf_func; /** Public function builder interface. The parser (sql/sql_yacc.yy) uses a factory / builder pattern to construct an Item object for each function call. All the concrete function builders implements this interface, either directly or indirectly with some adapter helpers. Keeping the function creation separated from the bison grammar allows to simplify the parser, and avoid the need to introduce a new token for each function, which has undesirable side effects in the grammar. */ class Create_func { public: /** The builder create method. Given the function name and list or arguments, this method creates an Item that represents the function call. In case or errors, a NULL item is returned, and an error is reported. Note that the thd object may be modified by the builder. In particular, the following members/methods can be set/called, depending on the function called and the function possible side effects.
  • thd->lex->binlog_row_based_if_mixed
  • thd->lex->current_context()
  • thd->lex->safe_to_cache_query
  • thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT)
  • thd->lex->uncacheable(UNCACHEABLE_RAND)
  • thd->lex->add_time_zone_tables_to_query_tables(thd)
@param thd The current thread @param name The function name @param item_list The list of arguments to the function, can be NULL @return An item representing the parsed function call, or NULL */ virtual Item *create_func(THD *thd, const LEX_CSTRING *name, List *item_list) = 0; protected: /** Constructor */ Create_func() = default; /** Destructor */ virtual ~Create_func() = default; }; /** Adapter for functions that takes exactly zero arguments. */ class Create_func_arg0 : public Create_func { public: Item *create_func(THD *thd, const LEX_CSTRING *name, List *item_list) override; /** Builder method, with no arguments. @param thd The current thread @return An item representing the function call */ virtual Item *create_builder(THD *thd) = 0; protected: /** Constructor. */ Create_func_arg0() = default; /** Destructor. */ virtual ~Create_func_arg0() = default; }; /** Adapter for functions that takes exactly one argument. */ class Create_func_arg1 : public Create_func { public: Item *create_func(THD *thd, const LEX_CSTRING *name, List *item_list) override; /** Builder method, with one argument. @param thd The current thread @param arg1 The first argument of the function @return An item representing the function call */ virtual Item *create_1_arg(THD *thd, Item *arg1) = 0; protected: /** Constructor. */ Create_func_arg1() = default; /** Destructor. */ virtual ~Create_func_arg1() = default; }; /** Adapter for functions that takes exactly two arguments. */ class Create_func_arg2 : public Create_func { public: Item *create_func(THD *thd, const LEX_CSTRING *name, List *item_list) override; /** Builder method, with two arguments. @param thd The current thread @param arg1 The first argument of the function @param arg2 The second argument of the function @return An item representing the function call */ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0; protected: /** Constructor. */ Create_func_arg2() = default; /** Destructor. */ virtual ~Create_func_arg2() = default; }; /** Adapter for functions that takes exactly three arguments. */ class Create_func_arg3 : public Create_func { public: Item *create_func(THD *thd, const LEX_CSTRING *name, List *item_list) override; /** Builder method, with three arguments. @param thd The current thread @param arg1 The first argument of the function @param arg2 The second argument of the function @param arg3 The third argument of the function @return An item representing the function call */ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0; protected: /** Constructor. */ Create_func_arg3() = default; /** Destructor. */ virtual ~Create_func_arg3() = default; }; /** Adapter for native functions with a variable number of arguments. The main use of this class is to discard the following calls: foo(expr1 AS name1, expr2 AS name2, ...) which are syntactically correct (the syntax can refer to a UDF), but semantically invalid for native functions. */ class Create_native_func : public Create_func { public: Item *create_func(THD *thd, const LEX_CSTRING *name, List *item_list) override; /** Builder method, with no arguments. @param thd The current thread @param name The native function name @param item_list The function parameters, none of which are named @return An item representing the function call */ virtual Item *create_native(THD *thd, const LEX_CSTRING *name, List *item_list) = 0; protected: /** Constructor. */ Create_native_func() = default; /** Destructor. */ virtual ~Create_native_func() = default; }; /** Function builder for qualified functions. This builder is used with functions call using a qualified function name syntax, as in db.func(expr, expr, ...). */ class Create_qfunc : public Create_func { public: /** The builder create method, for unqualified functions. This builder will use the current database for the database name. @param thd The current thread @param name The function name @param item_list The list of arguments to the function, can be NULL @return An item representing the parsed function call */ Item *create_func(THD *thd, const LEX_CSTRING *name, List *item_list) override; /** The builder create method, for qualified functions. @param thd The current thread @param db The database name @param name The function name @param use_explicit_name Should the function be represented as 'db.name'? @param item_list The list of arguments to the function, can be NULL @return An item representing the parsed function call */ virtual Item *create_with_db(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *name, bool use_explicit_name, List *item_list) = 0; protected: /** Constructor. */ Create_qfunc() = default; /** Destructor. */ virtual ~Create_qfunc() = default; }; /** Find the function builder for qualified functions. @param thd The current thread @return A function builder for qualified functions */ extern Create_qfunc * find_qualified_function_builder(THD *thd); #ifdef HAVE_DLOPEN /** Function builder for User Defined Functions. */ class Create_udf_func : public Create_func { public: Item *create_func(THD *thd, const LEX_CSTRING *name, List *item_list) override; /** The builder create method, for User Defined Functions. @param thd The current thread @param fct The User Defined Function metadata @param item_list The list of arguments to the function, can be NULL @return An item representing the parsed function call */ Item *create(THD *thd, udf_func *fct, List *item_list); /** Singleton. */ static Create_udf_func s_singleton; protected: /** Constructor. */ Create_udf_func() = default; /** Destructor. */ virtual ~Create_udf_func() = default; }; #endif struct Native_func_registry { LEX_CSTRING name; Create_func *builder; }; class Native_functions_hash: public HASH { public: Native_functions_hash() { bzero((void*) this, sizeof(*this)); } ~Native_functions_hash() { /* No automatic free because objects of this type are expected to be declared statically. The code in cleanup() calls my_hash_free() which may not work correctly at the very end of mariadbd shutdown. The the upper level code should call cleanup() explicitly. Unfortunatelly, it's not possible to use DBUG_ASSERT(!records) here, because the server terminates using exit() in some cases, e.g. in the test main.named_pipe with the "Create named pipe failed" error. */ } bool init(size_t count); bool append(const Native_func_registry array[], size_t count); bool remove(const Native_func_registry array[], size_t count); bool replace(const Native_func_registry array[], size_t count) { DBUG_ENTER("Native_functions_hash::replace"); remove(array, count); DBUG_RETURN(append(array, count)); } void cleanup(); /** Find the native function builder associated with a given function name. @param thd The current thread @param name The native function name @return The native function builder associated with the name, or NULL */ Create_func *find(THD *thd, const LEX_CSTRING &name) const; }; extern MYSQL_PLUGIN_IMPORT Native_functions_hash native_functions_hash; extern MYSQL_PLUGIN_IMPORT Native_functions_hash native_functions_hash_oracle; extern const Native_func_registry func_array[]; extern const size_t func_array_length; int item_create_init(); void item_create_cleanup(); Item *create_func_dyncol_create(THD *thd, List &list); Item *create_func_dyncol_add(THD *thd, Item *str, List &list); Item *create_func_dyncol_delete(THD *thd, Item *str, List &nums); Item *create_func_dyncol_get(THD *thd, Item *num, Item *str, const Type_handler *handler, const char *c_len, const char *c_dec, CHARSET_INFO *cs); Item *create_func_dyncol_json(THD *thd, Item *str); class Native_func_registry_array { const Native_func_registry *m_elements; size_t m_count; public: Native_func_registry_array() :m_elements(NULL), m_count(0) { } Native_func_registry_array(const Native_func_registry *elements, size_t count) :m_elements(elements), m_count(count) { } const Native_func_registry& element(size_t i) const { DBUG_ASSERT(i < m_count); return m_elements[i]; } const Native_func_registry *elements() const { return m_elements; } size_t count() const { return m_count; } }; #endif server/private/sql_help.h000064400000001743151031265040011506 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_HELP_INCLUDED #define SQL_HELP_INCLUDED class THD; /* Function prototypes */ bool mysqld_help (THD *thd, const char *text); bool mysqld_help_prepare(THD *thd, const char *text, List *fields); #endif /* SQL_HELP_INCLUDED */ server/private/welcome_copyright_notice.h000064400000002302151031265040014753 0ustar00/* Copyright (c) 2011, 2017, Oracle and/or its affiliates. Copyright (c) 2011, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _welcome_copyright_notice_h_ #define _welcome_copyright_notice_h_ #define COPYRIGHT_NOTICE_CURRENT_YEAR "2018" /* This define specifies copyright notice which is displayed by every MySQL program on start, or on help screen. */ #define ORACLE_WELCOME_COPYRIGHT_NOTICE(first_year) \ "Copyright (c) " first_year ", " COPYRIGHT_NOTICE_CURRENT_YEAR \ ", Oracle, MariaDB Corporation Ab and others.\n" #endif /* _welcome_copyright_notice_h_ */ server/private/select_handler.h000064400000004264151031265040012654 0ustar00/* Copyright (c) 2018, 2019 MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SELECT_HANDLER_INCLUDED #define SELECT_HANDLER_INCLUDED #include "mariadb.h" #include "sql_priv.h" /** @class select_handler This interface class is to be used for execution of select queries by foreign engines */ class select_handler { public: THD *thd; handlerton *ht; SELECT_LEX *select; // Select to be excuted /* Temporary table where all results should be stored in record[0] The table has a field for every item from the select_lex::item_list. The table is actually never filled. Only its record buffer is used. */ TABLE *table; List result_columns; bool is_analyze; bool send_result_set_metadata(); bool send_data(); select_handler(THD *thd_arg, handlerton *ht_arg); virtual ~select_handler(); int execute(); virtual bool prepare(); static TABLE *create_tmp_table(THD *thd, SELECT_LEX *sel); protected: /* Functions to scan the select result set. All these returns 0 if ok, error code in case of error. */ /* Initialize the process of producing rows of result set */ virtual int init_scan() = 0; /* Put the next produced row of the result set in table->record[0] and return 0. Return HA_ERR_END_OF_FILE if there are no more rows, return other error number in case of fatal error. */ virtual int next_row() = 0; /* Finish scanning */ virtual int end_scan() = 0; /* Report errors */ virtual void print_error(int error, myf errflag); bool send_eof(); }; #endif /* SELECT_HANDLER_INCLUDED */ server/private/gstream.h000064400000004605151031265040011341 0ustar00#ifndef GSTREAM_INCLUDED #define GSTREAM_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include /* MY_ALLOW_ZERO_PTR */ #include "m_ctype.h" /* my_charset_latin1, my_charset_bin */ class Gis_read_stream { public: enum enum_tok_types { unknown, eostream, word, numeric, l_bra, r_bra, comma }; Gis_read_stream(CHARSET_INFO *charset, const char *buffer, int size) :m_cur(buffer), m_limit(buffer + size), m_err_msg(NULL), m_charset(charset) {} Gis_read_stream(): m_cur(NullS), m_limit(NullS), m_err_msg(NullS) {} ~Gis_read_stream() { my_free(m_err_msg); } enum enum_tok_types get_next_toc_type(); bool lookup_next_word(LEX_STRING *res); bool get_next_word(LEX_STRING *); bool get_next_number(double *); bool check_next_symbol(char); inline void skip_space() { while ((m_cur < m_limit) && my_isspace(&my_charset_latin1, *m_cur)) m_cur++; } /* Skip next character, if match. Return 1 if no match */ inline bool skip_char(char skip) { skip_space(); if ((m_cur >= m_limit) || *m_cur != skip) return 1; /* Didn't find char */ m_cur++; return 0; } /* Returns the next notempty character. */ char next_symbol() { skip_space(); if (m_cur >= m_limit) return 0; /* EOL meet. */ return *m_cur; } void set_error_msg(const char *msg); // caller should free this pointer char *get_error_msg() { char *err_msg = m_err_msg; m_err_msg= NullS; return err_msg; } protected: const char *m_cur; const char *m_limit; char *m_err_msg; CHARSET_INFO *m_charset; }; #endif /* GSTREAM_INCLUDED */ server/private/wqueue.h000064400000003035151031265040011206 0ustar00/* Copyright (c) 2007, 2008, Sun Microsystems, Inc, Copyright (c) 2011, 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef WQUEUE_INCLUDED #define WQUEUE_INCLUDED #include /* info about requests in a waiting queue */ typedef struct st_pagecache_wqueue { struct st_my_thread_var *last_thread; /* circular list of waiting threads */ } WQUEUE; void wqueue_link_into_queue(WQUEUE *wqueue, struct st_my_thread_var *thread); void wqueue_unlink_from_queue(WQUEUE *wqueue, struct st_my_thread_var *thread); void wqueue_add_to_queue(WQUEUE *wqueue, struct st_my_thread_var *thread); void wqueue_add_and_wait(WQUEUE *wqueue, struct st_my_thread_var *thread, mysql_mutex_t *lock); void wqueue_release_queue(WQUEUE *wqueue); void wqueue_release_one_locktype_from_queue(WQUEUE *wqueue); #endif server/private/sql_handler.h000064400000005536151031265040012177 0ustar00#ifndef SQL_HANDLER_INCLUDED #define SQL_HANDLER_INCLUDED /* Copyright (c) 2006, 2015, Oracle and/or its affiliates. Copyright (C) 2010, 2015, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_class.h" /* enum_ha_read_mode */ #include "my_base.h" /* ha_rkey_function, ha_rows */ #include "sql_list.h" /* List */ /* Open handlers are stored here */ class SQL_HANDLER { public: TABLE *table; List fields; /* Fields, set on open */ THD *thd; LEX_CSTRING handler_name; LEX_CSTRING db; LEX_CSTRING table_name; MEM_ROOT mem_root; MYSQL_LOCK *lock; MDL_request mdl_request; key_part_map keypart_map; int keyno; /* Used key */ uint key_len; enum enum_ha_read_modes mode; /* This is only used when deleting many handler objects */ SQL_HANDLER *next; Query_arena arena; char *base_data; SQL_HANDLER(THD *thd_arg) : thd(thd_arg), arena(&mem_root, Query_arena::STMT_INITIALIZED) { init(); clear_alloc_root(&mem_root); base_data= 0; } void init() { keyno= -1; table= 0; lock= 0; mdl_request.ticket= 0; } void reset(); ~SQL_HANDLER(); }; class THD; struct TABLE_LIST; bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen); bool mysql_ha_close(THD *thd, TABLE_LIST *tables); bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes, const char *, List *,enum ha_rkey_function,Item *,ha_rows,ha_rows); void mysql_ha_flush(THD *thd); void mysql_ha_flush_tables(THD *thd, TABLE_LIST *all_tables); void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables); void mysql_ha_cleanup_no_free(THD *thd); void mysql_ha_cleanup(THD *thd); void mysql_ha_set_explicit_lock_duration(THD *thd); void mysql_ha_rm_temporary_tables(THD *thd); SQL_HANDLER *mysql_ha_read_prepare(THD *thd, TABLE_LIST *tables, enum enum_ha_read_modes mode, const char *keyname, List *key_expr, enum ha_rkey_function ha_rkey_mode, Item *cond); #endif server/private/pfs_table_provider.h000064400000005101151031265040013540 0ustar00/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef PFS_TABLE_PROVIDER_H #define PFS_TABLE_PROVIDER_H /** @file include/pfs_table_provider.h Performance schema instrumentation (declarations). */ #ifdef HAVE_PSI_TABLE_INTERFACE #ifdef MYSQL_SERVER #ifndef EMBEDDED_LIBRARY #ifndef MYSQL_DYNAMIC_PLUGIN #include "mysql/psi/psi.h" #define PSI_TABLE_CALL(M) pfs_ ## M ## _v1 C_MODE_START PSI_table_share* pfs_get_table_share_v1(my_bool temporary, struct TABLE_SHARE *share); void pfs_release_table_share_v1(PSI_table_share* share); void pfs_drop_table_share_v1(my_bool temporary, const char *schema_name, int schema_name_length, const char *table_name, int table_name_length); PSI_table* pfs_open_table_v1(PSI_table_share *share, const void *identity); void pfs_unbind_table_v1(PSI_table *table); PSI_table * pfs_rebind_table_v1(PSI_table_share *share, const void *identity, PSI_table *table); void pfs_close_table_v1(struct TABLE_SHARE *server_share, PSI_table *table); PSI_table_locker* pfs_start_table_io_wait_v1(PSI_table_locker_state *state, PSI_table *table, PSI_table_io_operation op, uint index, const char *src_file, uint src_line); PSI_table_locker* pfs_start_table_lock_wait_v1(PSI_table_locker_state *state, PSI_table *table, PSI_table_lock_operation op, ulong op_flags, const char *src_file, uint src_line); void pfs_end_table_io_wait_v1(PSI_table_locker* locker, ulonglong numrows); void pfs_end_table_lock_wait_v1(PSI_table_locker* locker); void pfs_unlock_table_v1(PSI_table *table); C_MODE_END #endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_SERVER */ #endif /* HAVE_PSI_TABLE_INTERFACE */ #endif server/private/sql_union.h000064400000002050151031265040011676 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_UNION_INCLUDED #define SQL_UNION_INCLUDED class THD; class select_result; struct LEX; typedef class st_select_lex_unit SELECT_LEX_UNIT; bool mysql_union(THD *thd, LEX *lex, select_result *result, SELECT_LEX_UNIT *unit, ulong setup_tables_done_option); #endif /* SQL_UNION_INCLUDED */ server/private/violite.h000064400000023546151031265040011357 0ustar00/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. Copyright (c) 2012, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* * Vio Lite. * Purpose: include file for Vio that will work with C and C++ */ #ifndef vio_violite_h_ #define vio_violite_h_ #include "my_net.h" /* needed because of struct in_addr */ #include /* Simple vio interface in C; The functions are implemented in violite.c */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifdef __cplusplus typedef struct st_vio Vio; #endif /* __cplusplus */ enum enum_vio_type { VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET, VIO_TYPE_NAMEDPIPE, VIO_TYPE_SSL /* see also vio_type_names[] */ }; enum enum_vio_state { VIO_STATE_NOT_INITIALIZED, VIO_STATE_ACTIVE, VIO_STATE_SHUTDOWN, VIO_STATE_CLOSED }; #define FIRST_VIO_TYPE VIO_CLOSED #define LAST_VIO_TYPE VIO_TYPE_SSL /** VIO I/O events. */ enum enum_vio_io_event { VIO_IO_EVENT_READ, VIO_IO_EVENT_WRITE, VIO_IO_EVENT_CONNECT }; struct vio_keepalive_opts { int interval; int idle; int probes; }; #define VIO_TLSv1_0 1 #define VIO_TLSv1_1 2 #define VIO_TLSv1_2 4 #define VIO_TLSv1_3 8 #define VIO_LOCALHOST 1U /* a localhost connection */ #define VIO_BUFFERED_READ 2U /* use buffered read */ #define VIO_READ_BUFFER_SIZE 16384U /* size of read buffer */ #define VIO_DESCRIPTION_SIZE 30 /* size of description */ Vio* vio_new(my_socket sd, enum enum_vio_type type, uint flags); Vio* mysql_socket_vio_new(MYSQL_SOCKET mysql_socket, enum enum_vio_type type, uint flags); #ifdef _WIN32 Vio* vio_new_win32pipe(HANDLE hPipe); #else #define HANDLE void * #endif /* _WIN32 */ void vio_delete(Vio* vio); int vio_close(Vio* vio); my_bool vio_reset(Vio* vio, enum enum_vio_type type, my_socket sd, void *ssl, uint flags); size_t vio_read(Vio *vio, uchar * buf, size_t size); size_t vio_read_buff(Vio *vio, uchar * buf, size_t size); size_t vio_write(Vio *vio, const uchar * buf, size_t size); int vio_blocking(Vio *vio, my_bool onoff, my_bool *old_mode); my_bool vio_is_blocking(Vio *vio); /* setsockopt TCP_NODELAY at IPPROTO_TCP level, when possible */ int vio_nodelay(Vio *vio, my_bool on); int vio_fastsend(Vio *vio); /* setsockopt SO_KEEPALIVE at SOL_SOCKET level, when possible */ int vio_keepalive(Vio *vio, my_bool onoff); int vio_set_keepalive_options(Vio * vio, const struct vio_keepalive_opts *opts); /* Whenever we should retry the last read/write operation. */ my_bool vio_should_retry(Vio *vio); /* Check that operation was timed out */ my_bool vio_was_timeout(Vio *vio); /* Short text description of the socket for those, who are curious.. */ const char* vio_description(Vio *vio); /* Return the type of the connection */ enum enum_vio_type vio_type(Vio* vio); /* Return last error number */ int vio_errno(Vio*vio); /* Get socket number */ my_socket vio_fd(Vio*vio); /* Remote peer's address and name in text form */ my_bool vio_peer_addr(Vio *vio, char *buf, uint16 *port, size_t buflen); /* Wait for an I/O event notification. */ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout); my_bool vio_is_connected(Vio *vio); ssize_t vio_pending(Vio *vio); /* Set timeout for a network operation. */ extern int vio_timeout(Vio *vio, uint which, int timeout_sec); extern void vio_set_wait_callback(void (*before_wait)(void), void (*after_wait)(void)); /* Connect to a peer. */ my_bool vio_socket_connect(Vio *vio, struct sockaddr *addr, socklen_t len, int timeout); void vio_get_normalized_ip(const struct sockaddr *src, size_t src_length, struct sockaddr *dst); my_bool vio_get_normalized_ip_string(const struct sockaddr *addr, size_t addr_length, char *ip_string, size_t ip_string_size); my_bool vio_is_no_name_error(int err_code); int vio_getnameinfo(const struct sockaddr *sa, char *hostname, size_t hostname_size, char *port, size_t port_size, int flags); #ifdef HAVE_OPENSSL /* apple deprecated openssl in MacOSX Lion */ #ifdef __APPLE__ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #define HEADER_DES_LOCL_H dummy_something #define YASSL_MYSQL_COMPATIBLE #ifndef YASSL_PREFIX #define YASSL_PREFIX #endif /* Set yaSSL to use same type as MySQL do for socket handles */ typedef my_socket YASSL_SOCKET_T; #define YASSL_SOCKET_T_DEFINED #define template _template /* bug in WolfSSL 4.4.0, see also my_crypt.cc */ #include #undef template #include #ifdef DEPRECATED #undef DEPRECATED #endif enum enum_ssl_init_error { SSL_INITERR_NOERROR= 0, SSL_INITERR_CERT, SSL_INITERR_KEY, SSL_INITERR_NOMATCH, SSL_INITERR_BAD_PATHS, SSL_INITERR_CIPHERS, SSL_INITERR_MEMFAIL, SSL_INITERR_DH, SSL_INITERR_PROTOCOL, SSL_INITERR_LASTERR }; const char* sslGetErrString(enum enum_ssl_init_error err); struct st_VioSSLFd { SSL_CTX *ssl_context; }; int sslaccept(struct st_VioSSLFd*, Vio *, long timeout, unsigned long *errptr); int sslconnect(struct st_VioSSLFd*, Vio *, long timeout, unsigned long *errptr); void vio_check_ssl_init(); struct st_VioSSLFd *new_VioSSLConnectorFd(const char *key_file, const char *cert_file, const char *ca_file, const char *ca_path, const char *cipher, enum enum_ssl_init_error *error, const char *crl_file, const char *crl_path); struct st_VioSSLFd *new_VioSSLAcceptorFd(const char *key_file, const char *cert_file, const char *ca_file,const char *ca_path, const char *cipher, enum enum_ssl_init_error *error, const char *crl_file, const char *crl_path, ulonglong tls_version); void free_vio_ssl_acceptor_fd(struct st_VioSSLFd *fd); #endif /* HAVE_OPENSSL */ void vio_end(void); const char *vio_type_name(enum enum_vio_type vio_type, size_t *len); #ifdef __cplusplus } #endif #if !defined(DONT_MAP_VIO) #define vio_delete(vio) (vio)->viodelete(vio) #define vio_errno(vio) (vio)->vioerrno(vio) #define vio_read(vio, buf, size) ((vio)->read)(vio,buf,size) #define vio_write(vio, buf, size) ((vio)->write)(vio, buf, size) #define vio_blocking(vio, set_blocking_mode, old_mode)\ (vio)->vioblocking(vio, set_blocking_mode, old_mode) #define vio_is_blocking(vio) (vio)->is_blocking(vio) #define vio_fastsend(vio) (vio)->fastsend(vio) #define vio_keepalive(vio, set_keep_alive) (vio)->viokeepalive(vio, set_keep_alive) #define vio_should_retry(vio) (vio)->should_retry(vio) #define vio_was_timeout(vio) (vio)->was_timeout(vio) #define vio_close(vio) ((vio)->vioclose)(vio) #define vio_shutdown(vio,how) ((vio)->shutdown)(vio,how) #define vio_peer_addr(vio, buf, prt, buflen) (vio)->peer_addr(vio, buf, prt, buflen) #define vio_io_wait(vio, event, timeout) (vio)->io_wait(vio, event, timeout) #define vio_is_connected(vio) (vio)->is_connected(vio) #endif /* !defined(DONT_MAP_VIO) */ #ifdef _WIN32 /* shutdown(2) flags */ #ifndef SHUT_RD #define SHUT_RD SD_RECEIVE #endif #endif /* This enumerator is used in parser - should be always visible */ enum SSL_type { SSL_TYPE_NOT_SPECIFIED= -1, SSL_TYPE_NONE, SSL_TYPE_ANY, SSL_TYPE_X509, SSL_TYPE_SPECIFIED }; /* HFTODO - hide this if we don't want client in embedded server */ /* This structure is for every connection on both sides */ struct st_vio { MYSQL_SOCKET mysql_socket; /* Instrumented socket */ my_bool localhost; /* Are we from localhost? */ int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */ struct sockaddr_storage local; /* Local internet address */ struct sockaddr_storage remote; /* Remote internet address */ enum enum_vio_type type; /* Type of connection */ enum enum_vio_state state; /* State of the connection */ const char *desc; /* String description */ char *read_buffer; /* buffer for vio_read_buff */ char *read_pos; /* start of unfetched data in the read buffer */ char *read_end; /* end of unfetched data */ int read_timeout; /* Timeout value (ms) for read ops. */ int write_timeout; /* Timeout value (ms) for write ops. */ /* function pointers. They are similar for socket/SSL/whatever */ void (*viodelete)(Vio*); int (*vioerrno)(Vio*); size_t (*read)(Vio*, uchar *, size_t); size_t (*write)(Vio*, const uchar *, size_t); int (*timeout)(Vio*, uint, my_bool); int (*vioblocking)(Vio*, my_bool, my_bool *); my_bool (*is_blocking)(Vio*); int (*viokeepalive)(Vio*, my_bool); int (*fastsend)(Vio*); my_bool (*peer_addr)(Vio*, char *, uint16*, size_t); void (*in_addr)(Vio*, struct sockaddr_storage*); my_bool (*should_retry)(Vio*); my_bool (*was_timeout)(Vio*); int (*vioclose)(Vio*); my_bool (*is_connected)(Vio*); int (*shutdown)(Vio *, int); my_bool (*has_data) (Vio*); int (*io_wait)(Vio*, enum enum_vio_io_event, int); my_bool (*connect)(Vio*, struct sockaddr *, socklen_t, int); #ifdef HAVE_OPENSSL void *ssl_arg; #endif #ifdef _WIN32 HANDLE hPipe; OVERLAPPED overlapped; int shutdown_flag; void *tp_ctx; /* threadpool context */ #endif }; #endif /* vio_violite_h_ */ server/private/sql_update.h000064400000003603151031265040012035 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_UPDATE_INCLUDED #define SQL_UPDATE_INCLUDED #include "sql_class.h" /* enum_duplicates */ class Item; struct TABLE_LIST; class THD; typedef class st_select_lex SELECT_LEX; typedef class st_select_lex_unit SELECT_LEX_UNIT; bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, Item **conds, uint order_num, ORDER *order); bool check_unique_table(THD *thd, TABLE_LIST *table_list); int mysql_update(THD *thd,TABLE_LIST *tables,List &fields, List &values,COND *conds, uint order_num, ORDER *order, ha_rows limit, bool ignore, ha_rows *found_return, ha_rows *updated_return); bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List *fields, List *values, COND *conds, ulonglong options, enum enum_duplicates handle_duplicates, bool ignore, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, multi_update **result); bool records_are_comparable(const TABLE *table); bool compare_record(const TABLE *table); #endif /* SQL_UPDATE_INCLUDED */ server/private/sql_get_diagnostics.h000064400000017273151031265040013731 0ustar00/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_GET_DIAGNOSTICS_H #define SQL_GET_DIAGNOSTICS_H /** Diagnostics information forward reference. */ class Diagnostics_information; /** Sql_cmd_get_diagnostics represents a GET DIAGNOSTICS statement. The GET DIAGNOSTICS statement retrieves exception or completion condition information from a diagnostics area, usually pertaining to the last non-diagnostic SQL statement that was executed. */ class Sql_cmd_get_diagnostics : public Sql_cmd { public: /** Constructor, used to represent a GET DIAGNOSTICS statement. @param info Diagnostics information to be obtained. */ Sql_cmd_get_diagnostics(Diagnostics_information *info) : m_info(info) {} enum_sql_command sql_command_code() const override { return SQLCOM_GET_DIAGNOSTICS; } bool execute(THD *thd) override; private: /** The information to be obtained. */ Diagnostics_information *m_info; }; /** Represents the diagnostics information to be obtained. Diagnostic information is made available through statement information and condition information items. */ class Diagnostics_information : public Sql_alloc { public: /** Which diagnostics area to access. Only CURRENT is supported for now. */ enum Which_area { /** Access the first diagnostics area. */ CURRENT_AREA }; /** Set which diagnostics area to access. */ void set_which_da(Which_area area) { m_area= area; } /** Get which diagnostics area to access. */ Which_area get_which_da(void) const { return m_area; } /** Aggregate diagnostics information. @param thd The current thread. @param da The diagnostics area. @retval false on success. @retval true on error */ virtual bool aggregate(THD *thd, const Diagnostics_area *da) = 0; protected: /** Diagnostics_information objects are allocated in thd->mem_root. Do not rely on the destructor for any cleanup. */ virtual ~Diagnostics_information() { DBUG_ASSERT(false); } /** Evaluate a diagnostics information item in a specific context. @param thd The current thread. @param diag_item The diagnostics information item. @param ctx The context to evaluate the item. @retval false on success. @retval true on error. */ template bool evaluate(THD *thd, Diag_item *diag_item, Context ctx) { Item *value; /* Get this item's value. */ if (! (value= diag_item->get_value(thd, ctx))) return true; /* Set variable/parameter value. */ return diag_item->set_value(thd, &value); } private: /** Which diagnostics area to access. */ Which_area m_area; }; /** A diagnostics information item. Used to associate a specific diagnostics information item to a target variable. */ class Diagnostics_information_item : public Sql_alloc { public: /** Set a value for this item. @param thd The current thread. @param value The obtained value. @retval false on success. @retval true on error. */ bool set_value(THD *thd, Item **value); protected: /** Constructor, used to represent a diagnostics information item. @param target A target that gets the value of this item. */ Diagnostics_information_item(Item *target) : m_target(target) {} /** Diagnostics_information_item objects are allocated in thd->mem_root. Do not rely on the destructor for any cleanup. */ virtual ~Diagnostics_information_item() { DBUG_ASSERT(false); } private: /** The target variable that will receive the value of this item. */ Item *m_target; }; /** A statement information item. */ class Statement_information_item : public Diagnostics_information_item { public: /** The name of a statement information item. */ enum Name { NUMBER, ROW_COUNT }; /** Constructor, used to represent a statement information item. @param name The name of this item. @param target A target that gets the value of this item. */ Statement_information_item(Name name, Item *target) : Diagnostics_information_item(target), m_name(name) {} /** Obtain value of this statement information item. */ Item *get_value(THD *thd, const Diagnostics_area *da); private: /** The name of this statement information item. */ Name m_name; }; /** Statement information. @remark Provides information about the execution of a statement. */ class Statement_information : public Diagnostics_information { public: /** Constructor, used to represent the statement information of a GET DIAGNOSTICS statement. @param items List of requested statement information items. */ Statement_information(List *items) : m_items(items) {} /** Obtain statement information in the context of a diagnostics area. */ bool aggregate(THD *thd, const Diagnostics_area *da) override; private: /* List of statement information items. */ List *m_items; }; /** A condition information item. */ class Condition_information_item : public Diagnostics_information_item { public: /** The name of a condition information item. */ enum Name { CLASS_ORIGIN, SUBCLASS_ORIGIN, CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME, CATALOG_NAME, SCHEMA_NAME, TABLE_NAME, COLUMN_NAME, CURSOR_NAME, MESSAGE_TEXT, MYSQL_ERRNO, RETURNED_SQLSTATE }; /** Constructor, used to represent a condition information item. @param name The name of this item. @param target A target that gets the value of this item. */ Condition_information_item(Name name, Item *target) : Diagnostics_information_item(target), m_name(name) {} /** Obtain value of this condition information item. */ Item *get_value(THD *thd, const Sql_condition *cond); private: /** The name of this condition information item. */ Name m_name; /** Create an string item to represent a condition item string. */ Item *make_utf8_string_item(THD *thd, const String *str); }; /** Condition information. @remark Provides information about conditions raised during the execution of a statement. */ class Condition_information : public Diagnostics_information { public: /** Constructor, used to represent the condition information of a GET DIAGNOSTICS statement. @param cond_number_expr Number that identifies the diagnostic condition. @param items List of requested condition information items. */ Condition_information(Item *cond_number_expr, List *items) : m_cond_number_expr(cond_number_expr), m_items(items) {} /** Obtain condition information in the context of a diagnostics area. */ bool aggregate(THD *thd, const Diagnostics_area *da) override; private: /** Number that identifies the diagnostic condition for which information is to be obtained. */ Item *m_cond_number_expr; /** List of condition information items. */ List *m_items; }; #endif server/private/sql_tablespace.h000064400000001674151031265040012664 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_TABLESPACE_INCLUDED #define SQL_TABLESPACE_INCLUDED class THD; class st_alter_tablespace; int mysql_alter_tablespace(THD* thd, st_alter_tablespace *ts_info); #endif /* SQL_TABLESPACE_INCLUDED */ server/private/myisammrg.h000064400000011441151031265040011700 0ustar00/* Copyright (c) 2000-2002, 2004, 2006-2008 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file should be included when using merge_isam_functions */ #ifndef _myisammrg_h #define _myisammrg_h #ifdef __cplusplus extern "C" { #endif #ifndef _my_base_h #include #endif #ifndef _myisam_h #include #endif #include #define MYRG_NAME_EXT ".MRG" #define MYRG_NAME_TMPEXT ".MRG_TMP" /* In which table to INSERT rows */ #define MERGE_INSERT_DISABLED 0 #define MERGE_INSERT_TO_FIRST 1 #define MERGE_INSERT_TO_LAST 2 extern TYPELIB merge_insert_method; /* Param to/from myrg_info */ typedef struct st_mymerge_info /* Struct from h_info */ { ulonglong records; /* Records in database */ ulonglong deleted; /* Deleted records in database */ ulonglong recpos; /* Pos for last used record */ ulonglong data_file_length; ulonglong dupp_key_pos; /* Offset of the Duplicate key in the merge table */ uint reclength; /* Recordlength */ int errkey; /* With key was duplicated on err */ uint options; /* HA_OPTION_... used */ ulong *rec_per_key; /* for sql optimizing */ } MYMERGE_INFO; typedef struct st_myrg_table_info { struct st_myisam_info *table; ulonglong file_offset; } MYRG_TABLE; typedef struct st_myrg_info { MYRG_TABLE *open_tables,*current_table,*end_table,*last_used_table; ulonglong records; /* records in tables */ ulonglong del; /* Removed records */ ulonglong data_file_length; ulong cache_size; uint merge_insert_method; uint tables,options,reclength,keys; uint key_parts; my_bool cache_in_use; /* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */ my_bool children_attached; LIST open_list; QUEUE by_key; ulong *rec_per_key_part; /* for sql optimizing */ mysql_mutex_t mutex; } MYRG_INFO; /* Prototypes for merge-functions */ extern int myrg_close(MYRG_INFO *file); extern int myrg_delete(MYRG_INFO *file,const uchar *buff); extern MYRG_INFO *myrg_open(const char *name,int mode,int wait_if_locked); extern MYRG_INFO *myrg_parent_open(const char *parent_name, int (*callback)(void*, const char*), void *callback_param); extern int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, MI_INFO *(*callback)(void*), void *callback_param, my_bool *need_compat_check); extern int myrg_detach_children(MYRG_INFO *m_info); extern int myrg_panic(enum ha_panic_function function); extern int myrg_rfirst(MYRG_INFO *file,uchar *buf,int inx); extern int myrg_rlast(MYRG_INFO *file,uchar *buf,int inx); extern int myrg_rnext(MYRG_INFO *file,uchar *buf,int inx); extern int myrg_rprev(MYRG_INFO *file,uchar *buf,int inx); extern int myrg_rnext_same(MYRG_INFO *file,uchar *buf); extern int myrg_rkey(MYRG_INFO *info,uchar *buf,int inx, const uchar *key, key_part_map keypart_map, enum ha_rkey_function search_flag); extern int myrg_rrnd(MYRG_INFO *file,uchar *buf,ulonglong pos); extern int myrg_rsame(MYRG_INFO *file,uchar *record,int inx); extern int myrg_update(MYRG_INFO *file,const uchar *old, const uchar *new_rec); extern int myrg_write(MYRG_INFO *info,const uchar *rec); extern int myrg_status(MYRG_INFO *file,MYMERGE_INFO *x,int flag); extern int myrg_lock_database(MYRG_INFO *file,int lock_type); extern int myrg_create(const char *name, const char **table_names, uint insert_method, my_bool fix_names); extern int myrg_extra(MYRG_INFO *file,enum ha_extra_function function, void *extra_arg); extern int myrg_reset(MYRG_INFO *info); extern void myrg_extrafunc(MYRG_INFO *info,invalidator_by_filename inv); extern ha_rows myrg_records_in_range(MYRG_INFO *info, int inx, const key_range *min_key, const key_range *max_key, page_range *pages); extern ha_rows myrg_records(MYRG_INFO *info); extern ulonglong myrg_position(MYRG_INFO *info); #ifdef __cplusplus } #endif #endif server/private/my_time.h000064400000024256151031265040011346 0ustar00/* Copyright (c) 2004, 2011, Oracle and/or its affiliates. Copyright (c) 2017, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This is a private header of sql-common library, containing declarations for my_time.c */ #ifndef _my_time_h_ #define _my_time_h_ #include "mysql_time.h" #include "my_decimal_limits.h" C_MODE_START extern MYSQL_PLUGIN_IMPORT ulonglong log_10_int[20]; extern uchar days_in_month[]; #define MY_TIME_T_MAX LONG_MAX #define MY_TIME_T_MIN LONG_MIN /* Time handling defaults */ #define TIMESTAMP_MAX_YEAR 2038 #define TIMESTAMP_MIN_YEAR (1900 + YY_PART_YEAR - 1) #define TIMESTAMP_MAX_VALUE INT_MAX32 #define TIMESTAMP_MIN_VALUE 0 /* two-digit years < this are 20..; >= this are 19.. */ #define YY_PART_YEAR 70 /* check for valid times only if the range of time_t is greater than the range of my_time_t */ #if SIZEOF_TIME_T > 4 || defined(TIME_T_UNSIGNED) # define IS_TIME_T_VALID_FOR_TIMESTAMP(x) \ ((x) <= TIMESTAMP_MAX_VALUE && \ (x) >= TIMESTAMP_MIN_VALUE) #else # define IS_TIME_T_VALID_FOR_TIMESTAMP(x) \ ((x) >= TIMESTAMP_MIN_VALUE) #endif /* Flags to str_to_datetime */ #define C_TIME_NO_ZERO_IN_DATE (1UL << 23) /* == MODE_NO_ZERO_IN_DATE */ #define C_TIME_NO_ZERO_DATE (1UL << 24) /* == MODE_NO_ZERO_DATE */ #define C_TIME_INVALID_DATES (1UL << 25) /* == MODE_INVALID_DATES */ #define MYSQL_TIME_WARN_TRUNCATED 1U #define MYSQL_TIME_WARN_OUT_OF_RANGE 2U #define MYSQL_TIME_WARN_EDOM 4U #define MYSQL_TIME_WARN_ZERO_DATE 8U #define MYSQL_TIME_NOTE_TRUNCATED 16U #define MYSQL_TIME_WARN_WARNINGS (MYSQL_TIME_WARN_TRUNCATED|\ MYSQL_TIME_WARN_OUT_OF_RANGE|\ MYSQL_TIME_WARN_EDOM|\ MYSQL_TIME_WARN_ZERO_DATE) #define MYSQL_TIME_WARN_NOTES (MYSQL_TIME_NOTE_TRUNCATED) #define MYSQL_TIME_WARN_HAVE_WARNINGS(x) MY_TEST((x) & MYSQL_TIME_WARN_WARNINGS) #define MYSQL_TIME_WARN_HAVE_NOTES(x) MY_TEST((x) & MYSQL_TIME_WARN_NOTES) /* Useful constants */ #define SECONDS_IN_24H 86400L /* Limits for the INTERVAL data type */ /* Number of hours between '0001-01-01 00h' and '9999-12-31 23h' */ #define TIME_MAX_INTERVAL_HOUR 87649415 #define TIME_MAX_INTERVAL_HOUR_CHAR_LENGTH 8 /* Number of full days between '0001-01-01' and '9999-12-31'*/ #define TIME_MAX_INTERVAL_DAY 3652058 /*87649415/24*/ #define TIME_MAX_INTERVAL_DAY_CHAR_LENGTH 7 /* Limits for the TIME data type */ #define TIME_MAX_HOUR 838 #define TIME_MAX_MINUTE 59 #define TIME_MAX_SECOND 59 #define TIME_MAX_SECOND_PART 999999 #define TIME_SECOND_PART_FACTOR (TIME_MAX_SECOND_PART+1) #define TIME_SECOND_PART_DIGITS 6 #define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND) #define TIME_MAX_VALUE_SECONDS (TIME_MAX_HOUR * 3600L + \ TIME_MAX_MINUTE * 60L + TIME_MAX_SECOND) /* Structure to return status from str_to_datetime(), str_to_time(). */ typedef struct st_mysql_time_status { int warnings; uint precision; uint nanoseconds; } MYSQL_TIME_STATUS; static inline void my_time_status_init(MYSQL_TIME_STATUS *status) { status->warnings= 0; status->precision= 0; status->nanoseconds= 0; } my_bool check_date(const MYSQL_TIME *ltime, my_bool not_zero_date, ulonglong flags, int *was_cut); my_bool str_to_DDhhmmssff(const char *str, size_t length, MYSQL_TIME *l_time, ulong max_hour, MYSQL_TIME_STATUS *status); my_bool str_to_datetime_or_date_or_time(const char *str, size_t length, MYSQL_TIME *to, ulonglong flag, MYSQL_TIME_STATUS *status, ulong time_max_hour, ulong time_err_hour); my_bool str_to_datetime_or_date_or_interval_hhmmssff(const char *str, size_t length, MYSQL_TIME *to, ulonglong flag, MYSQL_TIME_STATUS *status, ulong time_max_hour, ulong time_err_hour); my_bool str_to_datetime_or_date_or_interval_day(const char *str, size_t length, MYSQL_TIME *to, ulonglong flag, MYSQL_TIME_STATUS *status, ulong time_max_hour, ulong time_err_hour); my_bool str_to_datetime_or_date(const char *str, size_t length, MYSQL_TIME *to, ulonglong flags, MYSQL_TIME_STATUS *status); longlong number_to_datetime_or_date(longlong nr, ulong sec_part, MYSQL_TIME *time_res, ulonglong flags, int *was_cut); int number_to_time_only(my_bool neg, ulonglong nr, ulong sec_part, ulong max_hour, MYSQL_TIME *to, int *was_cut); ulonglong TIME_to_ulonglong_datetime(const MYSQL_TIME *); ulonglong TIME_to_ulonglong_date(const MYSQL_TIME *); ulonglong TIME_to_ulonglong_time(const MYSQL_TIME *); ulonglong TIME_to_ulonglong(const MYSQL_TIME *); double TIME_to_double(const MYSQL_TIME *my_time); int check_time_range(struct st_mysql_time *my_time, uint dec, int *warning); my_bool check_datetime_range(const MYSQL_TIME *ltime); long calc_daynr(uint year,uint month,uint day); uint calc_days_in_year(uint year); uint year_2000_handling(uint year); void my_init_time(void); /* Function to check sanity of a TIMESTAMP value DESCRIPTION Check if a given MYSQL_TIME value fits in TIMESTAMP range. This function doesn't make precise check, but rather a rough estimate. RETURN VALUES TRUE The value seems sane FALSE The MYSQL_TIME value is definitely out of range */ static inline my_bool validate_timestamp_range(const MYSQL_TIME *t) { if ((t->year > TIMESTAMP_MAX_YEAR || t->year < TIMESTAMP_MIN_YEAR) || (t->year == TIMESTAMP_MAX_YEAR && (t->month > 1 || t->day > 19)) || (t->year == TIMESTAMP_MIN_YEAR && (t->month < 12 || t->day < 31))) return FALSE; return TRUE; } /* Can't include mysqld_error.h, it needs mysys to build, thus hardcode 2 error values here. */ #ifndef ER_WARN_DATA_OUT_OF_RANGE #define ER_WARN_DATA_OUT_OF_RANGE 1264 #define ER_WARN_INVALID_TIMESTAMP 1299 #endif my_time_t my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, uint *error_code); void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type); /* Required buffer length for my_time_to_str, my_date_to_str, my_datetime_to_str and TIME_to_string functions. Note, that the caller is still responsible to check that given TIME structure has values in valid ranges, otherwise size of the buffer could be not enough. We also rely on the fact that even wrong values sent using binary protocol fit in this buffer. */ #define MAX_DATE_STRING_REP_LENGTH 30 #define AUTO_SEC_PART_DIGITS DECIMAL_NOT_SPECIFIED int my_interval_DDhhmmssff_to_str(const MYSQL_TIME *, char *to, uint digits); int my_time_to_str(const MYSQL_TIME *l_time, char *to, uint digits); int my_date_to_str(const MYSQL_TIME *l_time, char *to); int my_datetime_to_str(const MYSQL_TIME *l_time, char *to, uint digits); int my_TIME_to_str(const MYSQL_TIME *l_time, char *to, uint digits); int my_timeval_to_str(const struct timeval *tm, char *to, uint dec); static inline longlong sec_part_shift(longlong second_part, uint digits) { return second_part / (longlong)log_10_int[TIME_SECOND_PART_DIGITS - digits]; } static inline longlong sec_part_unshift(longlong second_part, uint digits) { return second_part * (longlong)log_10_int[TIME_SECOND_PART_DIGITS - digits]; } /* Date/time rounding and truncation functions */ static inline long my_time_fraction_remainder(long nr, uint decimals) { return nr % (long) log_10_int[TIME_SECOND_PART_DIGITS - decimals]; } static inline void my_datetime_trunc(MYSQL_TIME *ltime, uint decimals) { ltime->second_part-= my_time_fraction_remainder(ltime->second_part, decimals); } static inline void my_time_trunc(MYSQL_TIME *ltime, uint decimals) { ltime->second_part-= my_time_fraction_remainder(ltime->second_part, decimals); if (!ltime->second_part && ltime->neg && !ltime->hour && !ltime->minute && !ltime->second) ltime->neg= FALSE; } #ifdef _WIN32 #define suseconds_t long #endif static inline void my_timeval_trunc(struct timeval *tv, uint decimals) { tv->tv_usec-= (suseconds_t) my_time_fraction_remainder(tv->tv_usec, decimals); } #define hrtime_to_my_time(X) ((my_time_t)hrtime_to_time(X)) /* Available interval types used in any statement. 'interval_type' must be sorted so that simple intervals comes first, ie year, quarter, month, week, day, hour, etc. The order based on interval size is also important and the intervals should be kept in a large to smaller order. (get_interval_value() depends on this) Note: If you change the order of elements in this enum you should fix order of elements in 'interval_type_to_name' and 'interval_names' arrays See also interval_type_to_name, get_interval_value, interval_names, append_interval */ enum interval_type { INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_WEEK, INTERVAL_DAY, INTERVAL_HOUR, INTERVAL_MINUTE, INTERVAL_SECOND, INTERVAL_MICROSECOND, INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND, INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND, INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND, INTERVAL_LAST }; C_MODE_END #endif /* _my_time_h_ */ server/private/custom_conf.h000064400000002072151031265040012212 0ustar00/* Copyright (c) 2000, 2006 MySQL AB Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef __MYSQL_CUSTOM_BUILD_CONFIG__ #define __MYSQL_CUSTOM_BUILD_CONFIG__ #define MYSQL_PORT 5002 #ifdef _WIN32 #define MYSQL_NAMEDPIPE "SwSqlServer" #define MYSQL_SERVICENAME "SwSqlServer" #define KEY_SERVICE_PARAMETERS "SYSTEM\\CurrentControlSet\\Services\\SwSqlServer\\Parameters" #endif #endif /* __MYSQL_CUSTOM_BUILD_CONFIG__ */ server/private/sql_analyze_stmt.h000064400000030611151031265040013264 0ustar00/* Copyright (c) 2015, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* == ANALYZE-stmt classes == This file contains classes for supporting "ANALYZE statement" feature. These are a set of data structures that can be used to store the data about how the statement executed. There are two kinds of data collection: 1. Various counters. We assume that incrementing counters has very low overhead. Because of that, execution code increments counters unconditionally (even when not running "ANALYZE $statement" commands. You run regular SELECT/ UPDATE/DELETE/etc and the counters are incremented). As a free bonus, this lets us print detailed information into the slow query log, should the query be slow. 2. Timing data. Measuring the time it took to run parts of query has noticeable overhead. Because of that, we measure the time only when running "ANALYZE $stmt"). */ /* fake microseconds as cycles if cycles isn't available */ static inline double timer_tracker_frequency() { #if (MY_TIMER_ROUTINE_CYCLES) return static_cast(sys_timer_info.cycles.frequency); #else return static_cast(sys_timer_info.microseconds.frequency); #endif } class Gap_time_tracker; void attach_gap_time_tracker(THD *thd, Gap_time_tracker *gap_tracker, ulonglong timeval); void process_gap_time_tracker(THD *thd, ulonglong timeval); /* A class for tracking time it takes to do a certain action */ class Exec_time_tracker { protected: ulonglong count; ulonglong cycles; ulonglong last_start; ulonglong measure() const { #if (MY_TIMER_ROUTINE_CYCLES) return my_timer_cycles(); #else return my_timer_microseconds(); #endif } void cycles_stop_tracking(THD *thd) { ulonglong end= measure(); cycles += end - last_start; process_gap_time_tracker(thd, end); if (my_gap_tracker) attach_gap_time_tracker(thd, my_gap_tracker, end); } /* The time spent after stop_tracking() call on this object and any subsequent time tracking call will be billed to this tracker. */ Gap_time_tracker *my_gap_tracker; public: Exec_time_tracker() : count(0), cycles(0), my_gap_tracker(NULL) {} void set_gap_tracker(Gap_time_tracker *gap_tracker) { my_gap_tracker= gap_tracker; } // interface for collecting time void start_tracking(THD *thd) { last_start= measure(); process_gap_time_tracker(thd, last_start); } void stop_tracking(THD *thd) { count++; cycles_stop_tracking(thd); } // interface for getting the time ulonglong get_loops() const { return count; } inline double cycles_to_ms(ulonglong cycles_arg) const { // convert 'cycles' to milliseconds. return 1000.0 * static_cast(cycles_arg) / timer_tracker_frequency(); } double get_time_ms() const { return cycles_to_ms(cycles); } ulonglong get_cycles() const { return cycles; } bool has_timed_statistics() const { return cycles > 0; } }; /* Tracker for time spent between the calls to Exec_time_tracker's {start| stop}_tracking(). @seealso Gap_time_tracker_data in sql_class.h */ class Gap_time_tracker { ulonglong cycles; public: Gap_time_tracker() : cycles(0) {} void log_time(ulonglong start, ulonglong end) { cycles += end - start; } double get_time_ms() const { // convert 'cycles' to milliseconds. return 1000.0 * static_cast(cycles) / timer_tracker_frequency(); } }; /* A class for counting certain actions (in all queries), and optionally collecting the timings (in ANALYZE queries). */ class Time_and_counter_tracker: public Exec_time_tracker { public: const bool timed; Time_and_counter_tracker(bool timed_arg) : timed(timed_arg) {} /* Loops are counted in both ANALYZE and regular queries, as this is cheap */ void incr_loops() { count++; } /* Unlike Exec_time_tracker::stop_tracking, we don't increase loops. */ void stop_tracking(THD *thd) { cycles_stop_tracking(thd); } }; #define ANALYZE_START_TRACKING(thd, tracker) \ { \ (tracker)->incr_loops(); \ if (unlikely((tracker)->timed)) \ { (tracker)->start_tracking(thd); } \ } #define ANALYZE_STOP_TRACKING(thd, tracker) \ if (unlikely((tracker)->timed)) \ { (tracker)->stop_tracking(thd); } /* Just a counter to increment one value. Wrapped in a class to be uniform with other counters used by ANALYZE. */ class Counter_tracker { public: Counter_tracker() : r_scans(0) {} ha_rows r_scans; inline void on_scan_init() { r_scans++; } bool has_scans() const { return (r_scans != 0); } ha_rows get_loops() const { return r_scans; } }; /* A class for collecting read statistics. The idea is that we run several scans. Each scans gets rows, and then filters some of them out. We count scans, rows, and rows left after filtering. (note: at the moment, the class is not actually tied to a physical table. It can be used to track reading from files, buffers, etc). */ class Table_access_tracker { public: Table_access_tracker() : r_scans(0), r_rows(0), r_rows_after_where(0) {} ha_rows r_scans; /* how many scans were ran on this join_tab */ ha_rows r_rows; /* How many rows we've got after that */ ha_rows r_rows_after_where; /* Rows after applying attached part of WHERE */ double get_avg_rows() const { return r_scans ? static_cast(r_rows) / static_cast(r_scans) : 0; } double get_filtered_after_where() const { return r_rows > 0 ? static_cast(r_rows_after_where) / static_cast(r_rows) : 1.0; } inline void on_scan_init() { r_scans++; } inline void on_record_read() { r_rows++; } inline void on_record_after_where() { r_rows_after_where++; } bool has_scans() const { return (r_scans != 0); } ha_rows get_loops() const { return r_scans; } }; class Json_writer; /* This stores the data about how filesort executed. A few things from here (e.g. r_used_pq, r_limit) belong to the query plan, however, these parameters are calculated right during the execution so we can't easily put them into the query plan. The class is designed to handle multiple invocations of filesort(). */ class Filesort_tracker : public Sql_alloc { public: Filesort_tracker(bool do_timing) : time_tracker(do_timing), r_limit(0), r_used_pq(0), r_examined_rows(0), r_sorted_rows(0), r_output_rows(0), sort_passes(0), sort_buffer_size(0), r_using_addons(false), r_packed_addon_fields(false), r_sort_keys_packed(false) {} /* Functions that filesort uses to report various things about its execution */ inline void report_use(THD *thd, ha_rows r_limit_arg) { if (!time_tracker.get_loops()) r_limit= r_limit_arg; else r_limit= (r_limit != r_limit_arg)? 0: r_limit_arg; ANALYZE_START_TRACKING(thd, &time_tracker); } inline void incr_pq_used() { r_used_pq++; } inline void report_row_numbers(ha_rows examined_rows, ha_rows sorted_rows, ha_rows returned_rows) { r_examined_rows += examined_rows; r_sorted_rows += sorted_rows; r_output_rows += returned_rows; } inline void report_merge_passes_at_start(ulong passes) { sort_passes -= passes; } inline void report_merge_passes_at_end(THD *thd, ulong passes) { ANALYZE_STOP_TRACKING(thd, &time_tracker); sort_passes += passes; } inline void report_sort_buffer_size(size_t bufsize) { if (sort_buffer_size) sort_buffer_size= ulonglong(-1); // multiple buffers of different sizes else sort_buffer_size= bufsize; } inline void report_addon_fields_format(bool addons_packed) { r_using_addons= true; r_packed_addon_fields= addons_packed; } inline void report_sort_keys_format(bool sort_keys_packed) { r_sort_keys_packed= sort_keys_packed; } void get_data_format(String *str); /* Functions to get the statistics */ void print_json_members(Json_writer *writer); ulonglong get_r_loops() const { return time_tracker.get_loops(); } double get_avg_examined_rows() const { return static_cast(r_examined_rows) / static_cast(get_r_loops()); } double get_avg_returned_rows() const { return static_cast(r_output_rows) / static_cast(get_r_loops()); } double get_r_filtered() const { return r_examined_rows > 0 ? static_cast(r_sorted_rows) / static_cast(r_examined_rows) : 1.0; } private: Time_and_counter_tracker time_tracker; //ulonglong r_loops; /* How many times filesort was invoked */ /* LIMIT is typically a constant. There is never "LIMIT 0". HA_POS_ERROR means we never had a limit 0 means different values of LIMIT were used in different filesort invocations other value means the same LIMIT value was used every time. */ ulonglong r_limit; ulonglong r_used_pq; /* How many times PQ was used */ /* How many rows were examined (before checking the select->cond) */ ulonglong r_examined_rows; /* How many rows were put into sorting (this is examined_rows minus rows that didn't pass the WHERE condition) */ ulonglong r_sorted_rows; /* How many rows were returned. This is equal to r_sorted_rows, unless there was a LIMIT N clause in which case filesort would not have returned more than N rows. */ ulonglong r_output_rows; /* How many sorts in total (divide by r_count to get the average) */ ulonglong sort_passes; /* 0 - means not used (or not known (ulonglong)-1 - multiple other - value */ ulonglong sort_buffer_size; bool r_using_addons; bool r_packed_addon_fields; bool r_sort_keys_packed; }; /** A class to collect data about how rowid filter is executed. It stores information about how rowid filter container is filled, containers size and observed selectivity. The observed selectivity is calculated in this way. Some elements elem_set are checked if they belong to container. Observed selectivity is calculated as the count of elem_set elements that belong to container devided by all elem_set elements. */ class Rowid_filter_tracker : public Sql_alloc { private: /* A member to track the time to fill the rowid filter */ Time_and_counter_tracker time_tracker; /* Size of the rowid filter container buffer */ size_t container_buff_size; /* Count of elements that were used to fill the rowid filter container */ uint container_elements; /* Elements counts used for observed selectivity calculation */ uint n_checks; uint n_positive_checks; public: Rowid_filter_tracker(bool do_timing) : time_tracker(do_timing), container_buff_size(0), container_elements(0), n_checks(0), n_positive_checks(0) {} inline void start_tracking(THD *thd) { ANALYZE_START_TRACKING(thd, &time_tracker); } inline void stop_tracking(THD *thd) { ANALYZE_STOP_TRACKING(thd, &time_tracker); } /* Save container buffer size in bytes */ inline void report_container_buff_size(uint elem_size) { container_buff_size= container_elements * elem_size / 8; } Time_and_counter_tracker *get_time_tracker() { return &time_tracker; } double get_time_fill_container_ms() const { return time_tracker.get_time_ms(); } void increment_checked_elements_count(bool was_checked) { n_checks++; if (was_checked) n_positive_checks++; } inline void increment_container_elements_count() { container_elements++; } uint get_container_elements() const { return container_elements; } uint get_container_lookups() { return n_checks; } double get_r_selectivity_pct() const { return n_checks ? static_cast(n_positive_checks) / static_cast(n_checks) : 0; } size_t get_container_buff_size() const { return container_buff_size; } }; server/private/pfs_transaction_provider.h000064400000005436151031265040015011 0ustar00/* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef PFS_TRANSACTION_PROVIDER_H #define PFS_TRANSACTION_PROVIDER_H /** @file include/pfs_transaction_provider.h Performance schema instrumentation (declarations). */ #ifdef HAVE_PSI_TRANSACTION_INTERFACE #ifdef MYSQL_SERVER #ifndef EMBEDDED_LIBRARY #ifndef MYSQL_DYNAMIC_PLUGIN #include "mysql/psi/psi.h" #define PSI_TRANSACTION_CALL(M) pfs_ ## M ## _v1 C_MODE_START PSI_transaction_locker* pfs_get_thread_transaction_locker_v1(PSI_transaction_locker_state *state, const void *xid, ulonglong trxid, int isolation_level, my_bool read_only, my_bool autocommit); void pfs_start_transaction_v1(PSI_transaction_locker *locker, const char *src_file, uint src_line); void pfs_set_transaction_xid_v1(PSI_transaction_locker *locker, const void *xid, int xa_state); void pfs_set_transaction_xa_state_v1(PSI_transaction_locker *locker, int xa_state); void pfs_set_transaction_gtid_v1(PSI_transaction_locker *locker, const void *sid, const void *gtid_spec); void pfs_set_transaction_trxid_v1(PSI_transaction_locker *locker, const ulonglong *trxid); void pfs_inc_transaction_savepoints_v1(PSI_transaction_locker *locker, ulong count); void pfs_inc_transaction_rollback_to_savepoint_v1(PSI_transaction_locker *locker, ulong count); void pfs_inc_transaction_release_savepoint_v1(PSI_transaction_locker *locker, ulong count); void pfs_end_transaction_v1(PSI_transaction_locker *locker, my_bool commit); C_MODE_END #endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_SERVER */ #endif /* HAVE_PSI_TRANSACTION_INTERFACE */ #endif server/private/probes_mysql_dtrace.h000064400000100355151031265040013737 0ustar00/* Generated by the Systemtap dtrace wrapper */ #define _SDT_HAS_SEMAPHORES 1 #define STAP_HAS_SEMAPHORES 1 /* deprecated */ #include /* MYSQL_CONNECTION_START ( unsigned long conn_id, char * user, char * host ) */ #if defined STAP_SDT_V1 #define MYSQL_CONNECTION_START_ENABLED() __builtin_expect (connection__start_semaphore, 0) #define mysql_connection__start_semaphore connection__start_semaphore #else #define MYSQL_CONNECTION_START_ENABLED() __builtin_expect (mysql_connection__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_connection__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_CONNECTION_START(arg1, arg2, arg3) \ DTRACE_PROBE3 (mysql, connection__start, arg1, arg2, arg3) /* MYSQL_CONNECTION_DONE ( int status, unsigned long conn_id ) */ #if defined STAP_SDT_V1 #define MYSQL_CONNECTION_DONE_ENABLED() __builtin_expect (connection__done_semaphore, 0) #define mysql_connection__done_semaphore connection__done_semaphore #else #define MYSQL_CONNECTION_DONE_ENABLED() __builtin_expect (mysql_connection__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_connection__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_CONNECTION_DONE(arg1, arg2) \ DTRACE_PROBE2 (mysql, connection__done, arg1, arg2) /* MYSQL_COMMAND_START ( unsigned long conn_id, int command, char * user, char * host ) */ #if defined STAP_SDT_V1 #define MYSQL_COMMAND_START_ENABLED() __builtin_expect (command__start_semaphore, 0) #define mysql_command__start_semaphore command__start_semaphore #else #define MYSQL_COMMAND_START_ENABLED() __builtin_expect (mysql_command__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_command__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_COMMAND_START(arg1, arg2, arg3, arg4) \ DTRACE_PROBE4 (mysql, command__start, arg1, arg2, arg3, arg4) /* MYSQL_COMMAND_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_COMMAND_DONE_ENABLED() __builtin_expect (command__done_semaphore, 0) #define mysql_command__done_semaphore command__done_semaphore #else #define MYSQL_COMMAND_DONE_ENABLED() __builtin_expect (mysql_command__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_command__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_COMMAND_DONE(arg1) \ DTRACE_PROBE1 (mysql, command__done, arg1) /* MYSQL_QUERY_START ( char * query, unsigned long conn_id, char * db_name, char * user, char * host ) */ #if defined STAP_SDT_V1 #define MYSQL_QUERY_START_ENABLED() __builtin_expect (query__start_semaphore, 0) #define mysql_query__start_semaphore query__start_semaphore #else #define MYSQL_QUERY_START_ENABLED() __builtin_expect (mysql_query__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_query__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_QUERY_START(arg1, arg2, arg3, arg4, arg5) \ DTRACE_PROBE5 (mysql, query__start, arg1, arg2, arg3, arg4, arg5) /* MYSQL_QUERY_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_QUERY_DONE_ENABLED() __builtin_expect (query__done_semaphore, 0) #define mysql_query__done_semaphore query__done_semaphore #else #define MYSQL_QUERY_DONE_ENABLED() __builtin_expect (mysql_query__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_query__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_QUERY_DONE(arg1) \ DTRACE_PROBE1 (mysql, query__done, arg1) /* MYSQL_QUERY_PARSE_START ( char * query ) */ #if defined STAP_SDT_V1 #define MYSQL_QUERY_PARSE_START_ENABLED() __builtin_expect (query__parse__start_semaphore, 0) #define mysql_query__parse__start_semaphore query__parse__start_semaphore #else #define MYSQL_QUERY_PARSE_START_ENABLED() __builtin_expect (mysql_query__parse__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_query__parse__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_QUERY_PARSE_START(arg1) \ DTRACE_PROBE1 (mysql, query__parse__start, arg1) /* MYSQL_QUERY_PARSE_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_QUERY_PARSE_DONE_ENABLED() __builtin_expect (query__parse__done_semaphore, 0) #define mysql_query__parse__done_semaphore query__parse__done_semaphore #else #define MYSQL_QUERY_PARSE_DONE_ENABLED() __builtin_expect (mysql_query__parse__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_query__parse__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_QUERY_PARSE_DONE(arg1) \ DTRACE_PROBE1 (mysql, query__parse__done, arg1) /* MYSQL_QUERY_CACHE_HIT ( char * query, unsigned long rows ) */ #if defined STAP_SDT_V1 #define MYSQL_QUERY_CACHE_HIT_ENABLED() __builtin_expect (query__cache__hit_semaphore, 0) #define mysql_query__cache__hit_semaphore query__cache__hit_semaphore #else #define MYSQL_QUERY_CACHE_HIT_ENABLED() __builtin_expect (mysql_query__cache__hit_semaphore, 0) #endif __extension__ extern unsigned short mysql_query__cache__hit_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_QUERY_CACHE_HIT(arg1, arg2) \ DTRACE_PROBE2 (mysql, query__cache__hit, arg1, arg2) /* MYSQL_QUERY_CACHE_MISS ( char * query ) */ #if defined STAP_SDT_V1 #define MYSQL_QUERY_CACHE_MISS_ENABLED() __builtin_expect (query__cache__miss_semaphore, 0) #define mysql_query__cache__miss_semaphore query__cache__miss_semaphore #else #define MYSQL_QUERY_CACHE_MISS_ENABLED() __builtin_expect (mysql_query__cache__miss_semaphore, 0) #endif __extension__ extern unsigned short mysql_query__cache__miss_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_QUERY_CACHE_MISS(arg1) \ DTRACE_PROBE1 (mysql, query__cache__miss, arg1) /* MYSQL_QUERY_EXEC_START ( char * query, unsigned long connid, char * db_name, char * user, char * host, int exec_type ) */ #if defined STAP_SDT_V1 #define MYSQL_QUERY_EXEC_START_ENABLED() __builtin_expect (query__exec__start_semaphore, 0) #define mysql_query__exec__start_semaphore query__exec__start_semaphore #else #define MYSQL_QUERY_EXEC_START_ENABLED() __builtin_expect (mysql_query__exec__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_query__exec__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_QUERY_EXEC_START(arg1, arg2, arg3, arg4, arg5, arg6) \ DTRACE_PROBE6 (mysql, query__exec__start, arg1, arg2, arg3, arg4, arg5, arg6) /* MYSQL_QUERY_EXEC_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_QUERY_EXEC_DONE_ENABLED() __builtin_expect (query__exec__done_semaphore, 0) #define mysql_query__exec__done_semaphore query__exec__done_semaphore #else #define MYSQL_QUERY_EXEC_DONE_ENABLED() __builtin_expect (mysql_query__exec__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_query__exec__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_QUERY_EXEC_DONE(arg1) \ DTRACE_PROBE1 (mysql, query__exec__done, arg1) /* MYSQL_INSERT_ROW_START ( char * db, char * table ) */ #if defined STAP_SDT_V1 #define MYSQL_INSERT_ROW_START_ENABLED() __builtin_expect (insert__row__start_semaphore, 0) #define mysql_insert__row__start_semaphore insert__row__start_semaphore #else #define MYSQL_INSERT_ROW_START_ENABLED() __builtin_expect (mysql_insert__row__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_insert__row__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_INSERT_ROW_START(arg1, arg2) \ DTRACE_PROBE2 (mysql, insert__row__start, arg1, arg2) /* MYSQL_INSERT_ROW_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_INSERT_ROW_DONE_ENABLED() __builtin_expect (insert__row__done_semaphore, 0) #define mysql_insert__row__done_semaphore insert__row__done_semaphore #else #define MYSQL_INSERT_ROW_DONE_ENABLED() __builtin_expect (mysql_insert__row__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_insert__row__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_INSERT_ROW_DONE(arg1) \ DTRACE_PROBE1 (mysql, insert__row__done, arg1) /* MYSQL_UPDATE_ROW_START ( char * db, char * table ) */ #if defined STAP_SDT_V1 #define MYSQL_UPDATE_ROW_START_ENABLED() __builtin_expect (update__row__start_semaphore, 0) #define mysql_update__row__start_semaphore update__row__start_semaphore #else #define MYSQL_UPDATE_ROW_START_ENABLED() __builtin_expect (mysql_update__row__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_update__row__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_UPDATE_ROW_START(arg1, arg2) \ DTRACE_PROBE2 (mysql, update__row__start, arg1, arg2) /* MYSQL_UPDATE_ROW_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_UPDATE_ROW_DONE_ENABLED() __builtin_expect (update__row__done_semaphore, 0) #define mysql_update__row__done_semaphore update__row__done_semaphore #else #define MYSQL_UPDATE_ROW_DONE_ENABLED() __builtin_expect (mysql_update__row__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_update__row__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_UPDATE_ROW_DONE(arg1) \ DTRACE_PROBE1 (mysql, update__row__done, arg1) /* MYSQL_DELETE_ROW_START ( char * db, char * table ) */ #if defined STAP_SDT_V1 #define MYSQL_DELETE_ROW_START_ENABLED() __builtin_expect (delete__row__start_semaphore, 0) #define mysql_delete__row__start_semaphore delete__row__start_semaphore #else #define MYSQL_DELETE_ROW_START_ENABLED() __builtin_expect (mysql_delete__row__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_delete__row__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_DELETE_ROW_START(arg1, arg2) \ DTRACE_PROBE2 (mysql, delete__row__start, arg1, arg2) /* MYSQL_DELETE_ROW_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_DELETE_ROW_DONE_ENABLED() __builtin_expect (delete__row__done_semaphore, 0) #define mysql_delete__row__done_semaphore delete__row__done_semaphore #else #define MYSQL_DELETE_ROW_DONE_ENABLED() __builtin_expect (mysql_delete__row__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_delete__row__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_DELETE_ROW_DONE(arg1) \ DTRACE_PROBE1 (mysql, delete__row__done, arg1) /* MYSQL_READ_ROW_START ( char * db, char * table, int scan_flag ) */ #if defined STAP_SDT_V1 #define MYSQL_READ_ROW_START_ENABLED() __builtin_expect (read__row__start_semaphore, 0) #define mysql_read__row__start_semaphore read__row__start_semaphore #else #define MYSQL_READ_ROW_START_ENABLED() __builtin_expect (mysql_read__row__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_read__row__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_READ_ROW_START(arg1, arg2, arg3) \ DTRACE_PROBE3 (mysql, read__row__start, arg1, arg2, arg3) /* MYSQL_READ_ROW_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_READ_ROW_DONE_ENABLED() __builtin_expect (read__row__done_semaphore, 0) #define mysql_read__row__done_semaphore read__row__done_semaphore #else #define MYSQL_READ_ROW_DONE_ENABLED() __builtin_expect (mysql_read__row__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_read__row__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_READ_ROW_DONE(arg1) \ DTRACE_PROBE1 (mysql, read__row__done, arg1) /* MYSQL_INDEX_READ_ROW_START ( char * db, char * table ) */ #if defined STAP_SDT_V1 #define MYSQL_INDEX_READ_ROW_START_ENABLED() __builtin_expect (index__read__row__start_semaphore, 0) #define mysql_index__read__row__start_semaphore index__read__row__start_semaphore #else #define MYSQL_INDEX_READ_ROW_START_ENABLED() __builtin_expect (mysql_index__read__row__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_index__read__row__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_INDEX_READ_ROW_START(arg1, arg2) \ DTRACE_PROBE2 (mysql, index__read__row__start, arg1, arg2) /* MYSQL_INDEX_READ_ROW_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_INDEX_READ_ROW_DONE_ENABLED() __builtin_expect (index__read__row__done_semaphore, 0) #define mysql_index__read__row__done_semaphore index__read__row__done_semaphore #else #define MYSQL_INDEX_READ_ROW_DONE_ENABLED() __builtin_expect (mysql_index__read__row__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_index__read__row__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_INDEX_READ_ROW_DONE(arg1) \ DTRACE_PROBE1 (mysql, index__read__row__done, arg1) /* MYSQL_HANDLER_RDLOCK_START ( char * db, char * table ) */ #if defined STAP_SDT_V1 #define MYSQL_HANDLER_RDLOCK_START_ENABLED() __builtin_expect (handler__rdlock__start_semaphore, 0) #define mysql_handler__rdlock__start_semaphore handler__rdlock__start_semaphore #else #define MYSQL_HANDLER_RDLOCK_START_ENABLED() __builtin_expect (mysql_handler__rdlock__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_handler__rdlock__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_HANDLER_RDLOCK_START(arg1, arg2) \ DTRACE_PROBE2 (mysql, handler__rdlock__start, arg1, arg2) /* MYSQL_HANDLER_WRLOCK_START ( char * db, char * table ) */ #if defined STAP_SDT_V1 #define MYSQL_HANDLER_WRLOCK_START_ENABLED() __builtin_expect (handler__wrlock__start_semaphore, 0) #define mysql_handler__wrlock__start_semaphore handler__wrlock__start_semaphore #else #define MYSQL_HANDLER_WRLOCK_START_ENABLED() __builtin_expect (mysql_handler__wrlock__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_handler__wrlock__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_HANDLER_WRLOCK_START(arg1, arg2) \ DTRACE_PROBE2 (mysql, handler__wrlock__start, arg1, arg2) /* MYSQL_HANDLER_UNLOCK_START ( char * db, char * table ) */ #if defined STAP_SDT_V1 #define MYSQL_HANDLER_UNLOCK_START_ENABLED() __builtin_expect (handler__unlock__start_semaphore, 0) #define mysql_handler__unlock__start_semaphore handler__unlock__start_semaphore #else #define MYSQL_HANDLER_UNLOCK_START_ENABLED() __builtin_expect (mysql_handler__unlock__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_handler__unlock__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_HANDLER_UNLOCK_START(arg1, arg2) \ DTRACE_PROBE2 (mysql, handler__unlock__start, arg1, arg2) /* MYSQL_HANDLER_RDLOCK_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_HANDLER_RDLOCK_DONE_ENABLED() __builtin_expect (handler__rdlock__done_semaphore, 0) #define mysql_handler__rdlock__done_semaphore handler__rdlock__done_semaphore #else #define MYSQL_HANDLER_RDLOCK_DONE_ENABLED() __builtin_expect (mysql_handler__rdlock__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_handler__rdlock__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_HANDLER_RDLOCK_DONE(arg1) \ DTRACE_PROBE1 (mysql, handler__rdlock__done, arg1) /* MYSQL_HANDLER_WRLOCK_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_HANDLER_WRLOCK_DONE_ENABLED() __builtin_expect (handler__wrlock__done_semaphore, 0) #define mysql_handler__wrlock__done_semaphore handler__wrlock__done_semaphore #else #define MYSQL_HANDLER_WRLOCK_DONE_ENABLED() __builtin_expect (mysql_handler__wrlock__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_handler__wrlock__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_HANDLER_WRLOCK_DONE(arg1) \ DTRACE_PROBE1 (mysql, handler__wrlock__done, arg1) /* MYSQL_HANDLER_UNLOCK_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_HANDLER_UNLOCK_DONE_ENABLED() __builtin_expect (handler__unlock__done_semaphore, 0) #define mysql_handler__unlock__done_semaphore handler__unlock__done_semaphore #else #define MYSQL_HANDLER_UNLOCK_DONE_ENABLED() __builtin_expect (mysql_handler__unlock__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_handler__unlock__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_HANDLER_UNLOCK_DONE(arg1) \ DTRACE_PROBE1 (mysql, handler__unlock__done, arg1) /* MYSQL_FILESORT_START ( char * db, char * table ) */ #if defined STAP_SDT_V1 #define MYSQL_FILESORT_START_ENABLED() __builtin_expect (filesort__start_semaphore, 0) #define mysql_filesort__start_semaphore filesort__start_semaphore #else #define MYSQL_FILESORT_START_ENABLED() __builtin_expect (mysql_filesort__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_filesort__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_FILESORT_START(arg1, arg2) \ DTRACE_PROBE2 (mysql, filesort__start, arg1, arg2) /* MYSQL_FILESORT_DONE ( int status, unsigned long rows ) */ #if defined STAP_SDT_V1 #define MYSQL_FILESORT_DONE_ENABLED() __builtin_expect (filesort__done_semaphore, 0) #define mysql_filesort__done_semaphore filesort__done_semaphore #else #define MYSQL_FILESORT_DONE_ENABLED() __builtin_expect (mysql_filesort__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_filesort__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_FILESORT_DONE(arg1, arg2) \ DTRACE_PROBE2 (mysql, filesort__done, arg1, arg2) /* MYSQL_SELECT_START ( char * query ) */ #if defined STAP_SDT_V1 #define MYSQL_SELECT_START_ENABLED() __builtin_expect (select__start_semaphore, 0) #define mysql_select__start_semaphore select__start_semaphore #else #define MYSQL_SELECT_START_ENABLED() __builtin_expect (mysql_select__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_select__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_SELECT_START(arg1) \ DTRACE_PROBE1 (mysql, select__start, arg1) /* MYSQL_SELECT_DONE ( int status, unsigned long rows ) */ #if defined STAP_SDT_V1 #define MYSQL_SELECT_DONE_ENABLED() __builtin_expect (select__done_semaphore, 0) #define mysql_select__done_semaphore select__done_semaphore #else #define MYSQL_SELECT_DONE_ENABLED() __builtin_expect (mysql_select__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_select__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_SELECT_DONE(arg1, arg2) \ DTRACE_PROBE2 (mysql, select__done, arg1, arg2) /* MYSQL_INSERT_START ( char * query ) */ #if defined STAP_SDT_V1 #define MYSQL_INSERT_START_ENABLED() __builtin_expect (insert__start_semaphore, 0) #define mysql_insert__start_semaphore insert__start_semaphore #else #define MYSQL_INSERT_START_ENABLED() __builtin_expect (mysql_insert__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_insert__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_INSERT_START(arg1) \ DTRACE_PROBE1 (mysql, insert__start, arg1) /* MYSQL_INSERT_DONE ( int status, unsigned long rows ) */ #if defined STAP_SDT_V1 #define MYSQL_INSERT_DONE_ENABLED() __builtin_expect (insert__done_semaphore, 0) #define mysql_insert__done_semaphore insert__done_semaphore #else #define MYSQL_INSERT_DONE_ENABLED() __builtin_expect (mysql_insert__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_insert__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_INSERT_DONE(arg1, arg2) \ DTRACE_PROBE2 (mysql, insert__done, arg1, arg2) /* MYSQL_INSERT_SELECT_START ( char * query ) */ #if defined STAP_SDT_V1 #define MYSQL_INSERT_SELECT_START_ENABLED() __builtin_expect (insert__select__start_semaphore, 0) #define mysql_insert__select__start_semaphore insert__select__start_semaphore #else #define MYSQL_INSERT_SELECT_START_ENABLED() __builtin_expect (mysql_insert__select__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_insert__select__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_INSERT_SELECT_START(arg1) \ DTRACE_PROBE1 (mysql, insert__select__start, arg1) /* MYSQL_INSERT_SELECT_DONE ( int status, unsigned long rows ) */ #if defined STAP_SDT_V1 #define MYSQL_INSERT_SELECT_DONE_ENABLED() __builtin_expect (insert__select__done_semaphore, 0) #define mysql_insert__select__done_semaphore insert__select__done_semaphore #else #define MYSQL_INSERT_SELECT_DONE_ENABLED() __builtin_expect (mysql_insert__select__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_insert__select__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_INSERT_SELECT_DONE(arg1, arg2) \ DTRACE_PROBE2 (mysql, insert__select__done, arg1, arg2) /* MYSQL_UPDATE_START ( char * query ) */ #if defined STAP_SDT_V1 #define MYSQL_UPDATE_START_ENABLED() __builtin_expect (update__start_semaphore, 0) #define mysql_update__start_semaphore update__start_semaphore #else #define MYSQL_UPDATE_START_ENABLED() __builtin_expect (mysql_update__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_update__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_UPDATE_START(arg1) \ DTRACE_PROBE1 (mysql, update__start, arg1) /* MYSQL_UPDATE_DONE ( int status, unsigned long rowsmatches, unsigned long rowschanged ) */ #if defined STAP_SDT_V1 #define MYSQL_UPDATE_DONE_ENABLED() __builtin_expect (update__done_semaphore, 0) #define mysql_update__done_semaphore update__done_semaphore #else #define MYSQL_UPDATE_DONE_ENABLED() __builtin_expect (mysql_update__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_update__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_UPDATE_DONE(arg1, arg2, arg3) \ DTRACE_PROBE3 (mysql, update__done, arg1, arg2, arg3) /* MYSQL_MULTI_UPDATE_START ( char * query ) */ #if defined STAP_SDT_V1 #define MYSQL_MULTI_UPDATE_START_ENABLED() __builtin_expect (multi__update__start_semaphore, 0) #define mysql_multi__update__start_semaphore multi__update__start_semaphore #else #define MYSQL_MULTI_UPDATE_START_ENABLED() __builtin_expect (mysql_multi__update__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_multi__update__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_MULTI_UPDATE_START(arg1) \ DTRACE_PROBE1 (mysql, multi__update__start, arg1) /* MYSQL_MULTI_UPDATE_DONE ( int status, unsigned long rowsmatches, unsigned long rowschanged ) */ #if defined STAP_SDT_V1 #define MYSQL_MULTI_UPDATE_DONE_ENABLED() __builtin_expect (multi__update__done_semaphore, 0) #define mysql_multi__update__done_semaphore multi__update__done_semaphore #else #define MYSQL_MULTI_UPDATE_DONE_ENABLED() __builtin_expect (mysql_multi__update__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_multi__update__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_MULTI_UPDATE_DONE(arg1, arg2, arg3) \ DTRACE_PROBE3 (mysql, multi__update__done, arg1, arg2, arg3) /* MYSQL_DELETE_START ( char * query ) */ #if defined STAP_SDT_V1 #define MYSQL_DELETE_START_ENABLED() __builtin_expect (delete__start_semaphore, 0) #define mysql_delete__start_semaphore delete__start_semaphore #else #define MYSQL_DELETE_START_ENABLED() __builtin_expect (mysql_delete__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_delete__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_DELETE_START(arg1) \ DTRACE_PROBE1 (mysql, delete__start, arg1) /* MYSQL_DELETE_DONE ( int status, unsigned long rows ) */ #if defined STAP_SDT_V1 #define MYSQL_DELETE_DONE_ENABLED() __builtin_expect (delete__done_semaphore, 0) #define mysql_delete__done_semaphore delete__done_semaphore #else #define MYSQL_DELETE_DONE_ENABLED() __builtin_expect (mysql_delete__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_delete__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_DELETE_DONE(arg1, arg2) \ DTRACE_PROBE2 (mysql, delete__done, arg1, arg2) /* MYSQL_MULTI_DELETE_START ( char * query ) */ #if defined STAP_SDT_V1 #define MYSQL_MULTI_DELETE_START_ENABLED() __builtin_expect (multi__delete__start_semaphore, 0) #define mysql_multi__delete__start_semaphore multi__delete__start_semaphore #else #define MYSQL_MULTI_DELETE_START_ENABLED() __builtin_expect (mysql_multi__delete__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_multi__delete__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_MULTI_DELETE_START(arg1) \ DTRACE_PROBE1 (mysql, multi__delete__start, arg1) /* MYSQL_MULTI_DELETE_DONE ( int status, unsigned long rows ) */ #if defined STAP_SDT_V1 #define MYSQL_MULTI_DELETE_DONE_ENABLED() __builtin_expect (multi__delete__done_semaphore, 0) #define mysql_multi__delete__done_semaphore multi__delete__done_semaphore #else #define MYSQL_MULTI_DELETE_DONE_ENABLED() __builtin_expect (mysql_multi__delete__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_multi__delete__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_MULTI_DELETE_DONE(arg1, arg2) \ DTRACE_PROBE2 (mysql, multi__delete__done, arg1, arg2) /* MYSQL_NET_READ_START ( ) */ #if defined STAP_SDT_V1 #define MYSQL_NET_READ_START_ENABLED() __builtin_expect (net__read__start_semaphore, 0) #define mysql_net__read__start_semaphore net__read__start_semaphore #else #define MYSQL_NET_READ_START_ENABLED() __builtin_expect (mysql_net__read__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_net__read__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_NET_READ_START() \ DTRACE_PROBE (mysql, net__read__start) /* MYSQL_NET_READ_DONE ( int status, unsigned long bytes ) */ #if defined STAP_SDT_V1 #define MYSQL_NET_READ_DONE_ENABLED() __builtin_expect (net__read__done_semaphore, 0) #define mysql_net__read__done_semaphore net__read__done_semaphore #else #define MYSQL_NET_READ_DONE_ENABLED() __builtin_expect (mysql_net__read__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_net__read__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_NET_READ_DONE(arg1, arg2) \ DTRACE_PROBE2 (mysql, net__read__done, arg1, arg2) /* MYSQL_NET_WRITE_START ( unsigned long bytes ) */ #if defined STAP_SDT_V1 #define MYSQL_NET_WRITE_START_ENABLED() __builtin_expect (net__write__start_semaphore, 0) #define mysql_net__write__start_semaphore net__write__start_semaphore #else #define MYSQL_NET_WRITE_START_ENABLED() __builtin_expect (mysql_net__write__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_net__write__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_NET_WRITE_START(arg1) \ DTRACE_PROBE1 (mysql, net__write__start, arg1) /* MYSQL_NET_WRITE_DONE ( int status ) */ #if defined STAP_SDT_V1 #define MYSQL_NET_WRITE_DONE_ENABLED() __builtin_expect (net__write__done_semaphore, 0) #define mysql_net__write__done_semaphore net__write__done_semaphore #else #define MYSQL_NET_WRITE_DONE_ENABLED() __builtin_expect (mysql_net__write__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_net__write__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_NET_WRITE_DONE(arg1) \ DTRACE_PROBE1 (mysql, net__write__done, arg1) /* MYSQL_KEYCACHE_READ_START ( char * filepath, unsigned long bytes, unsigned long mem_used, unsigned long mem_free ) */ #if defined STAP_SDT_V1 #define MYSQL_KEYCACHE_READ_START_ENABLED() __builtin_expect (keycache__read__start_semaphore, 0) #define mysql_keycache__read__start_semaphore keycache__read__start_semaphore #else #define MYSQL_KEYCACHE_READ_START_ENABLED() __builtin_expect (mysql_keycache__read__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_keycache__read__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_KEYCACHE_READ_START(arg1, arg2, arg3, arg4) \ DTRACE_PROBE4 (mysql, keycache__read__start, arg1, arg2, arg3, arg4) /* MYSQL_KEYCACHE_READ_BLOCK ( unsigned long bytes ) */ #if defined STAP_SDT_V1 #define MYSQL_KEYCACHE_READ_BLOCK_ENABLED() __builtin_expect (keycache__read__block_semaphore, 0) #define mysql_keycache__read__block_semaphore keycache__read__block_semaphore #else #define MYSQL_KEYCACHE_READ_BLOCK_ENABLED() __builtin_expect (mysql_keycache__read__block_semaphore, 0) #endif __extension__ extern unsigned short mysql_keycache__read__block_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_KEYCACHE_READ_BLOCK(arg1) \ DTRACE_PROBE1 (mysql, keycache__read__block, arg1) /* MYSQL_KEYCACHE_READ_HIT ( ) */ #if defined STAP_SDT_V1 #define MYSQL_KEYCACHE_READ_HIT_ENABLED() __builtin_expect (keycache__read__hit_semaphore, 0) #define mysql_keycache__read__hit_semaphore keycache__read__hit_semaphore #else #define MYSQL_KEYCACHE_READ_HIT_ENABLED() __builtin_expect (mysql_keycache__read__hit_semaphore, 0) #endif __extension__ extern unsigned short mysql_keycache__read__hit_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_KEYCACHE_READ_HIT() \ DTRACE_PROBE (mysql, keycache__read__hit) /* MYSQL_KEYCACHE_READ_MISS ( ) */ #if defined STAP_SDT_V1 #define MYSQL_KEYCACHE_READ_MISS_ENABLED() __builtin_expect (keycache__read__miss_semaphore, 0) #define mysql_keycache__read__miss_semaphore keycache__read__miss_semaphore #else #define MYSQL_KEYCACHE_READ_MISS_ENABLED() __builtin_expect (mysql_keycache__read__miss_semaphore, 0) #endif __extension__ extern unsigned short mysql_keycache__read__miss_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_KEYCACHE_READ_MISS() \ DTRACE_PROBE (mysql, keycache__read__miss) /* MYSQL_KEYCACHE_READ_DONE ( unsigned long mem_used, unsigned long mem_free ) */ #if defined STAP_SDT_V1 #define MYSQL_KEYCACHE_READ_DONE_ENABLED() __builtin_expect (keycache__read__done_semaphore, 0) #define mysql_keycache__read__done_semaphore keycache__read__done_semaphore #else #define MYSQL_KEYCACHE_READ_DONE_ENABLED() __builtin_expect (mysql_keycache__read__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_keycache__read__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_KEYCACHE_READ_DONE(arg1, arg2) \ DTRACE_PROBE2 (mysql, keycache__read__done, arg1, arg2) /* MYSQL_KEYCACHE_WRITE_START ( char * filepath, unsigned long bytes, unsigned long mem_used, unsigned long mem_free ) */ #if defined STAP_SDT_V1 #define MYSQL_KEYCACHE_WRITE_START_ENABLED() __builtin_expect (keycache__write__start_semaphore, 0) #define mysql_keycache__write__start_semaphore keycache__write__start_semaphore #else #define MYSQL_KEYCACHE_WRITE_START_ENABLED() __builtin_expect (mysql_keycache__write__start_semaphore, 0) #endif __extension__ extern unsigned short mysql_keycache__write__start_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_KEYCACHE_WRITE_START(arg1, arg2, arg3, arg4) \ DTRACE_PROBE4 (mysql, keycache__write__start, arg1, arg2, arg3, arg4) /* MYSQL_KEYCACHE_WRITE_BLOCK ( unsigned long bytes ) */ #if defined STAP_SDT_V1 #define MYSQL_KEYCACHE_WRITE_BLOCK_ENABLED() __builtin_expect (keycache__write__block_semaphore, 0) #define mysql_keycache__write__block_semaphore keycache__write__block_semaphore #else #define MYSQL_KEYCACHE_WRITE_BLOCK_ENABLED() __builtin_expect (mysql_keycache__write__block_semaphore, 0) #endif __extension__ extern unsigned short mysql_keycache__write__block_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_KEYCACHE_WRITE_BLOCK(arg1) \ DTRACE_PROBE1 (mysql, keycache__write__block, arg1) /* MYSQL_KEYCACHE_WRITE_DONE ( unsigned long mem_used, unsigned long mem_free ) */ #if defined STAP_SDT_V1 #define MYSQL_KEYCACHE_WRITE_DONE_ENABLED() __builtin_expect (keycache__write__done_semaphore, 0) #define mysql_keycache__write__done_semaphore keycache__write__done_semaphore #else #define MYSQL_KEYCACHE_WRITE_DONE_ENABLED() __builtin_expect (mysql_keycache__write__done_semaphore, 0) #endif __extension__ extern unsigned short mysql_keycache__write__done_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes"))); #define MYSQL_KEYCACHE_WRITE_DONE(arg1, arg2) \ DTRACE_PROBE2 (mysql, keycache__write__done, arg1, arg2) server/private/sql_plugin_compat.h000064400000004275151031265040013422 0ustar00/* Copyright (C) 2013 Sergei Golubchik and Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* old plugin api structures, used for backward compatibility */ #define upgrade_var(X) latest->X= X #define upgrade_str(X) strmake_buf(latest->X, X) #define downgrade_var(X) X= latest->X #define downgrade_str(X) strmake_buf(X, latest->X) /**************************************************************/ /* Authentication API, version 0x0100 *************************/ #define MIN_AUTHENTICATION_INTERFACE_VERSION 0x0100 struct MYSQL_SERVER_AUTH_INFO_0x0100 { const char *user_name; unsigned int user_name_length; const char *auth_string; unsigned long auth_string_length; char authenticated_as[49]; char external_user[512]; int password_used; const char *host_or_ip; unsigned int host_or_ip_length; void upgrade(MYSQL_SERVER_AUTH_INFO *latest) { upgrade_var(user_name); upgrade_var(user_name_length); upgrade_var(auth_string); upgrade_var(auth_string_length); upgrade_str(authenticated_as); upgrade_str(external_user); upgrade_var(password_used); upgrade_var(host_or_ip); upgrade_var(host_or_ip_length); } void downgrade(MYSQL_SERVER_AUTH_INFO *latest) { downgrade_var(user_name); downgrade_var(user_name_length); downgrade_var(auth_string); downgrade_var(auth_string_length); downgrade_str(authenticated_as); downgrade_str(external_user); downgrade_var(password_used); downgrade_var(host_or_ip); downgrade_var(host_or_ip_length); } }; /**************************************************************/ server/private/item_row.h000064400000012145151031265040011522 0ustar00#ifndef ITEM_ROW_INCLUDED #define ITEM_ROW_INCLUDED /* Copyright (c) 2002, 2013, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** Row items used for comparing rows and IN operations on rows: @verbatim (a, b, c) > (10, 10, 30) (a, b, c) = (select c, d, e, from t1 where x=12) (a, b, c) IN ((1,2,2), (3,4,5), (6,7,8) (a, b, c) IN (select c, d, e, from t1) @endverbatim */ /** Item which stores (x,y,...) and ROW(x,y,...). Note that this can be recursive: ((x,y),(z,t)) is a ROW of ROWs. */ class Item_row: public Item_fixed_hybrid, private Item_args, private Used_tables_and_const_cache { table_map not_null_tables_cache; /** If elements are made only of constants, of which one or more are NULL. For example, this item is (1,2,NULL), or ( (1,NULL), (2,3) ). */ bool with_null; public: Item_row(THD *thd, List &list) :Item_fixed_hybrid(thd), Item_args(thd, list), not_null_tables_cache(0), with_null(0) { } Item_row(THD *thd, Item_row *row) :Item_fixed_hybrid(thd), Item_args(thd, static_cast(row)), Used_tables_and_const_cache(), not_null_tables_cache(0), with_null(0) { } enum Type type() const override { return ROW_ITEM; }; const Type_handler *type_handler() const override { return &type_handler_row; } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { return NULL; // Check with Vicentiu why it's called for Item_row } void illegal_method_call(const char *); bool is_null() override { return null_value; } void make_send_field(THD *thd, Send_field *) override { illegal_method_call((const char*)"make_send_field"); }; double val_real() override { illegal_method_call((const char*)"val"); return 0; }; longlong val_int() override { illegal_method_call((const char*)"val_int"); return 0; }; String *val_str(String *) override { illegal_method_call((const char*)"val_str"); return 0; }; my_decimal *val_decimal(my_decimal *) override { illegal_method_call((const char*)"val_decimal"); return 0; }; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { illegal_method_call((const char*)"get_date"); return true; } bool fix_fields(THD *thd, Item **ref) override; void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; void cleanup() override; void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, uint flags) override; table_map used_tables() const override { return used_tables_cache; }; bool const_item() const override { return const_item_cache; }; void update_used_tables() override { used_tables_and_const_cache_init(); used_tables_and_const_cache_update_and_join(arg_count, args); } table_map not_null_tables() const override { return not_null_tables_cache; } void print(String *str, enum_query_type query_type) override; bool walk(Item_processor processor, bool walk_subquery, void *arg) override { if (walk_args(processor, walk_subquery, arg)) return true; return (this->*processor)(arg); } Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override; bool eval_not_null_tables(void *opt_arg) override; bool find_not_null_fields(table_map allowed) override; uint cols() const override { return arg_count; } Item* element_index(uint i) override { return args[i]; } Item** addr(uint i) override { return args + i; } bool check_cols(uint c) override; bool null_inside() override { return with_null; }; void bring_value() override; Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { Item_args::propagate_equal_fields(thd, Context_identity(), cond); return this; } bool excl_dep_on_table(table_map tab_map) override { return Item_args::excl_dep_on_table(tab_map); } bool excl_dep_on_grouping_fields(st_select_lex *sel) override { return Item_args::excl_dep_on_grouping_fields(sel); } bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override { return Item_args::excl_dep_on_in_subq_left_part(subq_pred); } bool check_vcol_func_processor(void *arg) override {return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override; }; #endif /* ITEM_ROW_INCLUDED */ server/private/wsrep_priv.h000064400000003142151031265040012072 0ustar00/* Copyright 2010-2023 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ //! @file declares symbols private to wsrep integration layer #ifndef WSREP_PRIV_H #define WSREP_PRIV_H #include "wsrep_api.h" #include "wsrep/server_state.hpp" ssize_t wsrep_sst_prepare (void** msg); wsrep_cb_status wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx, const wsrep_buf_t* msg, const wsrep_gtid_t* state_id, const wsrep_buf_t* state, bool bypass); extern wsrep_uuid_t local_uuid; extern wsrep_seqno_t local_seqno; // a helper function bool wsrep_sst_received(THD*, const wsrep_uuid_t&, wsrep_seqno_t, const void*, size_t); void wsrep_notify_status(enum wsrep::server_state::state status, const wsrep::view* view= 0); #endif /* WSREP_PRIV_H */ server/private/mariadb.h000064400000002375151031265040011300 0ustar00/* Copyright (c) 2010, 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Include file that should always be included first in all file in the sql directory. Used to ensure that some files, like my_global.h and my_config.h are always included first. It can also be used to speed up compilation by using precompiled headers. This file should include a minum set of header files used by all files and header files that are very seldom changed. It can also include some defines that all files should be aware of. */ #ifndef MARIADB_INCLUDED #define MARIADB_INCLUDED #include #endif /* MARIADB_INCLUDED */ server/private/pfs_metadata_provider.h000064400000003552151031265040014241 0ustar00/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef PFS_METADATA_PROVIDER_H #define PFS_METADATA_PROVIDER_H /** @file include/pfs_metadata_provider.h Performance schema instrumentation (declarations). */ #ifdef HAVE_PSI_METADATA_INTERFACE #ifdef MYSQL_SERVER #ifndef EMBEDDED_LIBRARY #ifndef MYSQL_DYNAMIC_PLUGIN #include "mysql/psi/psi.h" #define PSI_METADATA_CALL(M) pfs_ ## M ## _v1 C_MODE_START PSI_metadata_lock* pfs_create_metadata_lock_v1 (void *identity, const MDL_key *key, opaque_mdl_type mdl_type, opaque_mdl_duration mdl_duration, opaque_mdl_status mdl_status, const char *src_file, uint src_line); void pfs_set_metadata_lock_status_v1 (PSI_metadata_lock *lock, opaque_mdl_status mdl_status); void pfs_destroy_metadata_lock_v1(PSI_metadata_lock *lock); struct PSI_metadata_locker* pfs_start_metadata_wait_v1 (struct PSI_metadata_locker_state_v1 *state, struct PSI_metadata_lock *mdl, const char *src_file, uint src_line); void pfs_end_metadata_wait_v1 (struct PSI_metadata_locker *locker, int rc); C_MODE_END #endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_SERVER */ #endif /* HAVE_PSI_METADATA_INTERFACE */ #endif server/private/sql_callback.h000064400000003006151031265040012304 0ustar00/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_CALLBACK_INCLUDED #define SQL_CALLBACK_INCLUDED /** Macro used for an internal callback. The macro will check that the object exists and that the function is defined. If that is the case, it will call the function with the given parameters. If the object or the function is not defined, the callback will be considered successful (nothing needed to be done) and will therefore return no error. */ #define MYSQL_CALLBACK(OBJ, FUNC, PARAMS) \ do { \ if ((OBJ) && ((OBJ)->FUNC)) \ (OBJ)->FUNC PARAMS; \ } while (0) #define MYSQL_CALLBACK_ELSE(OBJ, FUNC, PARAMS, ELSE) \ (((OBJ) && ((OBJ)->FUNC)) ? (OBJ)->FUNC PARAMS : (ELSE)) #endif /* SQL_CALLBACK_INCLUDED */ server/private/wsrep_sst.h000064400000007557151031265040011741 0ustar00/* Copyright (C) 2013-2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA. */ #ifndef WSREP_SST_H #define WSREP_SST_H #include #include "wsrep/gtid.hpp" #include #include #define WSREP_SST_OPT_ROLE "--role" #define WSREP_SST_OPT_ADDR "--address" #define WSREP_SST_OPT_AUTH "--auth" #define WSREP_SST_OPT_DATA "--datadir" #define WSREP_SST_OPT_CONF "--defaults-file" #define WSREP_SST_OPT_CONF_SUFFIX "--defaults-group-suffix" #define WSREP_SST_OPT_CONF_EXTRA "--defaults-extra-file" #define WSREP_SST_OPT_PARENT "--parent" #define WSREP_SST_OPT_BINLOG "--binlog" #define WSREP_SST_OPT_BINLOG_INDEX "--binlog-index" #define WSREP_SST_OPT_PROGRESS "--progress" #define WSREP_SST_OPT_MYSQLD "--mysqld-args" // mysqldump-specific options #define WSREP_SST_OPT_USER "--user" #define WSREP_SST_OPT_PSWD "--password" #define WSREP_SST_OPT_HOST "--host" #define WSREP_SST_OPT_PORT "--port" #define WSREP_SST_OPT_LPORT "--local-port" // donor-specific #define WSREP_SST_OPT_SOCKET "--socket" #define WSREP_SST_OPT_GTID "--gtid" #define WSREP_SST_OPT_BYPASS "--bypass" #define WSREP_SST_OPT_GTID_DOMAIN_ID "--gtid-domain-id" #define WSREP_SST_MYSQLDUMP "mysqldump" #define WSREP_SST_RSYNC "rsync" #define WSREP_SST_SKIP "skip" #define WSREP_SST_MARIABACKUP "mariabackup" #define WSREP_SST_XTRABACKUP "xtrabackup" #define WSREP_SST_XTRABACKUPV2 "xtrabackupv2" #define WSREP_SST_DEFAULT WSREP_SST_RSYNC #define WSREP_SST_ADDRESS_AUTO "AUTO" #define WSREP_SST_AUTH_MASK "********" /* system variables */ extern const char* wsrep_sst_method; extern const char* wsrep_sst_receive_address; extern const char* wsrep_sst_donor; extern const char* wsrep_sst_auth; extern my_bool wsrep_sst_donor_rejects_queries; /*! Synchronizes applier thread start with init thread */ extern void wsrep_sst_grab(); /*! Init thread waits for SST completion */ extern bool wsrep_sst_wait(); /*! Signals wsrep that initialization is complete, writesets can be applied */ extern bool wsrep_sst_continue(); extern void wsrep_sst_auth_init(); extern void wsrep_sst_auth_free(); extern void wsrep_SE_init_grab(); /*! grab init critical section */ extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */ extern void wsrep_SE_init_done(); /*! signal that SE init is complte */ extern void wsrep_SE_initialized(); /*! mark SE initialization complete */ /** Return a string containing the state transfer request string. Note that the string may contain a '\0' in the middle. */ std::string wsrep_sst_prepare(); /** Donate a SST. @param request SST request string received from the joiner. Note that the string may contain a '\0' in the middle. @param gtid Current position of the donor @param bypass If true, full SST is not needed. Joiner needs to be notified that it can continue starting from gtid. */ int wsrep_sst_donate(const std::string& request, const wsrep::gtid& gtid, bool bypass); #else #define wsrep_SE_initialized() do { } while(0) #define wsrep_SE_init_grab() do { } while(0) #define wsrep_SE_init_done() do { } while(0) #define wsrep_sst_continue() (0) #endif /* WSREP_SST_H */ server/private/log.h000064400000132003151031265040010452 0ustar00/* Copyright (c) 2005, 2016, Oracle and/or its affiliates. Copyright (c) 2009, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef LOG_H #define LOG_H #include "handler.h" /* my_xid */ #include "rpl_constants.h" class Relay_log_info; class Format_description_log_event; bool reopen_fstreams(const char *filename, FILE *outstream, FILE *errstream); void setup_log_handling(); bool trans_has_updated_trans_table(const THD* thd); bool stmt_has_updated_trans_table(const THD *thd); bool use_trans_cache(const THD* thd, bool is_transactional); bool ending_trans(THD* thd, const bool all); bool ending_single_stmt_trans(THD* thd, const bool all); bool trans_has_updated_non_trans_table(const THD* thd); bool stmt_has_updated_non_trans_table(const THD* thd); /* Transaction Coordinator log - a base abstract class for two different implementations */ class TC_LOG { public: int using_heuristic_recover(); TC_LOG() = default; virtual ~TC_LOG() = default; virtual int open(const char *opt_name)=0; virtual void close()=0; /* Transaction coordinator 2-phase commit. Must invoke the run_prepare_ordered and run_commit_ordered methods, as described below for these methods. In addition, must invoke THD::wait_for_prior_commit(), or equivalent wait, to ensure that one commit waits for another if registered to do so. */ virtual int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered) = 0; virtual int unlog(ulong cookie, my_xid xid)=0; virtual int unlog_xa_prepare(THD *thd, bool all)= 0; virtual void commit_checkpoint_notify(void *cookie)= 0; protected: /* These methods are meant to be invoked from log_and_order() implementations to run any prepare_ordered() respectively commit_ordered() methods in participating handlers. They must be called using suitable thread syncronisation to ensure that they are each called in the correct commit order among all transactions. However, it is only necessary to call them if the corresponding flag passed to log_and_order is set (it is safe, but not required, to call them when the flag is false). The caller must be holding LOCK_prepare_ordered respectively LOCK_commit_ordered when calling these methods. */ void run_prepare_ordered(THD *thd, bool all); void run_commit_ordered(THD *thd, bool all); }; /* Locks used to ensure serialised execution of TC_LOG::run_prepare_ordered() and TC_LOG::run_commit_ordered(), or any other code that calls handler prepare_ordered() or commit_ordered() methods. */ extern mysql_mutex_t LOCK_prepare_ordered; extern mysql_cond_t COND_prepare_ordered; extern mysql_mutex_t LOCK_after_binlog_sync; extern mysql_mutex_t LOCK_commit_ordered; #ifdef HAVE_PSI_INTERFACE extern PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered; extern PSI_mutex_key key_LOCK_after_binlog_sync; extern PSI_cond_key key_COND_prepare_ordered; #endif class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging { public: TC_LOG_DUMMY() = default; int open(const char *opt_name) override { return 0; } void close() override { } /* TC_LOG_DUMMY is only used when there are <= 1 XA-capable engines, and we only use internal XA during commit when >= 2 XA-capable engines participate. */ int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered) override { DBUG_ASSERT(0); return 1; } int unlog(ulong cookie, my_xid xid) override { return 0; } int unlog_xa_prepare(THD *thd, bool all) override { return 0; } void commit_checkpoint_notify(void *cookie) override { DBUG_ASSERT(0); }; }; #define TC_LOG_PAGE_SIZE 8192 #ifdef HAVE_MMAP class TC_LOG_MMAP: public TC_LOG { public: // only to keep Sun Forte on sol9x86 happy typedef enum { PS_POOL, // page is in pool PS_ERROR, // last sync failed PS_DIRTY // new xids added since last sync } PAGE_STATE; struct pending_cookies { uint count; uint pending_count; ulong cookies[1]; }; private: typedef struct st_page { struct st_page *next; // page a linked in a fifo queue my_xid *start, *end; // usable area of a page my_xid *ptr; // next xid will be written here int size, free; // max and current number of free xid slots on the page int waiters; // number of waiters on condition PAGE_STATE state; // see above mysql_mutex_t lock; // to access page data or control structure mysql_cond_t cond; // to wait for a sync } PAGE; /* List of THDs for which to invoke commit_ordered(), in order. */ struct commit_entry { struct commit_entry *next; THD *thd; }; char logname[FN_REFLEN]; File fd; my_off_t file_length; uint npages, inited; uchar *data; struct st_page *pages, *syncing, *active, *pool, **pool_last_ptr; /* note that, e.g. LOCK_active is only used to protect 'active' pointer, to protect the content of the active page one has to use active->lock. Same for LOCK_pool and LOCK_sync */ mysql_mutex_t LOCK_active, LOCK_pool, LOCK_sync, LOCK_pending_checkpoint; mysql_cond_t COND_pool, COND_active; /* Queue of threads that need to call commit_ordered(). Access to this queue must be protected by LOCK_prepare_ordered. */ commit_entry *commit_ordered_queue; /* This flag and condition is used to reserve the queue while threads in it each run the commit_ordered() methods one after the other. Only once the last commit_ordered() in the queue is done can we start on a new queue run. Since we start this process in the first thread in the queue and finish in the last (and possibly different) thread, we need a condition variable for this (we cannot unlock a mutex in a different thread than the one who locked it). The condition is used together with the LOCK_prepare_ordered mutex. */ mysql_cond_t COND_queue_busy; my_bool commit_ordered_queue_busy; pending_cookies* pending_checkpoint; public: TC_LOG_MMAP(): inited(0), pending_checkpoint(0) {} int open(const char *opt_name) override; void close() override; int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered) override; int unlog(ulong cookie, my_xid xid) override; int unlog_xa_prepare(THD *thd, bool all) override { return 0; } void commit_checkpoint_notify(void *cookie) override; int recover(); private: int log_one_transaction(my_xid xid); void get_active_from_pool(); int sync(); int overflow(); int delete_entry(ulong cookie); }; #else #define TC_LOG_MMAP TC_LOG_DUMMY #endif extern TC_LOG *tc_log; extern TC_LOG_MMAP tc_log_mmap; extern TC_LOG_DUMMY tc_log_dummy; /* log info errors */ #define LOG_INFO_EOF -1 #define LOG_INFO_IO -2 #define LOG_INFO_INVALID -3 #define LOG_INFO_SEEK -4 #define LOG_INFO_MEM -6 #define LOG_INFO_FATAL -7 #define LOG_INFO_IN_USE -8 #define LOG_INFO_EMFILE -9 /* bitmap to SQL_LOG::close() */ #define LOG_CLOSE_INDEX 1 #define LOG_CLOSE_TO_BE_OPENED 2 #define LOG_CLOSE_STOP_EVENT 4 #define LOG_CLOSE_DELAYED_CLOSE 8 /* Maximum unique log filename extension. Note: setting to 0x7FFFFFFF due to atol windows overflow/truncate. */ #define MAX_LOG_UNIQUE_FN_EXT 0x7FFFFFFF /* Number of warnings that will be printed to error log before extension number is exhausted. */ #define LOG_WARN_UNIQUE_FN_EXT_LEFT 1000 class Relay_log_info; /* Note that we destroy the lock mutex in the desctructor here. This means that object instances cannot be destroyed/go out of scope, until we have reset thd->current_linfo to NULL; */ typedef struct st_log_info { char log_file_name[FN_REFLEN]; my_off_t index_file_offset, index_file_start_offset; my_off_t pos; bool fatal; // if the purge happens to give us a negative offset st_log_info() : index_file_offset(0), index_file_start_offset(0), pos(0), fatal(0) { DBUG_ENTER("LOG_INFO"); log_file_name[0] = '\0'; DBUG_VOID_RETURN; } } LOG_INFO; /* Currently we have only 3 kinds of logging functions: old-fashioned logs, stdout and csv logging routines. */ #define MAX_LOG_HANDLERS_NUM 3 /* log event handler flags */ #define LOG_NONE 1U #define LOG_FILE 2U #define LOG_TABLE 4U class Log_event; class Rows_log_event; enum enum_log_type { LOG_UNKNOWN, LOG_NORMAL, LOG_BIN }; enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED }; /* Use larger buffers when reading from and to binary log We make it one step smaller than 64K to account for malloc overhead. */ #define LOG_BIN_IO_SIZE MY_ALIGN_DOWN(65536-1, IO_SIZE) /* TODO use mmap instead of IO_CACHE for binlog (mmap+fsync is two times faster than write+fsync) */ class MYSQL_LOG { public: MYSQL_LOG(); virtual ~MYSQL_LOG() = default; void init_pthread_objects(); void cleanup(); bool open( #ifdef HAVE_PSI_INTERFACE PSI_file_key log_file_key, #endif const char *log_name, enum_log_type log_type, const char *new_name, ulong next_file_number, enum cache_type io_cache_type_arg); void close(uint exiting); inline bool is_open() { return log_state != LOG_CLOSED; } const char *generate_name(const char *log_name, const char *suffix, bool strip_ext, char *buff); virtual int generate_new_name(char *new_name, const char *log_name, ulong next_log_number); protected: /* LOCK_log is inited by init_pthread_objects() */ mysql_mutex_t LOCK_log; char *name; char log_file_name[FN_REFLEN]; char time_buff[20], db[NAME_LEN + 1]; bool write_error, inited; IO_CACHE log_file; enum_log_type log_type; volatile enum_log_state log_state; enum cache_type io_cache_type; friend class Log_event; #ifdef HAVE_PSI_INTERFACE /** Instrumentation key to use for file io in @c log_file */ PSI_file_key m_log_file_key; #endif bool init_and_set_log_file_name(const char *log_name, const char *new_name, ulong next_log_number, enum_log_type log_type_arg, enum cache_type io_cache_type_arg); }; /* Tell the io thread if we can delay the master info sync. */ #define SEMI_SYNC_SLAVE_DELAY_SYNC 1 /* Tell the io thread if the current event needs a ack. */ #define SEMI_SYNC_NEED_ACK 2 class MYSQL_QUERY_LOG: public MYSQL_LOG { public: MYSQL_QUERY_LOG() : last_time(0) {} void reopen_file(); bool write(time_t event_time, const char *user_host, size_t user_host_len, my_thread_id thread_id, const char *command_type, size_t command_type_len, const char *sql_text, size_t sql_text_len); bool write(THD *thd, time_t current_time, const char *user_host, size_t user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, size_t sql_text_len); bool open_slow_log(const char *log_name) { char buf[FN_REFLEN]; return open( #ifdef HAVE_PSI_INTERFACE key_file_slow_log, #endif generate_name(log_name, "-slow.log", 0, buf), LOG_NORMAL, 0, 0, WRITE_CACHE); } bool open_query_log(const char *log_name) { char buf[FN_REFLEN]; return open( #ifdef HAVE_PSI_INTERFACE key_file_query_log, #endif generate_name(log_name, ".log", 0, buf), LOG_NORMAL, 0, 0, WRITE_CACHE); } private: time_t last_time; }; /* We assign each binlog file an internal ID, used to identify them for unlog(). The IDs start from 0 and increment for each new binlog created. In unlog() we need to know the ID of the binlog file that the corresponding transaction was written into. We also need a special value for a corner case where there is no corresponding binlog id (since nothing was logged). And we need an error flag to mark that unlog() must return failure. We use the following macros to pack all of this information into the single ulong available with log_and_order() / unlog(). Note that we cannot use the value 0 for cookie, as that is reserved as error return value from log_and_order(). */ #define BINLOG_COOKIE_ERROR_RETURN 0 #define BINLOG_COOKIE_DUMMY_ID 1 #define BINLOG_COOKIE_BASE 2 #define BINLOG_COOKIE_DUMMY(error_flag) \ ( (BINLOG_COOKIE_DUMMY_ID<<1) | ((error_flag)&1) ) #define BINLOG_COOKIE_MAKE(id, error_flag) \ ( (((id)+BINLOG_COOKIE_BASE)<<1) | ((error_flag)&1) ) #define BINLOG_COOKIE_GET_ERROR_FLAG(c) ((c) & 1) #define BINLOG_COOKIE_GET_ID(c) ( ((ulong)(c)>>1) - BINLOG_COOKIE_BASE ) #define BINLOG_COOKIE_IS_DUMMY(c) \ ( ((ulong)(c)>>1) == BINLOG_COOKIE_DUMMY_ID ) class binlog_cache_mngr; class binlog_cache_data; struct rpl_gtid; struct wait_for_commit; class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG { #ifdef HAVE_PSI_INTERFACE /** The instrumentation key to use for @ LOCK_index. */ PSI_mutex_key m_key_LOCK_index; /** The instrumentation key to use for @ COND_relay_log_updated */ PSI_cond_key m_key_relay_log_update; /** The instrumentation key to use for @ COND_bin_log_updated */ PSI_cond_key m_key_bin_log_update; /** The instrumentation key to use for opening the log file. */ PSI_file_key m_key_file_log, m_key_file_log_cache; /** The instrumentation key to use for opening the log index file. */ PSI_file_key m_key_file_log_index, m_key_file_log_index_cache; PSI_cond_key m_key_COND_queue_busy; /** The instrumentation key to use for LOCK_binlog_end_pos. */ PSI_mutex_key m_key_LOCK_binlog_end_pos; #else static constexpr PSI_mutex_key m_key_LOCK_index= 0; static constexpr PSI_cond_key m_key_relay_log_update= 0; static constexpr PSI_cond_key m_key_bin_log_update= 0; static constexpr PSI_file_key m_key_file_log= 0, m_key_file_log_cache= 0; static constexpr PSI_file_key m_key_file_log_index= 0; static constexpr PSI_file_key m_key_file_log_index_cache= 0; static constexpr PSI_cond_key m_key_COND_queue_busy= 0; static constexpr PSI_mutex_key m_key_LOCK_binlog_end_pos= 0; #endif struct group_commit_entry { struct group_commit_entry *next; THD *thd; binlog_cache_mngr *cache_mngr; bool using_stmt_cache; bool using_trx_cache; /* Extra events (COMMIT/ROLLBACK/XID, and possibly INCIDENT) to be written during group commit. The incident_event is only valid if trx_data->has_incident() is true. */ Log_event *end_event; Log_event *incident_event; /* Set during group commit to record any per-thread error. */ int error; int commit_errno; IO_CACHE *error_cache; /* This is the `all' parameter for ha_commit_ordered(). */ bool all; /* True if we need to increment xid_count in trx_group_commit_leader() and decrement in unlog() (this is needed if there is a participating engine that does not implement the commit_checkpoint_request() handlerton method). */ bool need_unlog; /* Fields used to pass the necessary information to the last thread in a group commit, only used when opt_optimize_thread_scheduling is not set. */ bool check_purge; /* Flag used to optimise around wait_for_prior_commit. */ bool queued_by_other; ulong binlog_id; bool ro_1pc; // passes the binlog_cache_mngr::ro_1pc value to Gtid ctor }; /* When this is set, a RESET MASTER is in progress. Then we should not write any binlog checkpoints into the binlog (that could result in deadlock on LOCK_log, and we will delete all binlog files anyway). Instead we should signal COND_xid_list whenever a new binlog checkpoint arrives - when all have arrived, RESET MASTER will complete. */ uint reset_master_pending; ulong mark_xid_done_waiting; /* LOCK_log and LOCK_index are inited by init_pthread_objects() */ mysql_mutex_t LOCK_index; mysql_mutex_t LOCK_binlog_end_pos; mysql_mutex_t LOCK_xid_list; mysql_cond_t COND_xid_list; mysql_cond_t COND_relay_log_updated, COND_bin_log_updated; ulonglong bytes_written; IO_CACHE index_file; char index_file_name[FN_REFLEN]; /* purge_file is a temp file used in purge_logs so that the index file can be updated before deleting files from disk, yielding better crash recovery. It is created on demand the first time purge_logs is called and then reused for subsequent calls. It is cleaned up in cleanup(). */ IO_CACHE purge_index_file; char purge_index_file_name[FN_REFLEN]; /* The max size before rotation (usable only if log_type == LOG_BIN: binary logs and relay logs). For a binlog, max_size should be max_binlog_size. max_size is set in init(), and dynamically changed (when one does SET GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) from sys_vars.cc */ ulong max_size; /* Number generated by last call of find_uniq_filename(). Corresponds closely with current_binlog_id */ ulong last_used_log_number; // current file sequence number for load data infile binary logging uint file_id; uint open_count; // For replication int readers_count; /* Queue of transactions queued up to participate in group commit. */ group_commit_entry *group_commit_queue; /* Condition variable to mark that the group commit queue is busy. Used when each thread does it's own commit_ordered() (when binlog_optimize_thread_scheduling=1). Used with the LOCK_commit_ordered mutex. */ my_bool group_commit_queue_busy; mysql_cond_t COND_queue_busy; /* Total number of committed transactions. */ ulonglong num_commits; /* Number of group commits done. */ ulonglong num_group_commits; /* The reason why the group commit was grouped */ ulonglong group_commit_trigger_count, group_commit_trigger_timeout; ulonglong group_commit_trigger_lock_wait; /* binlog encryption data */ struct Binlog_crypt_data crypto; /* pointer to the sync period variable, for binlog this will be sync_binlog_period, for relay log this will be sync_relay_log_period */ uint *sync_period_ptr; uint sync_counter; bool state_file_deleted; bool binlog_state_recover_done; inline uint get_sync_period() { return *sync_period_ptr; } int write_to_file(IO_CACHE *cache); /* This is used to start writing to a new log file. The difference from new_file() is locking. new_file_without_locking() does not acquire LOCK_log. */ int new_file_without_locking(); int new_file_impl(); void do_checkpoint_request(ulong binlog_id); void purge(); int write_transaction_or_stmt(group_commit_entry *entry, uint64 commit_id); int queue_for_group_commit(group_commit_entry *entry); bool write_transaction_to_binlog_events(group_commit_entry *entry); void trx_group_commit_leader(group_commit_entry *leader); bool is_xidlist_idle_nolock(); public: /* A list of struct xid_count_per_binlog is used to keep track of how many XIDs are in prepared, but not committed, state in each binlog. And how many commit_checkpoint_request()'s are pending. When count drops to zero in a binlog after rotation, it means that there are no more XIDs in prepared state, so that binlog is no longer needed for XA crash recovery, and we can log a new binlog checkpoint event. The list is protected against simultaneous access from multiple threads by LOCK_xid_list. */ struct xid_count_per_binlog : public ilink { char *binlog_name; uint binlog_name_len; ulong binlog_id; /* Total prepared XIDs and pending checkpoint requests in this binlog. */ long xid_count; long notify_count; /* For linking in requests to the binlog background thread. */ xid_count_per_binlog *next_in_queue; xid_count_per_binlog(char *log_file_name, uint log_file_name_len) :binlog_id(0), xid_count(0), notify_count(0) { binlog_name_len= log_file_name_len; binlog_name= (char *) my_malloc(PSI_INSTRUMENT_ME, binlog_name_len, MYF(MY_ZEROFILL)); if (binlog_name) memcpy(binlog_name, log_file_name, binlog_name_len); } ~xid_count_per_binlog() { my_free(binlog_name); } }; I_List binlog_xid_count_list; mysql_mutex_t LOCK_binlog_background_thread; mysql_cond_t COND_binlog_background_thread; mysql_cond_t COND_binlog_background_thread_end; void stop_background_thread(); using MYSQL_LOG::generate_name; using MYSQL_LOG::is_open; /* This is relay log */ bool is_relay_log; ulong relay_signal_cnt; // update of the counter is checked by heartbeat enum enum_binlog_checksum_alg checksum_alg_reset; // to contain a new value when binlog is rotated /* Holds the last seen in Relay-Log FD's checksum alg value. The initial value comes from the slave's local FD that heads the very first Relay-Log file. In the following the value may change with each received master's FD_m. Besides to be used in verification events that IO thread receives (except the 1st fake Rotate, see @c Master_info:: checksum_alg_before_fd), the value specifies if/how to compute checksum for slave's local events and the first fake Rotate (R_f^1) coming from the master. R_f^1 needs logging checksum-compatibly with the RL's heading FD_s. Legends for the checksum related comments: FD - Format-Description event, R - Rotate event R_f - the fake Rotate event E - an arbirary event The underscore indexes for any event `_s' indicates the event is generated by Slave `_m' - by Master Two special underscore indexes of FD: FD_q - Format Description event for queuing (relay-logging) FD_e - Format Description event for executing (relay-logging) Upper indexes: E^n - n:th event is a sequence RL - Relay Log (A) - checksum algorithm descriptor value FD.(A) - the value of (A) in FD */ enum enum_binlog_checksum_alg relay_log_checksum_alg; /* These describe the log's format. This is used only for relay logs. _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's necessary to have 2 distinct objects, because the I/O thread may be reading events in a different format from what the SQL thread is reading (consider the case of a master which has been upgraded from 5.0 to 5.1 without doing RESET MASTER, or from 4.x to 5.0). */ Format_description_log_event *description_event_for_exec, *description_event_for_queue; /* Binlog position of last commit (or non-transactional write) to the binlog. Access to this is protected by LOCK_commit_ordered. */ char last_commit_pos_file[FN_REFLEN]; my_off_t last_commit_pos_offset; ulong current_binlog_id; /* Tracks the number of times that the master has been reset */ Atomic_counter reset_master_count; MYSQL_BIN_LOG(uint *sync_period); /* note that there's no destructor ~MYSQL_BIN_LOG() ! The reason is that we don't want it to be automatically called on exit() - but only during the correct shutdown process */ #ifdef HAVE_PSI_INTERFACE void set_psi_keys(PSI_mutex_key key_LOCK_index, PSI_cond_key key_relay_log_update, PSI_cond_key key_bin_log_update, PSI_file_key key_file_log, PSI_file_key key_file_log_cache, PSI_file_key key_file_log_index, PSI_file_key key_file_log_index_cache, PSI_cond_key key_COND_queue_busy, PSI_mutex_key key_LOCK_binlog_end_pos) { m_key_LOCK_index= key_LOCK_index; m_key_relay_log_update= key_relay_log_update; m_key_bin_log_update= key_bin_log_update; m_key_file_log= key_file_log; m_key_file_log_cache= key_file_log_cache; m_key_file_log_index= key_file_log_index; m_key_file_log_index_cache= key_file_log_index_cache; m_key_COND_queue_busy= key_COND_queue_busy; m_key_LOCK_binlog_end_pos= key_LOCK_binlog_end_pos; } #endif int open(const char *opt_name) override; void close() override; int generate_new_name(char *new_name, const char *log_name, ulong next_log_number) override; int log_and_order(THD *thd, my_xid xid, bool all, bool need_prepare_ordered, bool need_commit_ordered) override; int unlog(ulong cookie, my_xid xid) override; int unlog_xa_prepare(THD *thd, bool all) override; void commit_checkpoint_notify(void *cookie) override; int recover(LOG_INFO *linfo, const char *last_log_name, IO_CACHE *first_log, Format_description_log_event *fdle, bool do_xa); int do_binlog_recovery(const char *opt_name, bool do_xa_recovery); #if !defined(MYSQL_CLIENT) int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event, bool is_transactional); int remove_pending_rows_event(THD *thd, bool is_transactional); #endif /* !defined(MYSQL_CLIENT) */ void reset_bytes_written() { bytes_written = 0; } void harvest_bytes_written(Atomic_counter *counter) { #ifdef DBUG_TRACE char buf1[22],buf2[22]; #endif DBUG_ENTER("harvest_bytes_written"); (*counter)+=bytes_written; DBUG_PRINT("info",("counter: %s bytes_written: %s", llstr(*counter,buf1), llstr(bytes_written,buf2))); bytes_written=0; DBUG_VOID_RETURN; } void set_max_size(ulong max_size_arg); /* Handle signaling that relay has been updated */ void signal_relay_log_update() { mysql_mutex_assert_owner(&LOCK_log); DBUG_ASSERT(is_relay_log); DBUG_ENTER("MYSQL_BIN_LOG::signal_relay_log_update"); relay_signal_cnt++; mysql_cond_broadcast(&COND_relay_log_updated); DBUG_VOID_RETURN; } void signal_bin_log_update() { mysql_mutex_assert_owner(&LOCK_binlog_end_pos); DBUG_ASSERT(!is_relay_log); DBUG_ENTER("MYSQL_BIN_LOG::signal_bin_log_update"); mysql_cond_broadcast(&COND_bin_log_updated); DBUG_VOID_RETURN; } void update_binlog_end_pos() { if (is_relay_log) signal_relay_log_update(); else { lock_binlog_end_pos(); binlog_end_pos= my_b_safe_tell(&log_file); signal_bin_log_update(); unlock_binlog_end_pos(); } } void update_binlog_end_pos(my_off_t pos) { mysql_mutex_assert_owner(&LOCK_log); mysql_mutex_assert_not_owner(&LOCK_binlog_end_pos); lock_binlog_end_pos(); /* Note: it would make more sense to assert(pos > binlog_end_pos) but there are two places triggered by mtr that has pos == binlog_end_pos i didn't investigate but accepted as it should do no harm */ DBUG_ASSERT(pos >= binlog_end_pos); binlog_end_pos= pos; signal_bin_log_update(); unlock_binlog_end_pos(); } void wait_for_sufficient_commits(); void binlog_trigger_immediate_group_commit(); void wait_for_update_relay_log(THD* thd); void init(ulong max_size); void init_pthread_objects(); void cleanup(); bool open(const char *log_name, const char *new_name, ulong next_log_number, enum cache_type io_cache_type_arg, ulong max_size, bool null_created, bool need_mutex); bool open_index_file(const char *index_file_name_arg, const char *log_name, bool need_mutex); /* Use this to start writing a new log file */ int new_file(); bool write(Log_event* event_info, my_bool *with_annotate= 0); // binary log write bool write_transaction_to_binlog(THD *thd, binlog_cache_mngr *cache_mngr, Log_event *end_ev, bool all, bool using_stmt_cache, bool using_trx_cache, bool is_ro_1pc); bool write_incident_already_locked(THD *thd); bool write_incident(THD *thd); void write_binlog_checkpoint_event_already_locked(const char *name, uint len); int write_cache(THD *thd, IO_CACHE *cache); void set_write_error(THD *thd, bool is_transactional); bool check_write_error(THD *thd); bool check_cache_error(THD *thd, binlog_cache_data *cache_data); void start_union_events(THD *thd, query_id_t query_id_param); void stop_union_events(THD *thd); bool is_query_in_union(THD *thd, query_id_t query_id_param); bool write_event(Log_event *ev, binlog_cache_data *data, IO_CACHE *file); bool write_event(Log_event *ev) { return write_event(ev, 0, &log_file); } bool write_event_buffer(uchar* buf,uint len); bool append(Log_event* ev); bool append_no_lock(Log_event* ev); void mark_xids_active(ulong cookie, uint xid_count); void mark_xid_done(ulong cookie, bool write_checkpoint); void make_log_name(char* buf, const char* log_ident); bool is_active(const char* log_file_name); bool can_purge_log(const char *log_file_name); int update_log_index(LOG_INFO* linfo, bool need_update_threads); int rotate(bool force_rotate, bool* check_purge); void checkpoint_and_purge(ulong binlog_id); int rotate_and_purge(bool force_rotate, DYNAMIC_ARRAY* drop_gtid_domain= NULL); /** Flush binlog cache and synchronize to disk. This function flushes events in binlog cache to binary log file, it will do synchronizing according to the setting of system variable 'sync_binlog'. If file is synchronized, @c synced will be set to 1, otherwise 0. @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0 @retval 0 Success @retval other Failure */ bool flush_and_sync(bool *synced); int purge_logs(const char *to_log, bool included, bool need_mutex, bool need_update_threads, ulonglong *decrease_log_space); int purge_logs_before_date(time_t purge_time); int purge_first_log(Relay_log_info* rli, bool included); int set_purge_index_file_name(const char *base_file_name); int open_purge_index_file(bool destroy); bool truncate_and_remove_binlogs(const char *truncate_file, my_off_t truncate_pos, rpl_gtid *gtid); bool is_inited_purge_index_file(); int close_purge_index_file(); int clean_purge_index_file(); int sync_purge_index_file(); int register_purge_index_entry(const char* entry); int register_create_index_entry(const char* entry); int purge_index_entry(THD *thd, ulonglong *decrease_log_space, bool need_mutex); bool reset_logs(THD* thd, bool create_new_log, rpl_gtid *init_state, uint32 init_state_len, ulong next_log_number); void wait_for_last_checkpoint_event(); void close(uint exiting); void clear_inuse_flag_when_closing(File file); // iterating through the log index file int find_log_pos(LOG_INFO* linfo, const char* log_name, bool need_mutex); int find_next_log(LOG_INFO* linfo, bool need_mutex); int get_current_log(LOG_INFO* linfo); int raw_get_current_log(LOG_INFO* linfo); uint next_file_id(); inline char* get_index_fname() { return index_file_name;} inline char* get_log_fname() { return log_file_name; } inline char* get_name() { return name; } inline mysql_mutex_t* get_log_lock() { return &LOCK_log; } inline mysql_cond_t* get_bin_log_cond() { return &COND_bin_log_updated; } inline IO_CACHE* get_log_file() { return &log_file; } inline uint64 get_reset_master_count() { return reset_master_count; } inline void lock_index() { mysql_mutex_lock(&LOCK_index);} inline void unlock_index() { mysql_mutex_unlock(&LOCK_index);} inline IO_CACHE *get_index_file() { return &index_file;} inline uint32 get_open_count() { return open_count; } void set_status_variables(THD *thd); bool is_xidlist_idle(); bool write_gtid_event(THD *thd, bool standalone, bool is_transactional, uint64 commit_id, bool has_xid= false, bool ro_1pc= false); int read_state_from_file(); int write_state_to_file(); int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size); bool append_state_pos(String *str); bool append_state(String *str); bool is_empty_state(); bool find_in_binlog_state(uint32 domain_id, uint32 server_id, rpl_gtid *out_gtid); bool lookup_domain_in_binlog_state(uint32 domain_id, rpl_gtid *out_gtid); int bump_seq_no_counter_if_needed(uint32 domain_id, uint64 seq_no); bool check_strict_gtid_sequence(uint32 domain_id, uint32 server_id, uint64 seq_no, bool no_error= false); /** * used when opening new file, and binlog_end_pos moves backwards */ void reset_binlog_end_pos(const char file_name[FN_REFLEN], my_off_t pos) { mysql_mutex_assert_owner(&LOCK_log); mysql_mutex_assert_not_owner(&LOCK_binlog_end_pos); lock_binlog_end_pos(); binlog_end_pos= pos; safe_strcpy(binlog_end_pos_file, sizeof(binlog_end_pos_file), file_name); signal_bin_log_update(); unlock_binlog_end_pos(); } /* It is called by the threads(e.g. dump thread) which want to read log without LOCK_log protection. */ my_off_t get_binlog_end_pos(char file_name_buf[FN_REFLEN]) const { mysql_mutex_assert_not_owner(&LOCK_log); mysql_mutex_assert_owner(&LOCK_binlog_end_pos); safe_strcpy(file_name_buf, FN_REFLEN, binlog_end_pos_file); return binlog_end_pos; } void lock_binlog_end_pos() { mysql_mutex_lock(&LOCK_binlog_end_pos); } void unlock_binlog_end_pos() { mysql_mutex_unlock(&LOCK_binlog_end_pos); } mysql_mutex_t* get_binlog_end_pos_lock() { return &LOCK_binlog_end_pos; } /* Ensures the log's state is either LOG_OPEN or LOG_CLOSED. If something failed along the desired path and left the log in invalid state, i.e. LOG_TO_BE_OPENED, forces the state to be LOG_CLOSED. */ void try_fix_log_state() { mysql_mutex_lock(get_log_lock()); /* Only change the log state if it is LOG_TO_BE_OPENED */ if (log_state == LOG_TO_BE_OPENED) log_state= LOG_CLOSED; mysql_mutex_unlock(get_log_lock()); } int wait_for_update_binlog_end_pos(THD* thd, struct timespec * timeout); /* Binlog position of end of the binlog. Access to this is protected by LOCK_binlog_end_pos The difference between this and last_commit_pos_{file,offset} is that the commit position is updated later. If semi-sync wait point is set to WAIT_AFTER_SYNC, the commit pos is update after semi-sync-ack has been received and the end point is updated after the write as it's needed for the dump threads to be able to semi-sync the event. */ my_off_t binlog_end_pos; char binlog_end_pos_file[FN_REFLEN]; }; class Log_event_handler { public: Log_event_handler() = default; virtual bool init()= 0; virtual void cleanup()= 0; virtual bool log_slow(THD *thd, my_hrtime_t current_time, const char *user_host, size_t user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, size_t sql_text_len)= 0; virtual bool log_error(enum loglevel level, const char *format, va_list args)= 0; virtual bool log_general(THD *thd, my_hrtime_t event_time, const char *user_host, size_t user_host_len, my_thread_id thread_id, const char *command_type, size_t command_type_len, const char *sql_text, size_t sql_text_len, CHARSET_INFO *client_cs)= 0; virtual ~Log_event_handler() = default; }; int check_if_log_table(const TABLE_LIST *table, bool check_if_opened, const char *errmsg); class Log_to_csv_event_handler: public Log_event_handler { friend class LOGGER; public: Log_to_csv_event_handler(); ~Log_to_csv_event_handler(); bool init() override; void cleanup() override; bool log_slow(THD *thd, my_hrtime_t current_time, const char *user_host, size_t user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, size_t sql_text_len) override; bool log_error(enum loglevel level, const char *format, va_list args) override; bool log_general(THD *thd, my_hrtime_t event_time, const char *user_host, size_t user_host_len, my_thread_id thread_id, const char *command_type, size_t command_type_len, const char *sql_text, size_t sql_text_len, CHARSET_INFO *client_cs) override; int activate_log(THD *thd, uint log_type); }; /* type of the log table */ #define QUERY_LOG_SLOW 1 #define QUERY_LOG_GENERAL 2 class Log_to_file_event_handler: public Log_event_handler { MYSQL_QUERY_LOG mysql_log; MYSQL_QUERY_LOG mysql_slow_log; bool is_initialized; public: Log_to_file_event_handler(): is_initialized(FALSE) {} bool init() override; void cleanup() override; bool log_slow(THD *thd, my_hrtime_t current_time, const char *user_host, size_t user_host_len, ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, size_t sql_text_len) override; bool log_error(enum loglevel level, const char *format, va_list args) override; bool log_general(THD *thd, my_hrtime_t event_time, const char *user_host, size_t user_host_len, my_thread_id thread_id, const char *command_type, size_t command_type_len, const char *sql_text, size_t sql_text_len, CHARSET_INFO *client_cs) override; void flush(); void init_pthread_objects(); MYSQL_QUERY_LOG *get_mysql_slow_log() { return &mysql_slow_log; } MYSQL_QUERY_LOG *get_mysql_log() { return &mysql_log; } }; /* Class which manages slow, general and error log event handlers */ class LOGGER { mysql_rwlock_t LOCK_logger; /* flag to check whether logger mutex is initialized */ uint inited; /* available log handlers */ Log_to_csv_event_handler *table_log_handler; Log_to_file_event_handler *file_log_handler; /* NULL-terminated arrays of log handlers */ Log_event_handler *error_log_handler_list[MAX_LOG_HANDLERS_NUM + 1]; Log_event_handler *slow_log_handler_list[MAX_LOG_HANDLERS_NUM + 1]; Log_event_handler *general_log_handler_list[MAX_LOG_HANDLERS_NUM + 1]; public: bool is_log_tables_initialized; LOGGER() : inited(0), table_log_handler(NULL), file_log_handler(NULL), is_log_tables_initialized(FALSE) {} void lock_shared() { mysql_rwlock_rdlock(&LOCK_logger); } void lock_exclusive() { mysql_rwlock_wrlock(&LOCK_logger); } void unlock() { mysql_rwlock_unlock(&LOCK_logger); } bool is_log_table_enabled(uint log_table_type); bool log_command(THD *thd, enum enum_server_command command); /* We want to initialize all log mutexes as soon as possible, but we cannot do it in constructor, as safe_mutex relies on initialization, performed by MY_INIT(). This why this is done in this function. */ void init_base(); void init_log_tables(); bool flush_slow_log(); bool flush_general_log(); /* Perform basic logger cleanup. this will leave e.g. error log open. */ void cleanup_base(); /* Free memory. Nothing could be logged after this function is called */ void cleanup_end(); bool error_log_print(enum loglevel level, const char *format, va_list args); bool slow_log_print(THD *thd, const char *query, size_t query_length, ulonglong current_utime); bool general_log_print(THD *thd,enum enum_server_command command, const char *format, va_list args); bool general_log_write(THD *thd, enum enum_server_command command, const char *query, size_t query_length); /* we use this function to setup all enabled log event handlers */ int set_handlers(ulonglong slow_log_printer, ulonglong general_log_printer); void init_error_log(ulonglong error_log_printer); void init_slow_log(ulonglong slow_log_printer); void init_general_log(ulonglong general_log_printer); void deactivate_log_handler(THD* thd, uint log_type); bool activate_log_handler(THD* thd, uint log_type); MYSQL_QUERY_LOG *get_slow_log_file_handler() const { if (file_log_handler) return file_log_handler->get_mysql_slow_log(); return NULL; } MYSQL_QUERY_LOG *get_log_file_handler() const { if (file_log_handler) return file_log_handler->get_mysql_log(); return NULL; } }; enum enum_binlog_format { BINLOG_FORMAT_MIXED= 0, ///< statement if safe, otherwise row - autodetected BINLOG_FORMAT_STMT= 1, ///< statement-based BINLOG_FORMAT_ROW= 2, ///< row-based BINLOG_FORMAT_UNSPEC=3 ///< thd_binlog_format() returns it when binlog is closed }; int query_error_code(THD *thd, bool not_killed); uint purge_log_get_error_code(int res); int vprint_msg_to_log(enum loglevel level, const char *format, va_list args); void sql_print_error(const char *format, ...); void sql_print_warning(const char *format, ...); void sql_print_information(const char *format, ...); void sql_print_information_v(const char *format, va_list ap); typedef void (*sql_print_message_func)(const char *format, ...); extern sql_print_message_func sql_print_message_handlers[]; int error_log_print(enum loglevel level, const char *format, va_list args); bool slow_log_print(THD *thd, const char *query, uint query_length, ulonglong current_utime); bool general_log_print(THD *thd, enum enum_server_command command, const char *format,...); bool general_log_write(THD *thd, enum enum_server_command command, const char *query, size_t query_length); void binlog_report_wait_for(THD *thd, THD *other_thd); void sql_perror(const char *message); bool flush_error_log(); File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg); void make_default_log_name(char **out, const char* log_ext, bool once); void binlog_reset_cache(THD *thd); bool write_annotated_row(THD *thd); extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log; extern handlerton *binlog_hton; extern LOGGER logger; extern const char *log_bin_index; extern const char *log_bin_basename; /** Turns a relative log binary log path into a full path, based on the opt_bin_logname or opt_relay_logname. @param from The log name we want to make into an absolute path. @param to The buffer where to put the results of the normalization. @param is_relay_log Switch that makes is used inside to choose which option (opt_bin_logname or opt_relay_logname) to use when calculating the base path. @returns true if a problem occurs, false otherwise. */ inline bool normalize_binlog_name(char *to, const char *from, bool is_relay_log) { DBUG_ENTER("normalize_binlog_name"); bool error= false; char buff[FN_REFLEN]; char *ptr= (char*) from; char *opt_name= is_relay_log ? opt_relay_logname : opt_bin_logname; DBUG_ASSERT(from); /* opt_name is not null and not empty and from is a relative path */ if (opt_name && opt_name[0] && from && !test_if_hard_path(from)) { // take the path from opt_name // take the filename from from char log_dirpart[FN_REFLEN], log_dirname[FN_REFLEN]; size_t log_dirpart_len, log_dirname_len; dirname_part(log_dirpart, opt_name, &log_dirpart_len); dirname_part(log_dirname, from, &log_dirname_len); /* log may be empty => relay-log or log-bin did not hold paths, just filename pattern */ if (log_dirpart_len > 0) { /* create the new path name */ if(fn_format(buff, from+log_dirname_len, log_dirpart, "", MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH)) == NULL) { error= true; goto end; } ptr= buff; } } DBUG_ASSERT(ptr); if (ptr) strmake(to, ptr, strlen(ptr)); end: DBUG_RETURN(error); } static inline TC_LOG *get_tc_log_implementation() { if (total_ha_2pc <= 1) return &tc_log_dummy; if (opt_bin_log) return &mysql_bin_log; return &tc_log_mmap; } #ifdef WITH_WSREP IO_CACHE* wsrep_get_cache(THD *, bool); bool wsrep_is_binlog_cache_empty(THD *); void wsrep_thd_binlog_trx_reset(THD * thd); void wsrep_thd_binlog_stmt_rollback(THD * thd); #endif /* WITH_WSREP */ class Gtid_list_log_event; const char * get_gtid_list_event(IO_CACHE *cache, Gtid_list_log_event **out_gtid_list); int binlog_commit(THD *thd, bool all, bool is_ro_1pc= false); int binlog_commit_by_xid(handlerton *hton, XID *xid); int binlog_rollback_by_xid(handlerton *hton, XID *xid); #endif /* LOG_H */ server/private/sql_type_string.h000064400000003135151031265040013122 0ustar00/* Copyright (c) 2019 MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_TYPE_STRING_INCLUDED #define SQL_TYPE_STRING_INCLUDED class StringPack { CHARSET_INFO *m_cs; uint32 m_octet_length; CHARSET_INFO *charset() const { return m_cs; } uint mbmaxlen() const { return m_cs->mbmaxlen; }; uint32 char_length() const { return m_octet_length / mbmaxlen(); } public: StringPack(CHARSET_INFO *cs, uint32 octet_length) :m_cs(cs), m_octet_length(octet_length) { } uchar *pack(uchar *to, const uchar *from, uint max_length) const; const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end, uint param_data) const; public: static uint max_packed_col_length(uint max_length) { return (max_length > 255 ? 2 : 1) + max_length; } static uint packed_col_length(const uchar *data_ptr, uint length) { if (length > 255) return uint2korr(data_ptr)+2; return (uint) *data_ptr + 1; } }; #endif // SQL_TYPE_STRING_INCLUDED server/private/hostname.h000064400000012453151031265040011515 0ustar00/* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef HOSTNAME_INCLUDED #define HOSTNAME_INCLUDED #include "my_net.h" #include "hash_filo.h" struct Host_errors { public: Host_errors(); ~Host_errors(); void reset(); void aggregate(const Host_errors *errors); /** Number of connect errors. */ ulong m_connect; /** Number of host blocked errors. */ ulong m_host_blocked; /** Number of transient errors from getnameinfo(). */ ulong m_nameinfo_transient; /** Number of permanent errors from getnameinfo(). */ ulong m_nameinfo_permanent; /** Number of errors from is_hostname_valid(). */ ulong m_format; /** Number of transient errors from getaddrinfo(). */ ulong m_addrinfo_transient; /** Number of permanent errors from getaddrinfo(). */ ulong m_addrinfo_permanent; /** Number of errors from Forward-Confirmed reverse DNS checks. */ ulong m_FCrDNS; /** Number of errors from host grants. */ ulong m_host_acl; /** Number of errors from missing auth plugin. */ ulong m_no_auth_plugin; /** Number of errors from auth plugin. */ ulong m_auth_plugin; /** Number of errors from authentication plugins. */ ulong m_handshake; /** Number of errors from proxy user. */ ulong m_proxy_user; /** Number of errors from proxy user acl. */ ulong m_proxy_user_acl; /** Number of errors from authentication. */ ulong m_authentication; /** Number of errors from ssl. */ ulong m_ssl; /** Number of errors from max user connection. */ ulong m_max_user_connection; /** Number of errors from max user connection per hour. */ ulong m_max_user_connection_per_hour; /** Number of errors from the default database. */ ulong m_default_database; /** Number of errors from init_connect. */ ulong m_init_connect; /** Number of errors from the server itself. */ ulong m_local; bool has_error() const { return ((m_host_blocked != 0) || (m_nameinfo_transient != 0) || (m_nameinfo_permanent != 0) || (m_format != 0) || (m_addrinfo_transient != 0) || (m_addrinfo_permanent != 0) || (m_FCrDNS != 0) || (m_host_acl != 0) || (m_no_auth_plugin != 0) || (m_auth_plugin != 0) || (m_handshake != 0) || (m_proxy_user != 0) || (m_proxy_user_acl != 0) || (m_authentication != 0) || (m_ssl != 0) || (m_max_user_connection != 0) || (m_max_user_connection_per_hour != 0) || (m_default_database != 0) || (m_init_connect != 0) || (m_local != 0)); } void sum_connect_errors() { /* Current (historical) behavior: */ m_connect= m_handshake; } void clear_connect_errors() { m_connect= 0; } }; /** Size of IP address string in the hash cache. */ #define HOST_ENTRY_KEY_SIZE INET6_ADDRSTRLEN /** An entry in the hostname hash table cache. Host name cache does two things: - caches host names to save DNS look ups; - counts errors from IP. Host name can be empty (that means DNS look up failed), but errors still are counted. */ class Host_entry : public hash_filo_element { public: Host_entry *next() { return (Host_entry*) hash_filo_element::next(); } /** Client IP address. This is the key used with the hash table. The client IP address is always expressed in IPv6, even when the network IPv6 stack is not present. This IP address is never used to connect to a socket. */ char ip_key[HOST_ENTRY_KEY_SIZE]; /** One of the host names for the IP address. May be a zero length string. */ char m_hostname[HOSTNAME_LENGTH + 1]; /** Length in bytes of @c m_hostname. */ uint m_hostname_length; /** The hostname is validated and used for authorization. */ bool m_host_validated; ulonglong m_first_seen; ulonglong m_last_seen; ulonglong m_first_error_seen; ulonglong m_last_error_seen; /** Error statistics. */ Host_errors m_errors; void set_error_timestamps(ulonglong now) { if (m_first_error_seen == 0) m_first_error_seen= now; m_last_error_seen= now; } }; /** The size of the host_cache. */ extern ulong host_cache_size; #define RC_OK 0 #define RC_BLOCKED_HOST 1 int ip_to_hostname(struct sockaddr_storage *ip_storage, const char *ip_string, const char **hostname, uint *connect_errors); void inc_host_errors(const char *ip_string, Host_errors *errors); void reset_host_connect_errors(const char *ip_string); bool hostname_cache_init(); void hostname_cache_free(); void hostname_cache_refresh(void); uint hostname_cache_size(); void hostname_cache_resize(uint size); void hostname_cache_lock(); void hostname_cache_unlock(); Host_entry *hostname_cache_first(); #endif /* HOSTNAME_INCLUDED */ server/private/hash.h000064400000010541151031265040010616 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. Copyright (c) 2011, 2013, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Dynamic hashing of record with different key-length */ #ifndef _hash_h #define _hash_h #include "my_sys.h" /* DYNAMIC_ARRAY */ /* This forward declaration is used from C files where the real definition is included before. Since C does not allow repeated typedef declarations, even when identical, the definition may not be repeated. */ #ifdef __cplusplus extern "C" { #endif /* Overhead to store an element in hash Can be used to approximate memory consumption for a hash */ #define HASH_OVERHEAD (sizeof(char*)*2) /* flags for hash_init */ #define HASH_UNIQUE 1 /* hash_insert fails on duplicate key */ #define HASH_THREAD_SPECIFIC 2 /* Mark allocated memory THREAD_SPECIFIC */ typedef uint32 my_hash_value_type; typedef const uchar *(*my_hash_get_key)(const void *, size_t *, my_bool); typedef my_hash_value_type (*my_hash_function)(CHARSET_INFO *, const uchar *, size_t); typedef void (*my_hash_free_key)(void *); typedef my_bool (*my_hash_walk_action)(void *,void *); typedef struct st_hash { size_t key_offset,key_length; /* Length of key if const length */ size_t blength; ulong records; uint flags; DYNAMIC_ARRAY array; /* Place for hash_keys */ my_hash_get_key get_key; my_hash_function hash_function; void (*free)(void *); CHARSET_INFO *charset; } HASH; /* A search iterator state */ typedef uint HASH_SEARCH_STATE; #define my_hash_init(A,B,C,D,E,F,G,H,I) my_hash_init2(A,B,0,C,D,E,F,G,0,H,I) my_bool my_hash_init2(PSI_memory_key psi_key, HASH *hash, uint growth_size, CHARSET_INFO *charset, ulong default_array_elements, size_t key_offset, size_t key_length, my_hash_get_key get_key, my_hash_function hash_function, void (*free_element)(void*), uint flags); void my_hash_free(HASH *tree); void my_hash_reset(HASH *hash); uchar *my_hash_element(HASH *hash, size_t idx); uchar *my_hash_search(const HASH *info, const uchar *key, size_t length); uchar *my_hash_search_using_hash_value(const HASH *info, my_hash_value_type hash_value, const uchar *key, size_t length); my_hash_value_type my_hash_sort(CHARSET_INFO *cs, const uchar *key, size_t length); #define my_calc_hash(A, B, C) my_hash_sort((A)->charset, B, C) uchar *my_hash_first(const HASH *info, const uchar *key, size_t length, HASH_SEARCH_STATE *state); uchar *my_hash_first_from_hash_value(const HASH *info, my_hash_value_type hash_value, const uchar *key, size_t length, HASH_SEARCH_STATE *state); uchar *my_hash_next(const HASH *info, const uchar *key, size_t length, HASH_SEARCH_STATE *state); my_bool my_hash_insert(HASH *info, const uchar *data); my_bool my_hash_delete(HASH *hash, uchar *record); my_bool my_hash_update(HASH *hash, uchar *record, uchar *old_key, size_t old_key_length); void my_hash_replace(HASH *hash, HASH_SEARCH_STATE *state, uchar *new_row); my_bool my_hash_check(HASH *hash); /* Only in debug library */ my_bool my_hash_iterate(HASH *hash, my_hash_walk_action action, void *argument); #define my_hash_clear(H) bzero((char*) (H), sizeof(*(H))) #define my_hash_inited(H) ((H)->blength != 0) #define my_hash_init_opt(A,B,C,D,E,F,G,H,I) \ (!my_hash_inited(B) && my_hash_init(A,B,C,D,E,F,G,H,I)) #ifdef __cplusplus } #endif #endif server/private/sql_string.h000064400000115535151031265040012071 0ustar00#ifndef SQL_STRING_INCLUDED #define SQL_STRING_INCLUDED /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. Copyright (c) 2008, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file is originally from the mysql distribution. Coded by monty */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "m_ctype.h" /* my_charset_bin */ #include /* alloc_root, my_free, my_realloc */ #include "m_string.h" /* TRASH */ #include "sql_list.h" class String; #ifdef MYSQL_SERVER extern PSI_memory_key key_memory_String_value; #define STRING_PSI_MEMORY_KEY key_memory_String_value #else #define STRING_PSI_MEMORY_KEY PSI_NOT_INSTRUMENTED #endif typedef struct st_io_cache IO_CACHE; typedef struct st_mem_root MEM_ROOT; #define ASSERT_LENGTH(A) DBUG_ASSERT(str_length + (uint32) (A) <= Alloced_length) #include "pack.h" class Binary_string; int sortcmp(const Binary_string *s, const Binary_string *t, CHARSET_INFO *cs); int stringcmp(const Binary_string *s, const Binary_string *t); String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); inline uint32 copy_and_convert(char *to, size_t to_length, CHARSET_INFO *to_cs, const char *from, size_t from_length, CHARSET_INFO *from_cs, uint *errors) { return my_convert(to, (uint)to_length, to_cs, from, (uint)from_length, from_cs, errors); } class String_copy_status: protected MY_STRCOPY_STATUS { public: const char *source_end_pos() const { return m_source_end_pos; } const char *well_formed_error_pos() const { return m_well_formed_error_pos; } }; class Well_formed_prefix_status: public String_copy_status { public: Well_formed_prefix_status(CHARSET_INFO *cs, const char *str, const char *end, size_t nchars) { cs->well_formed_char_length(str, end, nchars, this); } }; class Well_formed_prefix: public Well_formed_prefix_status { const char *m_str; // The beginning of the string public: Well_formed_prefix(CHARSET_INFO *cs, const char *str, const char *end, size_t nchars) :Well_formed_prefix_status(cs, str, end, nchars), m_str(str) { } Well_formed_prefix(CHARSET_INFO *cs, const char *str, size_t length, size_t nchars) :Well_formed_prefix_status(cs, str, str + length, nchars), m_str(str) { } Well_formed_prefix(CHARSET_INFO *cs, const char *str, size_t length) :Well_formed_prefix_status(cs, str, str + length, length), m_str(str) { } Well_formed_prefix(CHARSET_INFO *cs, LEX_CSTRING str, size_t nchars) :Well_formed_prefix_status(cs, str.str, str.str + str.length, nchars), m_str(str.str) { } size_t length() const { return m_source_end_pos - m_str; } }; class String_copier: public String_copy_status, protected MY_STRCONV_STATUS { public: const char *cannot_convert_error_pos() const { return m_cannot_convert_error_pos; } const char *most_important_error_pos() const { return well_formed_error_pos() ? well_formed_error_pos() : cannot_convert_error_pos(); } /* Convert a string between character sets. "dstcs" and "srccs" cannot be &my_charset_bin. */ size_t convert_fix(CHARSET_INFO *dstcs, char *dst, size_t dst_length, CHARSET_INFO *srccs, const char *src, size_t src_length, size_t nchars) { return my_convert_fix(dstcs, dst, dst_length, srccs, src, src_length, nchars, this, this); } /* Copy a string. Fix bad bytes/characters to '?'. */ uint well_formed_copy(CHARSET_INFO *to_cs, char *to, size_t to_length, CHARSET_INFO *from_cs, const char *from, size_t from_length, size_t nchars); // Same as above, but without the "nchars" limit. uint well_formed_copy(CHARSET_INFO *to_cs, char *to, size_t to_length, CHARSET_INFO *from_cs, const char *from, size_t from_length) { return well_formed_copy(to_cs, to, to_length, from_cs, from, from_length, from_length /* No limit on "nchars"*/); } }; size_t my_copy_with_hex_escaping(CHARSET_INFO *cs, char *dst, size_t dstlen, const char *src, size_t srclen); uint convert_to_printable(char *to, size_t to_len, const char *from, size_t from_len, CHARSET_INFO *from_cs, size_t nbytes= 0); size_t convert_to_printable_required_length(uint len); class Charset { CHARSET_INFO *m_charset; public: Charset() :m_charset(&my_charset_bin) { } Charset(CHARSET_INFO *cs) :m_charset(cs) { } CHARSET_INFO *charset() const { return m_charset; } bool use_mb() const { return m_charset->use_mb(); } uint mbminlen() const { return m_charset->mbminlen; } uint mbmaxlen() const { return m_charset->mbmaxlen; } bool is_good_for_ft() const { // Binary and UCS2/UTF16/UTF32 are not supported return m_charset != &my_charset_bin && m_charset->mbminlen == 1; } size_t numchars(const char *str, const char *end) const { return m_charset->numchars(str, end); } size_t lengthsp(const char *str, size_t length) const { return m_charset->lengthsp(str, length); } size_t charpos(const char *str, const char *end, size_t pos) const { return m_charset->charpos(str, end, pos); } void set_charset(CHARSET_INFO *charset_arg) { m_charset= charset_arg; } void set_charset(const Charset &other) { m_charset= other.m_charset; } void swap(Charset &other) { swap_variables(CHARSET_INFO*, m_charset, other.m_charset); } bool same_encoding(const Charset &other) const { return my_charset_same(m_charset, other.m_charset); } /* Collation name without the character set name. For example, in case of "latin1_swedish_ci", this method returns "_swedish_ci". */ LEX_CSTRING collation_specific_name() const; bool encoding_allows_reinterpret_as(CHARSET_INFO *cs) const; bool eq_collation_specific_names(CHARSET_INFO *cs) const; bool can_have_collate_clause() const { return m_charset != &my_charset_bin; } /* The MariaDB version when the last collation change happened, e.g. due to a bug fix. See functions below. */ static ulong latest_mariadb_version_with_collation_change() { return 110002; } /* Check if the collation with the given ID changed its order since the given MariaDB version. */ static bool collation_changed_order(ulong mysql_version, uint cs_number) { if ((mysql_version < 50048 && (cs_number == 11 || /* ascii_general_ci - bug #29499, bug #27562 */ cs_number == 41 || /* latin7_general_ci - bug #29461 */ cs_number == 42 || /* latin7_general_cs - bug #29461 */ cs_number == 20 || /* latin7_estonian_cs - bug #29461 */ cs_number == 21 || /* latin2_hungarian_ci - bug #29461 */ cs_number == 22 || /* koi8u_general_ci - bug #29461 */ cs_number == 23 || /* cp1251_ukrainian_ci - bug #29461 */ cs_number == 26)) || /* cp1250_general_ci - bug #29461 */ (mysql_version < 50124 && (cs_number == 33 || /* utf8mb3_general_ci - bug #27877 */ cs_number == 35))) /* ucs2_general_ci - bug #27877 */ return true; if (cs_number == 159 && /* ucs2_general_mysql500_ci - MDEV-30746 */ ((mysql_version >= 100400 && mysql_version < 100429) || (mysql_version >= 100500 && mysql_version < 100520) || (mysql_version >= 100600 && mysql_version < 100613) || (mysql_version >= 100700 && mysql_version < 100708) || (mysql_version >= 100800 && mysql_version < 100808) || (mysql_version >= 100900 && mysql_version < 100906) || (mysql_version >= 101000 && mysql_version < 101004) || (mysql_version >= 101100 && mysql_version < 101103) || (mysql_version >= 110000 && mysql_version < 110002))) return true; return false; } /** Check if a collation has changed ID since the given version. Return the new ID. @param mysql_version @param cs_number - collation ID @retval the new collation ID (or cs_number, if no change) */ static uint upgrade_collation_id(ulong mysql_version, uint cs_number) { if (mysql_version >= 50300 && mysql_version <= 50399) { switch (cs_number) { case 149: return MY_PAGE2_COLLATION_ID_UCS2; // ucs2_crotian_ci case 213: return MY_PAGE2_COLLATION_ID_UTF8; // utf8_crotian_ci } } if ((mysql_version >= 50500 && mysql_version <= 50599) || (mysql_version >= 100000 && mysql_version <= 100005)) { switch (cs_number) { case 149: return MY_PAGE2_COLLATION_ID_UCS2; // ucs2_crotian_ci case 213: return MY_PAGE2_COLLATION_ID_UTF8; // utf8_crotian_ci case 214: return MY_PAGE2_COLLATION_ID_UTF32; // utf32_croatian_ci case 215: return MY_PAGE2_COLLATION_ID_UTF16; // utf16_croatian_ci case 245: return MY_PAGE2_COLLATION_ID_UTF8MB4;// utf8mb4_croatian_ci } } return cs_number; } }; /** Storage for strings with both length and allocated length. Automatically grows on demand. */ class Binary_string: public Sql_alloc { protected: char *Ptr; uint32 str_length, Alloced_length, extra_alloc; bool alloced, thread_specific; void init_private_data() { Ptr= 0; Alloced_length= extra_alloc= str_length= 0; alloced= thread_specific= false; } inline void free_buffer() { if (alloced) { alloced=0; my_free(Ptr); } } public: Binary_string() { init_private_data(); } explicit Binary_string(size_t length_arg) { init_private_data(); (void) real_alloc(length_arg); } /* NOTE: If one intend to use the c_ptr() method, the following two contructors need the size of memory for STR to be at least LEN+1 (to make room for zero termination). */ Binary_string(const char *str, size_t len) { Ptr= (char*) str; str_length= (uint32) len; Alloced_length= 0; /* Memory cannot be written to */ extra_alloc= 0; alloced= thread_specific= 0; } Binary_string(char *str, size_t len) { Ptr= str; str_length= Alloced_length= (uint32) len; extra_alloc= 0; alloced= thread_specific= 0; } explicit Binary_string(const Binary_string &str) { Ptr= str.Ptr; str_length= str.str_length; Alloced_length= str.Alloced_length; extra_alloc= 0; alloced= thread_specific= 0; } ~Binary_string() { free(); } inline uint32 length() const { return str_length;} inline char& operator [] (size_t i) const { return Ptr[i]; } inline void length(size_t len) { str_length=(uint32)len ; } inline bool is_empty() const { return (str_length == 0); } inline const char *ptr() const { return Ptr; } inline const char *end() const { return Ptr + str_length; } bool has_8bit_bytes() const { for (const char *c= ptr(), *c_end= end(); c < c_end; c++) { if (!my_isascii(*c)) return true; } return false; } bool bin_eq(const Binary_string *other) const { return length() == other->length() && !memcmp(ptr(), other->ptr(), length()); } /* PMG 2004.11.12 This is a method that works the same as perl's "chop". It simply drops the last character of a string. This is useful in the case of the federated storage handler where I'm building a unknown number, list of values and fields to be used in a sql insert statement to be run on the remote server, and have a comma after each. When the list is complete, I "chop" off the trailing comma ex. String stringobj; stringobj.append("VALUES ('foo', 'fi', 'fo',"); stringobj.chop(); stringobj.append(")"); In this case, the value of string was: VALUES ('foo', 'fi', 'fo', VALUES ('foo', 'fi', 'fo' VALUES ('foo', 'fi', 'fo') */ inline void chop() { if (str_length) { str_length--; Ptr[str_length]= '\0'; DBUG_ASSERT(strlen(Ptr) == str_length); } } // Returns offset to substring or -1 int strstr(const Binary_string &search, uint32 offset=0) const; int strstr(const char *search, uint32 search_length, uint32 offset=0) const; // Returns offset to substring or -1 int strrstr(const Binary_string &search, uint32 offset=0) const; /* The following append operations do not extend the strings and in production mode do NOT check that alloced memory! q_*** methods writes values of parameters itself qs_*** methods writes string representation of value */ void q_append(const char c) { ASSERT_LENGTH(1); Ptr[str_length++] = c; } void q_append2b(const uint32 n) { ASSERT_LENGTH(2); int2store(Ptr + str_length, n); str_length += 2; } void q_append(const uint32 n) { ASSERT_LENGTH(4); int4store(Ptr + str_length, n); str_length += 4; } void q_append(double d) { ASSERT_LENGTH(8); float8store(Ptr + str_length, d); str_length += 8; } void q_append(double *d) { ASSERT_LENGTH(8); float8store(Ptr + str_length, *d); str_length += 8; } /* Append a wide character. The caller must have allocated at least cs->mbmaxlen bytes. */ int q_append_wc(my_wc_t wc, CHARSET_INFO *cs) { int mblen; if ((mblen= cs->cset->wc_mb(cs, wc, (uchar *) end(), (uchar *) end() + cs->mbmaxlen)) > 0) str_length+= (uint32) mblen; return mblen; } void q_append(const char *data, size_t data_len) { ASSERT_LENGTH(data_len); if (data_len) memcpy(Ptr + str_length, data, data_len); DBUG_ASSERT(str_length <= UINT_MAX32 - data_len); str_length += (uint)data_len; } void q_append(const LEX_CSTRING *ls) { DBUG_ASSERT(ls->length < UINT_MAX32 && ((ls->length == 0 && !ls->str) || ls->length == strlen(ls->str))); q_append(ls->str, (uint32) ls->length); } void write_at_position(uint32 position, uint32 value) { DBUG_ASSERT(str_length >= position + 4); int4store(Ptr + position,value); } void qs_append(const LEX_CSTRING *ls) { DBUG_ASSERT(ls->length < UINT_MAX32 && ((ls->length == 0 && !ls->str) || ls->length == strlen(ls->str))); qs_append(ls->str, (uint32)ls->length); } void qs_append(const char *str, size_t len); void qs_append_hex(const char *str, uint32 len); void qs_append_hex_uint32(uint32 num); void qs_append(double d); void qs_append(const double *d); inline void qs_append(const char c) { ASSERT_LENGTH(1); Ptr[str_length]= c; str_length++; } void qs_append(int i); void qs_append(uint i) { qs_append((ulonglong)i); } void qs_append(ulong i) { qs_append((ulonglong)i); } void qs_append(ulonglong i); void qs_append(longlong i, int radix) { ASSERT_LENGTH(22); char *buff= Ptr + str_length; char *end= ll2str(i, buff, radix, 0); str_length+= (uint32) (end-buff); } /* Mark variable thread specific it it's not allocated already */ inline void set_thread_specific() { if (!alloced) thread_specific= 1; } bool is_alloced() const { return alloced; } inline uint32 alloced_length() const { return Alloced_length;} inline uint32 extra_allocation() const { return extra_alloc;} inline void extra_allocation(size_t len) { extra_alloc= (uint32)len; } inline void mark_as_const() { Alloced_length= 0;} inline bool uses_buffer_owned_by(const Binary_string *s) const { return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->Alloced_length); } /* Swap two string objects. Efficient way to exchange data without memcpy. */ void swap(Binary_string &s) { swap_variables(char *, Ptr, s.Ptr); swap_variables(uint32, str_length, s.str_length); swap_variables(uint32, Alloced_length, s.Alloced_length); swap_variables(bool, alloced, s.alloced); } /** Points the internal buffer to the supplied one. The old buffer is freed. @param str Pointer to the new buffer. @param arg_length Length of the new buffer in characters, excluding any null character. @note The new buffer will not be null terminated. */ void set_alloced(char *str, size_t length, size_t alloced_length) { free_buffer(); Ptr= str; str_length= (uint32) length; DBUG_ASSERT(alloced_length < UINT_MAX32); Alloced_length= (uint32) alloced_length; } inline void set(char *str, size_t arg_length) { set_alloced(str, arg_length, arg_length); } inline void set(const char *str, size_t length) { free_buffer(); Ptr= (char*) str; str_length= (uint32) length; Alloced_length= 0; } void set(Binary_string &str, size_t offset, size_t length) { DBUG_ASSERT(&str != this); free_buffer(); Ptr= str.Ptr + offset; str_length= (uint32) length; Alloced_length= 0; if (str.Alloced_length) Alloced_length= (uint32) (str.Alloced_length - offset); } LEX_CSTRING to_lex_cstring() const { LEX_CSTRING tmp= {Ptr, str_length}; return tmp; } inline LEX_CSTRING *get_value(LEX_CSTRING *res) const { res->str= Ptr; res->length= str_length; return res; } /* Take over handling of buffer from some other object */ void reset(char *ptr_arg, size_t length_arg, size_t alloced_length_arg) { set_alloced(ptr_arg, length_arg, alloced_length_arg); alloced= ptr_arg != 0; } /* Forget about the buffer, let some other object handle it */ char *release() { char *old= Ptr; init_private_data(); return old; } /* This is used to set a new buffer for String. However if the String already has an allocated buffer, it will keep that one. It's not to be used to set the value or length of the string. */ inline void set_buffer_if_not_allocated(char *str, size_t arg_length) { if (!alloced) { /* Following should really set str_length= 0, but some code may depend on that the String length is same as buffer length. */ Ptr= str; str_length= Alloced_length= (uint32) arg_length; } /* One should set str_length before using it */ MEM_UNDEFINED(&str_length, sizeof(str_length)); } inline Binary_string& operator=(const Binary_string &s) { if (&s != this) { /* It is forbidden to do assignments like some_string = substring_of_that_string */ DBUG_ASSERT(!s.uses_buffer_owned_by(this)); set_alloced((char *) s.Ptr, s.str_length, s.Alloced_length); } return *this; } bool set_hex(ulonglong num); bool set_hex(const char *str, uint32 len); bool set_fcvt(double num, uint decimals); bool copy(); // Alloc string if not alloced bool copy(const Binary_string &s); // Allocate new string bool copy(const char *s, size_t arg_length); // Allocate new string bool copy_or_move(const char *s,size_t arg_length); /** Convert a string to a printable format. All non-convertable and control characters are replaced to 5-character sequences '\hhhh'. */ bool copy_printable_hhhh(CHARSET_INFO *to_cs, CHARSET_INFO *from_cs, const char *from, size_t from_length); bool append_ulonglong(ulonglong val); bool append_longlong(longlong val); bool append(const char *s, size_t size) { if (!size) return false; if (realloc_with_extra_if_needed(str_length + size)) return true; q_append(s, size); return false; } bool append(const LEX_CSTRING &s) { return append(s.str, s.length); } bool append(const Binary_string &s) { return append(s.ptr(), s.length()); } bool append(IO_CACHE* file, uint32 arg_length); inline bool append_char(char chr) { if (str_length < Alloced_length) { Ptr[str_length++]= chr; } else { if (unlikely(realloc_with_extra(str_length + 1))) return true; Ptr[str_length++]= chr; } return false; } bool append_hex(const char *src, uint32 srclen) { for (const char *src_end= src + srclen ; src != src_end ; src++) { if (unlikely(append_char(_dig_vec_lower[((uchar) *src) >> 4])) || unlikely(append_char(_dig_vec_lower[((uchar) *src) & 0x0F]))) return true; } return false; } bool append_hex_uint32(uint32 num) { if (reserve(8)) return true; qs_append_hex_uint32(num); return false; } bool append_with_step(const char *s, uint32 arg_length, uint32 step_alloc) { uint32 new_length= arg_length + str_length; if (new_length > Alloced_length && unlikely(realloc(new_length + step_alloc))) return true; q_append(s, arg_length); return false; } inline char *c_ptr() { if (unlikely(!Ptr)) return (char*) ""; /* Here we assume that any buffer used to initalize String has an end \0 or have at least an accessable character at end. This is to handle the case of String("Hello",5) and String("hello",5) efficiently. We have two options here. To test for !Alloced_length or !alloced. Using "Alloced_length" is slightly safer so that we do not read from potentially unintialized memory (normally not dangerous but may give warnings in valgrind), but "alloced" is safer as there are less change to get memory loss from code that is using String((char*), length) or String.set((char*), length) and does not free things properly (and there is several places in the code where this happens and it is hard to find out if any of these will call c_ptr(). */ if (unlikely(!alloced && !Ptr[str_length])) return Ptr; if (str_length < Alloced_length) { Ptr[str_length]=0; return Ptr; } (void) realloc(str_length); /* This will add end \0 */ return Ptr; } /* One should use c_ptr() instead for most cases. This will be deleted soon, kept for compatiblity. */ inline char *c_ptr_quick() { return c_ptr_safe(); } /* This is to be used only in the case when one cannot use c_ptr(). The cases are: - When one initializes String with an external buffer and length and buffer[length] could be uninitalized when c_ptr() is called. - When valgrind gives warnings about uninitialized memory with c_ptr(). */ inline char *c_ptr_safe() { if (Ptr && str_length < Alloced_length) Ptr[str_length]=0; else (void) realloc(str_length); return Ptr; } inline void free() { free_buffer(); /* We have to clear the values as some Strings, like in Field, are reused after free(). Because of this we cannot use MEM_UNDEFINED() here. */ Ptr= 0; str_length= 0; Alloced_length= extra_alloc= 0; } inline bool alloc(size_t arg_length) { /* Allocate if we need more space or if we don't have done any allocation yet (we don't want to have Ptr to be NULL for empty strings). Note that if arg_length == Alloced_length then we don't allocate. This ensures we don't do any extra allocations in protocol and String:int, but the string will not be automatically null terminated if c_ptr() is not called. */ if (arg_length <= Alloced_length && Alloced_length) return 0; return real_alloc(arg_length); } bool real_alloc(size_t arg_length); // Empties old string bool realloc_raw(size_t arg_length); bool realloc(size_t arg_length) { if (realloc_raw(arg_length+1)) return TRUE; Ptr[arg_length]= 0; // This make other funcs shorter return FALSE; } bool realloc_with_extra(size_t arg_length) { if (extra_alloc < 4096) extra_alloc= extra_alloc*2+128; if (realloc_raw(arg_length + extra_alloc)) return TRUE; Ptr[arg_length]=0; // This make other funcs shorter return FALSE; } bool realloc_with_extra_if_needed(size_t arg_length) { if (arg_length < Alloced_length) { Ptr[arg_length]=0; // behave as if realloc was called. return 0; } return realloc_with_extra(arg_length); } // Shrink the buffer, but only if it is allocated on the heap. void shrink(size_t arg_length); void move(Binary_string &s) { set_alloced(s.Ptr, s.str_length, s.Alloced_length); extra_alloc= s.extra_alloc; alloced= s.alloced; thread_specific= s.thread_specific; s.alloced= 0; } bool fill(size_t max_length,char fill); /* Replace substring with string If wrong parameter or not enough memory, do nothing */ bool replace(uint32 offset,uint32 arg_length, const char *to, uint32 length); bool replace(uint32 offset,uint32 arg_length, const Binary_string &to) { return replace(offset,arg_length,to.ptr(),to.length()); } int reserve(size_t space_needed) { DBUG_ASSERT((ulonglong) str_length + space_needed < UINT_MAX32); return realloc(str_length + space_needed); } int reserve(size_t space_needed, size_t grow_by); inline char *prep_append(uint32 arg_length, uint32 step_alloc) { uint32 new_length= arg_length + str_length; if (new_length > Alloced_length) { if (unlikely(realloc(new_length + step_alloc))) return 0; } uint32 old_length= str_length; str_length+= arg_length; return Ptr + old_length; // Area to use } void q_net_store_length(ulonglong length) { DBUG_ASSERT(Alloced_length >= (str_length + net_length_size(length))); char *pos= (char *) net_store_length((uchar *)(Ptr + str_length), length); str_length= uint32(pos - Ptr); } void q_net_store_data(const uchar *from, size_t length) { DBUG_ASSERT(length < UINT_MAX32); DBUG_ASSERT(Alloced_length >= (str_length + length + net_length_size(length))); q_net_store_length(length); q_append((const char *)from, (uint32) length); } }; class String: public Charset, public Binary_string { public: String() = default; String(size_t length_arg) :Binary_string(length_arg) { } /* NOTE: If one intend to use the c_ptr() method, the following two contructors need the size of memory for STR to be at least LEN+1 (to make room for zero termination). */ String(const char *str, size_t len, CHARSET_INFO *cs) :Charset(cs), Binary_string(str, len) { } String(char *str, size_t len, CHARSET_INFO *cs) :Charset(cs), Binary_string(str, len) { } String(const String &str) = default; String(String &&str) noexcept :Charset(std::move(str)), Binary_string(std::move(str)){} void set(String &str,size_t offset,size_t arg_length) { Binary_string::set(str, offset, arg_length); set_charset(str); } inline void set(char *str,size_t arg_length, CHARSET_INFO *cs) { Binary_string::set(str, arg_length); set_charset(cs); } inline void set(const char *str,size_t arg_length, CHARSET_INFO *cs) { Binary_string::set(str, arg_length); set_charset(cs); } bool set_ascii(const char *str, size_t arg_length); inline void set_buffer_if_not_allocated(char *str,size_t arg_length, CHARSET_INFO *cs) { Binary_string::set_buffer_if_not_allocated(str, arg_length); set_charset(cs); } bool set_int(longlong num, bool unsigned_flag, CHARSET_INFO *cs); bool set(int num, CHARSET_INFO *cs) { return set_int(num, false, cs); } bool set(uint num, CHARSET_INFO *cs) { return set_int(num, true, cs); } bool set(long num, CHARSET_INFO *cs) { return set_int(num, false, cs); } bool set(ulong num, CHARSET_INFO *cs) { return set_int(num, true, cs); } bool set(longlong num, CHARSET_INFO *cs) { return set_int(num, false, cs); } bool set(ulonglong num, CHARSET_INFO *cs) { return set_int((longlong)num, true, cs); } bool set_real(double num,uint decimals, CHARSET_INFO *cs); bool set_fcvt(double num, uint decimals) { set_charset(&my_charset_latin1); return Binary_string::set_fcvt(num, decimals); } bool set_hex(ulonglong num) { set_charset(&my_charset_latin1); return Binary_string::set_hex(num); } bool set_hex(const char *str, uint32 len) { set_charset(&my_charset_latin1); return Binary_string::set_hex(str, len); } /* Take over handling of buffer from some other object */ void reset(char *ptr_arg, size_t length_arg, size_t alloced_length_arg, CHARSET_INFO *cs) { Binary_string::reset(ptr_arg, length_arg, alloced_length_arg); set_charset(cs); } inline String& operator = (const String &s) { if (&s != this) { set_charset(s); Binary_string::operator=(s); } return *this; } bool copy() { return Binary_string::copy(); } bool copy(const String &s) { set_charset(s); return Binary_string::copy(s); } bool copy(const char *s, size_t arg_length, CHARSET_INFO *cs) { set_charset(cs); return Binary_string::copy(s, arg_length); } bool copy_or_move(const char *s, size_t arg_length, CHARSET_INFO *cs) { set_charset(cs); return Binary_string::copy_or_move(s, arg_length); } static bool needs_conversion(size_t arg_length, CHARSET_INFO *cs_from, CHARSET_INFO *cs_to, uint32 *offset); static bool needs_conversion_on_storage(size_t arg_length, CHARSET_INFO *cs_from, CHARSET_INFO *cs_to); bool copy_aligned(const char *s, size_t arg_length, size_t offset, CHARSET_INFO *cs); bool set_or_copy_aligned(const char *s, size_t arg_length, CHARSET_INFO *cs); bool can_be_safely_converted_to(CHARSET_INFO *tocs) const { if (charset() == &my_charset_bin) return Well_formed_prefix(tocs, ptr(), length()).length() == length(); String try_val; uint try_conv_error= 0; try_val.copy(ptr(), length(), charset(), tocs, &try_conv_error); return try_conv_error == 0; } bool copy(const char*s, size_t arg_length, CHARSET_INFO *csfrom, CHARSET_INFO *csto, uint *errors); bool copy(const String *str, CHARSET_INFO *tocs, uint *errors) { return copy(str->ptr(), str->length(), str->charset(), tocs, errors); } bool copy(CHARSET_INFO *tocs, CHARSET_INFO *fromcs, const char *src, size_t src_length, size_t nchars, String_copier *copier) { if (unlikely(alloc(tocs->mbmaxlen * src_length))) return true; str_length= copier->well_formed_copy(tocs, Ptr, alloced_length(), fromcs, src, (uint) src_length, (uint) nchars); set_charset(tocs); return false; } // Append without character set conversion bool append(const String &s) { return Binary_string::append(s); } inline bool append(char chr) { return Binary_string::append_char(chr); } bool append_hex(const char *src, uint32 srclen) { return Binary_string::append_hex(src, srclen); } bool append_hex(const uchar *src, uint32 srclen) { return Binary_string::append_hex((const char*)src, srclen); } bool append_introducer_and_hex(const String *str) { return append('_') || append(str->charset()->cs_name) || append(STRING_WITH_LEN(" 0x")) || append_hex(str->ptr(), (uint32) str->length()); } bool append(IO_CACHE* file, uint32 arg_length) { return Binary_string::append(file, arg_length); } inline bool append(const char *s, uint32 arg_length, uint32 step_alloc) { return append_with_step(s, arg_length, step_alloc); } // Append with optional character set conversion from ASCII (e.g. to UCS2) bool append(const LEX_STRING *ls) { DBUG_ASSERT(ls->length < UINT_MAX32 && ((ls->length == 0 && !ls->str) || ls->length == strlen(ls->str))); return append(ls->str, (uint32) ls->length); } bool append(const LEX_CSTRING *ls) { DBUG_ASSERT(ls->length < UINT_MAX32 && ((ls->length == 0 && !ls->str) || ls->length == strlen(ls->str))); return append(ls->str, (uint32) ls->length); } bool append(const LEX_CSTRING &ls) { return append(&ls); } bool append_name_value(const LEX_CSTRING &name, const LEX_CSTRING &value, uchar quot= '\0') { return append(name) || append('=') || (quot && append(quot)) || append(value) || (quot && append(quot)); } bool append(const char *s, size_t size); bool append_parenthesized(long nr, int radix= 10); // Append with optional character set conversion from cs to charset() bool append(const char *s, size_t arg_length, CHARSET_INFO *cs); bool append(const LEX_CSTRING &s, CHARSET_INFO *cs) { return append(s.str, s.length, cs); } // Append a wide character bool append_wc(my_wc_t wc) { if (reserve(mbmaxlen())) return true; int mblen= q_append_wc(wc, charset()); if (mblen > 0) return false; else if (mblen == MY_CS_ILUNI && wc != '?') return q_append_wc('?', charset()) <= 0; return true; } // Append a number with zero prefilling bool append_zerofill(uint num, uint width) { static const char zeros[15]= "00000000000000"; char intbuff[15]; uint length= (uint) (int10_to_str(num, intbuff, 10) - intbuff); if (length < width && append(zeros, width - length, &my_charset_latin1)) return true; return append(intbuff, length, &my_charset_latin1); } /* Append a bitmask in an uint32 with a translation into a C-style human readable representation, e.g.: 0x05 -> "(flag04|flag01)" @param flags - the flags to translate @param names - an array of flag names @param count - the number of available elements in "names" */ bool append_flag32_names(uint32 flags, LEX_CSTRING names[], size_t count) { bool added= false; if (flags && append('(')) return true; for (ulong i= 0; i <= 31; i++) { ulong bit= 31 - i; if (flags & (1 << bit)) { if (added && append('|')) return true; if (bit < count ? append(names[bit]) : append('?')) return true; added= true; } } if (flags && append(')')) return true; return false; } void strip_sp(); friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); friend class Field; uint32 numchars() const { return (uint32) Charset::numchars(ptr(), end()); } int charpos(longlong i, uint32 offset=0) { if (i <= 0) return (int) i; return (int) Charset::charpos(ptr() + offset, end(), (size_t) i); } size_t lengthsp() const { return Charset::lengthsp(Ptr, str_length); } void print(String *to) const; void print_with_conversion(String *to, CHARSET_INFO *cs) const; void print(String *to, CHARSET_INFO *cs) const { if (my_charset_same(charset(), cs)) print(to); else print_with_conversion(to, cs); } static my_wc_t escaped_wc_for_single_quote(my_wc_t ch) { switch (ch) { case '\\': return '\\'; case '\0': return '0'; case '\'': return '\''; case '\n': return 'n'; case '\r': return 'r'; case '\032': return 'Z'; } return 0; } // Append for single quote using mb_wc/wc_mb Unicode conversion bool append_for_single_quote_using_mb_wc(const char *str, size_t length, CHARSET_INFO *cs); // Append for single quote with optional mb_wc/wc_mb conversion bool append_for_single_quote_opt_convert(const char *str, size_t length, CHARSET_INFO *cs) { return charset() == &my_charset_bin || cs == &my_charset_bin || my_charset_same(charset(), cs) ? append_for_single_quote(str, length) : append_for_single_quote_using_mb_wc(str, length, cs); } bool append_for_single_quote_opt_convert(const String &str) { return append_for_single_quote_opt_convert(str.ptr(), str.length(), str.charset()); } bool append_for_single_quote(const char *st, size_t len); bool append_for_single_quote(const String *s) { return append_for_single_quote(s->ptr(), s->length()); } void swap(String &s) { Charset::swap(s); Binary_string::swap(s); } uint well_formed_length() const { return (uint) Well_formed_prefix(charset(), ptr(), length()).length(); } bool is_ascii() const { if (length() == 0) return TRUE; if (charset()->mbminlen > 1) return FALSE; return !has_8bit_bytes(); } bool eq(const String *other, CHARSET_INFO *cs) const { return !sortcmp(this, other, cs); } private: bool append_semi_hex(const char *s, uint len, CHARSET_INFO *cs); }; // The following class is a backport from MySQL 5.6: /** String class wrapper with a preallocated buffer of size buff_sz This class allows to replace sequences of: char buff[12345]; String str(buff, sizeof(buff)); str.length(0); with a simple equivalent declaration: StringBuffer<12345> str; */ template class StringBuffer : public String { char buff[buff_sz]; public: StringBuffer() : String(buff, buff_sz, &my_charset_bin) { length(0); } explicit StringBuffer(CHARSET_INFO *cs) : String(buff, buff_sz, cs) { length(0); } void set_buffer_if_not_allocated(CHARSET_INFO *cs) { if (!is_alloced()) { Ptr= buff; Alloced_length= (uint32) buff_sz; } str_length= 0; /* Safety, not required */ /* One should set str_length before using it */ MEM_UNDEFINED(&str_length, sizeof(str_length)); set_charset(cs); } }; template class BinaryStringBuffer : public Binary_string { char buff[buff_sz]; public: BinaryStringBuffer() : Binary_string(buff, buff_sz) { length(0); } }; static inline bool check_if_only_end_space(CHARSET_INFO *cs, const char *str, const char *end) { return str + cs->scan(str, end, MY_SEQ_SPACES) == end; } int append_query_string(CHARSET_INFO *csinfo, String *to, const char *str, size_t len, bool no_backslash); #endif /* SQL_STRING_INCLUDED */ server/private/sql_class.h000064400001012234151031265040011661 0ustar00/* Copyright (c) 2009, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_CLASS_INCLUDED #define SQL_CLASS_INCLUDED /* Classes in mysql */ #include #include #include "dur_prop.h" #include #include "sql_const.h" #include "lex_ident.h" #include #include "log.h" #include "rpl_tblmap.h" #include "mdl.h" #include "field.h" // Create_field #include "opt_trace_context.h" #include "probes_mysql.h" #include "sql_locale.h" /* my_locale_st */ #include "sql_profile.h" /* PROFILING */ #include "scheduler.h" /* thd_scheduler */ #include "protocol.h" /* Protocol_text, Protocol_binary */ #include "violite.h" /* vio_is_connected */ #include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA, THR_LOCK_INFO */ #include "thr_timer.h" #include "thr_malloc.h" #include "log_slow.h" /* LOG_SLOW_DISABLE_... */ #include #include "sql_digest_stream.h" // sql_digest_state #include #include #include #include #include #include "session_tracker.h" #include "backup.h" #include "xa.h" #include "scope.h" #include "ddl_log.h" /* DDL_LOG_STATE */ #include "ha_handler_stats.h" // ha_handler_stats */ extern "C" void set_thd_stage_info(void *thd, const PSI_stage_info *new_stage, PSI_stage_info *old_stage, const char *calling_func, const char *calling_file, const unsigned int calling_line); #define THD_STAGE_INFO(thd, stage) \ (thd)->enter_stage(&stage, __func__, __FILE__, __LINE__) #include "my_apc.h" #include "rpl_gtid.h" #include "wsrep.h" #include "wsrep_on.h" #include #ifdef WITH_WSREP /* wsrep-lib */ #include "wsrep_client_service.h" #include "wsrep_client_state.h" #include "wsrep_mutex.h" #include "wsrep_condition_variable.h" class Wsrep_applier_service; enum wsrep_consistency_check_mode { NO_CONSISTENCY_CHECK, CONSISTENCY_CHECK_DECLARED, CONSISTENCY_CHECK_RUNNING, }; #endif /* WITH_WSREP */ class Reprepare_observer; class Relay_log_info; struct rpl_group_info; class Rpl_filter; class Query_log_event; class Load_log_event; class Log_event_writer; class sp_rcontext; class sp_cache; class Lex_input_stream; class Parser_state; class Rows_log_event; class Sroutine_hash_entry; class user_var_entry; struct Trans_binlog_info; class rpl_io_thread_info; class rpl_sql_thread_info; #ifdef HAVE_REPLICATION struct Slave_info; #endif enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME }; enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE }; enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON, DELAY_KEY_WRITE_ALL }; enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT, SLAVE_EXEC_MODE_IDEMPOTENT, SLAVE_EXEC_MODE_LAST_BIT }; enum enum_slave_run_triggers_for_rbr { SLAVE_RUN_TRIGGERS_FOR_RBR_NO, SLAVE_RUN_TRIGGERS_FOR_RBR_YES, SLAVE_RUN_TRIGGERS_FOR_RBR_LOGGING, SLAVE_RUN_TRIGGERS_FOR_RBR_ENFORCE}; enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY, SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY}; /* COLUMNS_READ: A column is goind to be read. COLUMNS_WRITE: A column is going to be written to. MARK_COLUMNS_READ: A column is goind to be read. A bit in read set is set to inform handler that the field is to be read. If field list contains duplicates, then thd->dup_field is set to point to the last found duplicate. MARK_COLUMNS_WRITE: A column is going to be written to. A bit is set in write set to inform handler that it needs to update this field in write_row and update_row. */ enum enum_column_usage { COLUMNS_READ, COLUMNS_WRITE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE}; static inline bool should_mark_column(enum_column_usage column_usage) { return column_usage >= MARK_COLUMNS_READ; } enum enum_filetype { FILETYPE_CSV, FILETYPE_XML }; enum enum_binlog_row_image { /** PKE in the before image and changed columns in the after image */ BINLOG_ROW_IMAGE_MINIMAL= 0, /** Whenever possible, before and after image contain all columns except blobs. */ BINLOG_ROW_IMAGE_NOBLOB= 1, /** All columns in both before and after image. */ BINLOG_ROW_IMAGE_FULL= 2 }; /* Bits for different SQL modes modes (including ANSI mode) */ #define MODE_REAL_AS_FLOAT (1ULL << 0) #define MODE_PIPES_AS_CONCAT (1ULL << 1) #define MODE_ANSI_QUOTES (1ULL << 2) #define MODE_IGNORE_SPACE (1ULL << 3) #define MODE_IGNORE_BAD_TABLE_OPTIONS (1ULL << 4) #define MODE_ONLY_FULL_GROUP_BY (1ULL << 5) #define MODE_NO_UNSIGNED_SUBTRACTION (1ULL << 6) #define MODE_NO_DIR_IN_CREATE (1ULL << 7) #define MODE_POSTGRESQL (1ULL << 8) #define MODE_ORACLE (1ULL << 9) #define MODE_MSSQL (1ULL << 10) #define MODE_DB2 (1ULL << 11) #define MODE_MAXDB (1ULL << 12) #define MODE_NO_KEY_OPTIONS (1ULL << 13) #define MODE_NO_TABLE_OPTIONS (1ULL << 14) #define MODE_NO_FIELD_OPTIONS (1ULL << 15) #define MODE_MYSQL323 (1ULL << 16) #define MODE_MYSQL40 (1ULL << 17) #define MODE_ANSI (1ULL << 18) #define MODE_NO_AUTO_VALUE_ON_ZERO (1ULL << 19) #define MODE_NO_BACKSLASH_ESCAPES (1ULL << 20) #define MODE_STRICT_TRANS_TABLES (1ULL << 21) #define MODE_STRICT_ALL_TABLES (1ULL << 22) #define MODE_NO_ZERO_IN_DATE (1ULL << 23) #define MODE_NO_ZERO_DATE (1ULL << 24) #define MODE_INVALID_DATES (1ULL << 25) #define MODE_ERROR_FOR_DIVISION_BY_ZERO (1ULL << 26) #define MODE_TRADITIONAL (1ULL << 27) #define MODE_NO_AUTO_CREATE_USER (1ULL << 28) #define MODE_HIGH_NOT_PRECEDENCE (1ULL << 29) #define MODE_NO_ENGINE_SUBSTITUTION (1ULL << 30) #define MODE_PAD_CHAR_TO_FULL_LENGTH (1ULL << 31) /* SQL mode bits defined above are common for MariaDB and MySQL */ #define MODE_MASK_MYSQL_COMPATIBLE 0xFFFFFFFFULL /* The following modes are specific to MariaDB */ #define MODE_EMPTY_STRING_IS_NULL (1ULL << 32) #define MODE_SIMULTANEOUS_ASSIGNMENT (1ULL << 33) #define MODE_TIME_ROUND_FRACTIONAL (1ULL << 34) /* The following modes are specific to MySQL */ #define MODE_MYSQL80_TIME_TRUNCATE_FRACTIONAL (1ULL << 32) /* Bits for different old style modes */ #define OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE (1 << 0) #define OLD_MODE_NO_PROGRESS_INFO (1 << 1) #define OLD_MODE_ZERO_DATE_TIME_CAST (1 << 2) #define OLD_MODE_UTF8_IS_UTF8MB3 (1 << 3) extern char internal_table_name[2]; extern char empty_c_string[1]; extern MYSQL_PLUGIN_IMPORT const char **errmesg; extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd); extern "C" unsigned long long thd_query_id(const MYSQL_THD thd); extern "C" size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen); extern "C" const char *thd_priv_user(MYSQL_THD thd, size_t *length); extern "C" const char *thd_priv_host(MYSQL_THD thd, size_t *length); extern "C" const char *thd_user_name(MYSQL_THD thd); extern "C" const char *thd_client_host(MYSQL_THD thd); extern "C" const char *thd_client_ip(MYSQL_THD thd); extern "C" LEX_CSTRING *thd_current_db(MYSQL_THD thd); extern "C" int thd_current_status(MYSQL_THD thd); extern "C" enum enum_server_command thd_current_command(MYSQL_THD thd); extern "C" int thd_double_innodb_cardinality(MYSQL_THD thd); /** @class CSET_STRING @brief Character set armed LEX_STRING */ class CSET_STRING { private: LEX_STRING string; CHARSET_INFO *cs; public: CSET_STRING() : cs(&my_charset_bin) { string.str= NULL; string.length= 0; } CSET_STRING(char *str_arg, size_t length_arg, CHARSET_INFO *cs_arg) : cs(cs_arg) { DBUG_ASSERT(cs_arg != NULL); string.str= str_arg; string.length= length_arg; } inline char *str() const { return string.str; } inline size_t length() const { return string.length; } CHARSET_INFO *charset() const { return cs; } friend LEX_STRING * thd_query_string (MYSQL_THD thd); }; class Recreate_info { ha_rows m_records_copied; ha_rows m_records_duplicate; public: Recreate_info() :m_records_copied(0), m_records_duplicate(0) { } Recreate_info(ha_rows records_copied, ha_rows records_duplicate) :m_records_copied(records_copied), m_records_duplicate(records_duplicate) { } ha_rows records_copied() const { return m_records_copied; } ha_rows records_duplicate() const { return m_records_duplicate; } ha_rows records_processed() const { return m_records_copied + m_records_duplicate; } }; #define TC_HEURISTIC_RECOVER_COMMIT 1 #define TC_HEURISTIC_RECOVER_ROLLBACK 2 extern ulong tc_heuristic_recover; typedef struct st_user_var_events { user_var_entry *user_var_event; char *value; size_t length; const Type_handler *th; uint charset_number; } BINLOG_USER_VAR_EVENT; /* The COPY_INFO structure is used by INSERT/REPLACE code. The schema of the row counting by the INSERT/INSERT ... ON DUPLICATE KEY UPDATE code: If a row is inserted then the copied variable is incremented. If a row is updated by the INSERT ... ON DUPLICATE KEY UPDATE and the new data differs from the old one then the copied and the updated variables are incremented. The touched variable is incremented if a row was touched by the update part of the INSERT ... ON DUPLICATE KEY UPDATE no matter whether the row was actually changed or not. */ typedef struct st_copy_info { ha_rows records; /**< Number of processed records */ ha_rows deleted; /**< Number of deleted records */ ha_rows updated; /**< Number of updated records */ ha_rows copied; /**< Number of copied records */ ha_rows accepted_rows; /**< Number of accepted original rows (same as number of rows in RETURNING) */ ha_rows error_count; ha_rows touched; /* Number of touched records */ enum enum_duplicates handle_duplicates; int escape_char, last_errno; bool ignore; /* for INSERT ... UPDATE */ List *update_fields; List *update_values; /* for VIEW ... WITH CHECK OPTION */ TABLE_LIST *view; TABLE_LIST *table_list; /* Normal table */ } COPY_INFO; class Key_part_spec :public Sql_alloc { public: Lex_ident field_name; uint length; bool generated; Key_part_spec(const LEX_CSTRING *name, uint len, bool gen= false) : field_name(*name), length(len), generated(gen) {} bool operator==(const Key_part_spec& other) const; /** Construct a copy of this Key_part_spec. field_name is copied by-pointer as it is known to never change. At the same time 'length' may be reset in mysql_prepare_create_table, and this is why we supply it with a copy. @return If out of memory, 0 is returned and an error is set in THD. */ Key_part_spec *clone(MEM_ROOT *mem_root) const { return new (mem_root) Key_part_spec(*this); } bool check_key_for_blob(const class handler *file) const; bool check_key_length_for_blob() const; bool check_primary_key_for_blob(const class handler *file) const { return check_key_for_blob(file) || check_key_length_for_blob(); } bool check_foreign_key_for_blob(const class handler *file) const { return check_key_for_blob(file) || check_key_length_for_blob(); } bool init_multiple_key_for_blob(const class handler *file); }; class Alter_drop :public Sql_alloc { public: enum drop_type { KEY, COLUMN, FOREIGN_KEY, CHECK_CONSTRAINT, PERIOD }; const char *name; enum drop_type type; bool drop_if_exists; Alter_drop(enum drop_type par_type,const char *par_name, bool par_exists) :name(par_name), type(par_type), drop_if_exists(par_exists) { DBUG_ASSERT(par_name != NULL); } /** Used to make a clone of this object for ALTER/CREATE TABLE @sa comment for Key_part_spec::clone */ Alter_drop *clone(MEM_ROOT *mem_root) const { return new (mem_root) Alter_drop(*this); } const char *type_name() { return type == COLUMN ? "COLUMN" : type == CHECK_CONSTRAINT ? "CONSTRAINT" : type == PERIOD ? "PERIOD" : type == KEY ? "INDEX" : "FOREIGN KEY"; } }; class Alter_column :public Sql_alloc { public: LEX_CSTRING name; LEX_CSTRING new_name; Virtual_column_info *default_value; bool alter_if_exists; Alter_column(LEX_CSTRING par_name, Virtual_column_info *expr, bool par_exists) :name(par_name), new_name{NULL, 0}, default_value(expr), alter_if_exists(par_exists) {} Alter_column(LEX_CSTRING par_name, LEX_CSTRING _new_name, bool exists) :name(par_name), new_name(_new_name), default_value(NULL), alter_if_exists(exists) {} /** Used to make a clone of this object for ALTER/CREATE TABLE @sa comment for Key_part_spec::clone */ Alter_column *clone(MEM_ROOT *mem_root) const { return new (mem_root) Alter_column(*this); } bool is_rename() { DBUG_ASSERT(!new_name.str || !default_value); return new_name.str; } }; class Alter_rename_key : public Sql_alloc { public: LEX_CSTRING old_name; LEX_CSTRING new_name; bool alter_if_exists; Alter_rename_key(LEX_CSTRING old_name_arg, LEX_CSTRING new_name_arg, bool exists) : old_name(old_name_arg), new_name(new_name_arg), alter_if_exists(exists) {} Alter_rename_key *clone(MEM_ROOT *mem_root) const { return new (mem_root) Alter_rename_key(*this); } }; /* An ALTER INDEX operation that changes the ignorability of an index. */ class Alter_index_ignorability: public Sql_alloc { public: Alter_index_ignorability(const char *name, bool is_ignored, bool if_exists) : m_name(name), m_is_ignored(is_ignored), m_if_exists(if_exists) { assert(name != NULL); } const char *name() const { return m_name; } bool if_exists() const { return m_if_exists; } /* The ignorability after the operation is performed. */ bool is_ignored() const { return m_is_ignored; } Alter_index_ignorability *clone(MEM_ROOT *mem_root) const { return new (mem_root) Alter_index_ignorability(*this); } private: const char *m_name; bool m_is_ignored; bool m_if_exists; }; class Key :public Sql_alloc, public DDL_options { public: enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY, IGNORE_KEY}; enum Keytype type; KEY_CREATE_INFO key_create_info; List columns; LEX_CSTRING name; engine_option_value *option_list; bool generated; bool invisible; bool without_overlaps; bool old; uint length; Lex_ident period; Key(enum Keytype type_par, const LEX_CSTRING *name_arg, ha_key_alg algorithm_arg, bool generated_arg, DDL_options_st ddl_options) :DDL_options(ddl_options), type(type_par), key_create_info(default_key_create_info), name(*name_arg), option_list(NULL), generated(generated_arg), invisible(false), without_overlaps(false), old(false), length(0) { key_create_info.algorithm= algorithm_arg; } Key(enum Keytype type_par, const LEX_CSTRING *name_arg, KEY_CREATE_INFO *key_info_arg, bool generated_arg, List *cols, engine_option_value *create_opt, DDL_options_st ddl_options) :DDL_options(ddl_options), type(type_par), key_create_info(*key_info_arg), columns(*cols), name(*name_arg), option_list(create_opt), generated(generated_arg), invisible(false), without_overlaps(false), old(false), length(0) {} Key(const Key &rhs, MEM_ROOT *mem_root); virtual ~Key() = default; /* Equality comparison of keys (ignoring name) */ friend bool is_foreign_key_prefix(Key *a, Key *b); /** Used to make a clone of this object for ALTER/CREATE TABLE @sa comment for Key_part_spec::clone */ virtual Key *clone(MEM_ROOT *mem_root) const { return new (mem_root) Key(*this, mem_root); } }; class Foreign_key: public Key { public: enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL, FK_MATCH_PARTIAL, FK_MATCH_SIMPLE}; LEX_CSTRING constraint_name; LEX_CSTRING ref_db; LEX_CSTRING ref_table; List ref_columns; enum enum_fk_option delete_opt, update_opt; enum fk_match_opt match_opt; Foreign_key(const LEX_CSTRING *name_arg, List *cols, const LEX_CSTRING *constraint_name_arg, const LEX_CSTRING *ref_db_arg, const LEX_CSTRING *ref_table_arg, List *ref_cols, enum_fk_option delete_opt_arg, enum_fk_option update_opt_arg, fk_match_opt match_opt_arg, DDL_options ddl_options) :Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols, NULL, ddl_options), constraint_name(*constraint_name_arg), ref_db(*ref_db_arg), ref_table(*ref_table_arg), ref_columns(*ref_cols), delete_opt(delete_opt_arg), update_opt(update_opt_arg), match_opt(match_opt_arg) { } Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root); /** Used to make a clone of this object for ALTER/CREATE TABLE @sa comment for Key_part_spec::clone */ Key *clone(MEM_ROOT *mem_root) const override { return new (mem_root) Foreign_key(*this, mem_root); } /* Used to validate foreign key options */ bool validate(List &table_fields); }; typedef struct st_mysql_lock { TABLE **table; THR_LOCK_DATA **locks; uint table_count,lock_count; uint flags; } MYSQL_LOCK; class LEX_COLUMN : public Sql_alloc { public: String column; privilege_t rights; LEX_COLUMN (const String& x,const privilege_t & y ): column (x),rights (y) {} }; class MY_LOCALE; /** Query_cache_tls -- query cache thread local data. */ struct Query_cache_block; struct Query_cache_tls { /* 'first_query_block' should be accessed only via query cache functions and methods to maintain proper locking. */ Query_cache_block *first_query_block; void set_first_query_block(Query_cache_block *first_query_block_arg) { first_query_block= first_query_block_arg; } Query_cache_tls() :first_query_block(NULL) {} }; /* SIGNAL / RESIGNAL / GET DIAGNOSTICS */ /** This enumeration list all the condition item names of a condition in the SQL condition area. */ typedef enum enum_diag_condition_item_name { /* Conditions that can be set by the user (SIGNAL/RESIGNAL), and by the server implementation. */ DIAG_CLASS_ORIGIN= 0, FIRST_DIAG_SET_PROPERTY= DIAG_CLASS_ORIGIN, DIAG_SUBCLASS_ORIGIN= 1, DIAG_CONSTRAINT_CATALOG= 2, DIAG_CONSTRAINT_SCHEMA= 3, DIAG_CONSTRAINT_NAME= 4, DIAG_CATALOG_NAME= 5, DIAG_SCHEMA_NAME= 6, DIAG_TABLE_NAME= 7, DIAG_COLUMN_NAME= 8, DIAG_CURSOR_NAME= 9, DIAG_MESSAGE_TEXT= 10, DIAG_MYSQL_ERRNO= 11, LAST_DIAG_SET_PROPERTY= DIAG_MYSQL_ERRNO } Diag_condition_item_name; /** Name of each diagnostic condition item. This array is indexed by Diag_condition_item_name. */ extern const LEX_CSTRING Diag_condition_item_names[]; /** These states are bit coded with HARD. For each state there must be a pair , and _HARD. */ enum killed_state { NOT_KILLED= 0, KILL_HARD_BIT= 1, /* Bit for HARD KILL */ KILL_BAD_DATA= 2, KILL_BAD_DATA_HARD= 3, KILL_QUERY= 4, KILL_QUERY_HARD= 5, /* ABORT_QUERY signals to the query processor to stop execution ASAP without issuing an error. Instead a warning is issued, and when possible a partial query result is returned to the client. */ ABORT_QUERY= 6, ABORT_QUERY_HARD= 7, KILL_TIMEOUT= 8, KILL_TIMEOUT_HARD= 9, /* When binlog reading thread connects to the server it kills all the binlog threads with the same ID. */ KILL_SLAVE_SAME_ID= 10, /* All of the following killed states will kill the connection KILL_CONNECTION must be the first of these and it must start with an even number (becasue of HARD bit)! */ KILL_CONNECTION= 12, KILL_CONNECTION_HARD= 13, KILL_SYSTEM_THREAD= 14, KILL_SYSTEM_THREAD_HARD= 15, KILL_SERVER= 16, KILL_SERVER_HARD= 17, /* Used in threadpool to signal wait timeout. */ KILL_WAIT_TIMEOUT= 18, KILL_WAIT_TIMEOUT_HARD= 19 }; #define killed_mask_hard(killed) ((killed_state) ((killed) & ~KILL_HARD_BIT)) enum killed_type { KILL_TYPE_ID, KILL_TYPE_USER, KILL_TYPE_QUERY }; #define SECONDS_TO_WAIT_FOR_KILL 2 #define SECONDS_TO_WAIT_FOR_DUMP_THREAD_KILL 10 #if !defined(_WIN32) && defined(HAVE_SELECT) /* my_sleep() can wait for sub second times */ #define WAIT_FOR_KILL_TRY_TIMES 20 #else #define WAIT_FOR_KILL_TRY_TIMES 2 #endif #include "sql_lex.h" /* Must be here */ class Delayed_insert; class select_result; class Time_zone; #define THD_SENTRY_MAGIC 0xfeedd1ff #define THD_SENTRY_GONE 0xdeadbeef #define THD_CHECK_SENTRY(thd) DBUG_ASSERT(thd->dbug_sentry == THD_SENTRY_MAGIC) typedef struct system_variables { /* How dynamically allocated system variables are handled: The global_system_variables and max_system_variables are "authoritative" They both should have the same 'version' and 'size'. When attempting to access a dynamic variable, if the session version is out of date, then the session version is updated and realloced if neccessary and bytes copied from global to make up for missing data. Note that one should use my_bool instead of bool here, as the variables are used with my_getopt.c */ ulong dynamic_variables_version; char* dynamic_variables_ptr; uint dynamic_variables_head; /* largest valid variable offset */ uint dynamic_variables_size; /* how many bytes are in use */ ulonglong max_heap_table_size; ulonglong tmp_memory_table_size; ulonglong tmp_disk_table_size; ulonglong long_query_time; ulonglong max_statement_time; ulonglong optimizer_switch; ulonglong optimizer_trace; sql_mode_t sql_mode; ///< which non-standard SQL behaviour should be enabled sql_mode_t old_behavior; ///< which old SQL behaviour should be enabled ulonglong option_bits; ///< OPTION_xxx constants, e.g. OPTION_PROFILING ulonglong join_buff_space_limit; ulonglong log_slow_filter; ulonglong log_slow_verbosity; ulonglong log_slow_disabled_statements; ulonglong log_disabled_statements; ulonglong note_verbosity; ulonglong bulk_insert_buff_size; ulonglong join_buff_size; ulonglong sortbuff_size; ulonglong default_regex_flags; ulonglong max_mem_used; /* A bitmap of OPTIMIZER_ADJ_* flags (defined in sql_priv.h). See sys_vars.cc:adjust_secondary_key_cost for symbolic names. */ ulonglong optimizer_adjust_secondary_key_costs; /** Place holders to store Multi-source variables in sys_var.cc during update and show of variables. */ ulonglong slave_skip_counter; ulonglong max_relay_log_size; ha_rows select_limit; ha_rows max_join_size; ha_rows expensive_subquery_limit; uint analyze_max_length; ulong auto_increment_increment, auto_increment_offset; #ifdef WITH_WSREP /* Stored values of the auto_increment_increment and auto_increment_offset that are will be restored when wsrep_auto_increment_control will be set to 'OFF', because the setting it to 'ON' leads to overwriting of the original values (which are set by the user) by calculated ones (which are based on the cluster size): */ ulong saved_auto_increment_increment, saved_auto_increment_offset; ulong saved_lock_wait_timeout; ulonglong wsrep_gtid_seq_no; #endif /* WITH_WSREP */ uint eq_range_index_dive_limit; ulong column_compression_zlib_strategy; ulong lock_wait_timeout; ulong join_cache_level; ulong max_allowed_packet; ulong max_error_count; ulong max_length_for_sort_data; ulong max_recursive_iterations; ulong max_sort_length; ulong max_tmp_tables; ulong max_insert_delayed_threads; ulong min_examined_row_limit; ulong net_buffer_length; ulong net_interactive_timeout; ulong net_read_timeout; ulong net_retry_count; ulong net_wait_timeout; ulong net_write_timeout; ulonglong optimizer_join_limit_pref_ratio; ulong optimizer_prune_level; ulong optimizer_search_depth; ulong optimizer_selectivity_sampling_limit; ulong optimizer_use_condition_selectivity; ulong optimizer_max_sel_arg_weight; ulong optimizer_max_sel_args; ulong optimizer_trace_max_mem_size; ulong use_stat_tables; double sample_percentage; ulong histogram_size; ulong histogram_type; ulong preload_buff_size; ulong profiling_history_size; ulong read_buff_size; ulong read_rnd_buff_size; ulong mrr_buff_size; ulong div_precincrement; /* Total size of all buffers used by the subselect_rowid_merge_engine. */ ulong rowid_merge_buff_size; ulong max_sp_recursion_depth; ulong default_week_format; ulong max_seeks_for_key; ulong range_alloc_block_size; ulong query_alloc_block_size; ulong query_prealloc_size; ulong trans_alloc_block_size; ulong trans_prealloc_size; ulong log_warnings; ulong log_slow_max_warnings; /* Flags for slow log filtering */ ulong log_slow_rate_limit; ulong binlog_format; ///< binlog format for this thd (see enum_binlog_format) ulong binlog_row_image; ulong progress_report_time; ulong completion_type; ulong query_cache_type; ulong tx_isolation; ulong updatable_views_with_limit; ulong alter_algorithm; int max_user_connections; ulong server_id; /** In slave thread we need to know in behalf of which thread the query is being run to replicate temp tables properly */ my_thread_id pseudo_thread_id; /** When replicating an event group with GTID, keep these values around so slave binlog can receive the same GTID as the original. */ uint32 gtid_domain_id; uint64 gtid_seq_no; uint group_concat_max_len; /** Default transaction access mode. READ ONLY (true) or READ WRITE (false). */ my_bool tx_read_only; my_bool low_priority_updates; my_bool query_cache_wlock_invalidate; my_bool keep_files_on_create; my_bool old_mode; my_bool old_passwords; my_bool big_tables; my_bool only_standard_compliant_cte; my_bool query_cache_strip_comments; my_bool sql_log_slow; my_bool sql_log_bin; my_bool binlog_annotate_row_events; my_bool binlog_direct_non_trans_update; my_bool column_compression_zlib_wrap; plugin_ref table_plugin; plugin_ref tmp_table_plugin; plugin_ref enforced_table_plugin; /* Only charset part of these variables is sensible */ CHARSET_INFO *character_set_filesystem; CHARSET_INFO *character_set_client; CHARSET_INFO *character_set_results; /* Both charset and collation parts of these variables are important */ CHARSET_INFO *collation_server; CHARSET_INFO *collation_database; CHARSET_INFO *collation_connection; /* Names. These will be allocated in buffers in thd */ LEX_CSTRING default_master_connection; /* Error messages */ MY_LOCALE *lc_messages; const char ***errmsgs; /* lc_messages->errmsg->errmsgs */ /* Locale Support */ MY_LOCALE *lc_time_names; Time_zone *time_zone; my_bool sysdate_is_now; /* deadlock detection */ ulong wt_timeout_short, wt_deadlock_search_depth_short; ulong wt_timeout_long, wt_deadlock_search_depth_long; my_bool wsrep_on; my_bool wsrep_causal_reads; uint wsrep_sync_wait; ulong wsrep_retry_autocommit; ulonglong wsrep_trx_fragment_size; ulong wsrep_trx_fragment_unit; ulong wsrep_OSU_method; my_bool wsrep_dirty_reads; double long_query_time_double, max_statement_time_double; my_bool pseudo_slave_mode; char *session_track_system_variables; ulong session_track_transaction_info; my_bool session_track_schema; my_bool session_track_state_change; #ifdef USER_VAR_TRACKING my_bool session_track_user_variables; #endif // USER_VAR_TRACKING my_bool tcp_nodelay; ulong threadpool_priority; uint idle_transaction_timeout; uint idle_readonly_transaction_timeout; uint idle_write_transaction_timeout; uint column_compression_threshold; uint column_compression_zlib_level; uint in_subquery_conversion_threshold; ulonglong max_rowid_filter_size; vers_asof_timestamp_t vers_asof_timestamp; ulong vers_alter_history; } SV; /** Per thread status variables. Must be long/ulong up to last_system_status_var so that add_to_status/add_diff_to_status can work. */ typedef struct system_status_var { ulong column_compressions; ulong column_decompressions; ulong com_stat[(uint) SQLCOM_END]; ulong com_create_tmp_table; ulong com_drop_tmp_table; ulong com_other; ulong com_stmt_prepare; ulong com_stmt_reprepare; ulong com_stmt_execute; ulong com_stmt_send_long_data; ulong com_stmt_fetch; ulong com_stmt_reset; ulong com_stmt_close; ulong com_register_slave; ulong created_tmp_disk_tables_; ulong created_tmp_tables_; ulong ha_commit_count; ulong ha_delete_count; ulong ha_read_first_count; ulong ha_read_last_count; ulong ha_read_key_count; ulong ha_read_next_count; ulong ha_read_prev_count; ulong ha_read_retry_count; ulong ha_read_rnd_count; ulong ha_read_rnd_next_count; ulong ha_read_rnd_deleted_count; /* This number doesn't include calls to the default implementation and calls made by range access. The intent is to count only calls made by BatchedKeyAccess. */ ulong ha_mrr_init_count; ulong ha_mrr_key_refills_count; ulong ha_mrr_rowid_refills_count; ulong ha_rollback_count; ulong ha_update_count; ulong ha_write_count; /* The following are for internal temporary tables */ ulong ha_tmp_update_count; ulong ha_tmp_write_count; ulong ha_tmp_delete_count; ulong ha_prepare_count; ulong ha_icp_attempts; ulong ha_icp_match; ulong ha_discover_count; ulong ha_savepoint_count; ulong ha_savepoint_rollback_count; ulong ha_external_lock_count; ulong opened_tables; ulong opened_shares; ulong opened_views; /* +1 opening a view */ ulong select_full_join_count_; ulong select_full_range_join_count_; ulong select_range_count_; ulong select_range_check_count_; ulong select_scan_count_; ulong update_scan_count; ulong delete_scan_count; ulong executed_triggers; ulong long_query_count; ulong filesort_merge_passes_; ulong filesort_range_count_; ulong filesort_rows_; ulong filesort_scan_count_; ulong filesort_pq_sorts_; /* Features used */ ulong feature_custom_aggregate_functions; /* +1 when custom aggregate functions are used */ ulong feature_dynamic_columns; /* +1 when creating a dynamic column */ ulong feature_fulltext; /* +1 when MATCH is used */ ulong feature_gis; /* +1 opening a table with GIS features */ ulong feature_invisible_columns; /* +1 opening a table with invisible column */ ulong feature_json; /* +1 when JSON function appears in the statement */ ulong feature_locale; /* +1 when LOCALE is set */ ulong feature_subquery; /* +1 when subqueries are used */ ulong feature_system_versioning; /* +1 opening a table WITH SYSTEM VERSIONING */ ulong feature_application_time_periods; /* +1 opening a table with application-time period */ ulong feature_insert_returning; /* +1 when INSERT...RETURNING is used */ ulong feature_timezone; /* +1 when XPATH is used */ ulong feature_trigger; /* +1 opening a table with triggers */ ulong feature_xml; /* +1 when XPATH is used */ ulong feature_window_functions; /* +1 when window functions are used */ /* From MASTER_GTID_WAIT usage */ ulong master_gtid_wait_timeouts; /* Number of timeouts */ ulong master_gtid_wait_time; /* Time in microseconds */ ulong master_gtid_wait_count; ulong empty_queries; ulong access_denied_errors; ulong lost_connections; ulong max_statement_time_exceeded; /* Number of times where column info was not sent with prepared statement metadata. */ ulong skip_metadata_count; /* Number of statements sent from the client */ ulong questions; /* IMPORTANT! SEE last_system_status_var DEFINITION BELOW. Below 'last_system_status_var' are all variables that cannot be handled automatically by add_to_status()/add_diff_to_status(). */ ulonglong bytes_received; ulonglong bytes_sent; ulonglong rows_read; ulonglong rows_sent; ulonglong rows_tmp_read; ulonglong binlog_bytes_written; ulonglong table_open_cache_hits; ulonglong table_open_cache_misses; ulonglong table_open_cache_overflows; double last_query_cost; double cpu_time, busy_time; uint32 threads_running; /* Don't initialize */ /* Memory used for thread local storage */ int64 max_local_memory_used; volatile int64 local_memory_used; /* Memory allocated for global usage */ volatile int64 global_memory_used; } STATUS_VAR; /* This is used for 'SHOW STATUS'. It must be updated to the last ulong variable in system_status_var which is makes sense to add to the global counter */ #define last_system_status_var questions #define last_cleared_system_status_var local_memory_used /** Number of contiguous global status variables */ constexpr int COUNT_GLOBAL_STATUS_VARS= int(offsetof(STATUS_VAR, last_system_status_var) / sizeof(ulong)) + 1; /* Global status variables */ extern ulong feature_files_opened_with_delayed_keys, feature_check_constraint; void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var); void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, STATUS_VAR *dec_var); uint calc_sum_of_all_status(STATUS_VAR *to); static inline void calc_sum_of_all_status_if_needed(STATUS_VAR *to) { if (to->local_memory_used == 0) { mysql_mutex_lock(&LOCK_status); *to= global_status_var; mysql_mutex_unlock(&LOCK_status); calc_sum_of_all_status(to); DBUG_ASSERT(to->local_memory_used); } } /* Update global_memory_used. We have to do this with atomic_add as the global value can change outside of LOCK_status. */ static inline void update_global_memory_status(int64 size) { DBUG_PRINT("info", ("global memory_used: %lld size: %lld", (longlong) global_status_var.global_memory_used, size)); // workaround for gcc 4.2.4-1ubuntu4 -fPIE (from DEB_BUILD_HARDENING=1) int64 volatile * volatile ptr= &global_status_var.global_memory_used; my_atomic_add64_explicit(ptr, size, MY_MEMORY_ORDER_RELAXED); } /** Get collation by name, send error to client on failure. @param name Collation name @param name_cs Character set of the name string @return @retval NULL on error @retval Pointter to CHARSET_INFO with the given name on success */ static inline CHARSET_INFO * mysqld_collation_get_by_name(const char *name, myf utf8_flag, CHARSET_INFO *name_cs= system_charset_info) { CHARSET_INFO *cs; MY_CHARSET_LOADER loader; my_charset_loader_init_mysys(&loader); if (!(cs= my_collation_get_by_name(&loader, name, MYF(utf8_flag)))) { ErrConvString err(name, name_cs); my_error(ER_UNKNOWN_COLLATION, MYF(0), err.ptr()); if (loader.error[0]) push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_COLLATION, "%s", loader.error); } return cs; } static inline bool is_supported_parser_charset(CHARSET_INFO *cs) { return MY_TEST(cs->mbminlen == 1 && cs->number != 17 /* filename */); } /** THD registry */ class THD_list_iterator { protected: I_List threads; mutable mysql_rwlock_t lock; public: /** Iterates registered threads. @param action called for every element @param argument opque argument passed to action @return @retval 0 iteration completed successfully @retval 1 iteration was interrupted (action returned 1) */ template int iterate(my_bool (*action)(THD *thd, T *arg), T *arg= 0) { int res= 0; mysql_rwlock_rdlock(&lock); I_List_iterator it(threads); while (auto tmp= it++) if ((res= action(tmp, arg))) break; mysql_rwlock_unlock(&lock); return res; } static THD_list_iterator *iterator(); }; /** A counter of THDs It must be specified as a first base class of THD, so that increment is done before any other THD constructors and decrement - after any other THD destructors. Destructor unblocks close_conneciton() if there are no more THD's left. */ struct THD_count { static Atomic_counter count; static uint value() { return static_cast(count); } static uint connection_thd_count(); THD_count() { count++; } ~THD_count() { count--; } }; #ifdef MYSQL_SERVER void free_tmp_table(THD *thd, TABLE *entry); /* The following macro is to make init of Query_arena simpler */ #ifdef DBUG_ASSERT_EXISTS #define INIT_ARENA_DBUG_INFO is_backup_arena= 0; is_reprepared= FALSE; #else #define INIT_ARENA_DBUG_INFO #endif class Query_arena { public: /* List of items created in the parser for this query. Every item puts itself to the list on creation (see Item::Item() for details)) */ Item *free_list; MEM_ROOT *mem_root; // Pointer to current memroot #ifdef DBUG_ASSERT_EXISTS bool is_backup_arena; /* True if this arena is used for backup. */ bool is_reprepared; #endif /* The states relfects three diffrent life cycles for three different types of statements: Prepared statement: STMT_INITIALIZED -> STMT_PREPARED -> STMT_EXECUTED. Stored procedure: STMT_INITIALIZED_FOR_SP -> STMT_EXECUTED. Other statements: STMT_CONVENTIONAL_EXECUTION never changes. Special case for stored procedure arguments: STMT_SP_QUERY_ARGUMENTS This state never changes and used for objects whose lifetime is whole duration of function call (sp_rcontext, it's tables and items. etc). Such objects should be deallocated after every execution of a stored routine. Caller's arena/memroot can't be used for placing such objects since memory allocated on caller's arena not freed until termination of user's session. */ enum enum_state { STMT_INITIALIZED= 0, STMT_INITIALIZED_FOR_SP= 1, STMT_PREPARED= 2, STMT_CONVENTIONAL_EXECUTION= 3, STMT_EXECUTED= 4, STMT_SP_QUERY_ARGUMENTS= 5, STMT_ERROR= -1 }; enum_state state; public: /* We build without RTTI, so dynamic_cast can't be used. */ enum Type { STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE }; Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) : free_list(0), mem_root(mem_root_arg), state(state_arg) { INIT_ARENA_DBUG_INFO; } /* This constructor is used only when Query_arena is created as backup storage for another instance of Query_arena. */ Query_arena() { INIT_ARENA_DBUG_INFO; } virtual Type type() const; virtual ~Query_arena() = default; inline bool is_stmt_prepare() const { return state == STMT_INITIALIZED; } inline bool is_stmt_prepare_or_first_sp_execute() const { return (int)state < (int)STMT_PREPARED; } inline bool is_stmt_prepare_or_first_stmt_execute() const { return (int)state <= (int)STMT_PREPARED; } inline bool is_stmt_execute() const { return state == STMT_PREPARED || state == STMT_EXECUTED; } inline bool is_conventional() const { return state == STMT_CONVENTIONAL_EXECUTION; } inline void* alloc(size_t size) { return alloc_root(mem_root,size); } inline void* calloc(size_t size) { void *ptr; if (likely((ptr=alloc_root(mem_root,size)))) bzero(ptr, size); return ptr; } inline char *strdup(const char *str) { return strdup_root(mem_root,str); } inline char *strmake(const char *str, size_t size) { return strmake_root(mem_root,str,size); } inline void *memdup(const void *str, size_t size) { return memdup_root(mem_root,str,size); } inline void *memdup_w_gap(const void *str, size_t size, size_t gap) { void *ptr; if (likely((ptr= alloc_root(mem_root,size+gap)))) memcpy(ptr,str,size); return ptr; } void set_query_arena(Query_arena *set); void free_items(); /* Close the active state associated with execution of this statement */ virtual bool cleanup_stmt(bool /*restore_set_statement_vars*/); }; class Query_arena_memroot: public Query_arena, public Sql_alloc { public: Query_arena_memroot(MEM_ROOT *mem_root_arg, enum enum_state state_arg) : Query_arena(mem_root_arg, state_arg) {} Query_arena_memroot() : Query_arena() {} virtual ~Query_arena_memroot() = default; }; class Query_arena_stmt { THD *thd; Query_arena backup; Query_arena *arena; public: Query_arena_stmt(THD *_thd); ~Query_arena_stmt(); bool arena_replaced() { return arena != NULL; } }; class Server_side_cursor; /* Struct to catch changes in column metadata that is sent to client. in the "result set metadata". Used to support MARIADB_CLIENT_CACHE_METADATA. */ struct send_column_info_state { /* Last client charset (affects metadata) */ CHARSET_INFO *last_charset= nullptr; /* Checksum, only used to check changes if 'immutable' is false*/ uint32 checksum= 0; /* Column info can only be changed by PreparedStatement::reprepare() There is a class of "weird" prepared statements like SELECT ? or SELECT @a that are not immutable, and depend on input parameters or user variables */ bool immutable= false; bool initialized= false; /* Used by PreparedStatement::reprepare()*/ void reset() { initialized= false; checksum= 0; } }; /** @class Statement @brief State of a single command executed against this connection. One connection can contain a lot of simultaneously running statements, some of which could be: - prepared, that is, contain placeholders, - opened as cursors. We maintain 1 to 1 relationship between statement and cursor - if user wants to create another cursor for his query, we create another statement for it. To perform some action with statement we reset THD part to the state of that statement, do the action, and then save back modified state from THD to the statement. It will be changed in near future, and Statement will be used explicitly. */ class Statement: public ilink, public Query_arena { Statement(const Statement &rhs); /* not implemented: */ Statement &operator=(const Statement &rhs); /* non-copyable */ public: /* Uniquely identifies each statement object in thread scope; change during statement lifetime. FIXME: must be const */ ulong id; enum enum_column_usage column_usage; LEX_CSTRING name; /* name for named prepared statements */ LEX *lex; // parse tree descriptor my_hrtime_t hr_prepare_time; // time of preparation in microseconds /* Points to the query associated with this statement. It's const, but we need to declare it char * because all table handlers are written in C and need to point to it. Note that if we set query = NULL, we must at the same time set query_length = 0, and protect the whole operation with LOCK_thd_data mutex. To avoid crashes in races, if we do not know that thd->query cannot change at the moment, we should print thd->query like this: (1) reserve the LOCK_thd_data mutex; (2) print or copy the value of query and query_length (3) release LOCK_thd_data mutex. This printing is needed at least in SHOW PROCESSLIST and SHOW ENGINE INNODB STATUS. */ CSET_STRING query_string; /* If opt_query_cache_strip_comments is set, this contains query without comments. If not set, it contains pointer to query_string. */ String base_query; inline char *query() const { return query_string.str(); } inline uint32 query_length() const { return static_cast(query_string.length()); } inline char *query_end() const { return query_string.str() + query_string.length(); } CHARSET_INFO *query_charset() const { return query_string.charset(); } void set_query_inner(const CSET_STRING &string_arg) { query_string= string_arg; } void set_query_inner(char *query_arg, uint32 query_length_arg, CHARSET_INFO *cs_arg) { set_query_inner(CSET_STRING(query_arg, query_length_arg, cs_arg)); } void reset_query_inner() { set_query_inner(CSET_STRING()); } /** Name of the current (default) database. If there is the current (default) database, "db.str" contains its name. If there is no current (default) database, "db.str" is NULL and "db.length" is 0. In other words, db must either be NULL, or contain a valid database name. */ LEX_CSTRING db; send_column_info_state column_info_state; /* This is set to 1 of last call to send_result_to_client() was ok */ my_bool query_cache_is_applicable; /* This constructor is called for backup statements */ Statement() = default; Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg, enum enum_state state_arg, ulong id_arg); virtual ~Statement(); /* Assign execution context (note: not all members) of given stmt to self */ virtual void set_statement(Statement *stmt); void set_n_backup_statement(Statement *stmt, Statement *backup); void restore_backup_statement(Statement *stmt, Statement *backup); /* return class type */ Type type() const override; }; /** Container for all statements created/used in a connection. Statements in Statement_map have unique Statement::id (guaranteed by id assignment in Statement::Statement) Non-empty statement names are unique too: attempt to insert a new statement with duplicate name causes older statement to be deleted Statements are auto-deleted when they are removed from the map and when the map is deleted. */ class Statement_map { public: Statement_map(); int insert(THD *thd, Statement *statement); Statement *find_by_name(const LEX_CSTRING *name) { Statement *stmt; stmt= (Statement*)my_hash_search(&names_hash, (uchar*)name->str, name->length); return stmt; } Statement *find(ulong id) { if (last_found_statement == 0 || id != last_found_statement->id) { Statement *stmt; stmt= (Statement *) my_hash_search(&st_hash, (uchar *) &id, sizeof(id)); if (stmt && stmt->name.str) return NULL; last_found_statement= stmt; } return last_found_statement; } /* Close all cursors of this connection that use tables of a storage engine that has transaction-specific state and therefore can not survive COMMIT or ROLLBACK. Currently all but MyISAM cursors are closed. */ void close_transient_cursors(); void erase(Statement *statement); /* Erase all statements (calls Statement destructor) */ void reset(); ~Statement_map(); private: HASH st_hash; HASH names_hash; I_List transient_cursor_list; Statement *last_found_statement; }; struct st_savepoint { struct st_savepoint *prev; char *name; uint length; Ha_trx_info *ha_list; /** State of metadata locks before this savepoint was set. */ MDL_savepoint mdl_savepoint; }; /** @class Security_context @brief A set of THD members describing the current authenticated user. */ class Security_context { public: Security_context() :master_access(NO_ACL), db_access(NO_ACL) {} /* Remove gcc warning */ /* host - host of the client user - user of the client, set to NULL until the user has been read from the connection priv_user - The user privilege we are using. May be "" for anonymous user. ip - client IP */ const char *host; const char *user, *ip; char priv_user[USERNAME_LENGTH]; char proxy_user[USERNAME_LENGTH + MAX_HOSTNAME + 5]; /* The host privilege we are using */ char priv_host[MAX_HOSTNAME]; /* The role privilege we are using */ char priv_role[USERNAME_LENGTH]; /* The external user (if available) */ char *external_user; /* points to host if host is available, otherwise points to ip */ const char *host_or_ip; privilege_t master_access; /* Global privileges from mysql.user */ privilege_t db_access; /* Privileges for current db */ bool password_expired; void init(); void destroy(); void skip_grants(); inline char *priv_host_name() { return (*priv_host ? priv_host : (char *)"%"); } bool set_user(char *user_arg); #ifndef NO_EMBEDDED_ACCESS_CHECKS bool change_security_context(THD *thd, LEX_CSTRING *definer_user, LEX_CSTRING *definer_host, LEX_CSTRING *db, Security_context **backup); void restore_security_context(THD *thd, Security_context *backup); #endif bool user_matches(Security_context *); /** Check global access @param want_access The required privileges @param match_any if the security context must match all or any of the req. * privileges. @return True if the security context fulfills the access requirements. */ bool check_access(const privilege_t want_access, bool match_any = false); bool is_priv_user(const char *user, const char *host); bool is_user_defined() const { return user && user != delayed_user && user != slave_user; }; }; /** A registry for item tree transformations performed during query optimization. We register only those changes which require a rollback to re-execute a prepared statement or stored procedure yet another time. */ struct Item_change_record; class Item_change_list { I_List change_list; public: void nocheck_register_item_tree_change(Item **place, Item *old_value, MEM_ROOT *runtime_memroot); void check_and_register_item_tree_change(Item **place, Item **new_value, MEM_ROOT *runtime_memroot); void rollback_item_tree_changes(); void move_elements_to(Item_change_list *to) { change_list.move_elements_to(&to->change_list); } bool is_empty() { return change_list.is_empty(); } }; class Item_change_list_savepoint: public Item_change_list { public: Item_change_list_savepoint(Item_change_list *list) { list->move_elements_to(this); } void rollback(Item_change_list *list) { list->rollback_item_tree_changes(); move_elements_to(list); } ~Item_change_list_savepoint() { DBUG_ASSERT(is_empty()); } }; /** Type of locked tables mode. See comment for THD::locked_tables_mode for complete description. */ enum enum_locked_tables_mode { LTM_NONE= 0, LTM_LOCK_TABLES, LTM_PRELOCKED, LTM_PRELOCKED_UNDER_LOCK_TABLES, LTM_always_last }; /** The following structure is an extension to TABLE_SHARE and is exclusively for temporary tables. @note: Although, TDC_element has data members (like next, prev & all_tables) to store the list of TABLE_SHARE & TABLE objects related to a particular TABLE_SHARE, they cannot be moved to TABLE_SHARE in order to be reused for temporary tables. This is because, as concurrent threads iterating through hash of TDC_element's may need access to all_tables, but if all_tables is made part of TABLE_SHARE, then TDC_element->share->all_tables is not always guaranteed to be valid, as TDC_element can live longer than TABLE_SHARE. */ struct TMP_TABLE_SHARE : public TABLE_SHARE { private: /* Link to all temporary table shares. Declared as private to avoid direct manipulation with those objects. One should use methods of I_P_List template instead. */ TMP_TABLE_SHARE *tmp_next; TMP_TABLE_SHARE **tmp_prev; friend struct All_tmp_table_shares; public: /* Doubly-linked (back-linked) lists of used and unused TABLE objects for this share. */ All_share_tables_list all_tmp_tables; }; /** Helper class which specifies which members of TMP_TABLE_SHARE are used for participation in the list of temporary tables. */ struct All_tmp_table_shares { static inline TMP_TABLE_SHARE **next_ptr(TMP_TABLE_SHARE *l) { return &l->tmp_next; } static inline TMP_TABLE_SHARE ***prev_ptr(TMP_TABLE_SHARE *l) { return &l->tmp_prev; } }; /* Also used in rpl_rli.h. */ typedef I_P_List All_tmp_tables_list; /** Class that holds information about tables which were opened and locked by the thread. It is also used to save/restore this information in push_open_tables_state()/pop_open_tables_state(). */ class Open_tables_state { public: /** As part of class THD, this member is set during execution of a prepared statement. When it is set, it is used by the locking subsystem to report a change in table metadata. When Open_tables_state part of THD is reset to open a system or INFORMATION_SCHEMA table, the member is cleared to avoid spurious ER_NEED_REPREPARE errors -- system and INFORMATION_SCHEMA tables are not subject to metadata version tracking. @sa check_and_update_table_version() */ Reprepare_observer *m_reprepare_observer; /** List of regular tables in use by this thread. Contains temporary and base tables that were opened with @see open_tables(). */ TABLE *open_tables; /** A list of temporary tables used by this thread. This includes user-level temporary tables, created with CREATE TEMPORARY TABLE, and internal temporary tables, created, e.g., to resolve a SELECT, or for an intermediate table used in ALTER. */ All_tmp_tables_list *temporary_tables; /* Derived tables. */ TABLE *derived_tables; /* Temporary tables created for recursive table references. */ TABLE *rec_tables; /* During a MySQL session, one can lock tables in two modes: automatic or manual. In automatic mode all necessary tables are locked just before statement execution, and all acquired locks are stored in 'lock' member. Unlocking takes place automatically as well, when the statement ends. Manual mode comes into play when a user issues a 'LOCK TABLES' statement. In this mode the user can only use the locked tables. Trying to use any other tables will give an error. The locked tables are also stored in this member, however, thd->locked_tables_mode is turned on. Manual locking is described in the 'LOCK_TABLES' chapter of the MySQL manual. See also lock_tables() for details. */ MYSQL_LOCK *lock; /* CREATE-SELECT keeps an extra lock for the table being created. This field is used to keep the extra lock available for lower level routines, which would otherwise miss that lock. */ MYSQL_LOCK *extra_lock; /* Enum enum_locked_tables_mode and locked_tables_mode member are used to indicate whether the so-called "locked tables mode" is on, and what kind of mode is active. Locked tables mode is used when it's necessary to open and lock many tables at once, for usage across multiple (sub-)statements. This may be necessary either for queries that use stored functions and triggers, in which case the statements inside functions and triggers may be executed many times, or for implementation of LOCK TABLES, in which case the opened tables are reused by all subsequent statements until a call to UNLOCK TABLES. The kind of locked tables mode employed for stored functions and triggers is also called "prelocked mode". In this mode, first open_tables() call to open the tables used in a statement analyses all functions used by the statement and adds all indirectly used tables to the list of tables to open and lock. It also marks the parse tree of the statement as requiring prelocking. After that, lock_tables() locks the entire list of tables and changes THD::locked_tables_modeto LTM_PRELOCKED. All statements executed inside functions or triggers use the prelocked tables, instead of opening their own ones. Prelocked mode is turned off automatically once close_thread_tables() of the main statement is called. */ enum enum_locked_tables_mode locked_tables_mode; uint current_tablenr; enum enum_flags { BACKUPS_AVAIL = (1U << 0) /* There are backups available */ }; /* Flags with information about the open tables state. */ uint state_flags; /** This constructor initializes Open_tables_state instance which can only be used as backup storage. To prepare Open_tables_state instance for operations which open/lock/close tables (e.g. open_table()) one has to call init_open_tables_state(). */ Open_tables_state() : state_flags(0U) { } void set_open_tables_state(Open_tables_state *state) { *this= *state; } void reset_open_tables_state(THD *thd) { open_tables= 0; temporary_tables= 0; derived_tables= 0; rec_tables= 0; extra_lock= 0; lock= 0; locked_tables_mode= LTM_NONE; state_flags= 0U; m_reprepare_observer= NULL; } }; /** Storage for backup of Open_tables_state. Must be used only to open system tables (TABLE_CATEGORY_SYSTEM and TABLE_CATEGORY_LOG). */ class Open_tables_backup: public Open_tables_state { public: /** When we backup the open tables state to open a system table or tables, we want to save state of metadata locks which were acquired before the backup. It is used to release metadata locks on system tables after they are no longer used. */ MDL_savepoint mdl_system_tables_svp; }; /** @class Sub_statement_state @brief Used to save context when executing a function or trigger operations on stat tables aren't technically a sub-statement, but they are similar in a sense that they cannot change the transaction status. */ /* Defines used for Sub_statement_state::in_sub_stmt */ #define SUB_STMT_TRIGGER 1 #define SUB_STMT_FUNCTION 2 #define SUB_STMT_STAT_TABLES 4 class Sub_statement_state { public: Discrete_interval auto_inc_interval_for_cur_row; Discrete_intervals_list auto_inc_intervals_forced; SAVEPOINT *savepoints; ulonglong option_bits; ulonglong first_successful_insert_id_in_prev_stmt; ulonglong first_successful_insert_id_in_cur_stmt, insert_id_for_cur_row; ulonglong limit_found_rows; ulonglong tmp_tables_size; ulonglong client_capabilities; ulonglong cuted_fields, sent_row_count, examined_row_count; ulonglong affected_rows; ulonglong bytes_sent_old; ha_handler_stats handler_stats; ulong tmp_tables_used; ulong tmp_tables_disk_used; ulong query_plan_fsort_passes; ulong query_plan_flags; uint in_sub_stmt; /* 0, SUB_STMT_TRIGGER or SUB_STMT_FUNCTION */ bool enable_slow_log; bool last_insert_id_used; enum enum_check_fields count_cuted_fields; }; /* Flags for the THD::system_thread variable */ enum enum_thread_type { NON_SYSTEM_THREAD= 0, SYSTEM_THREAD_DELAYED_INSERT= 1, SYSTEM_THREAD_SLAVE_IO= 2, SYSTEM_THREAD_SLAVE_SQL= 4, SYSTEM_THREAD_EVENT_SCHEDULER= 8, SYSTEM_THREAD_EVENT_WORKER= 16, SYSTEM_THREAD_BINLOG_BACKGROUND= 32, SYSTEM_THREAD_SLAVE_BACKGROUND= 64, SYSTEM_THREAD_GENERIC= 128, SYSTEM_THREAD_SEMISYNC_MASTER_BACKGROUND= 256 }; inline char const * show_system_thread(enum_thread_type thread) { #define RETURN_NAME_AS_STRING(NAME) case (NAME): return #NAME switch (thread) { static char buf[64]; RETURN_NAME_AS_STRING(NON_SYSTEM_THREAD); RETURN_NAME_AS_STRING(SYSTEM_THREAD_DELAYED_INSERT); RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_IO); RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_SQL); RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_SCHEDULER); RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_WORKER); RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_BACKGROUND); RETURN_NAME_AS_STRING(SYSTEM_THREAD_SEMISYNC_MASTER_BACKGROUND); default: snprintf(buf, sizeof(buf), "", thread); return buf; } #undef RETURN_NAME_AS_STRING } /** This class represents the interface for internal error handlers. Internal error handlers are exception handlers used by the server implementation. */ class Internal_error_handler { protected: Internal_error_handler() : m_prev_internal_handler(NULL) {} virtual ~Internal_error_handler() = default; public: /** Handle a sql condition. This method can be implemented by a subclass to achieve any of the following: - mask a warning/error internally, prevent exposing it to the user, - mask a warning/error and throw another one instead. When this method returns true, the sql condition is considered 'handled', and will not be propagated to upper layers. It is the responsability of the code installing an internal handler to then check for trapped conditions, and implement logic to recover from the anticipated conditions trapped during runtime. This mechanism is similar to C++ try/throw/catch: - 'try' correspond to THD::push_internal_handler(), - 'throw' correspond to my_error(), which invokes my_message_sql(), - 'catch' correspond to checking how/if an internal handler was invoked, before removing it from the exception stack with THD::pop_internal_handler(). @param thd the calling thread @param cond the condition raised. @return true if the condition is handled */ virtual bool handle_condition(THD *thd, uint sql_errno, const char* sqlstate, Sql_condition::enum_warning_level *level, const char* msg, Sql_condition ** cond_hdl) = 0; private: Internal_error_handler *m_prev_internal_handler; friend class THD; }; /** Implements the trivial error handler which cancels all error states and prevents an SQLSTATE to be set. Remembers the first error */ class Dummy_error_handler : public Internal_error_handler { uint m_unhandled_errors; uint first_error; public: Dummy_error_handler() : m_unhandled_errors(0), first_error(0) {} bool handle_condition(THD *thd, uint sql_errno, const char* sqlstate, Sql_condition::enum_warning_level *level, const char* msg, Sql_condition ** cond_hdl) override { m_unhandled_errors++; if (!first_error) first_error= sql_errno; return TRUE; // Ignore error } bool any_error() { return m_unhandled_errors != 0; } uint got_error() { return first_error; } }; /** Implements the trivial error handler which counts errors as they happen. */ class Counting_error_handler : public Internal_error_handler { public: int errors; bool handle_condition(THD *thd, uint sql_errno, const char* sqlstate, Sql_condition::enum_warning_level *level, const char* msg, Sql_condition ** cond_hdl) override { if (*level == Sql_condition::WARN_LEVEL_ERROR) errors++; return false; } Counting_error_handler() : errors(0) {} }; /** This class is an internal error handler implementation for DROP TABLE statements. The thing is that there may be warnings during execution of these statements, which should not be exposed to the user. This class is intended to silence such warnings. */ class Drop_table_error_handler : public Internal_error_handler { public: Drop_table_error_handler() = default; public: bool handle_condition(THD *thd, uint sql_errno, const char* sqlstate, Sql_condition::enum_warning_level *level, const char* msg, Sql_condition ** cond_hdl) override; private: }; /** Internal error handler to process an error from MDL_context::upgrade_lock() and mysql_lock_tables(). Used by implementations of HANDLER READ and LOCK TABLES LOCAL. */ class MDL_deadlock_and_lock_abort_error_handler: public Internal_error_handler { public: virtual bool handle_condition(THD *thd, uint sql_errno, const char *sqlstate, Sql_condition::enum_warning_level *level, const char* msg, Sql_condition **cond_hdl) override; bool need_reopen() const { return m_need_reopen; }; void init() { m_need_reopen= FALSE; }; private: bool m_need_reopen; }; class Turn_errors_to_warnings_handler : public Internal_error_handler { public: Turn_errors_to_warnings_handler() = default; bool handle_condition(THD *, uint, const char*, Sql_condition::enum_warning_level *level, const char*, Sql_condition ** cond_hdl) override { *cond_hdl= NULL; if (*level == Sql_condition::WARN_LEVEL_ERROR) *level= Sql_condition::WARN_LEVEL_WARN; return(0); } }; struct Suppress_warnings_error_handler : public Internal_error_handler { bool handle_condition(THD *, uint, const char *, Sql_condition::enum_warning_level *level, const char *, Sql_condition **) override { return *level == Sql_condition::WARN_LEVEL_WARN; } }; /** Tables that were locked with LOCK TABLES statement. Encapsulates a list of TABLE_LIST instances for tables locked by LOCK TABLES statement, memory root for metadata locks, and, generally, the context of LOCK TABLES statement. In LOCK TABLES mode, the locked tables are kept open between statements. Therefore, we can't allocate metadata locks on execution memory root -- as well as tables, the locks need to stay around till UNLOCK TABLES is called. The locks are allocated in the memory root encapsulated in this class. Some SQL commands, like FLUSH TABLE or ALTER TABLE, demand that the tables they operate on are closed, at least temporarily. This class encapsulates a list of TABLE_LIST instances, one for each base table from LOCK TABLES list, which helps conveniently close the TABLEs when it's necessary and later reopen them. Implemented in sql_base.cc */ class Locked_tables_list { public: MEM_ROOT m_locked_tables_root; private: TABLE_LIST *m_locked_tables; TABLE_LIST **m_locked_tables_last; /** An auxiliary array used only in reopen_tables(). */ TABLE_LIST **m_reopen_array; /** Count the number of tables in m_locked_tables list. We can't rely on thd->lock->table_count because it excludes non-transactional temporary tables. We need to know an exact number of TABLE objects. */ uint m_locked_tables_count; public: bool some_table_marked_for_reopen; Locked_tables_list() :m_locked_tables(NULL), m_locked_tables_last(&m_locked_tables), m_reopen_array(NULL), m_locked_tables_count(0), some_table_marked_for_reopen(0) { init_sql_alloc(key_memory_locked_table_list, &m_locked_tables_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); } int unlock_locked_tables(THD *thd); int unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket); ~Locked_tables_list() { reset(); } void reset(); bool init_locked_tables(THD *thd); TABLE_LIST *locked_tables() { return m_locked_tables; } void unlink_from_list(THD *thd, TABLE_LIST *table_list, bool remove_from_locked_tables); void unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count); bool reopen_tables(THD *thd, bool need_reopen); bool restore_lock(THD *thd, TABLE_LIST *dst_table_list, TABLE *table, MYSQL_LOCK *lock); void add_back_last_deleted_lock(TABLE_LIST *dst_table_list); void mark_table_for_reopen(THD *thd, TABLE *table); }; /** Storage engine specific thread local data. */ struct Ha_data { /** Storage engine specific thread local data. Lifetime: one user connection. */ void *ha_ptr; /** 0: Life time: one statement within a transaction. If @@autocommit is on, also represents the entire transaction. @sa trans_register_ha() 1: Life time: one transaction within a connection. If the storage engine does not participate in a transaction, this should not be used. @sa trans_register_ha() */ Ha_trx_info ha_info[2]; /** NULL: engine is not bound to this thread non-NULL: engine is bound to this thread, engine shutdown forbidden */ plugin_ref lock; Ha_data() :ha_ptr(NULL) {} void reset() { ha_ptr= nullptr; for (auto &info : ha_info) info.reset(); lock= nullptr; } }; /** An instance of the global read lock in a connection. Implemented in lock.cc. */ class Global_read_lock { public: enum enum_grl_state { GRL_NONE, GRL_ACQUIRED, GRL_ACQUIRED_AND_BLOCKS_COMMIT }; Global_read_lock() : m_state(GRL_NONE), m_mdl_global_read_lock(NULL) {} bool lock_global_read_lock(THD *thd); void unlock_global_read_lock(THD *thd); bool make_global_read_lock_block_commit(THD *thd); bool is_acquired() const { return m_state != GRL_NONE; } void set_explicit_lock_duration(THD *thd); private: enum_grl_state m_state; /** Global read lock is acquired in two steps: 1. acquire MDL_BACKUP_FTWRL1 in BACKUP namespace to prohibit DDL and DML 2. upgrade to MDL_BACKUP_FTWRL2 to prohibit commits */ MDL_ticket *m_mdl_global_read_lock; }; /* Class to facilitate the commit of one transactions waiting for the commit of another transaction to complete first. This is used during (parallel) replication, to allow different transactions to be applied in parallel, but still commit in order. The transaction that wants to wait for a prior commit must first register to wait with register_wait_for_prior_commit(waitee). Such registration must be done holding the waitee->LOCK_wait_commit, to prevent the other THD from disappearing during the registration. Then during commit, if a THD is registered to wait, it will call wait_for_prior_commit() as part of ha_commit_trans(). If no wait is registered, or if the waitee for has already completed commit, then wait_for_prior_commit() returns immediately. And when a THD that may be waited for has completed commit (more precisely commit_ordered()), then it must call wakeup_subsequent_commits() to wake up any waiters. Note that this must be done at a point that is guaranteed to be later than any waiters registering themselves. It is safe to call wakeup_subsequent_commits() multiple times, as waiters are removed from registration as part of the wakeup. The reason for separate register and wait calls is that this allows to register the wait early, at a point where the waited-for THD is known to exist. And then the actual wait can be done much later, where the waited-for THD may have been long gone. By registering early, the waitee can signal before disappearing. */ struct wait_for_commit { /* The LOCK_wait_commit protects the fields subsequent_commits_list and wakeup_subsequent_commits_running (for a waitee), and the pointer waitee and associated COND_wait_commit (for a waiter). */ mysql_mutex_t LOCK_wait_commit; mysql_cond_t COND_wait_commit; /* List of threads that did register_wait_for_prior_commit() on us. */ wait_for_commit *subsequent_commits_list; /* Link field for entries in subsequent_commits_list. */ wait_for_commit *next_subsequent_commit; /* Our waitee, if we did register_wait_for_prior_commit(), and were not yet woken up. Else NULL. When this is cleared for wakeup, the COND_wait_commit condition is signalled. This pointer is protected by LOCK_wait_commit. But there is also a "fast path" where the waiter compares this to NULL without holding the lock. Such read must be done with acquire semantics (and all corresponding writes done with release semantics). This ensures that a wakeup with error is reliably detected as (waitee==NULL && wakeup_error != 0). */ std::atomic waitee; /* Generic pointer for use by the transaction coordinator to optimise the waiting for improved group commit. Currently used by binlog TC to signal that a waiter is ready to commit, so that the waitee can grab it and group commit it directly. It is free to be used by another transaction coordinator for similar purposes. */ void *opaque_pointer; /* The wakeup error code from the waitee. 0 means no error. */ int wakeup_error; /* Flag set when wakeup_subsequent_commits_running() is active, see comments on that function for details. */ bool wakeup_subsequent_commits_running; /* This flag can be set when a commit starts, but has not completed yet. It is used by binlog group commit to allow a waiting transaction T2 to join the group commit of an earlier transaction T1. When T1 has queued itself for group commit, it will set the commit_started flag. Then when T2 becomes ready to commit and needs to wait for T1 to commit first, T2 can queue itself before waiting, and thereby participate in the same group commit as T1. */ bool commit_started; /* Set to temporarily ignore calls to wakeup_subsequent_commits(). The caller must arrange that another wakeup_subsequent_commits() gets called later after wakeup_blocked has been set back to false. This is used for parallel replication with temporary tables. Temporary tables require strict single-threaded operation. The normal optimization, of doing wakeup_subsequent_commits early and overlapping part of the commit with the following transaction, is not safe. Thus when temporary tables are replicated, wakeup is blocked until the event group is fully done. */ bool wakeup_blocked; void register_wait_for_prior_commit(wait_for_commit *waitee); int wait_for_prior_commit(THD *thd, bool allow_kill=true) { /* Quick inline check, to avoid function call and locking in the common case where no wakeup is registered, or a registered wait was already signalled. */ if (waitee.load(std::memory_order_acquire)) return wait_for_prior_commit2(thd, allow_kill); else { if (unlikely(wakeup_error)) prior_commit_error(thd); return wakeup_error; } } void wakeup_subsequent_commits(int wakeup_error_arg) { /* Do the check inline, so only the wakeup case takes the cost of a function call for every commmit. Note that the check is done without locking. It is the responsibility of the user of the wakeup facility to ensure that no waiters can register themselves after the last call to wakeup_subsequent_commits(). This avoids having to take another lock for every commit, which would be pointless anyway - even if we check under lock, there is nothing to prevent a waiter from arriving just after releasing the lock. */ if (subsequent_commits_list) wakeup_subsequent_commits2(wakeup_error_arg); } void unregister_wait_for_prior_commit() { if (waitee.load(std::memory_order_relaxed)) unregister_wait_for_prior_commit2(); else wakeup_error= 0; } /* Remove a waiter from the list in the waitee. Used to unregister a wait. The caller must be holding the locks of both waiter and waitee. */ void remove_from_list(wait_for_commit **next_ptr_ptr) { wait_for_commit *cur; while ((cur= *next_ptr_ptr) != NULL) { if (cur == this) { *next_ptr_ptr= this->next_subsequent_commit; break; } next_ptr_ptr= &cur->next_subsequent_commit; } waitee.store(NULL, std::memory_order_relaxed); } void wakeup(int wakeup_error); int wait_for_prior_commit2(THD *thd, bool allow_kill); void prior_commit_error(THD *thd); void wakeup_subsequent_commits2(int wakeup_error); void unregister_wait_for_prior_commit2(); wait_for_commit(); ~wait_for_commit(); void reinit(); }; class Sp_caches { public: sp_cache *sp_proc_cache; sp_cache *sp_func_cache; sp_cache *sp_package_spec_cache; sp_cache *sp_package_body_cache; Sp_caches() :sp_proc_cache(NULL), sp_func_cache(NULL), sp_package_spec_cache(NULL), sp_package_body_cache(NULL) { } ~Sp_caches() { // All caches must be freed by the caller explicitly DBUG_ASSERT(sp_proc_cache == NULL); DBUG_ASSERT(sp_func_cache == NULL); DBUG_ASSERT(sp_package_spec_cache == NULL); DBUG_ASSERT(sp_package_body_cache == NULL); } void sp_caches_swap(Sp_caches &rhs) { swap_variables(sp_cache*, sp_proc_cache, rhs.sp_proc_cache); swap_variables(sp_cache*, sp_func_cache, rhs.sp_func_cache); swap_variables(sp_cache*, sp_package_spec_cache, rhs.sp_package_spec_cache); swap_variables(sp_cache*, sp_package_body_cache, rhs.sp_package_body_cache); } void sp_caches_clear(); /** Clear content of sp related caches. Don't delete cache objects itself. */ void sp_caches_empty(); }; extern "C" void my_message_sql(uint error, const char *str, myf MyFlags); class Gap_time_tracker; /* Thread context for Gap_time_tracker class. */ class Gap_time_tracker_data { public: Gap_time_tracker_data(): bill_to(NULL) {} Gap_time_tracker *bill_to; ulonglong start_time; void init() { bill_to = NULL; } }; /** Support structure for asynchronous group commit, or more generally any asynchronous operation that needs to finish before server writes response to client. An engine, or any other server component, can signal that there is a pending operation by incrementing a counter, i.e inc_pending_ops() and that pending operation is finished by decrementing that counter dec_pending_ops(). NOTE: Currently, pending operations can not fail, i.e there is no way to pass a return code in dec_pending_ops() The server does not write response to the client before the counter becomes 0. In case of group commit it ensures that data is persistent before success reported to client, i.e durability in ACID. */ struct thd_async_state { enum class enum_async_state { NONE, SUSPENDED, /* do_command() did not finish, and needs to be resumed */ RESUMED /* do_command() is resumed*/ }; enum_async_state m_state{enum_async_state::NONE}; /* Stuff we need to resume do_command where we finished last time*/ enum enum_server_command m_command{COM_SLEEP}; LEX_STRING m_packet{0,0}; mysql_mutex_t m_mtx; mysql_cond_t m_cond; /** Pending counter*/ Atomic_counter m_pending_ops=0; #ifndef DBUG_OFF /* Checks */ pthread_t m_dbg_thread; #endif thd_async_state() { mysql_mutex_init(PSI_NOT_INSTRUMENTED, &m_mtx, 0); mysql_cond_init(PSI_INSTRUMENT_ME, &m_cond, 0); } /* Currently only used with threadpool, one can "suspend" and "resume" a THD. Suspend only means leaving do_command earlier, after saving some state. Resume is continuing suspended THD's do_command(), from where it finished last time. */ bool try_suspend() { bool ret; mysql_mutex_lock(&m_mtx); DBUG_ASSERT(m_state == enum_async_state::NONE); DBUG_ASSERT(m_pending_ops >= 0); if(m_pending_ops) { ret=true; m_state= enum_async_state::SUSPENDED; } else { /* If there is no pending operations, can't suspend, since nobody can resume it. */ ret=false; } mysql_mutex_unlock(&m_mtx); return ret; } ~thd_async_state() { wait_for_pending_ops(); mysql_mutex_destroy(&m_mtx); mysql_cond_destroy(&m_cond); } /* Increment pending asynchronous operations. The client response may not be written if this count > 0. So, without threadpool query needs to wait for the operations to finish. With threadpool, THD can be suspended and resumed when this counter goes to 0. */ void inc_pending_ops() { mysql_mutex_lock(&m_mtx); #ifndef DBUG_OFF /* Check that increments are always done by the same thread. */ if (!m_pending_ops) m_dbg_thread= pthread_self(); else DBUG_ASSERT(pthread_equal(pthread_self(),m_dbg_thread)); #endif m_pending_ops++; mysql_mutex_unlock(&m_mtx); } int dec_pending_ops(enum_async_state* state) { int ret; mysql_mutex_lock(&m_mtx); ret= --m_pending_ops; if (!ret) mysql_cond_signal(&m_cond); *state = m_state; mysql_mutex_unlock(&m_mtx); return ret; } /* This is used for "dirty" reading pending ops, when dirty read is OK. */ int pending_ops() { return m_pending_ops; } /* Wait for pending operations to finish.*/ void wait_for_pending_ops() { /* It is fine to read m_pending_ops and compare it with 0, without mutex protection. The value is only incremented by the current thread, and will be decremented by another one, thus "dirty" may show positive number when it is really 0, but this is not a problem, and the only bad thing from that will be rechecking under mutex. */ if (!pending_ops()) return; mysql_mutex_lock(&m_mtx); DBUG_ASSERT(m_pending_ops >= 0); while (m_pending_ops) mysql_cond_wait(&m_cond, &m_mtx); mysql_mutex_unlock(&m_mtx); } }; enum class THD_WHERE { NOWHERE = 0, CHECKING_TRANSFORMED_SUBQUERY, IN_ALL_ANY_SUBQUERY, JSON_TABLE_ARGUMENT, FIELD_LIST, PARTITION_FUNCTION, FROM_CLAUSE, DEFAULT_WHERE, ON_CLAUSE, WHERE_CLAUSE, SET_LIST, INSERT_LIST, VALUES_CLAUSE, UPDATE_CLAUSE, RETURNING, FOR_SYSTEM_TIME, ORDER_CLAUSE, HAVING_CLAUSE, GROUP_STATEMENT, PROCEDURE_LIST, CHECK_OPTION, DO_STATEMENT, HANDLER_STATEMENT, USE_WHERE_STRING, // ugh, a compromise for vcol... }; class THD; const char *thd_where(THD *thd); /** @class THD For each client connection we create a separate thread with THD serving as a thread/connection descriptor */ class THD: public THD_count, /* this must be first */ public Statement, /* This is to track items changed during execution of a prepared statement/stored procedure. It's created by nocheck_register_item_tree_change() in memory root of THD, and freed in rollback_item_tree_changes(). For conventional execution it's always empty. */ public Item_change_list, public MDL_context_owner, public Open_tables_state, public Sp_caches { private: inline bool is_stmt_prepare() const { DBUG_ASSERT(0); return Statement::is_stmt_prepare(); } inline bool is_stmt_prepare_or_first_sp_execute() const { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_sp_execute(); } inline bool is_stmt_prepare_or_first_stmt_execute() const { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_stmt_execute(); } inline bool is_conventional() const { DBUG_ASSERT(0); return Statement::is_conventional(); } public: MDL_context mdl_context; /* Used to execute base64 coded binlog events in MySQL server */ Relay_log_info* rli_fake; rpl_group_info* rgi_fake; /* Slave applier execution context */ rpl_group_info* rgi_slave; union { rpl_io_thread_info *rpl_io_info; rpl_sql_thread_info *rpl_sql_info; } system_thread_info; /* Used for BACKUP LOCK */ MDL_ticket *mdl_backup_ticket, *mdl_backup_lock; /* Used to register that thread has a MDL_BACKUP_WAIT_COMMIT lock */ MDL_request *backup_commit_lock; void reset_for_next_command(bool do_clear_errors= 1); #ifdef EMBEDDED_LIBRARY struct st_mysql *mysql; unsigned long client_stmt_id; unsigned long client_param_count; struct st_mysql_bind *client_params; char *extra_data; ulong extra_length; struct st_mysql_data *cur_data; struct st_mysql_data *first_data; struct st_mysql_data **data_tail; void clear_data_list(); struct st_mysql_data *alloc_new_dataset(); /* In embedded server it points to the statement that is processed in the current query. We store some results directly in statement fields then. */ struct st_mysql_stmt *current_stmt; #endif #ifdef HAVE_QUERY_CACHE Query_cache_tls query_cache_tls; #endif NET net; // client connection descriptor /** Aditional network instrumentation for the server only. */ NET_SERVER m_net_server_extension; scheduler_functions *scheduler; // Scheduler for this connection Protocol *protocol; // Current protocol Protocol_text protocol_text; // Normal protocol Protocol_binary protocol_binary; // Binary protocol HASH user_vars; // hash for user variables String packet; // dynamic buffer for network I/O String convert_buffer; // buffer for charset conversions struct my_rnd_struct rand; // used for authentication struct system_variables variables; // Changeable local variables struct system_status_var status_var; // Per thread statistic vars struct system_status_var org_status_var; // For user statistics struct system_status_var *initial_status_var; /* used by show status */ ha_handler_stats handler_stats; // Handler statistics THR_LOCK_INFO lock_info; // Locking info of this thread /** Protects THD data accessed from other threads: - thd->query and thd->query_length (used by SHOW ENGINE INNODB STATUS and SHOW PROCESSLIST - thd->db (used in SHOW PROCESSLIST) Is locked when THD is deleted. */ mutable mysql_mutex_t LOCK_thd_data; /* Protects: - kill information - mysys_var (used by KILL statement and shutdown). - Also ensures that THD is not deleted while mutex is hold */ mutable mysql_mutex_t LOCK_thd_kill; /* all prepared statements and cursors of this connection */ Statement_map stmt_map; /* Last created prepared statement */ Statement *last_stmt; Statement *cur_stmt= 0; inline void set_last_stmt(Statement *stmt) { last_stmt= (is_error() ? NULL : stmt); } inline void clear_last_stmt() { last_stmt= NULL; } /* A pointer to the stack frame of handle_one_connection(), which is called first in the thread for handling a client */ void *thread_stack; /** Currently selected catalog. */ char *catalog; /** @note Some members of THD (currently 'Statement::db', 'catalog' and 'query') are set and alloced by the slave SQL thread (for the THD of that thread); that thread is (and must remain, for now) the only responsible for freeing these 3 members. If you add members here, and you add code to set them in replication, don't forget to free_them_and_set_them_to_0 in replication properly. For details see the 'err:' label of the handle_slave_sql() in sql/slave.cc. @see handle_slave_sql */ Security_context main_security_ctx; Security_context *security_ctx; Security_context *security_context() const { return security_ctx; } void set_security_context(Security_context *sctx) { security_ctx = sctx; } /* Points to info-string that we show in SHOW PROCESSLIST You are supposed to update thd->proc_info only if you have coded a time-consuming piece that MySQL can get stuck in for a long time. Set it using the thd_proc_info(THD *thread, const char *message) macro/function. This member is accessed and assigned without any synchronization. Therefore, it may point only to constant (statically allocated) strings, which memory won't go away over time. */ const char *proc_info; void set_psi(PSI_thread *psi) { my_atomic_storeptr((void*volatile*)&m_psi, psi); } PSI_thread* get_psi() { return static_cast(my_atomic_loadptr((void*volatile*)&m_psi)); } private: unsigned int m_current_stage_key; /** Performance schema thread instrumentation for this session. */ PSI_thread *m_psi; public: void enter_stage(const PSI_stage_info *stage, const char *calling_func, const char *calling_file, const unsigned int calling_line) { DBUG_PRINT("THD::enter_stage", ("%s at %s:%d", stage->m_name, calling_file, calling_line)); DBUG_ASSERT(stage); m_current_stage_key= stage->m_key; proc_info= stage->m_name; #if defined(ENABLED_PROFILING) profiling.status_change(proc_info, calling_func, calling_file, calling_line); #endif #ifdef HAVE_PSI_THREAD_INTERFACE m_stage_progress_psi= MYSQL_SET_STAGE(m_current_stage_key, calling_file, calling_line); #endif } void backup_stage(PSI_stage_info *stage) { stage->m_key= m_current_stage_key; stage->m_name= proc_info; } const char *get_proc_info() const { return proc_info; } // Used by thd_where() when where==USE_WHERE_STRING const char *where_str; /* Used in error messages to tell user in what part of MySQL we found an error. E. g. when where= "having clause", if fix_fields() fails, user will know that the error was in having clause. */ THD_WHERE where; /* Needed by MariaDB semi sync replication */ Trans_binlog_info *semisync_info; #ifndef DBUG_OFF /* If Active_tranx is missing an entry for a transaction which is planning to await an ACK, this ensures that the reason is because semi-sync was turned off then on in-between the binlogging of the transaction, and before it had started waiting for the ACK. */ ulong expected_semi_sync_offs; #endif /* If this is a semisync slave connection. */ bool semi_sync_slave; ulonglong client_capabilities; /* What the client supports */ ulong max_client_packet_length; HASH handler_tables_hash; /* A thread can hold named user-level locks. This variable contains granted tickets if a lock is present. See item_func.cc and chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK. */ HASH ull_hash; /* Hash of used seqeunces (for PREVIOUS value) */ HASH sequences; #ifdef DBUG_ASSERT_EXISTS uint dbug_sentry; // watch out for memory corruption #endif struct st_my_thread_var *mysys_var; /* Original charset number from the first client packet, or COM_CHANGE_USER*/ CHARSET_INFO *org_charset; private: /* Type of current query: COM_STMT_PREPARE, COM_QUERY, etc. Set from first byte of the packet in do_command() */ enum enum_server_command m_command; public: uint32 file_id; // for LOAD DATA INFILE /* remote (peer) port */ uint16 peer_port; my_time_t start_time; // start_time and its sec_part ulong start_time_sec_part; // are almost always used separately my_hrtime_t user_time; // track down slow pthread_create ulonglong prior_thr_create_utime, thr_create_utime; ulonglong start_utime, utime_after_lock, utime_after_query; /* This can be used by handlers to send signals to the SQL level */ ulonglong replication_flags; // Process indicator struct { /* true, if the currently running command can send progress report packets to a client. Set by mysql_execute_command() for safe commands See CF_REPORT_PROGRESS */ bool report_to_client; /* true, if we will send progress report packets to a client (client has requested them, see MARIADB_CLIENT_PROGRESS; report_to_client is true; not in sub-statement) */ bool report; uint stage, max_stage; ulonglong counter, max_counter; ulonglong next_report_time; Query_arena *arena; } progress; thr_lock_type update_lock_default; Delayed_insert *di; /* <> 0 if we are inside of trigger or stored function. */ uint in_sub_stmt; /* True when opt_userstat_running is set at start of query */ bool userstat_running; /* True if we have to log all errors. Are set by some engines to temporary force errors to the error log. */ bool log_all_errors; /* Do not set socket timeouts for wait_timeout (used with threadpool) */ bool skip_wait_timeout; bool prepare_derived_at_open; /* Set to 1 if status of this THD is already in global status */ bool status_in_global; /* To signal that the tmp table to be created is created for materialized derived table or a view. */ bool create_tmp_table_for_derived; bool save_prep_leaf_list; /** The data member reset_sp_cache is to signal that content of sp_cache must be reset (all items be removed from it). */ bool reset_sp_cache; /* container for handler's private per-connection data */ Ha_data ha_data[MAX_HA]; /** Bit field for the state of binlog warnings. The first Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types of unsafeness that the current statement has. This must be a member of THD and not of LEX, because warnings are detected and issued in different places (@c decide_logging_format() and @c binlog_query(), respectively). Between these calls, the THD->lex object may change; e.g., if a stored routine is invoked. Only THD persists between the calls. */ uint32 binlog_unsafe_warning_flags; #ifndef MYSQL_CLIENT binlog_cache_mngr * binlog_setup_trx_data(); /* If set, tell binlog to store the value as query 'xid' in the next Query_log_event */ ulonglong binlog_xid; /* Public interface to write RBR events to the binlog */ void binlog_start_trans_and_stmt(); void binlog_set_stmt_begin(); int binlog_write_row(TABLE* table, bool is_transactional, const uchar *buf); int binlog_delete_row(TABLE* table, bool is_transactional, const uchar *buf); int binlog_update_row(TABLE* table, bool is_transactional, const uchar *old_data, const uchar *new_data); bool prepare_handlers_for_update(uint flag); bool binlog_write_annotated_row(Log_event_writer *writer); void binlog_prepare_for_row_logging(); bool binlog_write_table_maps(); bool binlog_write_table_map(TABLE *table, bool with_annotate); static void binlog_prepare_row_images(TABLE* table); void set_server_id(uint32 sid) { variables.server_id = sid; } /* Member functions to handle pending event for row-level logging. */ template Rows_log_event* binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id, size_t needed, bool is_transactional, RowsEventT* hint); Rows_log_event* binlog_get_pending_rows_event(bool is_transactional) const; void binlog_set_pending_rows_event(Rows_log_event* ev, bool is_transactional); inline int binlog_flush_pending_rows_event(bool stmt_end) { return (binlog_flush_pending_rows_event(stmt_end, FALSE) || binlog_flush_pending_rows_event(stmt_end, TRUE)); } int binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional); int binlog_remove_pending_rows_event(bool clear_maps, bool is_transactional); /** Determine the binlog format of the current statement. @retval 0 if the current statement will be logged in statement format. @retval nonzero if the current statement will be logged in row format. */ int is_current_stmt_binlog_format_row() const { DBUG_ASSERT(current_stmt_binlog_format == BINLOG_FORMAT_STMT || current_stmt_binlog_format == BINLOG_FORMAT_ROW); return current_stmt_binlog_format == BINLOG_FORMAT_ROW; } /** Determine if binlogging is disabled for this session @retval 0 if the current statement binlogging is disabled (could be because of binlog closed/binlog option is set to false). @retval 1 if the current statement will be binlogged */ inline bool is_current_stmt_binlog_disabled() const { return (!(variables.option_bits & OPTION_BIN_LOG) || !mysql_bin_log.is_open()); } enum binlog_filter_state { BINLOG_FILTER_UNKNOWN, BINLOG_FILTER_CLEAR, BINLOG_FILTER_SET }; inline void reset_binlog_local_stmt_filter() { m_binlog_filter_state= BINLOG_FILTER_UNKNOWN; } inline void clear_binlog_local_stmt_filter() { DBUG_ASSERT(m_binlog_filter_state == BINLOG_FILTER_UNKNOWN); m_binlog_filter_state= BINLOG_FILTER_CLEAR; } inline void set_binlog_local_stmt_filter() { DBUG_ASSERT(m_binlog_filter_state == BINLOG_FILTER_UNKNOWN); m_binlog_filter_state= BINLOG_FILTER_SET; } inline binlog_filter_state get_binlog_local_stmt_filter() { return m_binlog_filter_state; } /** Checks if a user connection is read-only */ inline bool is_read_only_ctx() { return opt_readonly && !(security_ctx->master_access & PRIV_IGNORE_READ_ONLY) && !slave_thread; } private: /** Indicate if the current statement should be discarded instead of written to the binlog. This is used to discard special statements, such as DML or DDL that affects only 'local' (non replicated) tables, such as performance_schema.* */ binlog_filter_state m_binlog_filter_state; /** Indicates the format in which the current statement will be logged. This can only be set from @c decide_logging_format(). */ enum_binlog_format current_stmt_binlog_format; public: /* 1 if binlog table maps has been written */ bool binlog_table_maps; void issue_unsafe_warnings(); void reset_unsafe_warnings() { binlog_unsafe_warning_flags= 0; } void reset_binlog_for_next_statement() { binlog_table_maps= 0; } bool binlog_table_should_be_logged(const LEX_CSTRING *db); #endif /* MYSQL_CLIENT */ public: struct st_transactions { SAVEPOINT *savepoints; THD_TRANS all; // Trans since BEGIN WORK THD_TRANS stmt; // Trans for current statement bool on; // see ha_enable_transaction() XID_STATE xid_state; XID implicit_xid; WT_THD wt; ///< for deadlock detection Rows_log_event *m_pending_rows_event; struct st_trans_time : public timeval { void reset(THD *thd) { tv_sec= thd->query_start(); tv_usec= (long) thd->query_start_sec_part(); } } start_time; /* Tables changed in transaction (that must be invalidated in query cache). List contain only transactional tables, that not invalidated in query cache (instead of full list of changed in transaction tables). */ CHANGED_TABLE_LIST* changed_tables; MEM_ROOT mem_root; // Transaction-life memory allocation pool void cleanup() { DBUG_ENTER("THD::st_transactions::cleanup"); changed_tables= 0; savepoints= 0; implicit_xid.null(); free_root(&mem_root,MYF(MY_KEEP_PREALLOC)); DBUG_VOID_RETURN; } void free() { free_root(&mem_root,MYF(0)); } bool is_active() { return (all.ha_list != NULL); } bool is_empty() { return all.is_empty() && stmt.is_empty(); } st_transactions() { bzero((char*)this, sizeof(*this)); implicit_xid.null(); init_sql_alloc(key_memory_thd_transactions, &mem_root, DEFAULT_ROOT_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); } } default_transaction, *transaction; Global_read_lock global_read_lock; Field *dup_field; #ifndef _WIN32 sigset_t signals; #endif #ifdef SIGNAL_WITH_VIO_CLOSE Vio* active_vio; #endif /* A permanent memory area of the statement. For conventional execution, the parsed tree and execution runtime reside in the same memory root. In this case stmt_arena points to THD. In case of a prepared statement or a stored procedure statement, thd->mem_root conventionally points to runtime memory, and thd->stmt_arena points to the memory of the PS/SP, where the parsed tree of the statement resides. Whenever you need to perform a permanent transformation of a parsed tree, you should allocate new memory in stmt_arena, to allow correct re-execution of PS/SP. Note: in the parser, stmt_arena == thd, even for PS/SP. */ Query_arena *stmt_arena; /** Get either call or statement arena. In case some function is called from within a query the call arena has to be used for a memory allocation, else use the statement arena. */ Query_arena *active_stmt_arena_to_use() { return (state == Query_arena::STMT_SP_QUERY_ARGUMENTS) ? this : stmt_arena; } void *bulk_param; /* map for tables that will be updated for a multi-table update query statement, for other query statements, this will be zero. */ table_map table_map_for_update; /* Tells if LAST_INSERT_ID(#) was called for the current statement */ bool arg_of_last_insert_id_function; /* ALL OVER THIS FILE, "insert_id" means "*automatically generated* value for insertion into an auto_increment column". */ /* This is the first autogenerated insert id which was *successfully* inserted by the previous statement (exactly, if the previous statement didn't successfully insert an autogenerated insert id, then it's the one of the statement before, etc). It can also be set by SET LAST_INSERT_ID=# or SELECT LAST_INSERT_ID(#). It is returned by LAST_INSERT_ID(). */ ulonglong first_successful_insert_id_in_prev_stmt; /* Variant of the above, used for storing in statement-based binlog. The difference is that the one above can change as the execution of a stored function progresses, while the one below is set once and then does not change (which is the value which statement-based binlog needs). */ ulonglong first_successful_insert_id_in_prev_stmt_for_binlog; /* This is the first autogenerated insert id which was *successfully* inserted by the current statement. It is maintained only to set first_successful_insert_id_in_prev_stmt when statement ends. */ ulonglong first_successful_insert_id_in_cur_stmt; /* We follow this logic: - when stmt starts, first_successful_insert_id_in_prev_stmt contains the first insert id successfully inserted by the previous stmt. - as stmt makes progress, handler::insert_id_for_cur_row changes; every time get_auto_increment() is called, auto_inc_intervals_in_cur_stmt_for_binlog is augmented with the reserved interval (if statement-based binlogging). - at first successful insertion of an autogenerated value, first_successful_insert_id_in_cur_stmt is set to handler::insert_id_for_cur_row. - when stmt goes to binlog, auto_inc_intervals_in_cur_stmt_for_binlog is binlogged if non-empty. - when stmt ends, first_successful_insert_id_in_prev_stmt is set to first_successful_insert_id_in_cur_stmt. */ /* stmt_depends_on_first_successful_insert_id_in_prev_stmt is set when LAST_INSERT_ID() is used by a statement. If it is set, first_successful_insert_id_in_prev_stmt_for_binlog will be stored in the statement-based binlog. This variable is CUMULATIVE along the execution of a stored function or trigger: if one substatement sets it to 1 it will stay 1 until the function/trigger ends, thus making sure that first_successful_insert_id_in_prev_stmt_for_binlog does not change anymore and is propagated to the caller for binlogging. */ bool stmt_depends_on_first_successful_insert_id_in_prev_stmt; /* List of auto_increment intervals reserved by the thread so far, for storage in the statement-based binlog. Note that its minimum is not first_successful_insert_id_in_cur_stmt: assuming a table with an autoinc column, and this happens: INSERT INTO ... VALUES(3); SET INSERT_ID=3; INSERT IGNORE ... VALUES (NULL); then the latter INSERT will insert no rows (first_successful_insert_id_in_cur_stmt == 0), but storing "INSERT_ID=3" in the binlog is still needed; the list's minimum will contain 3. This variable is cumulative: if several statements are written to binlog as one (stored functions or triggers are used) this list is the concatenation of all intervals reserved by all statements. */ Discrete_intervals_list auto_inc_intervals_in_cur_stmt_for_binlog; /* Used by replication and SET INSERT_ID */ Discrete_intervals_list auto_inc_intervals_forced; /* There is BUG#19630 where statement-based replication of stored functions/triggers with two auto_increment columns breaks. We however ensure that it works when there is 0 or 1 auto_increment column; our rules are a) on master, while executing a top statement involving substatements, first top- or sub- statement to generate auto_increment values wins the exclusive right to see its values be written to binlog (the write will be done by the statement or its caller), and the losers won't see their values be written to binlog. b) on slave, while replicating a top statement involving substatements, first top- or sub- statement to need to read auto_increment values from the master's binlog wins the exclusive right to read them (so the losers won't read their values from binlog but instead generate on their own). a) implies that we mustn't backup/restore auto_inc_intervals_in_cur_stmt_for_binlog. b) implies that we mustn't backup/restore auto_inc_intervals_forced. If there are more than 1 auto_increment columns, then intervals for different columns may mix into the auto_inc_intervals_in_cur_stmt_for_binlog list, which is logically wrong, but there is no point in preventing this mixing by preventing intervals from the secondly inserted column to come into the list, as such prevention would be wrong too. What will happen in the case of INSERT INTO t1 (auto_inc) VALUES(NULL); where t1 has a trigger which inserts into an auto_inc column of t2, is that in binlog we'll store the interval of t1 and the interval of t2 (when we store intervals, soon), then in slave, t1 will use both intervals, t2 will use none; if t1 inserts the same number of rows as on master, normally the 2nd interval will not be used by t1, which is fine. t2's values will be wrong if t2's internal auto_increment counter is different from what it was on master (which is likely). In 5.1, in mixed binlogging mode, row-based binlogging is used for such cases where two auto_increment columns are inserted. */ inline void record_first_successful_insert_id_in_cur_stmt(ulonglong id_arg) { if (first_successful_insert_id_in_cur_stmt == 0) first_successful_insert_id_in_cur_stmt= id_arg; } inline ulonglong read_first_successful_insert_id_in_prev_stmt(void) { if (!stmt_depends_on_first_successful_insert_id_in_prev_stmt) { /* It's the first time we read it */ first_successful_insert_id_in_prev_stmt_for_binlog= first_successful_insert_id_in_prev_stmt; stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1; } return first_successful_insert_id_in_prev_stmt; } /* Used by Intvar_log_event::do_apply_event() and by "SET INSERT_ID=#" (mysqlbinlog). We'll soon add a variant which can take many intervals in argument. */ inline void force_one_auto_inc_interval(ulonglong next_id) { auto_inc_intervals_forced.empty(); // in case of multiple SET INSERT_ID auto_inc_intervals_forced.append(next_id, ULONGLONG_MAX, 0); } inline void set_binlog_bit() { if (variables.sql_log_bin) variables.option_bits |= OPTION_BIN_LOG; else variables.option_bits &= ~OPTION_BIN_LOG; } ulonglong limit_found_rows; private: /** Stores the result of ROW_COUNT() function. ROW_COUNT() function is a MySQL extention, but we try to keep it similar to ROW_COUNT member of the GET DIAGNOSTICS stack of the SQL standard (see SQL99, part 2, search for ROW_COUNT). It's value is implementation defined for anything except INSERT, DELETE, UPDATE. ROW_COUNT is assigned according to the following rules: - In my_ok(): - for DML statements: to the number of affected rows; - for DDL statements: to 0. - In my_eof(): to -1 to indicate that there was a result set. We derive this semantics from the JDBC specification, where int java.sql.Statement.getUpdateCount() is defined to (sic) "return the current result as an update count; if the result is a ResultSet object or there are no more results, -1 is returned". - In my_error(): to -1 to be compatible with the MySQL C API and MySQL ODBC driver. - For SIGNAL statements: to 0 per WL#2110 specification (see also sql_signal.cc comment). Zero is used since that's the "default" value of ROW_COUNT in the diagnostics area. */ longlong m_row_count_func; /* For the ROW_COUNT() function */ public: inline longlong get_row_count_func() const { return m_row_count_func; } inline void set_row_count_func(longlong row_count_func) { m_row_count_func= row_count_func; } inline void set_affected_rows(longlong row_count_func) { /* We have to add to affected_rows (used by slow log), as otherwise information for 'call' will be wrong */ affected_rows+= (row_count_func >= 0 ? row_count_func : 0); } ha_rows cuted_fields; private: /* number of rows we actually sent to the client, including "synthetic" rows in ROLLUP etc. */ ha_rows m_sent_row_count; /** Number of rows read and/or evaluated for a statement. Used for slow log reporting. An examined row is defined as a row that is read and/or evaluated according to a statement condition, including in create_sort_index(). Rows may be counted more than once, e.g., a statement including ORDER BY could possibly evaluate the row in filesort() before reading it for e.g. update. */ ha_rows m_examined_row_count; public: ha_rows get_sent_row_count() const { return m_sent_row_count; } ha_rows get_examined_row_count() const { DBUG_EXECUTE_IF("debug_huge_number_of_examined_rows", return (ULONGLONG_MAX - 1000000);); return m_examined_row_count; } ulonglong get_affected_rows() const { return affected_rows; } void set_sent_row_count(ha_rows count); void set_examined_row_count(ha_rows count); void inc_sent_row_count(ha_rows count); void inc_examined_row_count(ha_rows count); void inc_status_created_tmp_disk_tables(); void inc_status_created_tmp_files(); void inc_status_created_tmp_tables(); void inc_status_select_full_join(); void inc_status_select_full_range_join(); void inc_status_select_range(); void inc_status_select_range_check(); void inc_status_select_scan(); void inc_status_sort_merge_passes(); void inc_status_sort_range(); void inc_status_sort_rows(ha_rows count); void inc_status_sort_scan(); void set_status_no_index_used(); void set_status_no_good_index_used(); /** The number of rows and/or keys examined by the query, both read, changed or written. */ ulonglong accessed_rows_and_keys; /** Check if the number of rows accessed by a statement exceeded LIMIT ROWS EXAMINED. If so, signal the query engine to stop execution. */ void check_limit_rows_examined() { if (++accessed_rows_and_keys > lex->limit_rows_examined_cnt) set_killed(ABORT_QUERY); } USER_CONN *user_connect; CHARSET_INFO *db_charset; #if defined(ENABLED_PROFILING) PROFILING profiling; #endif /** Current stage progress instrumentation. */ PSI_stage_progress *m_stage_progress_psi; /** Current statement digest. */ sql_digest_state *m_digest; /** Current statement digest token array. */ unsigned char *m_token_array; /** Top level statement digest. */ sql_digest_state m_digest_state; /** Current statement instrumentation. */ PSI_statement_locker *m_statement_psi; #ifdef HAVE_PSI_STATEMENT_INTERFACE /** Current statement instrumentation state. */ PSI_statement_locker_state m_statement_state; #endif /* HAVE_PSI_STATEMENT_INTERFACE */ /** Current transaction instrumentation. */ PSI_transaction_locker *m_transaction_psi; #ifdef HAVE_PSI_TRANSACTION_INTERFACE /** Current transaction instrumentation state. */ PSI_transaction_locker_state m_transaction_state; #endif /* HAVE_PSI_TRANSACTION_INTERFACE */ /** Idle instrumentation. */ PSI_idle_locker *m_idle_psi; #ifdef HAVE_PSI_IDLE_INTERFACE /** Idle instrumentation state. */ PSI_idle_locker_state m_idle_state; #endif /* HAVE_PSI_IDLE_INTERFACE */ /* Id of current query. Statement can be reused to execute several queries query_id is global in context of the whole MySQL server. ID is automatically generated from mutex-protected counter. It's used in handler code for various purposes: to check which columns from table are necessary for this select, to check if it's necessary to update auto-updatable fields (like auto_increment and timestamp). */ query_id_t query_id; privilege_t col_access; /* Statement id is thread-wide. This counter is used to generate ids */ ulong statement_id_counter; ulong rand_saved_seed1, rand_saved_seed2; /* The following variables are used when printing to slow log */ ulong query_plan_flags; ulong query_plan_fsort_passes; ulong tmp_tables_used; ulong tmp_tables_disk_used; ulonglong tmp_tables_size; ulonglong bytes_sent_old; ulonglong affected_rows; /* Number of changed rows */ Opt_trace_context opt_trace; pthread_t real_id; /* For debugging */ my_thread_id thread_id, thread_dbug_id; uint32 os_thread_id; uint tmp_table, global_disable_checkpoint; uint server_status,open_options; enum enum_thread_type system_thread; enum backup_stages current_backup_stage; #ifdef WITH_WSREP bool wsrep_desynced_backup_stage; #endif /* WITH_WSREP */ /* Current or next transaction isolation level. When a connection is established, the value is taken from @@session.tx_isolation (default transaction isolation for the session), which is in turn taken from @@global.tx_isolation (the global value). If there is no transaction started, this variable holds the value of the next transaction's isolation level. When a transaction starts, the value stored in this variable becomes "actual". At transaction commit or rollback, we assign this variable again from @@session.tx_isolation. The only statement that can otherwise change the value of this variable is SET TRANSACTION ISOLATION LEVEL. Its purpose is to effect the isolation level of the next transaction in this session. When this statement is executed, the value in this variable is changed. However, since this statement is only allowed when there is no active transaction, this assignment (naturally) only affects the upcoming transaction. At the end of the current active transaction the value is be reset again from @@session.tx_isolation, as described above. */ enum_tx_isolation tx_isolation; /* Current or next transaction access mode. See comment above regarding tx_isolation. */ bool tx_read_only; enum_check_fields count_cuted_fields; DYNAMIC_ARRAY user_var_events; /* For user variables replication */ MEM_ROOT *user_var_events_alloc; /* Allocate above array elements here */ /* Define durability properties that engines may check to improve performance. Not yet used in MariaDB */ enum durability_properties durability_property; /* If checking this in conjunction with a wait condition, please include a check after enter_cond() if you want to avoid a race condition. For details see the implementation of awake(), especially the "broadcast" part. */ killed_state volatile killed; /* The following is used if one wants to have a specific error number and text for the kill */ struct err_info { int no; const char msg[256]; } *killed_err; /* See also thd_killed() */ inline bool check_killed(bool dont_send_error_message= 0) { if (unlikely(killed)) { if (!dont_send_error_message) send_kill_message(); return TRUE; } if (apc_target.have_apc_requests()) apc_target.process_apc_requests(false); return FALSE; } /* scramble - random string sent to client on handshake */ char scramble[SCRAMBLE_LENGTH+1]; /* If this is a slave, the name of the connection stored here. This is used for taging error messages in the log files. */ LEX_CSTRING connection_name; char default_master_connection_buff[MAX_CONNECTION_NAME+1]; uint8 password; /* 0, 1 or 2 */ uint8 failed_com_change_user; bool slave_thread; bool no_errors; /** Set to TRUE if execution of the current compound statement can not continue. In particular, disables activation of CONTINUE or EXIT handlers of stored routines. Reset in the end of processing of the current user request, in @see THD::reset_for_next_command(). */ bool is_fatal_error; /** Set by a storage engine to request the entire transaction (that possibly spans multiple engines) to rollback. Reset in ha_rollback. */ bool transaction_rollback_request; /** TRUE if we are in a sub-statement and the current error can not be safely recovered until we left the sub-statement mode. In particular, disables activation of CONTINUE and EXIT handlers inside sub-statements. E.g. if it is a deadlock error and requires a transaction-wide rollback, this flag is raised (traditionally, MySQL first has to close all the reads via @see handler::ha_index_or_rnd_end() and only then perform the rollback). Reset to FALSE when we leave the sub-statement mode. */ bool is_fatal_sub_stmt_error; bool rand_used, time_zone_used; bool query_start_sec_part_used; /* for IS NULL => = last_insert_id() fix in remove_eq_conds() */ bool substitute_null_with_insert_id; bool in_lock_tables; bool bootstrap, cleanup_done, free_connection_done; /** is set if some thread specific value(s) used in a statement. */ bool thread_specific_used; /** is set if a statement accesses a temporary table created through CREATE TEMPORARY TABLE. */ private: bool charset_is_system_charset, charset_is_collation_connection; bool charset_is_character_set_filesystem; public: bool enable_slow_log; /* Enable slow log for current statement */ bool abort_on_warning; bool got_warning; /* Set on call to push_warning() */ /* set during loop of derived table processing */ bool derived_tables_processing; bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ /* True if we have to log the current statement */ bool log_current_statement; /** True if a slave error. Causes the slave to stop. Not the same as the statement execution error (is_error()), since a statement may be expected to return an error, e.g. because it returned an error on master, and this is OK on the slave. */ bool is_slave_error; /* True if we have printed something to the error log for this statement */ bool error_printed_to_log; /* True when a transaction is queued up for binlog group commit. Used so that if another transaction needs to wait for a row lock held by this transaction, it can signal to trigger the group commit immediately, skipping the normal --binlog-commit-wait-count wait. */ bool waiting_on_group_commit; /* Set true when another transaction goes to wait on a row lock held by this transaction. Used together with waiting_on_group_commit. */ bool has_waiter; /* In case of a slave, set to the error code the master got when executing the query. 0 if no error on the master. The stored into variable master error code may get reset inside execution stack when the event turns out to be ignored. */ int slave_expected_error; enum_sql_command last_sql_command; // Last sql_command exceuted in mysql_execute_command() sp_rcontext *spcont; // SP runtime context /** number of name_const() substitutions, see sp_head.cc:subst_spvars() */ uint query_name_consts; NET* slave_net; // network connection from slave -> m. /* Used to update global user stats. The global user stats are updated occasionally with the 'diff' variables. After the update, the 'diff' variables are reset to 0. */ /* Time when the current thread connected to MySQL. */ time_t current_connect_time; /* Last time when THD stats were updated in global_user_stats. */ time_t last_global_update_time; /* Number of commands not reflected in global_user_stats yet. */ uint select_commands, update_commands, other_commands; ulonglong start_cpu_time; ulonglong start_bytes_received; /* Used by the sys_var class to store temporary values */ union { my_bool my_bool_value; int int_value; uint uint_value; long long_value; ulong ulong_value; ulonglong ulonglong_value; double double_value; void *ptr_value; } sys_var_tmp; struct { /* If true, mysql_bin_log::write(Log_event) call will not write events to binlog, and maintain 2 below variables instead (use mysql_bin_log.start_union_events to turn this on) */ bool do_union; /* If TRUE, at least one mysql_bin_log::write(Log_event) call has been made after last mysql_bin_log.start_union_events() call. */ bool unioned_events; /* If TRUE, at least one mysql_bin_log::write(Log_event e), where e.cache_stmt == TRUE call has been made after last mysql_bin_log.start_union_events() call. */ bool unioned_events_trans; /* 'queries' (actually SP statements) that run under inside this binlog union have thd->query_id >= first_query_id. */ query_id_t first_query_id; } binlog_evt_union; /** Internal parser state. Note that since the parser is not re-entrant, we keep only one parser state here. This member is valid only when executing code during parsing. */ Parser_state *m_parser_state; Locked_tables_list locked_tables_list; #ifdef WITH_PARTITION_STORAGE_ENGINE partition_info *work_part_info; #endif #ifndef EMBEDDED_LIBRARY /** Array of active audit plugins which have been used by this THD. This list is later iterated to invoke release_thd() on those plugins. */ DYNAMIC_ARRAY audit_class_plugins; /** Array of bits indicating which audit classes have already been added to the list of audit plugins which are currently in use. */ unsigned long audit_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; int audit_plugin_version; #endif #if defined(ENABLED_DEBUG_SYNC) /* Debug Sync facility. See debug_sync.cc. */ struct st_debug_sync_control *debug_sync_control; #endif /* defined(ENABLED_DEBUG_SYNC) */ /** @param id thread identifier @param is_wsrep_applier thread type */ THD(my_thread_id id, bool is_wsrep_applier= false); ~THD(); void init(); /* Initialize memory roots necessary for query processing and (!) pre-allocate memory for it. We can't do that in THD constructor because there are use cases (acl_init, delayed inserts, watcher threads, killing mysqld) where it's vital to not allocate excessive and not used memory. Note, that we still don't return error from init_for_queries(): if preallocation fails, we should notice that at the first call to alloc_root. */ void init_for_queries(); void update_all_stats(); void update_stats(void); void change_user(void); void cleanup(void); void cleanup_after_query(); void free_connection(); void reset_for_reuse(); void store_globals(); void reset_stack() { thread_stack= 0; } void reset_globals(); bool trace_started() { return opt_trace.is_started(); } #ifdef SIGNAL_WITH_VIO_CLOSE inline void set_active_vio(Vio* vio) { mysql_mutex_lock(&LOCK_thd_data); active_vio = vio; mysql_mutex_unlock(&LOCK_thd_data); } inline void clear_active_vio() { mysql_mutex_lock(&LOCK_thd_data); active_vio = 0; mysql_mutex_unlock(&LOCK_thd_data); } void close_active_vio(); #endif void awake_no_mutex(killed_state state_to_set); void awake(killed_state state_to_set) { mysql_mutex_lock(&LOCK_thd_kill); mysql_mutex_lock(&LOCK_thd_data); awake_no_mutex(state_to_set); mysql_mutex_unlock(&LOCK_thd_data); mysql_mutex_unlock(&LOCK_thd_kill); } void abort_current_cond_wait(bool force); /** Disconnect the associated communication endpoint. */ void disconnect(); /* Allows this thread to serve as a target for others to schedule Async Procedure Calls on. It's possible to schedule any code to be executed this way, by inheriting from the Apc_call object. Currently, only Show_explain_request uses this. */ Apc_target apc_target; Gap_time_tracker_data gap_tracker_data; #ifndef MYSQL_CLIENT enum enum_binlog_query_type { /* The query can be logged in row format or in statement format. */ ROW_QUERY_TYPE, /* The query has to be logged in statement format. */ STMT_QUERY_TYPE, QUERY_TYPE_COUNT }; int binlog_query(enum_binlog_query_type qtype, char const *query, ulong query_len, bool is_trans, bool direct, bool suppress_use, int errcode); bool binlog_current_query_unfiltered(); #endif inline void enter_cond(mysql_cond_t *cond, mysql_mutex_t* mutex, const PSI_stage_info *stage, PSI_stage_info *old_stage, const char *src_function, const char *src_file, int src_line) override { mysql_mutex_assert_owner(mutex); mysys_var->current_mutex = mutex; mysys_var->current_cond = cond; if (old_stage) backup_stage(old_stage); if (stage) enter_stage(stage, src_function, src_file, src_line); } inline void exit_cond(const PSI_stage_info *stage, const char *src_function, const char *src_file, int src_line) override { /* Putting the mutex unlock in thd->exit_cond() ensures that mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is locked (if that would not be the case, you'll get a deadlock if someone does a THD::awake() on you). */ mysql_mutex_unlock(mysys_var->current_mutex); mysql_mutex_lock(&mysys_var->mutex); mysys_var->current_mutex = 0; mysys_var->current_cond = 0; if (stage) enter_stage(stage, src_function, src_file, src_line); mysql_mutex_unlock(&mysys_var->mutex); return; } int is_killed() override { return killed; } THD* get_thd() override { return this; } /** A callback to the server internals that is used to address special cases of the locking protocol. Invoked when acquiring an exclusive lock, for each thread that has a conflicting shared metadata lock. This function: - aborts waiting of the thread on a data lock, to make it notice the pending exclusive lock and back off. - if the thread is an INSERT DELAYED thread, sends it a KILL signal to terminate it. @note This function does not wait for the thread to give away its locks. Waiting is done outside for all threads at once. @param ctx_in_use The MDL context owner (thread) to wake up. @param needs_thr_lock_abort Indicates that to wake up thread this call needs to abort its waiting on table-level lock. @retval TRUE if the thread was woken up @retval FALSE otherwise. */ bool notify_shared_lock(MDL_context_owner *ctx_in_use, bool needs_thr_lock_abort) override; // End implementation of MDL_context_owner interface. inline bool is_strict_mode() const { return (bool) (variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); } inline bool backslash_escapes() const { return !MY_TEST(variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES); } const Type_handler *type_handler_for_datetime() const; bool timestamp_to_TIME(MYSQL_TIME *ltime, my_time_t ts, ulong sec_part, date_mode_t fuzzydate); inline my_time_t query_start() { return start_time; } inline ulong query_start_sec_part() { query_start_sec_part_used=1; return start_time_sec_part; } MYSQL_TIME query_start_TIME(); time_round_mode_t temporal_round_mode() const { return variables.sql_mode & MODE_TIME_ROUND_FRACTIONAL ? TIME_FRAC_ROUND : TIME_FRAC_TRUNCATE; } private: struct { my_hrtime_t start; my_time_t sec; ulong sec_part; } system_time; void set_system_time() { my_hrtime_t hrtime= my_hrtime(); my_time_t sec= hrtime_to_my_time(hrtime); ulong sec_part= hrtime_sec_part(hrtime); if (sec > system_time.sec || (sec == system_time.sec && sec_part > system_time.sec_part) || hrtime.val < system_time.start.val) { system_time.sec= sec; system_time.sec_part= sec_part; system_time.start= hrtime; } else { if (system_time.sec_part < TIME_MAX_SECOND_PART) system_time.sec_part++; else { system_time.sec++; system_time.sec_part= 0; } } } public: timeval transaction_time() { if (!in_multi_stmt_transaction_mode()) transaction->start_time.reset(this); return transaction->start_time; } inline void set_start_time() { if (user_time.val) { start_time= hrtime_to_my_time(user_time); start_time_sec_part= hrtime_sec_part(user_time); } else { set_system_time(); start_time= system_time.sec; start_time_sec_part= system_time.sec_part; } PSI_CALL_set_thread_start_time(start_time); } inline void set_time() { set_start_time(); start_utime= utime_after_lock= microsecond_interval_timer(); } /* only used in SET @@timestamp=... */ inline void set_time(my_hrtime_t t) { user_time= t; set_time(); } inline void force_set_time(my_time_t t, ulong sec_part) { start_time= system_time.sec= t; start_time_sec_part= system_time.sec_part= sec_part; } /* this is only used by replication and BINLOG command. usecs > TIME_MAX_SECOND_PART means "was not in binlog" */ inline void set_time(my_time_t t, ulong sec_part) { if (opt_secure_timestamp > (slave_thread ? SECTIME_REPL : SECTIME_SUPER)) set_time(); // note that BINLOG itself requires SUPER else { if (sec_part <= TIME_MAX_SECOND_PART) force_set_time(t, sec_part); else if (t != system_time.sec) force_set_time(t, 0); else { start_time= t; start_time_sec_part= ++system_time.sec_part; } user_time.val= hrtime_from_time(start_time) + start_time_sec_part; PSI_CALL_set_thread_start_time(start_time); start_utime= utime_after_lock= microsecond_interval_timer(); } } void set_time_after_lock() { utime_after_lock= microsecond_interval_timer(); MYSQL_SET_STATEMENT_LOCK_TIME(m_statement_psi, (utime_after_lock - start_utime)); } ulonglong current_utime() { return microsecond_interval_timer(); } /* Tell SHOW PROCESSLIST to show time from this point */ inline void set_time_for_next_stage() { utime_after_query= current_utime(); } /** Update server status after execution of a top level statement. Currently only checks if a query was slow, and assigns the status accordingly. Evaluate the current time, and if it exceeds the long-query-time setting, mark the query as slow. */ void update_server_status() { set_time_for_next_stage(); if (utime_after_query >= utime_after_lock + variables.long_query_time) server_status|= SERVER_QUERY_WAS_SLOW; } inline ulonglong found_rows(void) { return limit_found_rows; } /** Returns TRUE if session is in a multi-statement transaction mode. OPTION_NOT_AUTOCOMMIT: When autocommit is off, a multi-statement transaction is implicitly started on the first statement after a previous transaction has been ended. OPTION_BEGIN: Regardless of the autocommit status, a multi-statement transaction can be explicitly started with the statements "START TRANSACTION", "BEGIN [WORK]", "[COMMIT | ROLLBACK] AND CHAIN", etc. Note: this doesn't tell you whether a transaction is active. A session can be in multi-statement transaction mode, and yet have no active transaction, e.g., in case of: set @@autocommit=0; set @a= 3; <-- these statements don't set transaction isolation level serializable; <-- start an active flush tables; <-- transaction I.e. for the above scenario this function returns TRUE, even though no active transaction has begun. @sa in_active_multi_stmt_transaction() */ inline bool in_multi_stmt_transaction_mode() { return variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN); } /** TRUE if the session is in a multi-statement transaction mode (@sa in_multi_stmt_transaction_mode()) *and* there is an active transaction, i.e. there is an explicit start of a transaction with BEGIN statement, or implicit with a statement that uses a transactional engine. For example, these scenarios don't start an active transaction (even though the server is in multi-statement transaction mode): set @@autocommit=0; select * from nontrans_table; set @var=TRUE; flush tables; Note, that even for a statement that starts a multi-statement transaction (i.e. select * from trans_table), this flag won't be set until we open the statement's tables and the engines register themselves for the transaction (see trans_register_ha()), hence this method is reliable to use only after open_tables() has completed. Why do we need a flag? ---------------------- We need to maintain a (at first glance redundant) session flag, rather than looking at thd->transaction.all.ha_list because of explicit start of a transaction with BEGIN. I.e. in case of BEGIN; select * from nontrans_t1; <-- in_active_multi_stmt_transaction() is true */ inline bool in_active_multi_stmt_transaction() { return server_status & SERVER_STATUS_IN_TRANS; } /* Commit both statement and full transaction */ int commit_whole_transaction_and_close_tables(); void give_protection_error(); /* Give an error if any of the following is true for this connection - BACKUP STAGE is active - FLUSH TABLE WITH READ LOCK is active - BACKUP LOCK table_name is active */ inline bool has_read_only_protection() { if (current_backup_stage == BACKUP_FINISHED && !global_read_lock.is_acquired() && !mdl_backup_lock) return FALSE; give_protection_error(); return TRUE; } inline bool fill_information_schema_tables() { return !stmt_arena->is_stmt_prepare(); } inline void* trans_alloc(size_t size) { return alloc_root(&transaction->mem_root,size); } LEX_CSTRING strmake_lex_cstring(const char *str, size_t length) { const char *tmp= strmake_root(mem_root, str, length); if (!tmp) return {0,0}; return {tmp, length}; } LEX_CSTRING strmake_lex_cstring(const LEX_CSTRING &from) { return strmake_lex_cstring(from.str, from.length); } LEX_CSTRING strmake_lex_cstring_trim_whitespace(const LEX_CSTRING &from) { return strmake_lex_cstring(Lex_cstring(from).trim_whitespace(charset())); } LEX_STRING *make_lex_string(LEX_STRING *lex_str, const char* str, size_t length) { if (!(lex_str->str= strmake_root(mem_root, str, length))) { lex_str->length= 0; return 0; } lex_str->length= length; return lex_str; } LEX_CSTRING *make_lex_string(LEX_CSTRING *lex_str, const char* str, size_t length) { if (!(lex_str->str= strmake_root(mem_root, str, length))) { lex_str->length= 0; return 0; } lex_str->length= length; return lex_str; } // Remove double quotes: aaa""bbb -> aaa"bbb bool quote_unescape(LEX_CSTRING *dst, const LEX_CSTRING *src, char quote) { const char *tmp= src->str; const char *tmpend= src->str + src->length; char *to; if (!(dst->str= to= (char *) alloc(src->length + 1))) { dst->length= 0; // Safety return true; } for ( ; tmp < tmpend; ) { if ((*to++= *tmp++) == quote) tmp++; // Skip double quotes } *to= 0; // End null for safety dst->length= to - dst->str; return false; } LEX_CSTRING *make_clex_string(const char* str, size_t length) { LEX_CSTRING *lex_str; char *tmp; if (unlikely(!(lex_str= (LEX_CSTRING *)alloc_root(mem_root, sizeof(LEX_CSTRING) + length+1)))) return 0; tmp= (char*) (lex_str+1); lex_str->str= tmp; memcpy(tmp, str, length); tmp[length]= 0; lex_str->length= length; return lex_str; } LEX_CSTRING *make_clex_string(const LEX_CSTRING from) { return make_clex_string(from.str, from.length); } // Allocate LEX_STRING for character set conversion bool alloc_lex_string(LEX_STRING *dst, size_t length) { if (likely((dst->str= (char*) alloc(length)))) return false; dst->length= 0; // Safety return true; // EOM } bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs, const char *from, size_t from_length, CHARSET_INFO *from_cs); bool reinterpret_string_from_binary(LEX_CSTRING *to, CHARSET_INFO *to_cs, const char *from, size_t from_length); bool convert_string(LEX_CSTRING *to, CHARSET_INFO *to_cs, const char *from, size_t from_length, CHARSET_INFO *from_cs) { LEX_STRING tmp; bool rc= convert_string(&tmp, to_cs, from, from_length, from_cs); to->str= tmp.str; to->length= tmp.length; return rc; } bool convert_string(LEX_CSTRING *to, CHARSET_INFO *tocs, const LEX_CSTRING *from, CHARSET_INFO *fromcs, bool simple_copy_is_possible) { if (!simple_copy_is_possible) return unlikely(convert_string(to, tocs, from->str, from->length, fromcs)); if (fromcs == &my_charset_bin) return reinterpret_string_from_binary(to, tocs, from->str, from->length); *to= *from; return false; } /* Convert a strings between character sets. Uses my_convert_fix(), which uses an mb_wc .. mc_mb loop internally. dstcs and srccs cannot be &my_charset_bin. */ bool convert_fix(CHARSET_INFO *dstcs, LEX_STRING *dst, CHARSET_INFO *srccs, const char *src, size_t src_length, String_copier *status); /* Same as above, but additionally sends ER_INVALID_CHARACTER_STRING in case of bad byte sequences or Unicode conversion problems. */ bool convert_with_error(CHARSET_INFO *dstcs, LEX_STRING *dst, CHARSET_INFO *srccs, const char *src, size_t src_length); /* If either "dstcs" or "srccs" is &my_charset_bin, then performs native copying using copy_fix(). Otherwise, performs Unicode conversion using convert_fix(). */ bool copy_fix(CHARSET_INFO *dstcs, LEX_STRING *dst, CHARSET_INFO *srccs, const char *src, size_t src_length, String_copier *status); /* Same as above, but additionally sends ER_INVALID_CHARACTER_STRING in case of bad byte sequences or Unicode conversion problems. */ bool copy_with_error(CHARSET_INFO *dstcs, LEX_STRING *dst, CHARSET_INFO *srccs, const char *src, size_t src_length); bool convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs); /* Check if the string is wellformed, raise an error if not wellformed. @param str - The string to check. @param length - the string length. */ bool check_string_for_wellformedness(const char *str, size_t length, CHARSET_INFO *cs) const; bool to_ident_sys_alloc(Lex_ident_sys_st *to, const Lex_ident_cli_st *from); /* Create a string literal with optional client->connection conversion. @param str - the string in the client character set @param length - length of the string @param repertoire - the repertoire of the string */ Item_basic_constant *make_string_literal(const char *str, size_t length, my_repertoire_t repertoire); Item_basic_constant *make_string_literal(const Lex_string_with_metadata_st &str) { my_repertoire_t repertoire= str.repertoire(variables.character_set_client); return make_string_literal(str.str, str.length, repertoire); } Item_basic_constant *make_string_literal_nchar(const Lex_string_with_metadata_st &str); Item_basic_constant *make_string_literal_charset(const Lex_string_with_metadata_st &str, CHARSET_INFO *cs); bool make_text_string_sys(LEX_CSTRING *to, const Lex_string_with_metadata_st *from) { return convert_string(to, system_charset_info, from, charset(), charset_is_system_charset); } bool make_text_string_connection(LEX_CSTRING *to, const Lex_string_with_metadata_st *from) { return convert_string(to, variables.collation_connection, from, charset(), charset_is_collation_connection); } bool make_text_string_filesystem(LEX_CSTRING *to, const Lex_string_with_metadata_st *from) { return convert_string(to, variables.character_set_filesystem, from, charset(), charset_is_character_set_filesystem); } void add_changed_table(TABLE *table); void add_changed_table(const char *key, size_t key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, size_t key_length); int prepare_explain_fields(select_result *result, List *field_list, uint8 explain_flags, bool is_analyze); int send_explain_fields(select_result *result, uint8 explain_flags, bool is_analyze); void make_explain_field_list(List &field_list, uint8 explain_flags, bool is_analyze); void make_explain_json_field_list(List &field_list, bool is_analyze); /** Clear the current error, if any. We do not clear is_fatal_error or is_fatal_sub_stmt_error since we assume this is never called if the fatal error is set. @todo: To silence an error, one should use Internal_error_handler mechanism. Issuing an error that can be possibly later "cleared" is not compatible with other installed error handlers and audit plugins. */ inline void clear_error(bool clear_diagnostics= 0) { DBUG_ENTER("clear_error"); if (get_stmt_da()->is_error() || clear_diagnostics) get_stmt_da()->reset_diagnostics_area(); is_slave_error= 0; if (killed == KILL_BAD_DATA) reset_killed(); my_errno= 0; DBUG_VOID_RETURN; } #ifndef EMBEDDED_LIBRARY inline bool vio_ok() const { return net.vio != 0; } /** Return FALSE if connection to client is broken. */ bool is_connected() { /* All system threads (e.g., the slave IO thread) are connected but not using vio. So this function always returns true for all system threads. */ return system_thread || (vio_ok() ? vio_is_connected(net.vio) : FALSE); } #else inline bool vio_ok() const { return TRUE; } inline bool is_connected() { return TRUE; } #endif void my_ok_with_recreate_info(const Recreate_info &info, ulong warn_count); /** Mark the current error as fatal. Warning: this does not set any error, it sets a property of the error, so must be followed or prefixed with my_error(). */ inline void fatal_error() { DBUG_ASSERT(get_stmt_da()->is_error() || killed); is_fatal_error= 1; DBUG_PRINT("error",("Fatal error set")); } /** TRUE if there is an error in the error stack. Please use this method instead of direct access to net.report_error. If TRUE, the current (sub)-statement should be aborted. The main difference between this member and is_fatal_error is that a fatal error can not be handled by a stored procedure continue handler, whereas a normal error can. To raise this flag, use my_error(). */ inline bool is_error() const { return m_stmt_da->is_error(); } void set_bulk_execution(void *bulk) { bulk_param= bulk; m_stmt_da->set_bulk_execution(MY_TEST(bulk)); } bool is_bulk_op() const { return MY_TEST(bulk_param); } /// Returns Diagnostics-area for the current statement. Diagnostics_area *get_stmt_da() { return m_stmt_da; } /// Returns Diagnostics-area for the current statement. const Diagnostics_area *get_stmt_da() const { return m_stmt_da; } /// Sets Diagnostics-area for the current statement. void set_stmt_da(Diagnostics_area *da) { m_stmt_da= da; } inline CHARSET_INFO *charset() const { return variables.character_set_client; } void update_charset(); void update_charset(CHARSET_INFO *character_set_client, CHARSET_INFO *collation_connection) { variables.character_set_client= character_set_client; variables.collation_connection= collation_connection; update_charset(); } void update_charset(CHARSET_INFO *character_set_client, CHARSET_INFO *collation_connection, CHARSET_INFO *character_set_results) { variables.character_set_client= character_set_client; variables.collation_connection= collation_connection; variables.character_set_results= character_set_results; update_charset(); } inline Query_arena *activate_stmt_arena_if_needed(Query_arena *backup) { if (state == Query_arena::STMT_SP_QUERY_ARGUMENTS) /* Caller uses the arena with state STMT_SP_QUERY_ARGUMENTS for stored routine's parameters. Lifetime of these objects spans a lifetime of stored routine call and freed every time the stored routine execution has been completed. That is the reason why switching to statement's arena is not performed for arguments, else we would observe increasing of memory usage while a stored routine be called over and over again. */ return NULL; /* Use the persistent arena if we are in a prepared statement or a stored procedure statement and we have not already changed to use this arena. */ if (!stmt_arena->is_conventional() && mem_root != stmt_arena->mem_root) { set_n_backup_active_arena(stmt_arena, backup); return stmt_arena; } return 0; } bool is_item_tree_change_register_required() { return !stmt_arena->is_conventional(); } void register_item_tree_change(Item **place) { /* TODO: check for OOM condition here */ if (is_item_tree_change_register_required()) nocheck_register_item_tree_change(place, *place, mem_root); } void change_item_tree(Item **place, Item *new_value) { DBUG_ENTER("THD::change_item_tree"); DBUG_PRINT("enter", ("Register: %p (%p) <- %p", *place, place, new_value)); register_item_tree_change(place); *place= new_value; DBUG_VOID_RETURN; } /** Make change in item tree after checking whether it needs registering @param place place where we should assign new value @param new_value place of the new value @details see check_and_register_item_tree_change details */ void check_and_register_item_tree(Item **place, Item **new_value) { if (!stmt_arena->is_conventional()) check_and_register_item_tree_change(place, new_value, mem_root); /* We have to use memcpy instead of *place= *new_value merge to avoid problems with strict aliasing. */ memcpy((char*) place, new_value, sizeof(*new_value)); } /* Cleanup statement parse state (parse tree, lex) and execution state after execution of a non-prepared SQL statement. */ void end_statement(); /* Mark thread to be killed, with optional error number and string. string is not released, so it has to be allocted on thd mem_root or be a global string Ensure that we don't replace a kill with a lesser one. For example if user has done 'kill_connection' we shouldn't replace it with KILL_QUERY. */ inline void set_killed(killed_state killed_arg, int killed_errno_arg= 0, const char *killed_err_msg_arg= 0) { mysql_mutex_lock(&LOCK_thd_kill); set_killed_no_mutex(killed_arg, killed_errno_arg, killed_err_msg_arg); mysql_mutex_unlock(&LOCK_thd_kill); } /* This is only used by THD::awake where we need to keep the lock mutex locked over some time. It's ok to have this inline, as in most cases killed_errno_arg will be a constant 0 and most of the function will disappear. */ inline void set_killed_no_mutex(killed_state killed_arg, int killed_errno_arg= 0, const char *killed_err_msg_arg= 0) { if (killed <= killed_arg) { killed= killed_arg; if (killed_errno_arg) { /* If alloc fails, we only remember the killed flag. The worst things that can happen is that we get a suboptimal error message. */ if (!killed_err) killed_err= (err_info*) my_malloc(PSI_INSTRUMENT_ME, sizeof(*killed_err), MYF(MY_WME)); if (likely(killed_err)) { killed_err->no= killed_errno_arg; ::strmake((char*) killed_err->msg, killed_err_msg_arg, sizeof(killed_err->msg)-1); } } } } int killed_errno(); void reset_killed(); inline void reset_kill_query() { if (killed < KILL_CONNECTION) { reset_killed(); mysys_var->abort= 0; } } inline void send_kill_message() { mysql_mutex_lock(&LOCK_thd_kill); int err= killed_errno(); if (err) my_message(err, killed_err ? killed_err->msg : ER_THD(this, err), MYF(0)); mysql_mutex_unlock(&LOCK_thd_kill); } /* return TRUE if we will abort query if we make a warning now */ inline bool really_abort_on_warning() { return (abort_on_warning && (!transaction->stmt.modified_non_trans_table || (variables.sql_mode & MODE_STRICT_ALL_TABLES))); } void set_status_var_init(); void reset_n_backup_open_tables_state(Open_tables_backup *backup); void restore_backup_open_tables_state(Open_tables_backup *backup); void reset_sub_statement_state(Sub_statement_state *backup, uint new_state); void restore_sub_statement_state(Sub_statement_state *backup); void store_slow_query_state(Sub_statement_state *backup); void reset_slow_query_state(); void add_slow_query_state(Sub_statement_state *backup); void set_n_backup_active_arena(Query_arena *set, Query_arena *backup); void restore_active_arena(Query_arena *set, Query_arena *backup); inline void get_binlog_format(enum_binlog_format *format, enum_binlog_format *current_format) { *format= (enum_binlog_format) variables.binlog_format; *current_format= current_stmt_binlog_format; } inline enum_binlog_format get_current_stmt_binlog_format() { return current_stmt_binlog_format; } inline void set_binlog_format(enum_binlog_format format, enum_binlog_format current_format) { DBUG_ENTER("set_binlog_format"); variables.binlog_format= format; current_stmt_binlog_format= current_format; DBUG_VOID_RETURN; } inline void set_binlog_format_stmt() { DBUG_ENTER("set_binlog_format_stmt"); variables.binlog_format= BINLOG_FORMAT_STMT; current_stmt_binlog_format= BINLOG_FORMAT_STMT; DBUG_VOID_RETURN; } /* @todo Make these methods private or remove them completely. Only decide_logging_format should call them. /Sven */ inline void set_current_stmt_binlog_format_row_if_mixed() { DBUG_ENTER("set_current_stmt_binlog_format_row_if_mixed"); /* This should only be called from decide_logging_format. @todo Once we have ensured this, uncomment the following statement, remove the big comment below that, and remove the in_sub_stmt==0 condition from the following 'if'. */ /* DBUG_ASSERT(in_sub_stmt == 0); */ /* If in a stored/function trigger, the caller should already have done the change. We test in_sub_stmt to prevent introducing bugs where people wouldn't ensure that, and would switch to row-based mode in the middle of executing a stored function/trigger (which is too late, see also reset_current_stmt_binlog_format_row()); this condition will make their tests fail and so force them to propagate the lex->binlog_row_based_if_mixed upwards to the caller. */ if ((wsrep_binlog_format(variables.binlog_format) == BINLOG_FORMAT_MIXED) && (in_sub_stmt == 0)) set_current_stmt_binlog_format_row(); DBUG_VOID_RETURN; } inline void set_current_stmt_binlog_format(enum_binlog_format format) { current_stmt_binlog_format= format; } inline void set_current_stmt_binlog_format_row() { DBUG_ENTER("set_current_stmt_binlog_format_row"); current_stmt_binlog_format= BINLOG_FORMAT_ROW; DBUG_VOID_RETURN; } /* Set binlog format temporarily to statement. Returns old format */ inline enum_binlog_format set_current_stmt_binlog_format_stmt() { enum_binlog_format orig_format= current_stmt_binlog_format; DBUG_ENTER("set_current_stmt_binlog_format_stmt"); current_stmt_binlog_format= BINLOG_FORMAT_STMT; DBUG_RETURN(orig_format); } inline void restore_stmt_binlog_format(enum_binlog_format format) { DBUG_ENTER("restore_stmt_binlog_format"); DBUG_ASSERT(!is_current_stmt_binlog_format_row()); current_stmt_binlog_format= format; DBUG_VOID_RETURN; } inline void reset_current_stmt_binlog_format_row() { DBUG_ENTER("reset_current_stmt_binlog_format_row"); /* If there are temporary tables, don't reset back to statement-based. Indeed it could be that: CREATE TEMPORARY TABLE t SELECT UUID(); # row-based # and row-based does not store updates to temp tables # in the binlog. INSERT INTO u SELECT * FROM t; # stmt-based and then the INSERT will fail as data inserted into t was not logged. So we continue with row-based until the temp table is dropped. If we are in a stored function or trigger, we mustn't reset in the middle of its execution (as the binary logging way of a stored function or trigger is decided when it starts executing, depending for example on the caller (for a stored function: if caller is SELECT or INSERT/UPDATE/DELETE...). */ DBUG_PRINT("debug", ("temporary_tables: %s, in_sub_stmt: %s, system_thread: %s", YESNO(has_temporary_tables()), YESNO(in_sub_stmt), show_system_thread(system_thread))); if (in_sub_stmt == 0) { if (wsrep_binlog_format(variables.binlog_format) == BINLOG_FORMAT_ROW) set_current_stmt_binlog_format_row(); else if (!has_temporary_tables()) set_current_stmt_binlog_format_stmt(); } DBUG_VOID_RETURN; } /** Set the current database; use deep copy of C-string. @param new_db a pointer to the new database name. @param new_db_len length of the new database name. Initialize the current database from a NULL-terminated string with length. If we run out of memory, we free the current database and return TRUE. This way the user will notice the error as there will be no current database selected (in addition to the error message set by malloc). @note This operation just sets {db, db_length}. Switching the current database usually involves other actions, like switching other database attributes including security context. In the future, this operation will be made private and more convenient interface will be provided. @return Operation status @retval FALSE Success @retval TRUE Out-of-memory error */ bool set_db(const LEX_CSTRING *new_db); /** Set the current database, without copying */ void reset_db(const LEX_CSTRING *new_db); /* Copy the current database to the argument. Use the current arena to allocate memory for a deep copy: current database may be freed after a statement is parsed but before it's executed. Can only be called by owner of thd (no mutex protection) */ bool copy_db_to(LEX_CSTRING *to) { if (db.str) { to->str= strmake(db.str, db.length); to->length= db.length; return to->str == NULL; /* True on error */ } /* No default database is set. In this case if it's guaranteed that no CTE can be used in the statement then we can throw an error right now at the parser stage. Otherwise the decision about throwing such a message must be postponed until a post-parser stage when we are able to resolve all CTE names as we don't need this message to be thrown for any CTE references. */ if (!lex->with_cte_resolution) my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); return TRUE; } /* Get db name or "". */ const char *get_db() { return safe_str(db.str); } thd_scheduler event_scheduler; public: inline Internal_error_handler *get_internal_handler() { return m_internal_handler; } /** Add an internal error handler to the thread execution context. @param handler the exception handler to add */ void push_internal_handler(Internal_error_handler *handler); private: /** Handle a sql condition. @param sql_errno the condition error number @param sqlstate the condition sqlstate @param level the condition level @param msg the condition message text @param[out] cond_hdl the sql condition raised, if any @return true if the condition is handled */ bool handle_condition(uint sql_errno, const char* sqlstate, Sql_condition::enum_warning_level *level, const char* msg, Sql_condition ** cond_hdl); public: /** Remove the error handler last pushed. */ Internal_error_handler *pop_internal_handler(); /** Raise an exception condition. @param code the MYSQL_ERRNO error code of the error */ void raise_error(uint code); /** Raise an exception condition, with a formatted message. @param code the MYSQL_ERRNO error code of the error */ void raise_error_printf(uint code, ...); /** Raise a completion condition (warning). @param code the MYSQL_ERRNO error code of the warning */ void raise_warning(uint code); /** Raise a completion condition (warning), with a formatted message. @param code the MYSQL_ERRNO error code of the warning */ void raise_warning_printf(uint code, ...); /** Raise a completion condition (note), with a fixed message. @param code the MYSQL_ERRNO error code of the note */ void raise_note(uint code); /** Raise an completion condition (note), with a formatted message. @param code the MYSQL_ERRNO error code of the note */ void raise_note_printf(uint code, ...); /** @brief Push an error message into MySQL error stack with line and position information. This function provides semantic action implementers with a way to push the famous "You have a syntax error near..." error message into the error stack, which is normally produced only if a parse error is discovered internally by the Bison generated parser. */ void parse_error(const char *err_text, const char *yytext) { Lex_input_stream *lip= &m_parser_state->m_lip; if (!yytext && !(yytext= lip->get_tok_start())) yytext= ""; /* Push an error into the error stack */ ErrConvString err(yytext, strlen(yytext), variables.character_set_client); my_printf_error(ER_PARSE_ERROR, ER_THD(this, ER_PARSE_ERROR), MYF(0), err_text, err.ptr(), lip->yylineno); } void parse_error(uint err_number, const char *yytext= 0) { parse_error(ER_THD(this, err_number), yytext); } void parse_error() { parse_error(ER_SYNTAX_ERROR); } #ifdef mysqld_error_find_printf_error_used void parse_error(const char *t) { } #endif private: /* Only the implementation of the SIGNAL and RESIGNAL statements is permitted to raise SQL conditions in a generic way, or to raise them by bypassing handlers (RESIGNAL). To raise a SQL condition, the code should use the public raise_error() or raise_warning() methods provided by class THD. */ friend class Sql_cmd_common_signal; friend class Sql_cmd_signal; friend class Sql_cmd_resignal; friend void push_warning(THD*, Sql_condition::enum_warning_level, uint, const char*); friend void my_message_sql(uint, const char *, myf); /** Raise a generic SQL condition. @param sql_errno the condition error number @param sqlstate the condition SQLSTATE @param level the condition level @param msg the condition message text @return The condition raised, or NULL */ Sql_condition* raise_condition(uint sql_errno, const char* sqlstate, Sql_condition::enum_warning_level level, const char* msg) { return raise_condition(sql_errno, sqlstate, level, Sql_user_condition_identity(), msg); } /** Raise a generic or a user defined SQL condition. @param ucid - the user condition identity (or an empty identity if not a user condition) @param sql_errno - the condition error number @param sqlstate - the condition SQLSTATE @param level - the condition level @param msg - the condition message text @return The condition raised, or NULL */ Sql_condition* raise_condition(uint sql_errno, const char* sqlstate, Sql_condition::enum_warning_level level, const Sql_user_condition_identity &ucid, const char* msg); Sql_condition* raise_condition(const Sql_condition *cond) { Sql_condition *raised= raise_condition(cond->get_sql_errno(), cond->get_sqlstate(), cond->get_level(), *cond/*Sql_user_condition_identity*/, cond->get_message_text()); if (raised) raised->copy_opt_attributes(cond); return raised; } private: void push_warning_truncated_priv(Sql_condition::enum_warning_level level, uint sql_errno, const char *type_str, const char *val) { DBUG_ASSERT(sql_errno == ER_TRUNCATED_WRONG_VALUE || sql_errno == ER_WRONG_VALUE); char buff[MYSQL_ERRMSG_SIZE]; CHARSET_INFO *cs= &my_charset_latin1; cs->cset->snprintf(cs, buff, sizeof(buff), ER_THD(this, sql_errno), type_str, val); /* Note: the format string can vary between ER_TRUNCATED_WRONG_VALUE and ER_WRONG_VALUE, but the code passed to push_warning() is always ER_TRUNCATED_WRONG_VALUE. This is intentional. */ push_warning(this, level, ER_TRUNCATED_WRONG_VALUE, buff); } public: void push_warning_truncated_wrong_value(Sql_condition::enum_warning_level level, const char *type_str, const char *val) { return push_warning_truncated_priv(level, ER_TRUNCATED_WRONG_VALUE, type_str, val); } void push_warning_wrong_value(Sql_condition::enum_warning_level level, const char *type_str, const char *val) { return push_warning_truncated_priv(level, ER_WRONG_VALUE, type_str, val); } void push_warning_truncated_wrong_value(const char *type_str, const char *val) { return push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_WARN, type_str, val); } void push_warning_truncated_value_for_field(Sql_condition::enum_warning_level level, const char *type_str, const char *val, const char *db_name, const char *table_name, const char *name) { DBUG_ASSERT(name); char buff[MYSQL_ERRMSG_SIZE]; CHARSET_INFO *cs= &my_charset_latin1; if (!db_name) db_name= ""; if (!table_name) table_name= ""; cs->cset->snprintf(cs, buff, sizeof(buff), ER_THD(this, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), type_str, val, db_name, table_name, name, (ulong) get_stmt_da()->current_row_for_warning()); push_warning(this, level, ER_TRUNCATED_WRONG_VALUE, buff); } void push_warning_wrong_or_truncated_value(Sql_condition::enum_warning_level level, bool totally_useless_value, const char *type_str, const char *val, const char *db_name, const char *table_name, const char *field_name) { if (field_name) push_warning_truncated_value_for_field(level, type_str, val, db_name, table_name, field_name); else if (totally_useless_value) push_warning_wrong_value(level, type_str, val); else push_warning_truncated_wrong_value(level, type_str, val); } public: /** Overloaded to guard query/query_length fields */ void set_statement(Statement *stmt) override; inline void set_command(enum enum_server_command command) { DBUG_ASSERT(command != COM_SLEEP); m_command= command; #ifdef HAVE_PSI_THREAD_INTERFACE PSI_STATEMENT_CALL(set_thread_command)(m_command); #endif } /* As sleep needs a bit of special handling, we have a special case for it */ inline void mark_connection_idle() { proc_info= 0; m_command= COM_SLEEP; #ifdef HAVE_PSI_THREAD_INTERFACE PSI_STATEMENT_CALL(set_thread_command)(m_command); #endif } inline enum enum_server_command get_command() const { return m_command; } /** Assign a new value to thd->query and thd->query_id and mysys_var. Protected with LOCK_thd_data mutex. */ void set_query(char *query_arg, size_t query_length_arg, CHARSET_INFO *cs_arg) { set_query(CSET_STRING(query_arg, query_length_arg, cs_arg)); } void set_query(char *query_arg, size_t query_length_arg) /*Mutex protected*/ { set_query(CSET_STRING(query_arg, query_length_arg, charset())); } void set_query(const CSET_STRING &string_arg) { mysql_mutex_lock(&LOCK_thd_data); set_query_inner(string_arg); mysql_mutex_unlock(&LOCK_thd_data); PSI_CALL_set_thread_info(query(), query_length()); } void reset_query() /* Mutex protected */ { set_query(CSET_STRING()); } void set_query_and_id(char *query_arg, uint32 query_length_arg, CHARSET_INFO *cs, query_id_t new_query_id); void set_query_id(query_id_t new_query_id) { query_id= new_query_id; #ifdef WITH_WSREP if (WSREP_NNULL(this)) { set_wsrep_next_trx_id(query_id); WSREP_DEBUG("assigned new next trx id: %" PRIu64, wsrep_next_trx_id()); } #endif /* WITH_WSREP */ } void set_open_tables(TABLE *open_tables_arg) { mysql_mutex_lock(&LOCK_thd_data); open_tables= open_tables_arg; mysql_mutex_unlock(&LOCK_thd_data); } void set_mysys_var(struct st_my_thread_var *new_mysys_var); void enter_locked_tables_mode(enum_locked_tables_mode mode_arg) { DBUG_ASSERT(locked_tables_mode == LTM_NONE); if (mode_arg == LTM_LOCK_TABLES) { /* When entering LOCK TABLES mode we should set explicit duration for all metadata locks acquired so far in order to avoid releasing them till UNLOCK TABLES statement. We don't do this when entering prelocked mode since sub-statements don't release metadata locks and restoring status-quo after leaving prelocking mode gets complicated. */ mdl_context.set_explicit_duration_for_all_locks(); } locked_tables_mode= mode_arg; } void leave_locked_tables_mode(); /* Relesae transactional locks if there are no active transactions */ void release_transactional_locks() { if (!in_active_multi_stmt_transaction()) mdl_context.release_transactional_locks(this); } int decide_logging_format(TABLE_LIST *tables); /* In Some cases when decide_logging_format is called it does not have all information to decide the logging format. So that cases we call decide_logging_format_2 at later stages in execution. One example would be binlog format for insert on duplicate key (IODKU) but column with unique key is not inserted. We do not have inserted columns info when we call decide_logging_format so on later stage we call reconsider_logging_format_for_iodup() */ void reconsider_logging_format_for_iodup(TABLE *table); enum need_invoker { INVOKER_NONE=0, INVOKER_USER, INVOKER_ROLE}; void binlog_invoker(bool role) { m_binlog_invoker= role ? INVOKER_ROLE : INVOKER_USER; } enum need_invoker need_binlog_invoker() { return m_binlog_invoker; } void get_definer(LEX_USER *definer, bool role); void set_invoker(const LEX_CSTRING *user, const LEX_CSTRING *host) { invoker.user= *user; invoker.host= *host; } LEX_CSTRING get_invoker_user() { return invoker.user; } LEX_CSTRING get_invoker_host() { return invoker.host; } bool has_invoker() { return invoker.user.length > 0; } void print_aborted_warning(uint threshold, const char *reason) { if (global_system_variables.log_warnings > threshold) { char real_ip_str[64]; real_ip_str[0]= 0; /* For proxied connections, add the real IP to the warning message */ if (net.using_proxy_protocol && net.vio) { if(net.vio->localhost) snprintf(real_ip_str, sizeof(real_ip_str), " real ip: 'localhost'"); else { char buf[INET6_ADDRSTRLEN]; if (!vio_getnameinfo((sockaddr *)&(net.vio->remote), buf, sizeof(buf),NULL, 0, NI_NUMERICHOST)) { snprintf(real_ip_str, sizeof(real_ip_str), " real ip: '%s'",buf); } } } Security_context *sctx= &main_security_ctx; sql_print_warning(ER_THD(this, ER_NEW_ABORTING_CONNECTION), thread_id, (db.str ? db.str : "unconnected"), sctx->user ? sctx->user : "unauthenticated", sctx->host_or_ip, real_ip_str, reason); } } public: void clear_wakeup_ready() { wakeup_ready= false; } /* Sleep waiting for others to wake us up with signal_wakeup_ready(). Must call clear_wakeup_ready() before waiting. */ void wait_for_wakeup_ready(); /* Wake this thread up from wait_for_wakeup_ready(). */ void signal_wakeup_ready(); void add_status_to_global() { DBUG_ASSERT(status_in_global == 0); mysql_mutex_lock(&LOCK_status); add_to_status(&global_status_var, &status_var); /* Mark that this THD status has already been added in global status */ status_var.global_memory_used= 0; status_in_global= 1; mysql_mutex_unlock(&LOCK_status); } wait_for_commit *wait_for_commit_ptr; int wait_for_prior_commit(bool allow_kill=true) { if (wait_for_commit_ptr) return wait_for_commit_ptr->wait_for_prior_commit(this, allow_kill); return 0; } void wakeup_subsequent_commits(int wakeup_error) { if (wait_for_commit_ptr) wait_for_commit_ptr->wakeup_subsequent_commits(wakeup_error); } wait_for_commit *suspend_subsequent_commits() { wait_for_commit *suspended= wait_for_commit_ptr; wait_for_commit_ptr= NULL; return suspended; } void resume_subsequent_commits(wait_for_commit *suspended) { DBUG_ASSERT(!wait_for_commit_ptr); wait_for_commit_ptr= suspended; } void mark_transaction_to_rollback(bool all); bool internal_transaction() { return transaction != &default_transaction; } private: /** The current internal error handler for this thread, or NULL. */ Internal_error_handler *m_internal_handler; /** The lex to hold the parsed tree of conventional (non-prepared) queries. Whereas for prepared and stored procedure statements we use an own lex instance for each new query, for conventional statements we reuse the same lex. (@see mysql_parse for details). */ LEX main_lex; /** This memory root is used for two purposes: - for conventional queries, to allocate structures stored in main_lex during parsing, and allocate runtime data (execution plan, etc.) during execution. - for prepared queries, only to allocate runtime data. The parsed tree itself is reused between executions and thus is stored elsewhere. */ MEM_ROOT main_mem_root; Diagnostics_area main_da; Diagnostics_area *m_stmt_da; /** It will be set if CURRENT_USER() or CURRENT_ROLE() is called in account management statements or default definer is set in CREATE/ALTER SP, SF, Event, TRIGGER or VIEW statements. Current user or role will be binlogged into Query_log_event if m_binlog_invoker is not NONE; It will be stored into invoker_host and invoker_user by SQL thread. */ enum need_invoker m_binlog_invoker; /** It points to the invoker in the Query_log_event. SQL thread use it as the default definer in CREATE/ALTER SP, SF, Event, TRIGGER or VIEW statements or current user in account management statements if it is not NULL. */ AUTHID invoker; public: Session_tracker session_tracker; /* Flag, mutex and condition for a thread to wait for a signal from another thread. Currently used to wait for group commit to complete, and COND_wakeup_ready is used for threads to wait on semi-sync ACKs (though is protected by Repl_semi_sync_master::LOCK_binlog). Note the following relationships between these two use-cases when using rpl_semi_sync_master_wait_point=AFTER_SYNC during group commit: 1) Non-leader threads use COND_wakeup_ready to wait for the leader thread to complete binlog commit. 2) The leader thread uses COND_wakeup_ready to await ACKs from the replica before signalling the non-leader threads to wake up. With wait_point=AFTER_COMMIT, there is no overlap as binlogging has finished, so COND_wakeup_ready is safe to re-use. */ bool wakeup_ready; mysql_mutex_t LOCK_wakeup_ready; mysql_cond_t COND_wakeup_ready; /* The GTID assigned to the last commit. If no GTID was assigned to any commit so far, this is indicated by last_commit_gtid.seq_no == 0. */ private: rpl_gtid m_last_commit_gtid; public: rpl_gtid get_last_commit_gtid() { return m_last_commit_gtid; } void set_last_commit_gtid(rpl_gtid >id); LF_PINS *tdc_hash_pins; LF_PINS *xid_hash_pins; bool fix_xid_hash_pins(); const XID *get_xid() const { #ifdef WITH_WSREP if (!wsrep_xid.is_null()) return &wsrep_xid; #endif /* WITH_WSREP */ return (transaction->xid_state.is_explicit_XA() ? transaction->xid_state.get_xid() : &transaction->implicit_xid); } /* Members related to temporary tables. */ public: /* Opened table states. */ enum Temporary_table_state { TMP_TABLE_IN_USE, TMP_TABLE_NOT_IN_USE, TMP_TABLE_ANY }; bool has_thd_temporary_tables(); bool has_temporary_tables(); TABLE *create_and_open_tmp_table(LEX_CUSTRING *frm, const char *path, const char *db, const char *table_name, bool open_internal_tables); TABLE *find_temporary_table(const char *db, const char *table_name, Temporary_table_state state= TMP_TABLE_IN_USE); TABLE *find_temporary_table(const TABLE_LIST *tl, Temporary_table_state state= TMP_TABLE_IN_USE); TMP_TABLE_SHARE *find_tmp_table_share_w_base_key(const char *key, uint key_length); TMP_TABLE_SHARE *find_tmp_table_share(const char *db, const char *table_name); TMP_TABLE_SHARE *find_tmp_table_share(const TABLE_LIST *tl); TMP_TABLE_SHARE *find_tmp_table_share(const char *key, size_t key_length); bool open_temporary_table(TABLE_LIST *tl); bool open_temporary_tables(TABLE_LIST *tl); bool close_temporary_tables(); bool rename_temporary_table(TABLE *table, const LEX_CSTRING *db, const LEX_CSTRING *table_name); bool drop_temporary_table(TABLE *table, bool *is_trans, bool delete_table); bool rm_temporary_table(handlerton *hton, const char *path); void mark_tmp_tables_as_free_for_reuse(); void mark_tmp_table_as_free_for_reuse(TABLE *table); TMP_TABLE_SHARE* save_tmp_table_share(TABLE *table); void restore_tmp_table_share(TMP_TABLE_SHARE *share); void close_unused_temporary_table_instances(const TABLE_LIST *tl); private: /* Whether a lock has been acquired? */ bool m_tmp_tables_locked; uint create_tmp_table_def_key(char *key, const char *db, const char *table_name); TMP_TABLE_SHARE *create_temporary_table(LEX_CUSTRING *frm, const char *path, const char *db, const char *table_name); TABLE *find_temporary_table(const char *key, uint key_length, Temporary_table_state state); TABLE *open_temporary_table(TMP_TABLE_SHARE *share, const char *alias); bool find_and_use_tmp_table(const TABLE_LIST *tl, TABLE **out_table); bool use_temporary_table(TABLE *table, TABLE **out_table); void close_temporary_table(TABLE *table); bool log_events_and_free_tmp_shares(); bool free_tmp_table_share(TMP_TABLE_SHARE *share, bool delete_table); void free_temporary_table(TABLE *table); bool lock_temporary_tables(); void unlock_temporary_tables(); inline uint tmpkeyval(TMP_TABLE_SHARE *share) { return uint4korr(share->table_cache_key.str + share->table_cache_key.length - 4); } inline TMP_TABLE_SHARE *tmp_table_share(TABLE *table) { DBUG_ASSERT(table->s->tmp_table); return static_cast(table->s); } public: thd_async_state async_state; #ifdef HAVE_REPLICATION /* If we do a purge of binary logs, log index info of the threads that are currently reading it needs to be adjusted. To do that each thread that is using LOG_INFO needs to adjust the pointer to it */ LOG_INFO *current_linfo; Slave_info *slave_info; void set_current_linfo(LOG_INFO *linfo); void reset_current_linfo() { set_current_linfo(0); } int register_slave(uchar *packet, size_t packet_length); void unregister_slave(); bool is_binlog_dump_thread(); #endif inline ulong wsrep_binlog_format(ulong binlog_format) const { #ifdef WITH_WSREP // During CTAS we force ROW format if (wsrep_ctas) return BINLOG_FORMAT_ROW; else return ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? wsrep_forced_binlog_format : binlog_format); #else return (binlog_format); #endif } #ifdef WITH_WSREP bool wsrep_applier; /* dedicated slave applier thread */ bool wsrep_applier_closing; /* applier marked to close */ bool wsrep_client_thread; /* to identify client threads*/ query_id_t wsrep_last_query_id; XID wsrep_xid; /** This flag denotes that record locking should be skipped during INSERT, gap locking during SELECT, and write-write conflicts due to innodb snapshot isolation during DELETE. Only used by the streaming replication thread that only modifies the mysql.wsrep_streaming_log table. */ my_bool wsrep_skip_locking; mysql_cond_t COND_wsrep_thd; // changed from wsrep_seqno_t to wsrep_trx_meta_t in wsrep API rev 75 uint32 wsrep_rand; rpl_group_info *wsrep_rgi; bool wsrep_converted_lock_session; char wsrep_info[128]; /* string for dynamic proc info */ ulong wsrep_retry_counter; // of autocommit bool wsrep_PA_safe; char* wsrep_retry_query; size_t wsrep_retry_query_len; enum enum_server_command wsrep_retry_command; enum wsrep_consistency_check_mode wsrep_consistency_check; std::vector wsrep_status_vars; int wsrep_mysql_replicated; const char* wsrep_TOI_pre_query; /* a query to apply before the actual TOI query */ size_t wsrep_TOI_pre_query_len; wsrep_po_handle_t wsrep_po_handle; size_t wsrep_po_cnt; void *wsrep_apply_format; uchar* wsrep_rbr_buf; wsrep_gtid_t wsrep_sync_wait_gtid; uint64 wsrep_last_written_gtid_seqno; uint64 wsrep_current_gtid_seqno; ulong wsrep_affected_rows; bool wsrep_has_ignored_error; /* true if wsrep_on was ON in last wsrep_on_update */ bool wsrep_was_on; /* When enabled, do not replicate/binlog updates from the current table that's being processed. At the moment, it is used to keep mysql.gtid_slave_pos table updates from being replicated to other nodes via galera replication. */ bool wsrep_ignore_table; /* thread who has started kill for this THD protected by LOCK_thd_data*/ my_thread_id wsrep_aborter; /* Kill signal used, if thread was killed by manual KILL. Protected by LOCK_thd_kill. */ std::atomic wsrep_abort_by_kill; /* */ struct err_info* wsrep_abort_by_kill_err; #ifndef DBUG_OFF int wsrep_killed_state; #endif /* DBUG_OFF */ /* true if BF abort is observed in do_command() right after reading client's packet, and if the client has sent PS execute command. */ bool wsrep_delayed_BF_abort; // true if this transaction is CREATE TABLE AS SELECT (CTAS) bool wsrep_ctas; /* Transaction id: * m_wsrep_next_trx_id is assigned on the first query after wsrep_next_trx_id() return WSREP_UNDEFINED_TRX_ID * Each storage engine must assign value of wsrep_next_trx_id() when the transaction starts. * Effective transaction id is returned via wsrep_trx_id() */ /* Return effective transaction id */ wsrep_trx_id_t wsrep_trx_id() const { return m_wsrep_client_state.transaction().id().get(); } /* Set next trx id */ void set_wsrep_next_trx_id(query_id_t query_id) { m_wsrep_next_trx_id = (wsrep_trx_id_t) query_id; } /* Return next trx id */ wsrep_trx_id_t wsrep_next_trx_id() const { return m_wsrep_next_trx_id; } /* If node is async slave and have parallel execution, wait for prior commits. */ bool wsrep_parallel_slave_wait_for_prior_commit(); private: wsrep_trx_id_t m_wsrep_next_trx_id; /* cast from query_id_t */ /* wsrep-lib */ Wsrep_mutex m_wsrep_mutex; Wsrep_condition_variable m_wsrep_cond; Wsrep_client_service m_wsrep_client_service; Wsrep_client_state m_wsrep_client_state; public: Wsrep_client_state& wsrep_cs() { return m_wsrep_client_state; } const Wsrep_client_state& wsrep_cs() const { return m_wsrep_client_state; } const wsrep::transaction& wsrep_trx() const { return m_wsrep_client_state.transaction(); } const wsrep::streaming_context& wsrep_sr() const { return m_wsrep_client_state.transaction().streaming_context(); } /* Pointer to applier service for streaming THDs. This is needed to be able to delete applier service object in case of background rollback. */ Wsrep_applier_service* wsrep_applier_service; /* wait_for_commit struct for binlog group commit */ wait_for_commit wsrep_wfc; #endif /* WITH_WSREP */ /* Handling of timeouts for commands */ thr_timer_t query_timer; public: void set_query_timer() { #ifndef EMBEDDED_LIBRARY /* Don't start a query timer if - If timeouts are not set - if we are in a stored procedure or sub statement - If this is a slave thread - If we already have set a timeout (happens when running prepared statements that calls mysql_execute_command()) */ if (!variables.max_statement_time || spcont || in_sub_stmt || slave_thread || query_timer.expired == 0) return; thr_timer_settime(&query_timer, variables.max_statement_time); #endif } void reset_query_timer() { #ifndef EMBEDDED_LIBRARY if (spcont || in_sub_stmt || slave_thread) return; if (!query_timer.expired) thr_timer_end(&query_timer); #endif } bool restore_set_statement_var() { return main_lex.restore_set_statement_var(); } /* Copy relevant `stmt` transaction flags to `all` transaction. */ void merge_unsafe_rollback_flags() { if (transaction->stmt.modified_non_trans_table) transaction->all.modified_non_trans_table= TRUE; transaction->all.m_unsafe_rollback_flags|= (transaction->stmt.m_unsafe_rollback_flags & (THD_TRANS::MODIFIED_NON_TRANS_TABLE | THD_TRANS::DID_WAIT | THD_TRANS::CREATED_TEMP_TABLE | THD_TRANS::DROPPED_TEMP_TABLE | THD_TRANS::DID_DDL | THD_TRANS::EXECUTED_TABLE_ADMIN_CMD)); } uint get_net_wait_timeout() { if (in_active_multi_stmt_transaction()) { if (transaction->all.is_trx_read_write()) { if (variables.idle_write_transaction_timeout > 0) return variables.idle_write_transaction_timeout; } else { if (variables.idle_readonly_transaction_timeout > 0) return variables.idle_readonly_transaction_timeout; } if (variables.idle_transaction_timeout > 0) return variables.idle_transaction_timeout; } return variables.net_wait_timeout; } /** Switch to a sublex, to parse a substatement or an expression. */ void set_local_lex(sp_lex_local *sublex) { DBUG_ASSERT(lex->sphead); lex= sublex; /* Reset part of parser state which needs this. */ m_parser_state->m_yacc.reset_before_substatement(); } /** Switch back from a sublex (currently pointed by this->lex) to the old lex. Sublex is merged to "oldlex" and this->lex is set to "oldlex". This method is called after parsing a substatement or an expression. set_local_lex() must be previously called. @param oldlex - The old lex which was active before set_local_lex(). @returns - false on success, true on error (failed to merge LEX's). See also sp_head::merge_lex(). */ bool restore_from_local_lex_to_old_lex(LEX *oldlex); Item *sp_fix_func_item(Item **it_addr); Item *sp_prepare_func_item(Item **it_addr, uint cols= 1); bool sp_eval_expr(Field *result_field, Item **expr_item_ptr); bool sql_parser(LEX *old_lex, LEX *lex, char *str, uint str_len, bool stmt_prepare_mode); myf get_utf8_flag() const { return (variables.old_behavior & OLD_MODE_UTF8_IS_UTF8MB3 ? MY_UTF8_IS_UTF8MB3 : 0); } /** Save current lex to the output parameter and reset it to point to main_lex. This method is called from mysql_client_binlog_statement() to temporary @param[out] backup_lex original value of current lex */ void backup_and_reset_current_lex(LEX **backup_lex) { *backup_lex= lex; lex= &main_lex; } /** Restore current lex to its original value it had before calling the method backup_and_reset_current_lex(). @param backup_lex original value of current lex */ void restore_current_lex(LEX *backup_lex) { lex= backup_lex; } bool should_collect_handler_stats() { /* We update handler_stats.active to ensure that we have the same value across the whole statement. This function is only called from TABLE::init() so the value will be the same for the whole statement. */ handler_stats.active= ((variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_ENGINE) || lex->analyze_stmt); return handler_stats.active; } /* Return true if we should create a note when an unusable key is found */ bool give_notes_for_unusable_keys() { return ((variables.note_verbosity & (NOTE_VERBOSITY_UNUSABLE_KEYS)) || (lex->describe && // Is EXPLAIN (variables.note_verbosity & NOTE_VERBOSITY_EXPLAIN))); } }; /* Start a new independent transaction for the THD. The old one is stored in this object and restored when calling restore_old_transaction() or when the object is freed */ class start_new_trans { /* container for handler's private per-connection data */ Ha_data old_ha_data[MAX_HA]; struct THD::st_transactions *old_transaction, new_transaction; Open_tables_backup open_tables_state_backup; MDL_savepoint mdl_savepoint; PSI_transaction_locker *m_transaction_psi; THD *org_thd; uint in_sub_stmt; uint server_status; my_bool wsrep_on; public: start_new_trans(THD *thd); ~start_new_trans() { destroy(); } void destroy() { if (org_thd) // Safety restore_old_transaction(); new_transaction.free(); } void restore_old_transaction(); }; /** A short cut for thd->get_stmt_da()->set_ok_status(). */ inline void my_ok(THD *thd, ulonglong affected_rows_arg= 0, ulonglong id= 0, const char *message= NULL) { thd->set_row_count_func(affected_rows_arg); thd->set_affected_rows(affected_rows_arg); thd->get_stmt_da()->set_ok_status(affected_rows_arg, id, message); } /** A short cut for thd->get_stmt_da()->set_eof_status(). */ inline void my_eof(THD *thd) { thd->set_row_count_func(-1); thd->get_stmt_da()->set_eof_status(thd); TRANSACT_TRACKER(add_trx_state(thd, TX_RESULT_SET)); } #define tmp_disable_binlog(A) \ {ulonglong tmp_disable_binlog__save_options= (A)->variables.option_bits; \ (A)->variables.option_bits&= ~OPTION_BIN_LOG; \ (A)->variables.option_bits|= OPTION_BIN_TMP_LOG_OFF; #define reenable_binlog(A) \ (A)->variables.option_bits= tmp_disable_binlog__save_options; } inline date_conv_mode_t sql_mode_for_dates(THD *thd) { static_assert((ulonglong(date_conv_mode_t::KNOWN_MODES) & ulonglong(time_round_mode_t::KNOWN_MODES)) == 0, "date_conv_mode_t and time_round_mode_t must use different " "bit values"); static_assert(MODE_NO_ZERO_DATE == date_mode_t::NO_ZERO_DATE && MODE_NO_ZERO_IN_DATE == date_mode_t::NO_ZERO_IN_DATE && MODE_INVALID_DATES == date_mode_t::INVALID_DATES, "sql_mode_t and date_mode_t values must be equal"); return date_conv_mode_t(thd->variables.sql_mode & (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE | MODE_INVALID_DATES)); } /* Used to hold information about file and file structure in exchange via non-DB file (...INTO OUTFILE..., ...LOAD DATA...) XXX: We never call destructor for objects of this class. */ class sql_exchange :public Sql_alloc { public: enum enum_filetype filetype; /* load XML, Added by Arnold & Erik */ const char *file_name; String *field_term,*enclosed,*line_term,*line_start,*escaped; bool opt_enclosed; bool dumpfile; ulong skip_lines; CHARSET_INFO *cs; sql_exchange(const char *name, bool dumpfile_flag, enum_filetype filetype_arg= FILETYPE_CSV); bool escaped_given(void) const; }; /* This is used to get result from a select */ class JOIN; /* Pure interface for sending tabular data */ class select_result_sink: public Sql_alloc { public: THD *thd; select_result_sink(THD *thd_arg): thd(thd_arg) {} inline int send_data_with_check(List &items, SELECT_LEX_UNIT *u, ha_rows sent) { if (u->lim.check_offset(sent)) return 0; if (u->thd->killed == ABORT_QUERY) return 0; return send_data(items); } /* send_data returns 0 on ok, 1 on error and -1 if data was ignored, for example for a duplicate row entry written to a temp table. */ virtual int send_data(List &items)=0; virtual ~select_result_sink() = default; // Used in cursors to initialize and reset void reinit(THD *thd_arg) { thd= thd_arg; } }; class select_result_interceptor; /* Interface for sending tabular data, together with some other stuff: - Primary purpose seems to be seding typed tabular data: = the DDL is sent with send_fields() = the rows are sent with send_data() Besides that, - there seems to be an assumption that the sent data is a result of SELECT_LEX_UNIT *unit, - nest_level is used by SQL parser */ class select_result :public select_result_sink { protected: /* All descendant classes have their send_data() skip the first unit->offset_limit_cnt rows sent. Select_materialize also uses unit->get_column_types(). */ SELECT_LEX_UNIT *unit; /* Something used only by the parser: */ public: ha_rows est_records; /* estimated number of records in the result */ select_result(THD *thd_arg): select_result_sink(thd_arg), est_records(0) {} void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; } virtual ~select_result() = default; /** Change wrapped select_result. Replace the wrapped result object with new_result and call prepare() and prepare2() on new_result. This base class implementation doesn't wrap other select_results. @param new_result The new result object to wrap around @retval false Success @retval true Error */ virtual bool change_result(select_result *new_result) { return false; } virtual int prepare(List &list, SELECT_LEX_UNIT *u) { unit= u; return 0; } virtual int prepare2(JOIN *join) { return 0; } /* Because of peculiarities of prepared statements protocol we need to know number of columns in the result set (if there is a result set) apart from sending columns metadata. */ virtual uint field_count(List &fields) const { return fields.elements; } virtual bool send_result_set_metadata(List &list, uint flags)=0; virtual bool initialize_tables (JOIN *join) { return 0; } virtual bool send_eof()=0; /** Check if this query returns a result set and therefore is allowed in cursors and set an error message if it is not the case. @retval FALSE success @retval TRUE error, an error message is set */ virtual bool check_simple_select() const; virtual void abort_result_set() {} virtual void reset_for_next_ps_execution(); void set_thd(THD *thd_arg) { thd= thd_arg; } void reinit(THD *thd_arg) { select_result_sink::reinit(thd_arg); unit= NULL; } #ifdef EMBEDDED_LIBRARY virtual void begin_dataset() {} #else void begin_dataset() {} #endif virtual void update_used_tables() {} /* this method is called just before the first row of the table can be read */ virtual void prepare_to_read_rows() {} void remove_offset_limit() { unit->lim.remove_offset(); } /* This returns - NULL if the class sends output row to the client - this if the output is set elsewhere (a file, @variable, or table). */ virtual select_result_interceptor *result_interceptor()=0; /* This method is used to distinguish an normal SELECT from the cursor structure discovery for cursor%ROWTYPE routine variables. If this method returns "true", then a SELECT execution performs only all preparation stages, but does not fetch any rows. */ virtual bool view_structure_only() const { return false; } }; /* This is a select_result_sink which simply writes all data into a (temporary) table. Creation/deletion of the table is outside of the scope of the class It is aimed at capturing SHOW EXPLAIN output, so: - Unlike select_result class, we don't assume that the sent data is an output of a SELECT_LEX_UNIT (and so we don't apply "LIMIT x,y" from the unit) - We don't try to convert the target table to MyISAM */ class select_result_explain_buffer : public select_result_sink { public: select_result_explain_buffer(THD *thd_arg, TABLE *table_arg) : select_result_sink(thd_arg), dst_table(table_arg) {}; TABLE *dst_table; /* table to write into */ /* The following is called in the child thread: */ int send_data(List &items) override; }; /* This is a select_result_sink which stores the data in text form. It is only used to save EXPLAIN output. */ class select_result_text_buffer : public select_result_sink { public: select_result_text_buffer(THD *thd_arg): select_result_sink(thd_arg) {} int send_data(List &items) override; bool send_result_set_metadata(List &fields, uint flag); void save_to(String *res); private: int append_row(List &items, bool send_names); List rows; int n_columns; }; /* Base class for select_result descendands which intercept and transform result set rows. As the rows are not sent to the client, sending of result set metadata should be suppressed as well. */ class select_result_interceptor: public select_result { public: select_result_interceptor(THD *thd_arg): select_result(thd_arg), suppress_my_ok(false) { DBUG_ENTER("select_result_interceptor::select_result_interceptor"); DBUG_PRINT("enter", ("this %p", this)); DBUG_VOID_RETURN; } /* Remove gcc warning */ uint field_count(List &fields) const override { return 0; } bool send_result_set_metadata(List &fields, uint flag) override { return FALSE; } select_result_interceptor *result_interceptor() override { return this; } /* Instruct the object to not call my_ok(). Client output will be handled elsewhere. (this is used by ANALYZE $stmt feature). */ void disable_my_ok_calls() { suppress_my_ok= true; } void reinit(THD *thd_arg) { select_result::reinit(thd_arg); suppress_my_ok= false; } protected: bool suppress_my_ok; }; class sp_cursor_statistics { protected: ulonglong m_fetch_count; // Number of FETCH commands since last OPEN ulonglong m_row_count; // Number of successful FETCH since last OPEN bool m_found; // If last FETCH fetched a row public: sp_cursor_statistics() :m_fetch_count(0), m_row_count(0), m_found(false) { } bool found() const { return m_found; } ulonglong row_count() const { return m_row_count; } ulonglong fetch_count() const { return m_fetch_count; } void reset() { *this= sp_cursor_statistics(); } }; /* A mediator between stored procedures and server side cursors */ class sp_lex_keeper; class sp_cursor: public sp_cursor_statistics { private: /// An interceptor of cursor result set used to implement /// FETCH INTO . class Select_fetch_into_spvars: public select_result_interceptor { List *spvar_list; uint field_count; bool m_view_structure_only; bool send_data_to_variable_list(List &vars, List &items); public: Select_fetch_into_spvars(THD *thd_arg, bool view_structure_only) :select_result_interceptor(thd_arg), m_view_structure_only(view_structure_only) {} void reset(THD *thd_arg) { select_result_interceptor::reinit(thd_arg); spvar_list= NULL; field_count= 0; } uint get_field_count() { return field_count; } void set_spvar_list(List *vars) { spvar_list= vars; } bool send_eof() override { return FALSE; } int send_data(List &items) override; int prepare(List &list, SELECT_LEX_UNIT *u) override; bool view_structure_only() const override { return m_view_structure_only; } }; public: sp_cursor() :result(NULL, false), m_lex_keeper(NULL), server_side_cursor(NULL) { } sp_cursor(THD *thd_arg, sp_lex_keeper *lex_keeper, bool view_structure_only) :result(thd_arg, view_structure_only), m_lex_keeper(lex_keeper), server_side_cursor(NULL) {} virtual ~sp_cursor() { destroy(); } sp_lex_keeper *get_lex_keeper() { return m_lex_keeper; } int open(THD *thd); int close(THD *thd); my_bool is_open() { return MY_TEST(server_side_cursor); } int fetch(THD *, List *vars, bool error_on_no_data); bool export_structure(THD *thd, Row_definition_list *list); void reset(THD *thd_arg, sp_lex_keeper *lex_keeper) { sp_cursor_statistics::reset(); result.reinit(thd_arg); m_lex_keeper= lex_keeper; server_side_cursor= NULL; } private: Select_fetch_into_spvars result; sp_lex_keeper *m_lex_keeper; Server_side_cursor *server_side_cursor; void destroy(); }; class select_send :public select_result { /** True if we have sent result set metadata to the client. In this case the client always expects us to end the result set with an eof or error packet */ bool is_result_set_started; public: select_send(THD *thd_arg): select_result(thd_arg), is_result_set_started(FALSE) {} bool send_result_set_metadata(List &list, uint flags) override; int send_data(List &items) override; bool send_eof() override; bool check_simple_select() const override { return FALSE; } void abort_result_set() override; void reset_for_next_ps_execution() override; select_result_interceptor *result_interceptor() override { return NULL; } }; /* We need this class, because select_send::send_eof() will call ::my_eof. See also class Protocol_discard. */ class select_send_analyze : public select_send { bool send_result_set_metadata(List &list, uint flags) override { return 0; } bool send_eof() override { return 0; } void abort_result_set() override {} public: select_send_analyze(THD *thd_arg): select_send(thd_arg) {} }; class select_to_file :public select_result_interceptor { protected: sql_exchange *exchange; File file; IO_CACHE cache; ha_rows row_count; char path[FN_REFLEN]; public: select_to_file(THD *thd_arg, sql_exchange *ex): select_result_interceptor(thd_arg), exchange(ex), file(-1),row_count(0L) { path[0]=0; } ~select_to_file(); bool send_eof() override; void abort_result_set() override; void reset_for_next_ps_execution() override; bool free_recources(); }; #define ESCAPE_CHARS "ntrb0ZN" // keep synchronous with READ_INFO::unescape /* List of all possible characters of a numeric value text representation. */ #define NUMERIC_CHARS ".0123456789e+-" class select_export :public select_to_file { uint field_term_length; int field_sep_char,escape_char,line_sep_char; int field_term_char; // first char of FIELDS TERMINATED BY or MAX_INT /* The is_ambiguous_field_sep field is true if a value of the field_sep_char field is one of the 'n', 't', 'r' etc characters (see the READ_INFO::unescape method and the ESCAPE_CHARS constant value). */ bool is_ambiguous_field_sep; /* The is_ambiguous_field_term is true if field_sep_char contains the first char of the FIELDS TERMINATED BY (ENCLOSED BY is empty), and items can contain this character. */ bool is_ambiguous_field_term; /* The is_unsafe_field_sep field is true if a value of the field_sep_char field is one of the '0'..'9', '+', '-', '.' and 'e' characters (see the NUMERIC_CHARS constant value). */ bool is_unsafe_field_sep; bool fixed_row_size; CHARSET_INFO *write_cs; // output charset public: select_export(THD *thd_arg, sql_exchange *ex): select_to_file(thd_arg, ex) {} ~select_export(); int prepare(List &list, SELECT_LEX_UNIT *u) override; int send_data(List &items) override; }; class select_dump :public select_to_file { public: select_dump(THD *thd_arg, sql_exchange *ex): select_to_file(thd_arg, ex) {} int prepare(List &list, SELECT_LEX_UNIT *u) override; int send_data(List &items) override; }; class select_insert :public select_result_interceptor { public: select_result *sel_result; TABLE_LIST *table_list; TABLE *table; List *fields; ulonglong autoinc_value_of_last_inserted_row; // autogenerated or not COPY_INFO info; bool insert_into_view; select_insert(THD *thd_arg, TABLE_LIST *table_list_par, TABLE *table_par, List *fields_par, List *update_fields, List *update_values, enum_duplicates duplic, bool ignore, select_result *sel_ret_list); ~select_insert(); int prepare(List &list, SELECT_LEX_UNIT *u) override; int prepare2(JOIN *join) override; int send_data(List &items) override; virtual bool store_values(List &values); virtual bool can_rollback_data() { return 0; } bool prepare_eof(); bool send_ok_packet(); bool send_eof() override; void abort_result_set() override; /* not implemented: select_insert is never re-used in prepared statements */ void reset_for_next_ps_execution() override; }; class select_create: public select_insert { TABLE_LIST *create_table; Table_specification_st *create_info; TABLE_LIST *select_tables; Alter_info *alter_info; Field **field; /* lock data for tmp table */ MYSQL_LOCK *m_lock; /* m_lock or thd->extra_lock */ MYSQL_LOCK **m_plock; bool exit_done; TMP_TABLE_SHARE *saved_tmp_table_share; DDL_LOG_STATE ddl_log_state_create, ddl_log_state_rm; public: select_create(THD *thd_arg, TABLE_LIST *table_arg, Table_specification_st *create_info_par, Alter_info *alter_info_arg, List &select_fields,enum_duplicates duplic, bool ignore, TABLE_LIST *select_tables_arg): select_insert(thd_arg, table_arg, NULL, &select_fields, 0, 0, duplic, ignore, NULL), create_table(table_arg), create_info(create_info_par), select_tables(select_tables_arg), alter_info(alter_info_arg), m_plock(NULL), exit_done(0), saved_tmp_table_share(0) { bzero(&ddl_log_state_create, sizeof(ddl_log_state_create)); bzero(&ddl_log_state_rm, sizeof(ddl_log_state_rm)); } int prepare(List &list, SELECT_LEX_UNIT *u) override; int binlog_show_create_table(TABLE **tables, uint count); bool store_values(List &values) override; bool send_eof() override; void abort_result_set() override; bool can_rollback_data() override { return 1; } // Needed for access from local class MY_HOOKS in prepare(), since thd is proteted. const THD *get_thd(void) { return thd; } const HA_CREATE_INFO *get_create_info() { return create_info; }; int prepare2(JOIN *join) override { return 0; } private: TABLE *create_table_from_items(THD *thd, List *items, MYSQL_LOCK **lock, TABLEOP_HOOKS *hooks); }; #include #ifdef WITH_ARIA_STORAGE_ENGINE #include #else #undef USE_ARIA_FOR_TMP_TABLES #endif #ifdef USE_ARIA_FOR_TMP_TABLES #define TMP_ENGINE_COLUMNDEF MARIA_COLUMNDEF #define TMP_ENGINE_HTON maria_hton #define TMP_ENGINE_NAME "Aria" inline uint tmp_table_max_key_length() { return maria_max_key_length(); } inline uint tmp_table_max_key_parts() { return maria_max_key_segments(); } #else #define TMP_ENGINE_COLUMNDEF MI_COLUMNDEF #define TMP_ENGINE_HTON myisam_hton #define TMP_ENGINE_NAME "MyISAM" inline uint tmp_table_max_key_length() { return MI_MAX_KEY_LENGTH; } inline uint tmp_table_max_key_parts() { return MI_MAX_KEY_SEG; } #endif /* Param to create temporary tables when doing SELECT:s NOTE This structure is copied using memcpy as a part of JOIN. */ class TMP_TABLE_PARAM :public Sql_alloc { public: List copy_funcs; Copy_field *copy_field, *copy_field_end; uchar *group_buff; const char *tmp_name; Item **items_to_copy; /* Fields in tmp table */ TMP_ENGINE_COLUMNDEF *recinfo, *start_recinfo; KEY *keyinfo; ha_rows end_write_records; /** Number of normal fields in the query, including those referred to from aggregate functions. Hence, "SELECT `field1`, SUM(`field2`) from t1" sets this counter to 2. @see count_field_types */ uint field_count; /** Number of fields in the query that have functions. Includes both aggregate functions (e.g., SUM) and non-aggregates (e.g., RAND). Also counts functions referred to from aggregate functions, i.e., "SELECT SUM(RAND())" sets this counter to 2. @see count_field_types */ uint func_count; /** Number of fields in the query that have aggregate functions. Note that the optimizer may choose to optimize away these fields by replacing them with constants, in which case sum_func_count will need to be updated. @see opt_sum_query, count_field_types */ uint sum_func_count; uint copy_func_count; // Allocated copy fields uint hidden_field_count; uint group_parts,group_length,group_null_parts; /* If we're doing a GROUP BY operation, shows which one is used: true TemporaryTableWithPartialSums algorithm (see end_update()). false OrderedGroupBy algorithm (see end_write_group()). */ uint quick_group; /** Enabled when we have atleast one outer_sum_func. Needed when used along with distinct. @see create_tmp_table */ bool using_outer_summary_function; CHARSET_INFO *table_charset; bool schema_table; /* TRUE if the temp table is created for subquery materialization. */ bool materialized_subquery; /* TRUE if all columns of the table are guaranteed to be non-nullable */ bool force_not_null_cols; /* True if GROUP BY and its aggregate functions are already computed by a table access method (e.g. by loose index scan). In this case query execution should not perform aggregation and should treat aggregate functions as normal functions. */ bool precomputed_group_by; bool group_concat; bool force_copy_fields; /* If TRUE, create_tmp_field called from create_tmp_table will convert all BIT fields to 64-bit longs. This is a workaround the limitation that MEMORY tables cannot index BIT columns. */ bool bit_fields_as_long; /* Whether to create or postpone actual creation of this temporary table. TRUE <=> create_tmp_table will create only the TABLE structure. */ bool skip_create_table; TMP_TABLE_PARAM() :copy_field(0), group_parts(0), group_length(0), group_null_parts(0), using_outer_summary_function(0), schema_table(0), materialized_subquery(0), force_not_null_cols(0), precomputed_group_by(0), group_concat(0), force_copy_fields(0), bit_fields_as_long(0), skip_create_table(0) { init(); } ~TMP_TABLE_PARAM() { cleanup(); } void init(void); inline void cleanup(void) { if (copy_field) /* Fix for Intel compiler */ { delete [] copy_field; copy_field= NULL; copy_field_end= NULL; } } }; class select_unit :public select_result_interceptor { protected: uint curr_step, prev_step, curr_sel; enum sub_select_type step; public: TMP_TABLE_PARAM tmp_table_param; /* Number of additional (hidden) field of the used temporary table */ int addon_cnt; int write_err; /* Error code from the last send_data->ha_write_row call. */ TABLE *table; select_unit(THD *thd_arg): select_result_interceptor(thd_arg), addon_cnt(0), table(0) { init(); tmp_table_param.init(); } int prepare(List &list, SELECT_LEX_UNIT *u) override; /** Do prepare() and prepare2() if they have been postponed until column type information is computed (used by select_union_direct). @param types Column types @return false on success, true on failure */ virtual bool postponed_prepare(List &types) { return false; } int send_data(List &items) override; int write_record(); int update_counter(Field *counter, longlong value); int delete_record(); bool send_eof() override; virtual bool flush(); void reset_for_next_ps_execution() override; virtual bool create_result_table(THD *thd, List *column_types, bool is_distinct, ulonglong options, const LEX_CSTRING *alias, bool bit_fields_as_long, bool create_table, bool keep_row_order, uint hidden); TMP_TABLE_PARAM *get_tmp_table_param() { return &tmp_table_param; } void init() { curr_step= prev_step= 0; curr_sel= UINT_MAX; step= UNION_TYPE; write_err= 0; } virtual void change_select(); virtual bool force_enable_index_if_needed() { return false; } }; /** @class select_unit_ext The class used when processing rows produced by operands of query expressions containing INTERSECT ALL and/or EXCEPT all operations. One or two extra fields of the temporary to store the rows of the partial and final result can be employed. Both of them contain counters. The second additional field is used only when the processed query expression contains INTERSECT ALL. Consider how these extra fields are used. Let table t1 (f char(8)) table t2 (f char(8)) table t3 (f char(8)) contain the following sets: ("b"),("a"),("d"),("c"),("b"),("a"),("c"),("a") ("c"),("b"),("c"),("c"),("a"),("b"),("g") ("c"),("a"),("b"),("d"),("b"),("e") - Let's demonstrate how the the set operation INTERSECT ALL is proceesed for the query SELECT f FROM t1 INTERSECT ALL SELECT f FROM t2 When send_data() is called for the rows of the first operand we put the processed record into the temporary table if there was no such record setting dup_cnt field to 1 and add_cnt field to 0 and increment the counter in the dup_cnt field by one otherwise. We get |add_cnt|dup_cnt| f | |0 |2 |b | |0 |3 |a | |0 |1 |d | |0 |2 |c | The call of send_eof() for the first operand swaps the values stored in dup_cnt and add_cnt. After this, we'll see the following rows in the temporary table |add_cnt|dup_cnt| f | |2 |0 |b | |3 |0 |a | |1 |0 |d | |2 |0 |c | When send_data() is called for the rows of the second operand we increment the counter in dup_cnt if the processed row is found in the table and do nothing otherwise. As a result we get |add_cnt|dup_cnt| f | |2 |2 |b | |3 |1 |a | |1 |0 |d | |2 |3 |c | At the call of send_eof() for the second operand first we disable index. Then for each record, the minimum of counters from dup_cnt and add_cnt m is taken. If m == 0 then the record is deleted. Otherwise record is replaced with m copies of it. Yet the counter in this copies are set to 1 for dup_cnt and to 0 for add_cnt |add_cnt|dup_cnt| f | |0 |1 |b | |0 |1 |b | |0 |1 |a | |0 |1 |c | |0 |1 |c | - Let's demonstrate how the the set operation EXCEPT ALL is proceesed for the query SELECT f FROM t1 EXCEPT ALL SELECT f FROM t3 Only one additional counter field dup_cnt is used for EXCEPT ALL. After the first operand has been processed we have in the temporary table |dup_cnt| f | |2 |b | |3 |a | |1 |d | |2 |c | When send_data() is called for the rows of the second operand we decrement the counter in dup_cnt if the processed row is found in the table and do nothing otherwise. If the counter becomes 0 we delete the record |dup_cnt| f | |2 |a | |1 |c | Finally at the call of send_eof() for the second operand we disable index unfold rows adding duplicates |dup_cnt| f | |1 |a | |1 |a | |1 |c | */ class select_unit_ext :public select_unit { public: select_unit_ext(THD *thd_arg): select_unit(thd_arg), increment(0), is_index_enabled(TRUE), curr_op_type(UNSPECIFIED) { }; int send_data(List &items) override; void change_select() override; int unfold_record(ha_rows cnt); bool send_eof() override; bool force_enable_index_if_needed() override { is_index_enabled= true; return true; } bool disable_index_if_needed(SELECT_LEX *curr_sl); /* How to change increment/decrement the counter in duplicate_cnt field when processing a record produced by the current operand in send_data(). The value can be 1 or -1 */ int increment; /* TRUE <=> the index of the result temporary table is enabled */ bool is_index_enabled; /* The type of the set operation currently executed */ enum set_op_type curr_op_type; /* Points to the extra field of the temporary table where duplicate counters are stored */ Field *duplicate_cnt; /* Points to the extra field of the temporary table where additional counters used only for INTERSECT ALL operations are stored */ Field *additional_cnt; }; class select_union_recursive :public select_unit { public: /* The temporary table with the new records generated by one iterative step */ TABLE *incr_table; /* The TMP_TABLE_PARAM structure used to create incr_table */ TMP_TABLE_PARAM incr_table_param; /* One of tables from the list rec_tables (determined dynamically) */ TABLE *first_rec_table_to_update; /* The list of all recursive table references to the CTE for whose specification this select_union_recursive was created */ List rec_table_refs; /* The count of how many times reset_for_next_ps_execution() was called with cleaned==false for the unit specifying the recursive CTE for which this object was created or for the unit specifying a CTE that mutually recursive with this CTE. */ uint cleanup_count; long row_counter; select_union_recursive(THD *thd_arg): select_unit(thd_arg), incr_table(0), first_rec_table_to_update(0), cleanup_count(0), row_counter(0) { incr_table_param.init(); }; int send_data(List &items) override; bool create_result_table(THD *thd, List *column_types, bool is_distinct, ulonglong options, const LEX_CSTRING *alias, bool bit_fields_as_long, bool create_table, bool keep_row_order, uint hidden) override; void reset_for_next_ps_execution() override; }; /** UNION result that is passed directly to the receiving select_result without filling a temporary table. Function calls are forwarded to the wrapped select_result, but some functions are expected to be called only once for each query, so they are only executed for the first SELECT in the union (execept for send_eof(), which is executed only for the last SELECT). This select_result is used when a UNION is not DISTINCT and doesn't have a global ORDER BY clause. @see st_select_lex_unit::prepare(). */ class select_union_direct :public select_unit { private: /* Result object that receives all rows */ select_result *result; /* The last SELECT_LEX of the union */ SELECT_LEX *last_select_lex; /* Wrapped result has received metadata */ bool done_send_result_set_metadata; /* Wrapped result has initialized tables */ bool done_initialize_tables; /* Accumulated limit_found_rows */ ulonglong limit_found_rows; /* Number of rows offset */ ha_rows offset; /* Number of rows limit + offset, @see select_union_direct::send_data() */ ha_rows limit; public: /* Number of rows in the union */ ha_rows send_records; select_union_direct(THD *thd_arg, select_result *result_arg, SELECT_LEX *last_select_lex_arg): select_unit(thd_arg), result(result_arg), last_select_lex(last_select_lex_arg), done_send_result_set_metadata(false), done_initialize_tables(false), limit_found_rows(0) { send_records= 0; } bool change_result(select_result *new_result) override; uint field_count(List &fields) const override { // Only called for top-level select_results, usually select_send DBUG_ASSERT(false); /* purecov: inspected */ return 0; /* purecov: inspected */ } bool postponed_prepare(List &types) override; bool send_result_set_metadata(List &list, uint flags) override; int send_data(List &items) override; bool initialize_tables (JOIN *join) override; bool send_eof() override; bool flush() override { return false; } bool check_simple_select() const override { /* Only called for top-level select_results, usually select_send */ DBUG_ASSERT(false); /* purecov: inspected */ return false; /* purecov: inspected */ } void abort_result_set() override { result->abort_result_set(); /* purecov: inspected */ } void reset_for_next_ps_execution() override { send_records= 0; } void set_thd(THD *thd_arg) { /* Only called for top-level select_results, usually select_send, and for the results of subquery engines (select__subselect). */ DBUG_ASSERT(false); /* purecov: inspected */ } void remove_offset_limit() { // EXPLAIN should never output to a select_union_direct DBUG_ASSERT(false); /* purecov: inspected */ } #ifdef EMBEDDED_LIBRARY void begin_dataset() override #else void begin_dataset() #endif { // Only called for sp_cursor::Select_fetch_into_spvars DBUG_ASSERT(false); /* purecov: inspected */ } }; /* Base subselect interface class */ class select_subselect :public select_result_interceptor { protected: Item_subselect *item; public: select_subselect(THD *thd_arg, Item_subselect *item_arg): select_result_interceptor(thd_arg), item(item_arg) {} int send_data(List &items) override=0; bool send_eof() override { return 0; }; }; /* Single value subselect interface class */ class select_singlerow_subselect :public select_subselect { public: select_singlerow_subselect(THD *thd_arg, Item_subselect *item_arg): select_subselect(thd_arg, item_arg) {} int send_data(List &items) override; }; /* This class specializes select_union to collect statistics about the data stored in the temp table. Currently the class collects statistcs about NULLs. */ class select_materialize_with_stats : public select_unit { protected: class Column_statistics { public: /* Count of NULLs per column. */ ha_rows null_count; /* The row number that contains the first NULL in a column. */ ha_rows min_null_row; /* The row number that contains the last NULL in a column. */ ha_rows max_null_row; }; /* Array of statistics data per column. */ Column_statistics* col_stat; /* The number of columns in the biggest sub-row that consists of only NULL values. */ uint max_nulls_in_row; /* Count of rows writtent to the temp table. This is redundant as it is already stored in handler::stats.records, however that one is relatively expensive to compute (given we need that for evry row). */ ha_rows count_rows; protected: void reset(); public: select_materialize_with_stats(THD *thd_arg): select_unit(thd_arg) { tmp_table_param.init(); } bool create_result_table(THD *thd, List *column_types, bool is_distinct, ulonglong options, const LEX_CSTRING *alias, bool bit_fields_as_long, bool create_table, bool keep_row_order, uint hidden) override; bool init_result_table(ulonglong select_options); int send_data(List &items) override; void reset_for_next_ps_execution() override; ha_rows get_null_count_of_col(uint idx) { DBUG_ASSERT(idx < table->s->fields); return col_stat[idx].null_count; } ha_rows get_max_null_of_col(uint idx) { DBUG_ASSERT(idx < table->s->fields); return col_stat[idx].max_null_row; } ha_rows get_min_null_of_col(uint idx) { DBUG_ASSERT(idx < table->s->fields); return col_stat[idx].min_null_row; } uint get_max_nulls_in_row() { return max_nulls_in_row; } }; /* used in independent ALL/ANY optimisation */ class select_max_min_finder_subselect :public select_subselect { Item_cache *cache; bool (select_max_min_finder_subselect::*op)(); bool fmax; bool is_all; void set_op(const Type_handler *ha); public: select_max_min_finder_subselect(THD *thd_arg, Item_subselect *item_arg, bool mx, bool all): select_subselect(thd_arg, item_arg), cache(0), fmax(mx), is_all(all) {} void reset_for_next_ps_execution() override; int send_data(List &items) override; bool cmp_real(); bool cmp_int(); bool cmp_decimal(); bool cmp_str(); bool cmp_time(); bool cmp_native(); }; /* EXISTS subselect interface class */ class select_exists_subselect :public select_subselect { public: select_exists_subselect(THD *thd_arg, Item_subselect *item_arg): select_subselect(thd_arg, item_arg) {} int send_data(List &items) override; }; /* Optimizer and executor structure for the materialized semi-join info. This structure contains - The sj-materialization temporary table - Members needed to make index lookup or a full scan of the temptable. */ class POSITION; class SJ_MATERIALIZATION_INFO : public Sql_alloc { public: /* Optimal join sub-order */ POSITION *positions; uint tables; /* Number of tables in the sj-nest */ /* Number of rows in the materialized table, before the de-duplication */ double rows_with_duplicates; /* Expected #rows in the materialized table, after de-duplication */ double rows; /* Cost to materialize - execute the sub-join and write rows into temp.table */ Cost_estimate materialization_cost; /* Cost to make one lookup in the temptable */ Cost_estimate lookup_cost; /* Cost of scanning the materialized table */ Cost_estimate scan_cost; /* --- Execution structures ---------- */ /* TRUE <=> This structure is used for execution. We don't necessarily pick sj-materialization, so some of SJ_MATERIALIZATION_INFO structures are not used by materialization */ bool is_used; bool materialized; /* TRUE <=> materialization already performed */ /* TRUE - the temptable is read with full scan FALSE - we use the temptable for index lookups */ bool is_sj_scan; /* The temptable and its related info */ TMP_TABLE_PARAM sjm_table_param; List sjm_table_cols; TABLE *table; /* Structure used to make index lookups */ struct st_table_ref *tab_ref; Item *in_equality; /* See create_subq_in_equalities() */ Item *join_cond; /* See comments in make_join_select() */ Copy_field *copy_field; /* Needed for SJ_Materialization scan */ }; /* Structs used when sorting */ struct SORT_FIELD_ATTR { /* If using mem-comparable fixed-size keys: length of the mem-comparable image of the field, in bytes. If using packed keys: still the same? Not clear what is the use of it. */ uint length; /* For most datatypes, this is 0. The exception are the VARBINARY columns. For those columns, the comparison actually compares (value_prefix(N), suffix=length(value)) Here value_prefix is either the whole value or its prefix if it was too long, and the suffix is the length of the original value. (this way, for values X and Y: if X=prefix(Y) then X compares as less than Y */ uint suffix_length; /* If using packed keys, number of bytes that are used to store the length of the packed key. */ uint length_bytes; /* Max. length of the original value, in bytes */ uint original_length; enum Type { FIXED_SIZE, VARIABLE_SIZE } type; /* TRUE : if the item or field is NULLABLE FALSE : otherwise */ bool maybe_null; CHARSET_INFO *cs; uint pack_sort_string(uchar *to, const Binary_string *str, CHARSET_INFO *cs) const; int compare_packed_fixed_size_vals(const uchar *a, size_t *a_len, const uchar *b, size_t *b_len); int compare_packed_varstrings(const uchar *a, size_t *a_len, const uchar *b, size_t *b_len); bool check_if_packing_possible(THD *thd) const; bool is_variable_sized() { return type == VARIABLE_SIZE; } void set_length_and_original_length(THD *thd, uint length_arg); }; struct SORT_FIELD: public SORT_FIELD_ATTR { Field *field; /* Field to sort */ Item *item; /* Item if not sorting fields */ bool reverse; /* if descending sort */ }; typedef struct st_sort_buffer { uint index; /* 0 or 1 */ uint sort_orders; uint change_pos; /* If sort-fields changed */ char **buff; SORT_FIELD *sortorder; } SORT_BUFFER; /* Structure for db & table in sql_yacc */ class Table_ident :public Sql_alloc { public: LEX_CSTRING db; LEX_CSTRING table; SELECT_LEX_UNIT *sel; inline Table_ident(THD *thd, const LEX_CSTRING *db_arg, const LEX_CSTRING *table_arg, bool force) :table(*table_arg), sel((SELECT_LEX_UNIT *)0) { if (!force && (thd->client_capabilities & CLIENT_NO_SCHEMA)) db= null_clex_str; else db= *db_arg; } inline Table_ident(const LEX_CSTRING *table_arg) :table(*table_arg), sel((SELECT_LEX_UNIT *)0) { db= null_clex_str; } /* This constructor is used only for the case when we create a derived table. A derived table has no name and doesn't belong to any database. Later, if there was an alias specified for the table, it will be set by add_table_to_list. */ inline Table_ident(SELECT_LEX_UNIT *s) : sel(s) { /* We must have a table name here as this is used with add_table_to_list */ db.str= empty_c_string; /* a subject to casedn_str */ db.length= 0; table.str= internal_table_name; table.length=1; } bool is_derived_table() const { return MY_TEST(sel); } inline void change_db(LEX_CSTRING *db_name) { db= *db_name; } bool resolve_table_rowtype_ref(THD *thd, Row_definition_list &defs); bool append_to(THD *thd, String *to) const; }; class Qualified_column_ident: public Table_ident { public: LEX_CSTRING m_column; public: Qualified_column_ident(const LEX_CSTRING *column) :Table_ident(&null_clex_str), m_column(*column) { } Qualified_column_ident(const LEX_CSTRING *table, const LEX_CSTRING *column) :Table_ident(table), m_column(*column) { } Qualified_column_ident(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table, const LEX_CSTRING *column) :Table_ident(thd, db, table, false), m_column(*column) { } bool resolve_type_ref(THD *thd, Column_definition *def); bool append_to(THD *thd, String *to) const; }; // this is needed for user_vars hash class user_var_entry: public Type_handler_hybrid_field_type { CHARSET_INFO *m_charset; public: user_var_entry() = default; /* Remove gcc warning */ LEX_CSTRING name; char *value; size_t length; query_id_t update_query_id, used_query_id; double val_real(bool *null_value); longlong val_int(bool *null_value) const; String *val_str(bool *null_value, String *str, uint decimals) const; my_decimal *val_decimal(bool *null_value, my_decimal *result); CHARSET_INFO *charset() const { return m_charset; } void set_charset(CHARSET_INFO *cs) { m_charset= cs; } }; user_var_entry *get_variable(HASH *hash, LEX_CSTRING *name, bool create_if_not_exists); class SORT_INFO; class multi_delete :public select_result_interceptor { TABLE_LIST *delete_tables, *table_being_deleted; Unique **tempfiles; ha_rows deleted, found; uint num_of_tables; int error; bool do_delete; /* True if at least one table we delete from is transactional */ bool transactional_tables; /* True if at least one table we delete from is not transactional */ bool normal_tables; bool delete_while_scanning; /* error handling (rollback and binlogging) can happen in send_eof() so that afterward abort_result_set() needs to find out that. */ bool error_handled; public: // Methods used by ColumnStore uint get_num_of_tables() const { return num_of_tables; } TABLE_LIST* get_tables() const { return delete_tables; } public: multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); int prepare(List &list, SELECT_LEX_UNIT *u) override; int send_data(List &items) override; bool initialize_tables (JOIN *join) override; int do_deletes(); int do_table_deletes(TABLE *table, SORT_INFO *sort_info, bool ignore); bool send_eof() override; inline ha_rows num_deleted() const { return deleted; } void abort_result_set() override; void prepare_to_read_rows() override; }; class multi_update :public select_result_interceptor { TABLE_LIST *all_tables; /* query/update command tables */ List *leaves; /* list of leaves of join table tree */ List updated_leaves; /* list of of updated leaves */ TABLE_LIST *update_tables; TABLE **tmp_tables, *main_table, *table_to_update; TMP_TABLE_PARAM *tmp_table_param; ha_rows updated, found; List *fields, *values; List **fields_for_table, **values_for_table; uint table_count; /* List of tables referenced in the CHECK OPTION condition of the updated view excluding the updated table. */ List
unupdated_check_opt_tables; Copy_field *copy_field; enum enum_duplicates handle_duplicates; bool do_update, trans_safe; /* True if the update operation has made a change in a transactional table */ bool transactional_tables; bool ignore; /* error handling (rollback and binlogging) can happen in send_eof() so that afterward abort_result_set() needs to find out that. */ bool error_handled; /* Need this to protect against multiple prepare() calls */ bool prepared; // For System Versioning (may need to insert new fields to a table). ha_rows updated_sys_ver; bool has_vers_fields; public: multi_update(THD *thd_arg, TABLE_LIST *ut, List *leaves_list, List *fields, List *values, enum_duplicates handle_duplicates, bool ignore); ~multi_update(); bool init(THD *thd); int prepare(List &list, SELECT_LEX_UNIT *u) override; int send_data(List &items) override; bool initialize_tables (JOIN *join) override; int prepare2(JOIN *join) override; int do_updates(); bool send_eof() override; inline ha_rows num_found() const { return found; } inline ha_rows num_updated() const { return updated; } void abort_result_set() override; void update_used_tables() override; void prepare_to_read_rows() override; }; class my_var_sp; class my_var : public Sql_alloc { public: const LEX_CSTRING name; enum type { SESSION_VAR, LOCAL_VAR, PARAM_VAR }; type scope; my_var(const LEX_CSTRING *j, enum type s) : name(*j), scope(s) { } virtual ~my_var() = default; virtual bool set(THD *thd, Item *val) = 0; virtual my_var_sp *get_my_var_sp() { return NULL; } }; class my_var_sp: public my_var { const Sp_rcontext_handler *m_rcontext_handler; const Type_handler *m_type_handler; public: uint offset; /* Routine to which this Item_splocal belongs. Used for checking if correct runtime context is used for variable handling. */ sp_head *sp; my_var_sp(const Sp_rcontext_handler *rcontext_handler, const LEX_CSTRING *j, uint o, const Type_handler *type_handler, sp_head *s) : my_var(j, LOCAL_VAR), m_rcontext_handler(rcontext_handler), m_type_handler(type_handler), offset(o), sp(s) { } ~my_var_sp() = default; bool set(THD *thd, Item *val) override; my_var_sp *get_my_var_sp() override { return this; } const Type_handler *type_handler() const { return m_type_handler; } sp_rcontext *get_rcontext(sp_rcontext *local_ctx) const; }; /* This class handles fields of a ROW SP variable when it's used as a OUT parameter in a stored procedure. */ class my_var_sp_row_field: public my_var_sp { uint m_field_offset; public: my_var_sp_row_field(const Sp_rcontext_handler *rcontext_handler, const LEX_CSTRING *varname, const LEX_CSTRING *fieldname, uint var_idx, uint field_idx, sp_head *s) :my_var_sp(rcontext_handler, varname, var_idx, &type_handler_double/*Not really used*/, s), m_field_offset(field_idx) { } bool set(THD *thd, Item *val) override; }; class my_var_user: public my_var { public: my_var_user(const LEX_CSTRING *j) : my_var(j, SESSION_VAR) { } ~my_var_user() = default; bool set(THD *thd, Item *val) override; }; class select_dumpvar :public select_result_interceptor { ha_rows row_count; my_var_sp *m_var_sp_row; // Not NULL if SELECT INTO row_type_sp_variable bool send_data_to_var_list(List &items); public: List var_list; select_dumpvar(THD *thd_arg) :select_result_interceptor(thd_arg), row_count(0), m_var_sp_row(NULL) { var_list.empty(); } ~select_dumpvar() = default; int prepare(List &list, SELECT_LEX_UNIT *u) override; int send_data(List &items) override; bool send_eof() override; bool check_simple_select() const override; void reset_for_next_ps_execution() override; }; /* Bits in sql_command_flags */ #define CF_CHANGES_DATA (1U << 0) #define CF_REPORT_PROGRESS (1U << 1) #define CF_STATUS_COMMAND (1U << 2) #define CF_SHOW_TABLE_COMMAND (1U << 3) #define CF_WRITE_LOGS_COMMAND (1U << 4) /** Must be set for SQL statements that may contain Item expressions and/or use joins and tables. Indicates that the parse tree of such statement may contain rule-based optimizations that depend on metadata (i.e. number of columns in a table), and consequently that the statement must be re-prepared whenever referenced metadata changes. Must not be set for statements that themselves change metadata, e.g. RENAME, ALTER and other DDL, since otherwise will trigger constant reprepare. Consequently, complex item expressions and joins are currently prohibited in these statements. */ #define CF_REEXECUTION_FRAGILE (1U << 5) /** Implicitly commit before the SQL statement is executed. Statements marked with this flag will cause any active transaction to end (commit) before proceeding with the command execution. This flag should be set for statements that probably can't be rolled back or that do not expect any previously metadata locked tables. */ #define CF_IMPLICIT_COMMIT_BEGIN (1U << 6) /** Implicitly commit after the SQL statement. Statements marked with this flag are automatically committed at the end of the statement. This flag should be set for statements that will implicitly open and take metadata locks on system tables that should not be carried for the whole duration of a active transaction. */ #define CF_IMPLICIT_COMMIT_END (1U << 7) /** CF_IMPLICT_COMMIT_BEGIN and CF_IMPLICIT_COMMIT_END are used to ensure that the active transaction is implicitly committed before and after every DDL statement and any statement that modifies our currently non-transactional system tables. */ #define CF_AUTO_COMMIT_TRANS (CF_IMPLICIT_COMMIT_BEGIN | CF_IMPLICIT_COMMIT_END) /** Diagnostic statement. Diagnostic statements: - SHOW WARNING - SHOW ERROR - GET DIAGNOSTICS (WL#2111) do not modify the diagnostics area during execution. */ #define CF_DIAGNOSTIC_STMT (1U << 8) /** Identifies statements that may generate row events and that may end up in the binary log. */ #define CF_CAN_GENERATE_ROW_EVENTS (1U << 9) /** Identifies statements which may deal with temporary tables and for which temporary tables should be pre-opened to simplify privilege checks. */ #define CF_PREOPEN_TMP_TABLES (1U << 10) /** Identifies statements for which open handlers should be closed in the beginning of the statement. */ #define CF_HA_CLOSE (1U << 11) /** Identifies statements that can be explained with EXPLAIN. */ #define CF_CAN_BE_EXPLAINED (1U << 12) /** Identifies statements which may generate an optimizer trace */ #define CF_OPTIMIZER_TRACE (1U << 14) /** Identifies statements that should always be disallowed in read only transactions. */ #define CF_DISALLOW_IN_RO_TRANS (1U << 15) /** Statement that need the binlog format to be unchanged. */ #define CF_FORCE_ORIGINAL_BINLOG_FORMAT (1U << 16) /** Statement that inserts new rows (INSERT, REPLACE, LOAD, ALTER TABLE) */ #define CF_INSERTS_DATA (1U << 17) /** Statement that updates existing rows (UPDATE, multi-update) */ #define CF_UPDATES_DATA (1U << 18) /** Not logged into slow log as "admin commands" */ #define CF_ADMIN_COMMAND (1U << 19) /** SP Bulk execution safe */ #define CF_PS_ARRAY_BINDING_SAFE (1U << 20) /** SP Bulk execution optimized */ #define CF_PS_ARRAY_BINDING_OPTIMIZED (1U << 21) /** If command creates or drops a table */ #define CF_SCHEMA_CHANGE (1U << 22) /** If command creates or drops a database */ #define CF_DB_CHANGE (1U << 23) #ifdef WITH_WSREP /** DDL statement that may be subject to error filtering. */ #define CF_WSREP_MAY_IGNORE_ERRORS (1U << 24) /** Basic DML statements that create writeset. */ #define CF_WSREP_BASIC_DML (1u << 25) #endif /* WITH_WSREP */ /* Bits in server_command_flags */ /** Statement that deletes existing rows (DELETE, DELETE_MULTI) */ #define CF_DELETES_DATA (1U << 24) /** Skip the increase of the global query id counter. Commonly set for commands that are stateless (won't cause any change on the server internal states). */ #define CF_SKIP_QUERY_ID (1U << 0) /** Skip the increase of the number of statements that clients have sent to the server. Commonly used for commands that will cause a statement to be executed but the statement might have not been sent by the user (ie: stored procedure). */ #define CF_SKIP_QUESTIONS (1U << 1) #ifdef WITH_WSREP /** Do not check that wsrep snapshot is ready before allowing this command */ #define CF_SKIP_WSREP_CHECK (1U << 2) #else #define CF_SKIP_WSREP_CHECK 0 #endif /* WITH_WSREP */ /* Inline functions */ inline bool add_item_to_list(THD *thd, Item *item) { bool res; LEX *lex= thd->lex; if (lex->current_select->parsing_place == IN_RETURNING) res= lex->returning()->add_item_to_list(thd, item); else res= lex->current_select->add_item_to_list(thd, item); return res; } inline bool add_value_to_list(THD *thd, Item *value) { return thd->lex->value_list.push_back(value, thd->mem_root); } inline bool add_order_to_list(THD *thd, Item *item, bool asc) { return thd->lex->current_select->add_order_to_list(thd, item, asc); } inline bool add_gorder_to_list(THD *thd, Item *item, bool asc) { return thd->lex->current_select->add_gorder_to_list(thd, item, asc); } inline bool add_group_to_list(THD *thd, Item *item, bool asc) { return thd->lex->current_select->add_group_to_list(thd, item, asc); } inline Item *and_conds(THD *thd, Item *a, Item *b) { if (!b) return a; if (!a) return b; return new (thd->mem_root) Item_cond_and(thd, a, b); } /* inline handler methods that need to know TABLE and THD structures */ inline void handler::increment_statistics(ulong SSV::*offset) const { status_var_increment(table->in_use->status_var.*offset); table->in_use->check_limit_rows_examined(); } inline void handler::decrement_statistics(ulong SSV::*offset) const { status_var_decrement(table->in_use->status_var.*offset); } inline int handler::ha_ft_read(uchar *buf) { int error= ft_read(buf); if (!error) { update_rows_read(); if (table->vfield && buf == table->record[0]) table->update_virtual_fields(this, VCOL_UPDATE_FOR_READ); } table->status=error ? STATUS_NOT_FOUND: 0; return error; } inline int handler::ha_rnd_pos_by_record(uchar *buf) { int error= rnd_pos_by_record(buf); table->status=error ? STATUS_NOT_FOUND: 0; return error; } inline int handler::ha_read_first_row(uchar *buf, uint primary_key) { int error= read_first_row(buf, primary_key); if (!error) update_rows_read(); table->status=error ? STATUS_NOT_FOUND: 0; return error; } inline int handler::ha_write_tmp_row(uchar *buf) { int error; MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str); increment_statistics(&SSV::ha_tmp_write_count); TABLE_IO_WAIT(tracker, PSI_TABLE_WRITE_ROW, MAX_KEY, error, { error= write_row(buf); }) MYSQL_INSERT_ROW_DONE(error); return error; } inline int handler::ha_delete_tmp_row(uchar *buf) { int error; MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str); increment_statistics(&SSV::ha_tmp_delete_count); TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, MAX_KEY, error, { error= delete_row(buf); }) MYSQL_DELETE_ROW_DONE(error); return error; } inline int handler::ha_update_tmp_row(const uchar *old_data, uchar *new_data) { int error; MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str); increment_statistics(&SSV::ha_tmp_update_count); TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, error, { error= update_row(old_data, new_data);}) MYSQL_UPDATE_ROW_DONE(error); return error; } inline bool handler::has_long_unique() { return table->s->long_unique_table; } extern pthread_attr_t *get_connection_attrib(void); /** Set thread entering a condition This function should be called before putting a thread to wait for a condition. @a mutex should be held before calling this function. After being waken up, @f thd_exit_cond should be called. @param thd The thread entering the condition, NULL means current thread @param cond The condition the thread is going to wait for @param mutex The mutex associated with the condition, this must be held before call this function @param stage The new process message for the thread @param old_stage The old process message for the thread @param src_function The caller source function name @param src_file The caller source file name @param src_line The caller source line number */ void thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond, mysql_mutex_t *mutex, const PSI_stage_info *stage, PSI_stage_info *old_stage, const char *src_function, const char *src_file, int src_line); #define THD_ENTER_COND(P1, P2, P3, P4, P5) \ thd_enter_cond(P1, P2, P3, P4, P5, __func__, __FILE__, __LINE__) /** Set thread leaving a condition This function should be called after a thread being waken up for a condition. @param thd The thread entering the condition, NULL means current thread @param stage The process message, ususally this should be the old process message before calling @f thd_enter_cond @param src_function The caller source function name @param src_file The caller source file name @param src_line The caller source line number */ void thd_exit_cond(MYSQL_THD thd, const PSI_stage_info *stage, const char *src_function, const char *src_file, int src_line); #define THD_EXIT_COND(P1, P2) \ thd_exit_cond(P1, P2, __func__, __FILE__, __LINE__) inline bool binlog_should_compress(size_t len) { return opt_bin_log_compress && len >= opt_bin_log_compress_min_len; } /** Save thd sql_mode on instantiation. On destruction it resets the mode to the previously stored value. */ class Sql_mode_save { public: Sql_mode_save(THD *thd) : thd(thd), old_mode(thd->variables.sql_mode) {} ~Sql_mode_save() { thd->variables.sql_mode = old_mode; } private: THD *thd; sql_mode_t old_mode; // SQL mode saved at construction time. }; /* Save the current sql_mode. Switch off sql_mode flags which can prevent normal parsing of VIEWs, expressions in generated columns. Restore the old sql_mode on destructor. */ class Sql_mode_save_for_frm_handling: public Sql_mode_save { public: Sql_mode_save_for_frm_handling(THD *thd) :Sql_mode_save(thd) { /* - MODE_REAL_AS_FLOAT affect only CREATE TABLE parsing + MODE_PIPES_AS_CONCAT affect expression parsing + MODE_ANSI_QUOTES affect expression parsing + MODE_IGNORE_SPACE affect expression parsing - MODE_IGNORE_BAD_TABLE_OPTIONS affect only CREATE/ALTER TABLE parsing * MODE_ONLY_FULL_GROUP_BY affect execution * MODE_NO_UNSIGNED_SUBTRACTION affect execution - MODE_NO_DIR_IN_CREATE affect table creation only - MODE_POSTGRESQL compounded from other modes + MODE_ORACLE affects Item creation (e.g for CONCAT) - MODE_MSSQL compounded from other modes - MODE_DB2 compounded from other modes - MODE_MAXDB affect only CREATE TABLE parsing - MODE_NO_KEY_OPTIONS affect only SHOW - MODE_NO_TABLE_OPTIONS affect only SHOW - MODE_NO_FIELD_OPTIONS affect only SHOW - MODE_MYSQL323 affect only SHOW - MODE_MYSQL40 affect only SHOW - MODE_ANSI compounded from other modes (+ transaction mode) ? MODE_NO_AUTO_VALUE_ON_ZERO affect UPDATEs + MODE_NO_BACKSLASH_ESCAPES affect expression parsing + MODE_EMPTY_STRING_IS_NULL affect expression parsing */ thd->variables.sql_mode&= ~(MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_NO_BACKSLASH_ESCAPES | MODE_ORACLE | MODE_EMPTY_STRING_IS_NULL); }; }; class Switch_to_definer_security_ctx { public: Switch_to_definer_security_ctx(THD *thd, TABLE_LIST *table) : m_thd(thd), m_sctx(thd->security_ctx) { if (table->security_ctx) thd->security_ctx= table->security_ctx; } ~Switch_to_definer_security_ctx() { m_thd->security_ctx = m_sctx; } private: THD *m_thd; Security_context *m_sctx; }; class Sql_mode_instant_set: public Sql_mode_save { public: Sql_mode_instant_set(THD *thd, sql_mode_t temporary_value) :Sql_mode_save(thd) { thd->variables.sql_mode= temporary_value; } }; class Sql_mode_instant_remove: public Sql_mode_save { public: Sql_mode_instant_remove(THD *thd, sql_mode_t temporary_remove_flags) :Sql_mode_save(thd) { thd->variables.sql_mode&= ~temporary_remove_flags; } }; class Abort_on_warning_instant_set { THD *m_thd; bool m_save_abort_on_warning; public: Abort_on_warning_instant_set(THD *thd, bool temporary_value) :m_thd(thd), m_save_abort_on_warning(thd->abort_on_warning) { thd->abort_on_warning= temporary_value; } ~Abort_on_warning_instant_set() { m_thd->abort_on_warning= m_save_abort_on_warning; } }; class Check_level_instant_set { THD *m_thd; enum_check_fields m_check_level; public: Check_level_instant_set(THD *thd, enum_check_fields temporary_value) :m_thd(thd), m_check_level(thd->count_cuted_fields) { thd->count_cuted_fields= temporary_value; } ~Check_level_instant_set() { m_thd->count_cuted_fields= m_check_level; } }; class Use_relaxed_field_copy: public Sql_mode_save, public Check_level_instant_set, public Abort_on_warning_instant_set { public: Use_relaxed_field_copy(THD *thd) : Sql_mode_save(thd), Check_level_instant_set(thd, CHECK_FIELD_IGNORE), Abort_on_warning_instant_set(thd, 0) { thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE); thd->variables.sql_mode|= MODE_INVALID_DATES; } }; class Identifier_chain2 { LEX_CSTRING m_name[2]; public: Identifier_chain2() :m_name{Lex_cstring(), Lex_cstring()} { } Identifier_chain2(const LEX_CSTRING &a, const LEX_CSTRING &b) :m_name{a, b} { } const LEX_CSTRING& operator [] (size_t i) const { return m_name[i]; } static Identifier_chain2 split(const LEX_CSTRING &txt) { DBUG_ASSERT(txt.str[txt.length] == '\0'); // Expect 0-terminated input const char *dot= strchr(txt.str, '.'); if (!dot) return Identifier_chain2(Lex_cstring(), txt); size_t length0= dot - txt.str; Lex_cstring name0(txt.str, length0); Lex_cstring name1(txt.str + length0 + 1, txt.length - length0 - 1); return Identifier_chain2(name0, name1); } // Export as a qualified name string: 'db.name' size_t make_qname(char *dst, size_t dstlen, bool casedn_part1) const { size_t res= my_snprintf(dst, dstlen, "%.*s.%.*s", (int) m_name[0].length, m_name[0].str, (int) m_name[1].length, m_name[1].str); if (casedn_part1 && dstlen > m_name[0].length) my_casedn_str(system_charset_info, dst + m_name[0].length + 1); return res; } // Export as a qualified name string, allocate on mem_root. LEX_CSTRING make_qname(MEM_ROOT *mem_root, bool casedn_part1) const { LEX_STRING dst; /* format: [pkg + dot] + name + '\0' */ size_t dst_size= m_name[0].length + 1 /*dot*/ + m_name[1].length + 1/*\0*/; if (unlikely(!(dst.str= (char*) alloc_root(mem_root, dst_size)))) return {NULL, 0}; if (!m_name[0].length) { DBUG_ASSERT(!casedn_part1); // Should not be called this way dst.length= my_snprintf(dst.str, dst_size, "%.*s", (int) m_name[1].length, m_name[1].str); return {dst.str, dst.length}; } dst.length= make_qname(dst.str, dst_size, casedn_part1); return {dst.str, dst.length}; } }; /** This class resembles the SQL Standard schema qualified object name: ::= [ ] */ class Database_qualified_name { public: LEX_CSTRING m_db; LEX_CSTRING m_name; Database_qualified_name(const LEX_CSTRING *db, const LEX_CSTRING *name) :m_db(*db), m_name(*name) { } Database_qualified_name(const LEX_CSTRING &db, const LEX_CSTRING &name) :m_db(db), m_name(name) { } Database_qualified_name(const char *db, size_t db_length, const char *name, size_t name_length) { m_db.str= db; m_db.length= db_length; m_name.str= name; m_name.length= name_length; } bool eq(const Database_qualified_name *other) const { CHARSET_INFO *cs= lower_case_table_names ? &my_charset_utf8mb3_general_ci : &my_charset_utf8mb3_bin; return m_db.length == other->m_db.length && m_name.length == other->m_name.length && !cs->strnncoll(m_db.str, m_db.length, other->m_db.str, other->m_db.length) && !cs->strnncoll(m_name.str, m_name.length, other->m_name.str, other->m_name.length); } void copy(MEM_ROOT *mem_root, const LEX_CSTRING &db, const LEX_CSTRING &name); // Export db and name as a qualified name string: 'db.name' size_t make_qname(char *dst, size_t dstlen, bool casedn_name) const { return Identifier_chain2(m_db, m_name).make_qname(dst, dstlen, casedn_name); } // Export db and name as a qualified name string, allocate on mem_root. LEX_CSTRING make_qname(MEM_ROOT *mem_root, bool casedn_name) const { DBUG_SLOW_ASSERT(ok_for_lower_case_names(m_db.str)); return Identifier_chain2(m_db, m_name).make_qname(mem_root, casedn_name); } bool make_package_routine_name(MEM_ROOT *mem_root, const LEX_CSTRING &package, const LEX_CSTRING &routine) { char *tmp; size_t length= package.length + 1 + routine.length + 1; if (unlikely(!(tmp= (char *) alloc_root(mem_root, length)))) return true; m_name.length= Identifier_chain2(package, routine).make_qname(tmp, length, false); m_name.str= tmp; return false; } bool make_package_routine_name(MEM_ROOT *mem_root, const LEX_CSTRING &db, const LEX_CSTRING &package, const LEX_CSTRING &routine) { if (unlikely(make_package_routine_name(mem_root, package, routine))) return true; if (unlikely(!(m_db.str= strmake_root(mem_root, db.str, db.length)))) return true; m_db.length= db.length; return false; } }; class ErrConvDQName: public ErrConv { const Database_qualified_name *m_name; public: ErrConvDQName(const Database_qualified_name *name) :m_name(name) { } LEX_CSTRING lex_cstring() const override { size_t length= m_name->make_qname(err_buffer, sizeof(err_buffer), false); return {err_buffer, length}; } }; class Type_holder: public Sql_alloc, public Item_args, public Type_handler_hybrid_field_type, public Type_all_attributes { const TYPELIB *m_typelib; bool m_maybe_null; public: Type_holder() :m_typelib(NULL), m_maybe_null(false) { } void set_type_maybe_null(bool maybe_null_arg) override { m_maybe_null= maybe_null_arg; } bool get_maybe_null() const { return m_maybe_null; } decimal_digits_t decimal_precision() const override { /* Type_holder is not used directly to create fields, so its virtual decimal_precision() is never called. We should eventually extend create_result_table() to accept an array of Type_holders directly, without having to allocate Item_type_holder's and put them into List. */ DBUG_ASSERT(0); return 0; } void set_typelib(const TYPELIB *typelib) override { m_typelib= typelib; } const TYPELIB *get_typelib() const override { return m_typelib; } bool aggregate_attributes(THD *thd) { static LEX_CSTRING union_name= { STRING_WITH_LEN("UNION") }; for (uint i= 0; i < arg_count; i++) m_maybe_null|= args[i]->maybe_null(); return type_handler()->Item_hybrid_func_fix_attributes(thd, union_name, this, this, args, arg_count); } }; /* A helper class to set THD flags to emit warnings/errors in case of overflow/type errors during assigning values into the SP variable fields. Saves original flags values in constructor. Restores original flags in destructor. */ class Sp_eval_expr_state { THD *m_thd; enum_check_fields m_count_cuted_fields; bool m_abort_on_warning; bool m_stmt_modified_non_trans_table; void start() { m_thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; m_thd->abort_on_warning= m_thd->is_strict_mode(); m_thd->transaction->stmt.modified_non_trans_table= false; } void stop() { m_thd->count_cuted_fields= m_count_cuted_fields; m_thd->abort_on_warning= m_abort_on_warning; m_thd->transaction->stmt.modified_non_trans_table= m_stmt_modified_non_trans_table; } public: Sp_eval_expr_state(THD *thd) :m_thd(thd), m_count_cuted_fields(thd->count_cuted_fields), m_abort_on_warning(thd->abort_on_warning), m_stmt_modified_non_trans_table(thd->transaction->stmt. modified_non_trans_table) { start(); } ~Sp_eval_expr_state() { stop(); } }; #ifndef DBUG_OFF void dbug_serve_apcs(THD *thd, int n_calls); #endif class ScopedStatementReplication { public: ScopedStatementReplication(THD *thd) : saved_binlog_format(thd ? thd->set_current_stmt_binlog_format_stmt() : BINLOG_FORMAT_MIXED), thd(thd) {} ~ScopedStatementReplication() { if (thd) thd->restore_stmt_binlog_format(saved_binlog_format); } private: const enum_binlog_format saved_binlog_format; THD *const thd; }; /** THD registry */ class THD_list: public THD_list_iterator { public: /** Constructor replacement. Unfortunately we can't use fair constructor to initialize mutex for two reasons: PFS and embedded. The former can probably be fixed, the latter can probably be dropped. */ void init() { mysql_rwlock_init(key_rwlock_THD_list, &lock); } /** Destructor replacement. */ void destroy() { mysql_rwlock_destroy(&lock); } /** Inserts thread to registry. @param thd thread Thread becomes accessible via server_threads. */ void insert(THD *thd) { mysql_rwlock_wrlock(&lock); threads.append(thd); mysql_rwlock_unlock(&lock); } /** Removes thread from registry. @param thd thread Thread becomes not accessible via server_threads. */ void erase(THD *thd) { thd->assert_linked(); mysql_rwlock_wrlock(&lock); thd->unlink(); mysql_rwlock_unlock(&lock); } }; extern THD_list server_threads; void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps, uint field_count); C_MODE_START void mariadb_sleep_for_space(unsigned int seconds); C_MODE_END #endif /* MYSQL_SERVER */ #endif /* SQL_CLASS_INCLUDED */ server/private/slave.h000064400000027763151031265040011023 0ustar00/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SLAVE_H #define SLAVE_H /** MASTER_DELAY can be at most (1 << 31) - 1. */ #define MASTER_DELAY_MAX (0x7FFFFFFF) #if INT_MAX < 0x7FFFFFFF #error "don't support platforms where INT_MAX < 0x7FFFFFFF" #endif /** @defgroup Replication Replication @{ @file */ /** Some of defines are need in parser even though replication is not compiled in (embedded). */ /** The maximum is defined as (ULONG_MAX/1000) with 4 bytes ulong */ #define SLAVE_MAX_HEARTBEAT_PERIOD 4294967 #ifdef HAVE_REPLICATION #include "log.h" #include "my_list.h" #include "rpl_filter.h" #include "rpl_tblmap.h" #include "rpl_gtid.h" #include "log_event.h" #define SLAVE_NET_TIMEOUT 60 #define MAX_SLAVE_ERROR ER_ERROR_LAST+1 #define MAX_REPLICATION_THREAD 64 // Forward declarations class Relay_log_info; class Master_info; class Master_info_index; struct rpl_group_info; struct rpl_parallel_thread; int init_intvar_from_file(int* var, IO_CACHE* f, int default_val); int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val); int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val); int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f); /***************************************************************************** MySQL Replication Replication is implemented via two types of threads: I/O Thread - One of these threads is started for each master server. They maintain a connection to their master server, read log events from the master as they arrive, and queues them into a single, shared relay log file. A Master_info represents each of these threads. SQL Thread - One of these threads is started and reads from the relay log file, executing each event. A Relay_log_info represents this thread. Buffering in the relay log file makes it unnecessary to reread events from a master server across a slave restart. It also decouples the slave from the master where long-running updates and event logging are concerned--ie it can continue to log new events while a slow query executes on the slave. *****************************************************************************/ /* MUTEXES in replication: LOCK_active_mi: [note: this was originally meant for multimaster, to switch from a master to another, to protect active_mi] It is used to SERIALIZE ALL administrative commands of replication: START SLAVE, STOP SLAVE, CHANGE MASTER, RESET SLAVE, end_slave() (when mysqld stops) [init_slave() does not need it it's called early]. Any of these commands holds the mutex from the start till the end. This thus protects us against a handful of deadlocks (consider start_slave_thread() which, when starting the I/O thread, releases mi->run_lock, keeps rli->run_lock, and tries to re-acquire mi->run_lock). Currently active_mi never moves (it's created at startup and deleted at shutdown, and not changed: it always points to the same Master_info struct), because we don't have multimaster. So for the moment, mi does not move, and mi->rli does not either. In Master_info: run_lock, data_lock run_lock protects all information about the run state: slave_running, thd and the existence of the I/O thread (to stop/start it, you need this mutex). data_lock protects some moving members of the struct: counters (log name, position) and relay log (MYSQL_BIN_LOG object). In Relay_log_info: run_lock, data_lock see Master_info However, note that run_lock does not protect Relay_log_info.run_state; that is protected by data_lock. Order of acquisition: if you want to have LOCK_active_mi and a run_lock, you must acquire LOCK_active_mi first. In MYSQL_BIN_LOG: LOCK_log, LOCK_index of the binlog and the relay log LOCK_log: when you write to it. LOCK_index: when you create/delete a binlog (so that you have to update the .index file). */ extern ulong master_retry_count; extern MY_BITMAP slave_error_mask; extern char slave_skip_error_names[]; extern bool use_slave_mask; extern char slave_transaction_retry_error_names[]; extern uint *slave_transaction_retry_errors; extern uint slave_transaction_retry_error_length; extern char *slave_load_tmpdir; extern char *master_info_file; extern MYSQL_PLUGIN_IMPORT char *relay_log_info_file; extern char *opt_relay_logname, *opt_relaylog_index_name; extern my_bool opt_skip_slave_start, opt_reckless_slave; extern my_bool opt_log_slave_updates; extern char *opt_slave_skip_errors; extern char *opt_slave_transaction_retry_errors; extern my_bool opt_replicate_annotate_row_events; extern ulonglong relay_log_space_limit; extern ulonglong opt_read_binlog_speed_limit; extern ulonglong slave_skipped_errors; extern const char *relay_log_index; extern const char *relay_log_basename; /* 4 possible values for Master_info::slave_running and Relay_log_info::slave_running. The values 0,1,2,3 are very important: to keep the diff small, I didn't substitute places where we use 0/1 with the newly defined symbols. So don't change these values. The same way, code is assuming that in Relay_log_info we use only values 0/1. I started with using an enum, but enum_variable=1; is not legal so would have required many line changes. */ #define MYSQL_SLAVE_NOT_RUN 0 #define MYSQL_SLAVE_RUN_NOT_CONNECT 1 #define MYSQL_SLAVE_RUN_CONNECT 2 #define MYSQL_SLAVE_RUN_READING 3 #define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\ "FIRST") #define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\ "FIRST") /* If the following is set, if first gives an error, second will be tried. Otherwise, if first fails, we fail. */ #define SLAVE_FORCE_ALL 4 /* Values for the option --replicate-events-marked-for-skip. Must match the names in replicate_events_marked_for_skip_names in sys_vars.cc */ #define RPL_SKIP_REPLICATE 0 #define RPL_SKIP_FILTER_ON_SLAVE 1 #define RPL_SKIP_FILTER_ON_MASTER 2 int init_slave(); int init_recovery(Master_info* mi, const char** errmsg); bool init_slave_skip_errors(const char* arg); bool init_slave_transaction_retry_errors(const char* arg); int register_slave_on_master(MYSQL* mysql); int terminate_slave_threads(Master_info* mi, int thread_mask, bool skip_lock = 0); int start_slave_threads(THD *thd, bool need_slave_mutex, bool wait_for_start, Master_info* mi, const char* master_info_fname, const char* slave_info_fname, int thread_mask); /* cond_lock is usually same as start_lock. It is needed for the case when start_lock is 0 which happens if start_slave_thread() is called already inside the start_lock section, but at the same time we want a mysql_cond_wait() on start_cond, start_lock */ int start_slave_thread( #ifdef HAVE_PSI_INTERFACE PSI_thread_key thread_key, #endif pthread_handler h_func, mysql_mutex_t *start_lock, mysql_mutex_t *cond_lock, mysql_cond_t *start_cond, volatile uint *slave_running, volatile ulong *slave_run_id, Master_info *mi); /* If fd is -1, dump to NET */ int mysql_table_dump(THD* thd, const char* db, const char* tbl_name, int fd = -1); /* retrieve table from master and copy to slave*/ int fetch_master_table(THD* thd, const char* db_name, const char* table_name, Master_info* mi, MYSQL* mysql, bool overwrite); void show_master_info_get_fields(THD *thd, List *field_list, bool full, size_t gtid_pos_length); bool show_master_info(THD* thd, Master_info* mi, bool full); bool show_all_master_info(THD* thd); void show_binlog_info_get_fields(THD *thd, List *field_list); bool show_binlog_info(THD* thd); bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report, bool (*pred)(const void *), const void *param, bool maria_master= false); bool rpl_master_erroneous_autoinc(THD* thd); const char *print_slave_db_safe(const char *db); void skip_load_data_infile(NET* net); void slave_prepare_for_shutdown(); void end_slave(); /* release slave threads */ void close_active_mi(); /* clean up slave threads data */ void clear_until_condition(Relay_log_info* rli); void clear_slave_error(Relay_log_info* rli); void end_relay_log_info(Relay_log_info* rli); void init_thread_mask(int* mask,Master_info* mi,bool inverse); Format_description_log_event * read_relay_log_description_event(IO_CACHE *cur_log, ulonglong start_pos, const char **errmsg); int init_relay_log_pos(Relay_log_info* rli,const char* log,ulonglong pos, bool need_data_lock, const char** errmsg, bool look_for_description_event); int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, const char** errmsg); void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD *thd, rpl_group_info *rgi); int rotate_relay_log(Master_info* mi); int has_temporary_error(THD *thd); int sql_delay_event(Log_event *ev, THD *thd, rpl_group_info *rgi); int apply_event_and_update_pos(Log_event* ev, THD* thd, struct rpl_group_info *rgi); int apply_event_and_update_pos_for_parallel(Log_event* ev, THD* thd, struct rpl_group_info *rgi); int init_intvar_from_file(int* var, IO_CACHE* f, int default_val); int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val); int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val); int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f); pthread_handler_t handle_slave_io(void *arg); void slave_output_error_info(rpl_group_info *rgi, THD *thd); pthread_handler_t handle_slave_sql(void *arg); bool net_request_file(NET* net, const char* fname); void slave_background_kill_request(THD *to_kill); void slave_background_gtid_pos_create_request (rpl_slave_state::gtid_pos_table *table_entry); void slave_background_gtid_pending_delete_request(void); extern Master_info *active_mi; /* active_mi for multi-master */ extern Master_info *default_master_info; /* To replace active_mi */ extern Master_info_index *master_info_index; extern LEX_CSTRING default_master_connection_name; extern my_bool replicate_same_server_id; extern int disconnect_slave_event_count, abort_slave_event_count ; /* the master variables are defaults read from my.cnf or command line */ extern uint report_port; extern char *master_info_file, *report_user; extern char *report_host, *report_password; extern I_List threads; /* Check that a binlog event (read from the relay log) is valid to update last_master_timestamp. That is, a valid event is one with a consistent timestamp which originated from a primary server. */ static inline bool event_can_update_last_master_timestamp(Log_event *ev) { return ev && !(ev->is_artificial_event() || ev->is_relay_log_event() || (ev->when == 0)); } #else #define close_active_mi() /* no-op */ #endif /* HAVE_REPLICATION */ /* masks for start/stop operations on io and sql slave threads */ #define SLAVE_IO 1 #define SLAVE_SQL 2 /** @} (end of group Replication) */ #endif server/private/my_cpu.h000064400000011367151031265040011176 0ustar00#ifndef MY_CPU_INCLUDED #define MY_CPU_INCLUDED /* Copyright (c) 2013, 2020, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* instructions for specific cpu's */ /* Macros for adjusting thread priority (hardware multi-threading) The defines are the same ones used by the linux kernel */ #ifdef _ARCH_PWR8 #ifdef __GLIBC__ #include /* Very low priority */ #define HMT_very_low() __ppc_set_ppr_very_low() /* Low priority */ #define HMT_low() __ppc_set_ppr_low() /* Medium low priority */ #define HMT_medium_low() __ppc_set_ppr_med_low() /* Medium priority */ #define HMT_medium() __ppc_set_ppr_med() /* Medium high priority */ #define HMT_medium_high() __ppc_set_ppr_med_high() /* High priority */ #define HMT_high() asm volatile("or 3,3,3") #else /* GLIBC */ #if defined(__FreeBSD__) #include #include #endif #define HMT_very_low() __asm__ volatile ("or 31,31,31") #define HMT_low() __asm__ volatile ("or 1,1,1") #define HMT_medium_low() __asm__ volatile ("or 6,6,6") #define HMT_medium() __asm__ volatile ("or 2,2,2") #define HMT_medium_high() __asm__ volatile ("or 5,5,5") #define HMT_high() asm volatile("or 3,3,3") #endif /* GLIBC */ #else #define HMT_very_low() #define HMT_low() #define HMT_medium_low() #define HMT_medium() #define HMT_medium_high() #define HMT_high() #endif #if defined __i386__ || defined __x86_64__ || defined _WIN32 # define HAVE_PAUSE_INSTRUCTION /* added in Intel Pentium 4 */ #endif #ifdef _WIN32 #elif defined HAVE_PAUSE_INSTRUCTION #elif defined(_ARCH_PWR8) #elif defined __GNUC__ && (defined __arm__ || defined __aarch64__) #else # include "my_global.h" # include "my_atomic.h" #endif static inline void MY_RELAX_CPU(void) { #ifdef _WIN32 /* In the Win32 API, the x86 PAUSE instruction is executed by calling the YieldProcessor macro defined in WinNT.h. It is a CPU architecture- independent way by using YieldProcessor. */ YieldProcessor(); #elif defined HAVE_PAUSE_INSTRUCTION /* According to the gcc info page, asm volatile means that the instruction has important side-effects and must not be removed. Also asm volatile may trigger a memory barrier (spilling all registers to memory). */ #ifdef __SUNPRO_CC asm ("pause" ); #else __asm__ __volatile__ ("pause"); #endif #elif defined(_ARCH_PWR8) /* Changed from __ppc_get_timebase for musl and clang compatibility */ __builtin_ppc_get_timebase(); #elif defined __GNUC__ && defined __riscv /* The GCC-only __builtin_riscv_pause() or the pause instruction is encoded like a fence instruction with special parameters. On RISC-V implementations that do not support arch=+zihintpause this instruction could be interpreted as a more expensive memory fence; it should not be an illegal instruction. */ __asm__ volatile(".long 0x0100000f" ::: "memory"); #elif defined __GNUC__ /* Mainly, prevent the compiler from optimizing away delay loops */ __asm__ __volatile__ ("":::"memory"); #endif } #ifdef HAVE_PAUSE_INSTRUCTION # ifdef __cplusplus extern "C" { # endif extern unsigned my_cpu_relax_multiplier; void my_cpu_init(void); # ifdef __cplusplus } # endif #else # define my_cpu_relax_multiplier 200 # define my_cpu_init() /* nothing */ #endif /* LF_BACKOFF should be used to improve performance on hyperthreaded CPUs. Intel recommends to use it in spin loops also on non-HT machines to reduce power consumption (see e.g http://softwarecommunity.intel.com/articles/eng/2004.htm) Running benchmarks for spinlocks implemented with InterlockedCompareExchange and YieldProcessor shows that much better performance is achieved by calling YieldProcessor in a loop - that is, yielding longer. On Intel boxes setting loop count in the range 200-300 brought best results. */ static inline int LF_BACKOFF(void) { unsigned i= my_cpu_relax_multiplier; while (i--) MY_RELAX_CPU(); return 1; } /** Run a delay loop while waiting for a shared resource to be released. @param delay originally, roughly microseconds on 100 MHz Intel Pentium */ static inline void ut_delay(unsigned delay) { unsigned i= my_cpu_relax_multiplier / 4 * delay; HMT_low(); while (i--) MY_RELAX_CPU(); HMT_medium(); } #endif server/private/lex_string.h000064400000007744151031265040012064 0ustar00/* Copyright (c) 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LEX_STRING_INCLUDED #define LEX_STRING_INCLUDED typedef struct st_mysql_const_lex_string LEX_CSTRING; class Lex_cstring : public LEX_CSTRING { public: Lex_cstring() { str= NULL; length= 0; } Lex_cstring(const LEX_CSTRING &str) { LEX_CSTRING::operator=(str); } Lex_cstring(const char *_str, size_t _len) { str= _str; length= _len; } Lex_cstring(const char *start, const char *end) { DBUG_ASSERT(start <= end); str= start; length= end - start; } void set(const char *_str, size_t _len) { str= _str; length= _len; } /* Trim left white spaces. Assumes that there are no multi-bytes characters that can be considered white-space. */ Lex_cstring ltrim_whitespace(CHARSET_INFO *cs) const { DBUG_ASSERT(cs->mbminlen == 1); Lex_cstring str= *this; while (str.length > 0 && my_isspace(cs, str.str[0])) { str.length--; str.str++; } return str; } /* Trim right white spaces. Assumes that there are no multi-bytes characters that can be considered white-space. Also, assumes that the character set supports backward space parsing. */ Lex_cstring rtrim_whitespace(CHARSET_INFO *cs) const { DBUG_ASSERT(cs->mbminlen == 1); Lex_cstring str= *this; while (str.length > 0 && my_isspace(cs, str.str[str.length - 1])) { str.length --; } return str; } /* Trim all spaces. */ Lex_cstring trim_whitespace(CHARSET_INFO *cs) const { return ltrim_whitespace(cs).rtrim_whitespace(cs); } /* Trim all spaces and return the length of the leading space sequence. */ Lex_cstring trim_whitespace(CHARSET_INFO *cs, size_t *prefix_length) const { Lex_cstring tmp= Lex_cstring(*this).ltrim_whitespace(cs); if (prefix_length) *prefix_length= tmp.str - str; return tmp.rtrim_whitespace(cs); } }; class Lex_cstring_strlen: public Lex_cstring { public: Lex_cstring_strlen(const char *from) :Lex_cstring(from, from ? strlen(from) : 0) { } }; /* Functions to compare if two lex strings are equal */ static inline bool lex_string_cmp(CHARSET_INFO *charset, const LEX_CSTRING *a, const LEX_CSTRING *b) { return my_strcasecmp(charset, a->str, b->str); } /* Compare to LEX_CSTRING's and return 0 if equal */ static inline bool cmp(const LEX_CSTRING *a, const LEX_CSTRING *b) { return a->length != b->length || (a->length && memcmp(a->str, b->str, a->length)); } static inline bool cmp(const LEX_CSTRING a, const LEX_CSTRING b) { return a.length != b.length || (a.length && memcmp(a.str, b.str, a.length)); } /* Compare if two LEX_CSTRING are equal. Assumption is that character set is ASCII (like for plugin names) */ static inline bool lex_string_eq(const LEX_CSTRING *a, const LEX_CSTRING *b) { if (a->length != b->length) return 0; /* Different */ return strcasecmp(a->str, b->str) == 0; } /* To be used when calling lex_string_eq with STRING_WITH_LEN() as second argument */ static inline bool lex_string_eq(const LEX_CSTRING *a, const char *b, size_t b_length) { if (a->length != b_length) return 0; /* Different */ return strcasecmp(a->str, b) == 0; } #endif /* LEX_STRING_INCLUDED */ server/private/event_queue.h000064400000006556151031265040012233 0ustar00#ifndef _EVENT_QUEUE_H_ #define _EVENT_QUEUE_H_ /* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @addtogroup Event_Scheduler @{ @file event_queue.h Queue of events awaiting execution. */ #ifdef HAVE_PSI_INTERFACE extern PSI_mutex_key key_LOCK_event_queue; extern PSI_cond_key key_COND_queue_state; #endif /* HAVE_PSI_INTERFACE */ #include "queues.h" // QUEUE #include "sql_string.h" /* LEX_CSTRING */ #include "my_time.h" /* my_time_t, interval_type */ class Event_basic; class Event_queue_element; class Event_queue_element_for_exec; class THD; /** Queue of active events awaiting execution. */ class Event_queue { public: Event_queue(); ~Event_queue(); bool init_queue(THD *thd); /* Methods for queue management follow */ bool create_event(THD *thd, Event_queue_element *new_element, bool *created); void update_event(THD *thd, const LEX_CSTRING *dbname, const LEX_CSTRING *name, Event_queue_element *new_element); void drop_event(THD *thd, const LEX_CSTRING *dbname, const LEX_CSTRING *name); void drop_schema_events(THD *thd, const LEX_CSTRING *schema); void recalculate_activation_times(THD *thd); bool get_top_for_execution_if_time(THD *thd, Event_queue_element_for_exec **event_name); void dump_internal_status(); private: void empty_queue(); void deinit_queue(); /* helper functions for working with mutexes & conditionals */ void lock_data(const char *func, uint line); void unlock_data(const char *func, uint line); void cond_wait(THD *thd, struct timespec *abstime, const PSI_stage_info *stage, const char *src_func, const char *src_file, uint src_line); void find_n_remove_event(const LEX_CSTRING *db, const LEX_CSTRING *name); void drop_matching_events(THD *thd, const LEX_CSTRING *pattern, bool (*)(const LEX_CSTRING*, Event_basic *)); void dbug_dump_queue(my_time_t now); /* LOCK_event_queue is the mutex which protects the access to the queue. */ mysql_mutex_t LOCK_event_queue; mysql_cond_t COND_queue_state; /* The sorted queue with the Event_queue_element objects */ QUEUE queue; my_time_t next_activation_at; uint mutex_last_locked_at_line; uint mutex_last_unlocked_at_line; uint mutex_last_attempted_lock_at_line; const char* mutex_last_locked_in_func; const char* mutex_last_unlocked_in_func; const char* mutex_last_attempted_lock_in_func; bool mutex_queue_data_locked; bool mutex_queue_data_attempting_lock; bool waiting_on_cond; }; /** @} (End of group Event_Scheduler) */ #endif /* _EVENT_QUEUE_H_ */ server/private/my_stack_alloc.h000064400000014535151031265040012666 0ustar00/* Copyright 2019 MariaDB corporation AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_stack_alloc_h #define _my_stack_alloc_h #ifdef _MSC_VER #include // For MSVC-specific intrinsics #else #include #endif /* Get the address of the current stack. This will fallback to using an estimate for the stack pointer in the cases where either the compiler or the architecture is not supported. */ static inline void *my_get_stack_pointer(void *default_stack) { void *stack_ptr= NULL; #if defined(__GNUC__) || defined(__clang__) /* GCC and Clang compilers */ #if defined(__i386__) /* Intel x86 (32-bit) */ __asm__ volatile ("movl %%esp, %0" : "=r" (stack_ptr)); #elif defined(__x86_64__) && defined (__ILP32__) /* Intel x86-64 (64-bit), X32 ABI */ __asm__ volatile ("movl %%esp, %0" : "=r" (stack_ptr)); #elif defined(__x86_64__) /* Intel x86-64 (64-bit) */ __asm__ volatile ("movq %%rsp, %0" : "=r" (stack_ptr)); #elif defined(__powerpc__) /* PowerPC (32-bit) */ __asm__ volatile ("mr %0, 1" : "=r" (stack_ptr)); /* GPR1 is the stack pointer */ #elif defined(__ppc64__) /* PowerPC (64-bit) */ __asm__ volatile ("mr %0, 1" : "=r" (stack_ptr)); #elif defined(__arm__) /* ARM 32-bit */ __asm__ volatile ("mov %0, sp" : "=r" (stack_ptr)); #elif defined(__aarch64__) /* ARM 64-bit */ __asm__ volatile ("mov %0, sp" : "=r" (stack_ptr)); #elif defined(__sparc__) /* SPARC 32-bit */ __asm__ volatile ("mov %%sp, %0" : "=r" (stack_ptr)); #elif defined(__sparc64__) /* SPARC 64-bit */ __asm__ volatile ("mov %%sp, %0" : "=r" (stack_ptr)); #elif defined(__s390x__) stack_ptr= __builtin_frame_address(0); #else /* Generic fallback for unsupported architectures in GCC/Clang */ stack_ptr= default_stack ? default_stack : (void*) &stack_ptr; #endif #elif defined(_MSC_VER) /* MSVC compiler (Intel only) */ #if defined(_M_IX86) /* Intel x86 (32-bit) */ __asm { mov stack_ptr, esp } #elif defined(_M_X64) /* Intel x86-64 (64-bit) */ /* rsp can’t be accessed directly in MSVC x64 */ stack_ptr= _AddressOfReturnAddress(); #else /* Generic fallback for unsupported architectures in MSVC */ stack_ptr= default_stack ? default_stack : (void*) &stack_ptr; #endif #else /* Generic fallback for unsupported compilers */ stack_ptr= default_stack ? default_stack : (void*) &stack_ptr; #endif return stack_ptr; } /* Do allocation through alloca if there is enough stack available. If not, use my_malloc() instead. The idea is that to be able to alloc as much as possible through the stack. To ensure this, we have two different limits, on for big blocks and one for small blocks. This will enable us to continue to do allocation for small blocks even when there is less stack space available. This is for example used by Aria when traversing the b-tree and the code needs to allocate one b-tree page and a few keys for each recursion. Even if there is not space to allocate the b-tree pages on stack we can still continue to allocate the keys. */ /* Default suggested allocations */ /* Allocate big blocks as long as there is this much left */ #define STACK_ALLOC_BIG_BLOCK 1024*64 /* Allocate small blocks as long as there is this much left */ #define STACK_ALLOC_SMALL_BLOCK 1024*32 /* Allocate small blocks as long as the block size is not bigger than */ #define STACK_ALLOC_SMALL_BLOCK_SIZE 4096 /* Allocate a block on stack or through malloc. The 'must_be_freed' variable will be set to 1 if malloc was called. 'must_be_freed' must be a variable on the stack! */ #ifdef HAVE_ALLOCA #define alloc_on_stack(stack_end, res, must_be_freed, size) \ do \ { \ size_t alloc_size= (size); \ void *stack= my_get_stack_pointer(0); \ size_t stack_left= available_stack_size(stack, (stack_end)); \ if (stack_left > alloc_size + STACK_ALLOC_SMALL_BLOCK && \ (stack_left > alloc_size + STACK_ALLOC_BIG_BLOCK || \ (STACK_ALLOC_SMALL_BLOCK_SIZE >= alloc_size))) \ { \ (must_be_freed)= 0; \ (res)= alloca(size); \ } \ else \ { \ (must_be_freed)= 1; \ (res)= my_malloc(PSI_INSTRUMENT_ME, size, MYF(MY_THREAD_SPECIFIC | MY_WME)); \ } \ } while(0) #else #define alloc_on_stack(stack_end, res, must_be_freed, size) \ do { \ (must_be_freed)= 1; \ (res)= my_malloc(PSI_INSTRUMENT_ME, size, MYF(MY_THREAD_SPECIFIC | MY_WME)); \ } while(0) #endif /* HAVE_ALLOCA */ /* Free memory allocated by stack_alloc */ static inline void stack_alloc_free(void *res, my_bool must_be_freed) { if (must_be_freed) my_free(res); } #endif /* _my_stack_alloc_h */ /* Get start and end of stack */ /* This is used in the case when we not know the exact stack start and have to estimate stack start with get_stack_pointer() */ #define MY_STACK_SAFE_MARGIN 8192 extern void my_get_stack_bounds(void **stack_start, void **stack_end, void *fallback_stack_start, size_t fallback_stack_size); server/private/events.h000064400000011140151031265040011173 0ustar00#ifndef _EVENT_H_ #define _EVENT_H_ /* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @defgroup Event_Scheduler Event Scheduler @ingroup Runtime_Environment @{ @file events.h A public interface of Events_Scheduler module. */ #ifdef HAVE_PSI_INTERFACE extern PSI_mutex_key key_event_scheduler_LOCK_scheduler_state; extern PSI_cond_key key_event_scheduler_COND_state; extern PSI_thread_key key_thread_event_scheduler, key_thread_event_worker; #endif /* HAVE_PSI_INTERFACE */ extern PSI_memory_key key_memory_event_basic_root; /* Always defined, for SHOW PROCESSLIST. */ extern PSI_stage_info stage_waiting_on_empty_queue; extern PSI_stage_info stage_waiting_for_next_activation; extern PSI_stage_info stage_waiting_for_scheduler_to_stop; #include "sql_string.h" /* LEX_CSTRING */ #include "my_time.h" /* interval_type */ class Event_db_repository; class Event_parse_data; class Event_queue; class Event_scheduler; struct TABLE_LIST; class THD; typedef class Item COND; int sortcmp_lex_string(const LEX_CSTRING *s, const LEX_CSTRING *t, const CHARSET_INFO *cs); /** @brief A facade to the functionality of the Event Scheduler. Every public operation against the scheduler has to be executed via the interface provided by a static method of this class. No instance of this class is ever created and it has no non-static data members. The life cycle of the Events module is the following: At server start up: init_mutexes() -> init() When the server is running: create_event(), drop_event(), start_or_stop_event_scheduler(), etc At shutdown: deinit(), destroy_mutexes(). The peculiar initialization and shutdown cycle is an adaptation to the outside server startup/shutdown framework and mimics the rest of MySQL subsystems (ACL, time zone tables, etc). */ class Events { public: /* the following block is to support --event-scheduler command line option and the @@global.event_scheduler SQL variable. See sys_var.cc */ enum enum_opt_event_scheduler { EVENTS_OFF, EVENTS_ON, EVENTS_DISABLED, EVENTS_ORIGINAL }; /* Protected using LOCK_global_system_variables only. */ static ulong opt_event_scheduler, startup_state; static ulong inited; static bool check_if_system_tables_error(); static bool start(int *err_no); static bool stop(); public: /* A hack needed for Event_queue_element */ static Event_db_repository * get_db_repository() { return db_repository; } static bool init(THD *thd, bool opt_noacl); static void deinit(); static void init_mutexes(); static void destroy_mutexes(); static bool create_event(THD *thd, Event_parse_data *parse_data); static bool update_event(THD *thd, Event_parse_data *parse_data, LEX_CSTRING *new_dbname, LEX_CSTRING *new_name); static bool drop_event(THD *thd, const LEX_CSTRING *dbname, const LEX_CSTRING *name, bool if_exists); static void drop_schema_events(THD *thd, const char *db); static bool show_create_event(THD *thd, const LEX_CSTRING *dbname, const LEX_CSTRING *name); /* Needed for both SHOW CREATE EVENT and INFORMATION_SCHEMA */ static int reconstruct_interval_expression(String *buf, interval_type interval, longlong expression); static int fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */); static void dump_internal_status(); static void set_original_state(ulong startup_state_org) { startup_state= startup_state_org; } private: static bool load_events_from_db(THD *thd); private: static Event_queue *event_queue; static Event_scheduler *scheduler; static Event_db_repository *db_repository; private: /* Prevent use of these */ Events(const Events &); void operator=(Events &); }; /** @} (end of group Event Scheduler) */ #endif /* _EVENT_H_ */ server/private/my_decimal.h000064400000034231151031265040012000 0ustar00/* Copyright (c) 2005, 2013, Oracle and/or its affiliates. Copyright (c) 2011, 2014, SkySQL Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file It is interface module to fixed precision decimals library. Most functions use 'uint mask' as parameter, if during operation error which fit in this mask is detected then it will be processed automatically here. (errors are E_DEC_* constants, see include/decimal.h) Most function are just inline wrappers around library calls */ #ifndef my_decimal_h #define my_decimal_h #include "sql_basic_types.h" #if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) #include "sql_string.h" /* String */ #endif C_MODE_START #include #include C_MODE_END class String; class Field; typedef struct st_mysql_time MYSQL_TIME; /** maximum size of packet length. */ #define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_PRECISION inline uint my_decimal_size(decimal_digits_t precision, decimal_digits_t scale) { /* Always allocate more space to allow library to put decimal point where it want */ return decimal_size(precision, scale) + 1; } inline decimal_digits_t my_decimal_int_part(decimal_digits_t precision, decimal_digits_t decimals) { return (decimal_digits_t) (precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals)); } #ifndef MYSQL_CLIENT int decimal_operation_results(int result, const char *value, const char *type); #else inline int decimal_operation_results(int result, const char *value, const char *type) { return result; } #endif /*MYSQL_CLIENT*/ inline int check_result(uint mask, int result) { if (result & mask) decimal_operation_results(result, "", "DECIMAL"); return result; } /** my_decimal class limits 'decimal_t' type to what we need in MySQL. It contains internally all necessary space needed by the instance so no extra memory is needed. One should call fix_buffer_pointer() function when he moves my_decimal objects in memory. */ class my_decimal :public decimal_t { /* Several of the routines in strings/decimal.c have had buffer overrun/underrun problems. These are *not* caught by valgrind. To catch them, we allocate dummy fields around the buffer, and test that their values do not change. */ #if !defined(DBUG_OFF) int foo1; #endif decimal_digit_t buffer[DECIMAL_BUFF_LENGTH]; #if !defined(DBUG_OFF) int foo2; static const int test_value= 123; #endif public: my_decimal(const my_decimal &rhs) : decimal_t(rhs) { init(); for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) buffer[i]= rhs.buffer[i]; } my_decimal& operator=(const my_decimal &rhs) { if (this == &rhs) return *this; decimal_t::operator=(rhs); for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) buffer[i]= rhs.buffer[i]; fix_buffer_pointer(); return *this; } void init() { #if !defined(DBUG_OFF) foo1= test_value; foo2= test_value; #endif len= DECIMAL_BUFF_LENGTH; buf= buffer; TRASH_ALLOC(buffer, sizeof(buffer)); } my_decimal() { init(); } my_decimal(const uchar *bin, decimal_digits_t prec, decimal_digits_t scale) { init(); check_result(E_DEC_FATAL_ERROR, bin2decimal(bin, this, prec, scale)); } my_decimal(Field *field); ~my_decimal() { sanity_check(); } void sanity_check() { DBUG_SLOW_ASSERT(foo1 == test_value); DBUG_SLOW_ASSERT(foo2 == test_value); } void fix_buffer_pointer() { buf= buffer; } bool sign() const { return decimal_t::sign; } void sign(bool s) { decimal_t::sign= s; } decimal_digits_t precision() const { return (decimal_digits_t) (intg + frac); } void set_zero() { /* We need the up-cast here, since my_decimal has sign() member functions, which conflicts with decimal_t::sign (and decimal_make_zero is a macro, rather than a funcion). */ decimal_make_zero(static_cast(this)); } int cmp(const my_decimal *other) const { return decimal_cmp(this, other); } #ifndef MYSQL_CLIENT bool to_bool() const { return !decimal_is_zero(this); } double to_double() const { double res; decimal2double(this, &res); return res; } longlong to_longlong(bool unsigned_flag) const; /* Return the value as a signed or unsigned longlong, depending on the sign. - Positive values are returned as unsigned. - Negative values are returned as signed. This is used by bit SQL operators: | & ^ ~ as well as by the SQL function BIT_COUNT(). */ longlong to_xlonglong() const { return to_longlong(!sign()); } // Convert to string returning decimal2string() error code int to_string_native(String *to, uint prec, uint dec, char filler, uint mask= E_DEC_FATAL_ERROR) const; // Convert to string returning the String pointer String *to_string(String *to, uint prec, uint dec, char filler) const { return to_string_native(to, prec, dec, filler) ? NULL : to; } String *to_string(String *to) const { return to_string(to, 0, 0, 0); } String *to_string_round(String *to, decimal_digits_t scale, my_decimal *round_buff) const { (void) round_to(round_buff, scale, HALF_UP); // QQ: check result? return round_buff->to_string(to); } /* Scale can be negative here when called from truncate() */ int round_to(my_decimal *to, int scale, decimal_round_mode mode, int mask= E_DEC_FATAL_ERROR) const { return check_result(mask, decimal_round(this, to, scale, mode)); } int to_binary(uchar *bin, int prec, decimal_digits_t scale, uint mask= E_DEC_FATAL_ERROR) const; #endif /** Swap two my_decimal values */ void swap(my_decimal &rhs) { swap_variables(my_decimal, *this, rhs); } }; #ifndef DBUG_OFF void print_decimal(const my_decimal *dec); void print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length); const char *dbug_decimal_as_string(char *buff, const my_decimal *val); #else #define dbug_decimal_as_string(A) NULL #endif bool str_set_decimal(uint mask, const my_decimal *val, uint fixed_prec, uint fixed_dec, char filler, String *str, CHARSET_INFO *cs); extern my_decimal decimal_zero; inline void max_my_decimal(my_decimal *to, decimal_digits_t precision, decimal_digits_t frac) { DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&& (frac <= DECIMAL_MAX_SCALE)); max_decimal(precision, frac, to); } inline void max_internal_decimal(my_decimal *to) { max_my_decimal(to, DECIMAL_MAX_PRECISION, 0); } inline int check_result_and_overflow(uint mask, int result, my_decimal *val) { if (check_result(mask, result) & E_DEC_OVERFLOW) { bool sign= val->sign(); val->fix_buffer_pointer(); max_internal_decimal(val); val->sign(sign); } return result; } inline decimal_digits_t my_decimal_length_to_precision(decimal_digits_t length, decimal_digits_t scale, bool unsigned_flag) { /* Precision can't be negative thus ignore unsigned_flag when length is 0. */ DBUG_ASSERT(length || !scale); return (decimal_digits_t) (length - (scale>0 ? 1:0) - (unsigned_flag || !length ? 0:1)); } inline decimal_digits_t my_decimal_precision_to_length_no_truncation(decimal_digits_t precision, decimal_digits_t scale, bool unsigned_flag) { /* When precision is 0 it means that original length was also 0. Thus unsigned_flag is ignored in this case. */ DBUG_ASSERT(precision || !scale); return (decimal_digits_t)(precision + (scale > 0 ? 1 : 0) + (unsigned_flag || !precision ? 0 : 1)); } inline decimal_digits_t my_decimal_precision_to_length(decimal_digits_t precision, decimal_digits_t scale, bool unsigned_flag) { /* When precision is 0 it means that original length was also 0. Thus unsigned_flag is ignored in this case. */ DBUG_ASSERT(precision || !scale); set_if_smaller(precision, DECIMAL_MAX_PRECISION); return my_decimal_precision_to_length_no_truncation(precision, scale, unsigned_flag); } inline uint my_decimal_string_length(const my_decimal *d) { /* length of string representation including terminating '\0' */ return decimal_string_size(d); } inline uint my_decimal_max_length(const my_decimal *d) { /* -1 because we do not count \0 */ return decimal_string_size(d) - 1; } inline uint my_decimal_get_binary_size(decimal_digits_t precision, decimal_digits_t scale) { return decimal_bin_size(precision, scale); } inline void my_decimal2decimal(const my_decimal *from, my_decimal *to) { *to= *from; } inline int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, decimal_digits_t prec, decimal_digits_t scale) { return check_result(mask, bin2decimal(bin, d, prec, scale)); } inline int my_decimal_set_zero(my_decimal *d) { d->set_zero(); return 0; } inline bool my_decimal_is_zero(const my_decimal *decimal_value) { return decimal_is_zero(decimal_value); } inline bool str_set_decimal(const my_decimal *val, String *str, CHARSET_INFO *cs) { return str_set_decimal(E_DEC_FATAL_ERROR, val, 0, 0, 0, str, cs); } bool my_decimal2seconds(const my_decimal *d, ulonglong *sec, ulong *microsec, ulong *nanosec); my_decimal *seconds2my_decimal(bool sign, ulonglong sec, ulong microsec, my_decimal *d); #define TIME_to_my_decimal(TIME, DECIMAL) \ seconds2my_decimal((TIME)->neg, TIME_to_ulonglong(TIME), \ (TIME)->second_part, (DECIMAL)) int my_decimal2int(uint mask, const decimal_t *d, bool unsigned_flag, longlong *l, decimal_round_mode round_type= HALF_UP); inline int my_decimal2double(uint, const decimal_t *d, double *result) { /* No need to call check_result as this will always succeed */ return decimal2double(d, result); } inline int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end) { return check_result_and_overflow(mask, string2decimal(str, d, end), d); } int str2my_decimal(uint mask, const char *from, size_t length, CHARSET_INFO *charset, my_decimal *decimal_value, const char **end); inline int str2my_decimal(uint mask, const char *from, size_t length, CHARSET_INFO *charset, my_decimal *decimal_value) { const char *end; return str2my_decimal(mask, from, length, charset, decimal_value, &end); } #if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) inline int string2my_decimal(uint mask, const String *str, my_decimal *d) { const char *end; return str2my_decimal(mask, str->ptr(), str->length(), str->charset(), d, &end); } my_decimal *date2my_decimal(const MYSQL_TIME *ltime, my_decimal *dec); #endif /*defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) */ inline int double2my_decimal(uint mask, double val, my_decimal *d) { return check_result_and_overflow(mask, double2decimal(val, d), d); } inline int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d) { return check_result(mask, (unsigned_flag ? ulonglong2decimal((ulonglong)i, d) : longlong2decimal(i, d))); } inline void decimal2my_decimal(decimal_t *from, my_decimal *to) { DBUG_ASSERT(to->len >= from->len); to->intg= from->intg; to->frac= from->frac; to->sign(from->sign); memcpy(to->buf, from->buf, to->len*sizeof(decimal_digit_t)); } inline void my_decimal_neg(decimal_t *arg) { if (decimal_is_zero(arg)) { arg->sign= 0; return; } decimal_neg(arg); } inline int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { return check_result_and_overflow(mask, decimal_add(a, b, res), res); } inline int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { return check_result_and_overflow(mask, decimal_sub(a, b, res), res); } inline int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { return check_result_and_overflow(mask, decimal_mul(a, b, res), res); } inline int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b, int div_scale_inc) { return check_result_and_overflow(mask, decimal_div(a, b, res, div_scale_inc), res); } inline int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { return check_result_and_overflow(mask, decimal_mod(a, b, res), res); } /** @return -1 if ab and 0 if a==b */ inline int my_decimal_cmp(const my_decimal *a, const my_decimal *b) { return decimal_cmp(a, b); } inline int my_decimal_intg(const my_decimal *a) { return decimal_intg(a); } void my_decimal_trim(ulonglong *precision, decimal_digits_t *scale); #endif /*my_decimal_h*/ server/private/event_parse_data.h000064400000005523151031265040013203 0ustar00/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _EVENT_PARSE_DATA_H_ #define _EVENT_PARSE_DATA_H_ #include "sql_alloc.h" class Item; class THD; class sp_name; #define EVEX_GET_FIELD_FAILED -2 #define EVEX_BAD_PARAMS -5 #define EVEX_MICROSECOND_UNSUP -6 #define EVEX_MAX_INTERVAL_VALUE 1000000000L class Event_parse_data : public Sql_alloc { public: /* ENABLED = feature can function normally (is turned on) SLAVESIDE_DISABLED = feature is turned off on slave DISABLED = feature is turned off */ enum enum_status { ENABLED = 1, DISABLED, SLAVESIDE_DISABLED }; enum enum_on_completion { /* On CREATE EVENT, DROP is the DEFAULT as per the docs. On ALTER EVENT, "no change" is the DEFAULT. */ ON_COMPLETION_DEFAULT = 0, ON_COMPLETION_DROP, ON_COMPLETION_PRESERVE }; int on_completion; int status; bool status_changed; uint32 originator; /* do_not_create will be set if STARTS time is in the past and on_completion == ON_COMPLETION_DROP. */ bool do_not_create; bool body_changed; LEX_CSTRING dbname; LEX_CSTRING name; LEX_CSTRING definer;// combination of user and host LEX_CSTRING comment; Item* item_starts; Item* item_ends; Item* item_execute_at; my_time_t starts; my_time_t ends; my_time_t execute_at; bool starts_null; bool ends_null; bool execute_at_null; sp_name *identifier; Item* item_expression; longlong expression; interval_type interval; static Event_parse_data * new_instance(THD *thd); bool check_parse_data(THD *thd); bool check_dates(THD *thd, int previous_on_completion); private: void init_definer(THD *thd); void init_name(THD *thd, sp_name *spn); int init_execute_at(THD *thd); int init_interval(THD *thd); int init_starts(THD *thd); int init_ends(THD *thd); Event_parse_data(); ~Event_parse_data(); void report_bad_value(const char *item_name, Item *bad_item); void check_if_in_the_past(THD *thd, my_time_t ltime_utc); Event_parse_data(const Event_parse_data &); /* Prevent use of these */ void check_originator_id(THD *thd); void operator=(Event_parse_data &); }; #endif server/private/sql_rename.h000064400000001726151031265040012026 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_RENAME_INCLUDED #define SQL_RENAME_INCLUDED class THD; struct TABLE_LIST; bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent, bool if_exists); #endif /* SQL_RENAME_INCLUDED */ server/private/assume_aligned.h000064400000004456151031265040012663 0ustar00/* Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #pragma once #include #include #ifdef _MSC_VER template static inline T my_assume_aligned(T ptr) { assert(reinterpret_cast(ptr) % Alignment == 0); __assume(reinterpret_cast(ptr) % Alignment == 0); return ptr; } #else template static inline T my_assume_aligned(T ptr) { assert(reinterpret_cast(ptr) % Alignment == 0); return static_cast(__builtin_assume_aligned(ptr, Alignment)); } #endif template inline void *memcpy_aligned(void *dest, const void *src, size_t n) { static_assert(Alignment && !(Alignment & (Alignment - 1)), "power of 2"); return std::memcpy(my_assume_aligned(dest), my_assume_aligned(src), n); } template inline void *memmove_aligned(void *dest, const void *src, size_t n) { static_assert(Alignment && !(Alignment & (Alignment - 1)), "power of 2"); return std::memmove(my_assume_aligned(dest), my_assume_aligned(src), n); } template inline int memcmp_aligned(const void *s1, const void *s2, size_t n) { static_assert(Alignment && !(Alignment & (Alignment - 1)), "power of 2"); return std::memcmp(my_assume_aligned(s1), my_assume_aligned(s2), n); } template inline void *memset_aligned(void *s, int c, size_t n) { static_assert(Alignment && !(Alignment & (Alignment - 1)), "power of 2"); return std::memset(my_assume_aligned(s), c, n); } server/private/sql_analyse.h000064400000025565151031265040012222 0ustar00#ifndef SQL_ANALYSE_INCLUDED #define SQL_ANALYSE_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Analyse database */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "procedure.h" /* Procedure */ #define my_thd_charset default_charset_info #define DEC_IN_AVG 4 typedef struct st_number_info { // if zerofill is true, the number must be zerofill, or string bool negative, is_float, zerofill, maybe_zerofill; int8 integers; int8 decimals; double dval; ulonglong ullval; } NUM_INFO; typedef struct st_extreme_value_number_info { ulonglong ullval; longlong llval; double max_dval, min_dval; } EV_NUM_INFO; typedef struct st_tree_info { bool found; String *str; Item *item; } TREE_INFO; uint check_ulonglong(const char *str, uint length); bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num); bool test_if_number(NUM_INFO *info, const char *str, uint str_len); int compare_double(const double *s, const double *t); int compare_double2(void *, const void *s, const void *t); int compare_longlong(const longlong *s, const longlong *t); int compare_longlong2(void *, const void *s, const void *t); int compare_ulonglong(const ulonglong *s, const ulonglong *t); int compare_ulonglong2(void *, const void *s, const void *t); int compare_decimal2(void *len, const void *s, const void *t); Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result, List &field_list); int free_string(void* str, TREE_FREE, void*); class analyse; class field_info :public Sql_alloc { protected: ulong treemem, tree_elements, empty, nulls, min_length, max_length; uint room_in_tree; bool found; TREE tree; Item *item; analyse *pc; public: field_info(Item* a, analyse* b) : treemem(0), tree_elements(0), empty(0), nulls(0), min_length(0), max_length(0), room_in_tree(1), found(0),item(a), pc(b) {}; virtual ~field_info() { delete_tree(&tree, 0); } virtual void add() = 0; virtual void get_opt_type(String*, ha_rows) = 0; virtual String *get_min_arg(String *) = 0; virtual String *get_max_arg(String *) = 0; virtual String *avg(String*, ha_rows) = 0; virtual String *std(String*, ha_rows) = 0; virtual tree_walk_action collect_enum() = 0; virtual uint decimals() { return 0; } friend class analyse; }; int collect_string(void *element, element_count count, void *info); int sortcmp2(void *, const void *a, const void *b); class field_str :public field_info { String min_arg, max_arg; ulonglong sum; bool must_be_blob, was_zero_fill, was_maybe_zerofill, can_be_still_num; NUM_INFO num_info; EV_NUM_INFO ev_num_info; public: field_str(Item* a, analyse* b) :field_info(a,b), min_arg("",0,default_charset_info), max_arg("",0,default_charset_info), sum(0), must_be_blob(0), was_zero_fill(0), was_maybe_zerofill(0), can_be_still_num(1) { init_tree(&tree, 0, 0, sizeof(String), sortcmp2, free_string, NULL, MYF(MY_THREAD_SPECIFIC)); }; void add() override; void get_opt_type(String*, ha_rows) override; String *get_min_arg(String *not_used __attribute__((unused))) override { return &min_arg; } String *get_max_arg(String *not_used __attribute__((unused))) override { return &max_arg; } String *avg(String *s, ha_rows rows) override { if (!(rows - nulls)) s->set_real((double) 0.0, 1,my_thd_charset); else s->set_real((ulonglong2double(sum) / ulonglong2double(rows - nulls)), DEC_IN_AVG,my_thd_charset); return s; } friend int collect_string(String *element, element_count count, TREE_INFO *info); tree_walk_action collect_enum() override { return collect_string; } String *std(String *s __attribute__((unused)), ha_rows rows __attribute__((unused))) override { return (String*) 0; } }; int collect_decimal(void *element, element_count count, void *info); class field_decimal :public field_info { my_decimal min_arg, max_arg; my_decimal sum[2], sum_sqr[2]; int cur_sum; int bin_size; public: field_decimal(Item* a, analyse* b) :field_info(a,b) { bin_size= my_decimal_get_binary_size(a->max_length, a->decimals); init_tree(&tree, 0, 0, bin_size, compare_decimal2, 0, (void *) &bin_size, MYF(MY_THREAD_SPECIFIC)); }; void add() override; void get_opt_type(String*, ha_rows) override; String *get_min_arg(String *) override; String *get_max_arg(String *) override; String *avg(String *s, ha_rows rows) override; friend int collect_decimal(uchar *element, element_count count, TREE_INFO *info); tree_walk_action collect_enum() override { return collect_decimal; } String *std(String *s, ha_rows rows) override; }; int collect_real(void *element, element_count count, void *info); class field_real: public field_info { double min_arg, max_arg; double sum, sum_sqr; uint max_notzero_dec_len; public: field_real(Item* a, analyse* b) :field_info(a,b), min_arg(0), max_arg(0), sum(0), sum_sqr(0), max_notzero_dec_len(0) { init_tree(&tree, 0, 0, sizeof(double), compare_double2, NULL, NULL, MYF(MY_THREAD_SPECIFIC)); } void add() override; void get_opt_type(String*, ha_rows) override; String *get_min_arg(String *s) override { s->set_real(min_arg, item->decimals, my_thd_charset); return s; } String *get_max_arg(String *s) override { s->set_real(max_arg, item->decimals, my_thd_charset); return s; } String *avg(String *s, ha_rows rows) override { if (!(rows - nulls)) s->set_real((double) 0.0, 1,my_thd_charset); else s->set_real(((double)sum / (double) (rows - nulls)), item->decimals,my_thd_charset); return s; } String *std(String *s, ha_rows rows) override { double tmp = ulonglong2double(rows); if (!(tmp - nulls)) s->set_real((double) 0.0, 1,my_thd_charset); else { double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) / (tmp - nulls)); s->set_real(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), item->decimals,my_thd_charset); } return s; } uint decimals() override { return item->decimals; } friend int collect_real(double *element, element_count count, TREE_INFO *info); tree_walk_action collect_enum() override { return collect_real;} }; int collect_longlong(void *element, element_count count, void *info); class field_longlong: public field_info { longlong min_arg, max_arg; longlong sum, sum_sqr; public: field_longlong(Item* a, analyse* b) :field_info(a,b), min_arg(0), max_arg(0), sum(0), sum_sqr(0) { init_tree(&tree, 0, 0, sizeof(longlong), compare_longlong2, NULL, NULL, MYF(MY_THREAD_SPECIFIC)); } void add() override; void get_opt_type(String*, ha_rows) override; String *get_min_arg(String *s) override { s->set(min_arg,my_thd_charset); return s; } String *get_max_arg(String *s) override { s->set(max_arg,my_thd_charset); return s; } String *avg(String *s, ha_rows rows) override { if (!(rows - nulls)) s->set_real((double) 0.0, 1,my_thd_charset); else s->set_real(((double) sum / (double) (rows - nulls)), DEC_IN_AVG,my_thd_charset); return s; } String *std(String *s, ha_rows rows) override { double tmp = ulonglong2double(rows); if (!(tmp - nulls)) s->set_real((double) 0.0, 1,my_thd_charset); else { double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) / (tmp - nulls)); s->set_real(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset); } return s; } friend int collect_longlong(longlong *element, element_count count, TREE_INFO *info); tree_walk_action collect_enum() override { return collect_longlong;} }; int collect_ulonglong(void *element, element_count count, void *info); class field_ulonglong: public field_info { ulonglong min_arg, max_arg; ulonglong sum, sum_sqr; public: field_ulonglong(Item* a, analyse * b) :field_info(a,b), min_arg(0), max_arg(0), sum(0),sum_sqr(0) { init_tree(&tree, 0, 0, sizeof(ulonglong), compare_ulonglong2, NULL, NULL, MYF(MY_THREAD_SPECIFIC)); } void add() override; void get_opt_type(String*, ha_rows) override; String *get_min_arg(String *s) override { s->set(min_arg,my_thd_charset); return s; } String *get_max_arg(String *s) override { s->set(max_arg,my_thd_charset); return s; } String *avg(String *s, ha_rows rows) override { if (!(rows - nulls)) s->set_real((double) 0.0, 1,my_thd_charset); else s->set_real((ulonglong2double(sum) / ulonglong2double(rows - nulls)), DEC_IN_AVG,my_thd_charset); return s; } String *std(String *s, ha_rows rows) override { double tmp = ulonglong2double(rows); if (!(tmp - nulls)) s->set_real((double) 0.0, 1,my_thd_charset); else { double tmp2 = ((ulonglong2double(sum_sqr) - ulonglong2double(sum * sum) / (tmp - nulls)) / (tmp - nulls)); s->set_real(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset); } return s; } friend int collect_ulonglong(ulonglong *element, element_count count, TREE_INFO *info); tree_walk_action collect_enum() override { return collect_ulonglong; } }; Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result, List &field_list); class analyse: public Procedure { protected: Item_proc *func_items[10]; List fields, result_fields; field_info **f_info, **f_end; ha_rows rows; uint output_str_length; public: uint max_tree_elements, max_treemem; analyse(select_result *res) :Procedure(res, PROC_NO_SORT), f_info(0), rows(0), output_str_length(0) {} ~analyse() { if (f_info) { for (field_info **f=f_info; f != f_end; f++) delete (*f); } } void add() override {} bool change_columns(THD *thd, List &fields) override; int send_row(List &field_list) override; void end_group(void) override {} int end_of_records(void) override; friend Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result, List &field_list); }; #endif /* SQL_ANALYSE_INCLUDED */ server/private/probes_mysql.h000064400000001715151031265040012415 0ustar00/* Copyright (c) 2008 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef PROBES_MYSQL_H #define PROBES_MYSQL_H #if defined(HAVE_DTRACE) && !defined(DISABLE_DTRACE) #include "probes_mysql_dtrace.h" #else /* no dtrace */ #include "probes_mysql_nodtrace.h" #endif #endif /* PROBES_MYSQL_H */ server/private/pfs_stage_provider.h000064400000003024151031265040013556 0ustar00/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef PFS_STAGE_PROVIDER_H #define PFS_STAGE_PROVIDER_H /** @file include/pfs_stage_provider.h Performance schema instrumentation (declarations). */ #ifdef HAVE_PSI_STAGE_INTERFACE #ifdef MYSQL_SERVER #ifndef EMBEDDED_LIBRARY #ifndef MYSQL_DYNAMIC_PLUGIN #include "mysql/psi/psi.h" #define PSI_STAGE_CALL(M) pfs_ ## M ## _v1 C_MODE_START void pfs_register_stage_v1(const char *category, PSI_stage_info_v1 **info_array, int count); PSI_stage_progress* pfs_start_stage_v1(PSI_stage_key key, const char *src_file, int src_line); PSI_stage_progress* pfs_get_current_stage_progress_v1(); void pfs_end_stage_v1(); C_MODE_END #endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_SERVER */ #endif /* HAVE_PSI_STAGE_INTERFACE */ #endif server/private/debug_sync.h000064400000003776151031265040012031 0ustar00#ifndef DEBUG_SYNC_INCLUDED #define DEBUG_SYNC_INCLUDED /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Declarations for the Debug Sync Facility. See debug_sync.cc for details. */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif class THD; #if defined(ENABLED_DEBUG_SYNC) /* Command line option --debug-sync-timeout. See mysqld.cc. */ extern MYSQL_PLUGIN_IMPORT uint opt_debug_sync_timeout; /* Default WAIT_FOR timeout if command line option is given without argument. */ #define DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT 300 /* Debug Sync prototypes. See debug_sync.cc. */ extern int debug_sync_init(void); extern void debug_sync_end(void); extern void debug_sync_init_thread(THD *thd); extern void debug_sync_end_thread(THD *thd); void debug_sync_reset_thread(THD *thd); extern bool debug_sync_set_action(THD *thd, const char *action_str, size_t len); extern bool debug_sync_update(THD *thd, char *val_str, size_t len); extern uchar *debug_sync_value_ptr(THD *thd); #else static inline void debug_sync_init_thread(THD *thd) {} static inline void debug_sync_end_thread(THD *thd) {} static inline void debug_sync_reset_thread(THD *thd) {} static inline bool debug_sync_set_action(THD *, const char *, size_t) { return false; } #endif /* defined(ENABLED_DEBUG_SYNC) */ #endif /* DEBUG_SYNC_INCLUDED */ server/private/pfs_idle_provider.h000064400000002551151031265040013374 0ustar00/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef PFS_IDLE_PROVIDER_H #define PFS_IDLE_PROVIDER_H /** @file include/pfs_idle_provider.h Performance schema instrumentation (declarations). */ #ifdef HAVE_PSI_IDLE_INTERFACE #ifdef MYSQL_SERVER #ifndef EMBEDDED_LIBRARY #ifndef MYSQL_DYNAMIC_PLUGIN #include "mysql/psi/psi.h" #define PSI_IDLE_CALL(M) pfs_ ## M ## _v1 C_MODE_START PSI_idle_locker* pfs_start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_line); void pfs_end_idle_wait_v1(PSI_idle_locker* locker); C_MODE_END #endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_SERVER */ #endif /* HAVE_PSI_IDLE_INTERFACE */ #endif server/private/atomic/generic-msvc.h000064400000007224151031265040013535 0ustar00#ifndef ATOMIC_MSC_INCLUDED #define ATOMIC_MSC_INCLUDED /* Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include static inline int my_atomic_cas32(int32 volatile *a, int32 *cmp, int32 set) { int32 initial_cmp= *cmp; int32 initial_a= InterlockedCompareExchange((volatile LONG*)a, set, initial_cmp); int ret= (initial_a == initial_cmp); if (!ret) *cmp= initial_a; return ret; } static inline int my_atomic_cas64(int64 volatile *a, int64 *cmp, int64 set) { int64 initial_cmp= *cmp; int64 initial_a= InterlockedCompareExchange64((volatile LONGLONG*)a, (LONGLONG)set, (LONGLONG)initial_cmp); int ret= (initial_a == initial_cmp); if (!ret) *cmp= initial_a; return ret; } static inline int my_atomic_casptr(void * volatile *a, void **cmp, void *set) { void *initial_cmp= *cmp; void *initial_a= InterlockedCompareExchangePointer(a, set, initial_cmp); int ret= (initial_a == initial_cmp); if (!ret) *cmp= initial_a; return ret; } static inline int32 my_atomic_add32(int32 volatile *a, int32 v) { return (int32)InterlockedExchangeAdd((volatile LONG*)a, v); } static inline int64 my_atomic_add64(int64 volatile *a, int64 v) { return (int64)InterlockedExchangeAdd64((volatile LONGLONG*)a, (LONGLONG)v); } /* According to MSDN: Simple reads and writes to properly-aligned 32-bit variables are atomic operations. ... Simple reads and writes to properly aligned 64-bit variables are atomic on 64-bit Windows. Reads and writes to 64-bit values are not guaranteed to be atomic on 32-bit Windows. https://msdn.microsoft.com/en-us/library/windows/desktop/ms684122(v=vs.85).aspx */ static inline int32 my_atomic_load32(int32 volatile *a) { int32 value= *a; MemoryBarrier(); return value; } static inline int64 my_atomic_load64(int64 volatile *a) { #ifdef _M_X64 int64 value= *a; MemoryBarrier(); return value; #else return (int64) InterlockedCompareExchange64((volatile LONGLONG *) a, 0, 0); #endif } static inline void* my_atomic_loadptr(void * volatile *a) { void *value= *a; MemoryBarrier(); return value; } static inline int32 my_atomic_fas32(int32 volatile *a, int32 v) { return (int32)InterlockedExchange((volatile LONG*)a, v); } static inline int64 my_atomic_fas64(int64 volatile *a, int64 v) { return (int64)InterlockedExchange64((volatile LONGLONG*)a, v); } static inline void * my_atomic_fasptr(void * volatile *a, void * v) { return InterlockedExchangePointer(a, v); } static inline void my_atomic_store32(int32 volatile *a, int32 v) { MemoryBarrier(); *a= v; } static inline void my_atomic_store64(int64 volatile *a, int64 v) { #ifdef _M_X64 MemoryBarrier(); *a= v; #else (void) InterlockedExchange64((volatile LONGLONG *) a, v); #endif } static inline void my_atomic_storeptr(void * volatile *a, void *v) { MemoryBarrier(); *a= v; } #endif /* ATOMIC_MSC_INCLUDED */ server/private/atomic/gcc_builtins.h000064400000007341151031265040013620 0ustar00#ifndef ATOMIC_GCC_BUILTINS_INCLUDED #define ATOMIC_GCC_BUILTINS_INCLUDED /* Copyright (c) 2017 MariaDB Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #define MY_MEMORY_ORDER_RELAXED __ATOMIC_RELAXED #define MY_MEMORY_ORDER_CONSUME __ATOMIC_CONSUME #define MY_MEMORY_ORDER_ACQUIRE __ATOMIC_ACQUIRE #define MY_MEMORY_ORDER_RELEASE __ATOMIC_RELEASE #define MY_MEMORY_ORDER_ACQ_REL __ATOMIC_ACQ_REL #define MY_MEMORY_ORDER_SEQ_CST __ATOMIC_SEQ_CST #define my_atomic_store32_explicit(P, D, O) __atomic_store_n((P), (D), (O)) #define my_atomic_store64_explicit(P, D, O) __atomic_store_n((P), (D), (O)) #define my_atomic_storeptr_explicit(P, D, O) __atomic_store_n((P), (D), (O)) #define my_atomic_load32_explicit(P, O) __atomic_load_n((P), (O)) #define my_atomic_load64_explicit(P, O) __atomic_load_n((P), (O)) #define my_atomic_loadptr_explicit(P, O) __atomic_load_n((P), (O)) #define my_atomic_fas32_explicit(P, D, O) __atomic_exchange_n((P), (D), (O)) #define my_atomic_fas64_explicit(P, D, O) __atomic_exchange_n((P), (D), (O)) #define my_atomic_fasptr_explicit(P, D, O) __atomic_exchange_n((P), (D), (O)) #define my_atomic_add32_explicit(P, A, O) __atomic_fetch_add((P), (A), (O)) #define my_atomic_add64_explicit(P, A, O) __atomic_fetch_add((P), (A), (O)) #define my_atomic_cas32_weak_explicit(P, E, D, S, F) \ __atomic_compare_exchange_n((P), (E), (D), 1, (S), (F)) #define my_atomic_cas64_weak_explicit(P, E, D, S, F) \ __atomic_compare_exchange_n((P), (E), (D), 1, (S), (F)) #define my_atomic_casptr_weak_explicit(P, E, D, S, F) \ __atomic_compare_exchange_n((P), (E), (D), 1, (S), (F)) #define my_atomic_cas32_strong_explicit(P, E, D, S, F) \ __atomic_compare_exchange_n((P), (E), (D), 0, (S), (F)) #define my_atomic_cas64_strong_explicit(P, E, D, S, F) \ __atomic_compare_exchange_n((P), (E), (D), 0, (S), (F)) #define my_atomic_casptr_strong_explicit(P, E, D, S, F) \ __atomic_compare_exchange_n((P), (E), (D), 0, (S), (F)) #define my_atomic_store32(P, D) __atomic_store_n((P), (D), __ATOMIC_SEQ_CST) #define my_atomic_store64(P, D) __atomic_store_n((P), (D), __ATOMIC_SEQ_CST) #define my_atomic_storeptr(P, D) __atomic_store_n((P), (D), __ATOMIC_SEQ_CST) #define my_atomic_load32(P) __atomic_load_n((P), __ATOMIC_SEQ_CST) #define my_atomic_load64(P) __atomic_load_n((P), __ATOMIC_SEQ_CST) #define my_atomic_loadptr(P) __atomic_load_n((P), __ATOMIC_SEQ_CST) #define my_atomic_fas32(P, D) __atomic_exchange_n((P), (D), __ATOMIC_SEQ_CST) #define my_atomic_fas64(P, D) __atomic_exchange_n((P), (D), __ATOMIC_SEQ_CST) #define my_atomic_fasptr(P, D) __atomic_exchange_n((P), (D), __ATOMIC_SEQ_CST) #define my_atomic_add32(P, A) __atomic_fetch_add((P), (A), __ATOMIC_SEQ_CST) #define my_atomic_add64(P, A) __atomic_fetch_add((P), (A), __ATOMIC_SEQ_CST) #define my_atomic_cas32(P, E, D) \ __atomic_compare_exchange_n((P), (E), (D), 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) #define my_atomic_cas64(P, E, D) \ __atomic_compare_exchange_n((P), (E), (D), 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) #define my_atomic_casptr(P, E, D) \ __atomic_compare_exchange_n((P), (E), (D), 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) #endif /* ATOMIC_GCC_BUILTINS_INCLUDED */ server/private/atomic/solaris.h000064400000006125151031265040012626 0ustar00#ifndef ATOMIC_SOLARIS_INCLUDED #define ATOMIC_SOLARIS_INCLUDED /* Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include #if defined(__GNUC__) #define atomic_typeof(T,V) __typeof__(V) #else #define atomic_typeof(T,V) T #endif static inline int my_atomic_cas32(int32 volatile *a, int32 *cmp, int32 set) { int ret; atomic_typeof(uint32_t, *cmp) sav; sav= atomic_cas_32((volatile uint32_t *)a, (uint32_t)*cmp, (uint32_t)set); ret= (sav == *cmp); if (!ret) *cmp= sav; return ret; } static inline int my_atomic_cas64(int64 volatile *a, int64 *cmp, int64 set) { int ret; atomic_typeof(uint64_t, *cmp) sav; sav= atomic_cas_64((volatile uint64_t *)a, (uint64_t)*cmp, (uint64_t)set); ret= (sav == *cmp); if (!ret) *cmp= sav; return ret; } static inline int my_atomic_casptr(void * volatile *a, void **cmp, void *set) { int ret; atomic_typeof(void *, *cmp) sav; sav= atomic_cas_ptr((volatile void **)a, (void *)*cmp, (void *)set); ret= (sav == *cmp); if (!ret) *cmp= sav; return ret; } static inline int32 my_atomic_add32(int32 volatile *a, int32 v) { int32 nv= atomic_add_32_nv((volatile uint32_t *)a, v); return nv - v; } static inline int64 my_atomic_add64(int64 volatile *a, int64 v) { int64 nv= atomic_add_64_nv((volatile uint64_t *)a, v); return nv - v; } static inline int32 my_atomic_fas32(int32 volatile *a, int32 v) { return atomic_swap_32((volatile uint32_t *)a, (uint32_t)v); } static inline int64 my_atomic_fas64(int64 volatile *a, int64 v) { return atomic_swap_64((volatile uint64_t *)a, (uint64_t)v); } static inline void * my_atomic_fasptr(void * volatile *a, void * v) { return atomic_swap_ptr(a, v); } static inline int32 my_atomic_load32(int32 volatile *a) { return atomic_or_32_nv((volatile uint32_t *)a, 0); } static inline int64 my_atomic_load64(int64 volatile *a) { return atomic_or_64_nv((volatile uint64_t *)a, 0); } static inline void* my_atomic_loadptr(void * volatile *a) { return atomic_add_ptr_nv(a, 0); } static inline void my_atomic_store32(int32 volatile *a, int32 v) { (void) atomic_swap_32((volatile uint32_t *)a, (uint32_t)v); } static inline void my_atomic_store64(int64 volatile *a, int64 v) { (void) atomic_swap_64((volatile uint64_t *)a, (uint64_t)v); } static inline void my_atomic_storeptr(void * volatile *a, void *v) { (void) atomic_swap_ptr((volatile void **)a, (void *)v); } #endif /* ATOMIC_SOLARIS_INCLUDED */ server/private/rpl_reporting.h000064400000007201151031265040012560 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef RPL_REPORTING_H #define RPL_REPORTING_H #include /* loglevel */ /** Maximum size of an error message from a slave thread. */ #define MAX_SLAVE_ERRMSG 1024 /** Mix-in to handle the message logging and reporting for relay log info and master log info structures. By inheriting from this class, the class is imbued with capabilities to do slave reporting. */ class Slave_reporting_capability { public: /** lock used to synchronize m_last_error on 'SHOW SLAVE STATUS' **/ mutable mysql_mutex_t err_lock; /** Constructor. @param thread_name Printable name of the slave thread that is reporting. */ Slave_reporting_capability(char const *thread_name); mutable my_thread_id err_thread_id; /** Writes a message and, if it's an error message, to Last_Error (which will be displayed by SHOW SLAVE STATUS). @param level The severity level @param err_code The error code @param msg The message (usually related to the error code, but can contain more information), in printf() format. */ void report(loglevel level, int err_code, const char *extra_info, const char *msg, ...) const ATTRIBUTE_FORMAT(printf, 5, 6); /** Clear errors. They will not show up under SHOW SLAVE STATUS. */ void clear_error() { mysql_mutex_lock(&err_lock); m_last_error.clear(); mysql_mutex_unlock(&err_lock); } /** Error information structure. */ class Error { friend class Slave_reporting_capability; public: Error() { clear(); } void clear() { number= 0; message[0]= '\0'; timestamp[0]= '\0'; } void update_timestamp() { struct tm tm_tmp; struct tm *start; skr= my_time(0); localtime_r(&skr, &tm_tmp); start=&tm_tmp; snprintf(timestamp, sizeof(timestamp), "%02d%02d%02d %02d:%02d:%02d", start->tm_year % 100, start->tm_mon+1, start->tm_mday, start->tm_hour, start->tm_min, start->tm_sec); timestamp[15]= '\0'; } /** Error code */ uint32 number; /** Error message */ char message[MAX_SLAVE_ERRMSG]; /** Error timestamp as string */ char timestamp[64]; /** Error timestamp as time_t variable. Used in performance_schema */ time_t skr; }; Error const& last_error() const { return m_last_error; } virtual ~Slave_reporting_capability()= 0; private: /** Last error produced by the I/O or SQL thread respectively. */ mutable Error m_last_error; char const *const m_thread_name; // not implemented Slave_reporting_capability(const Slave_reporting_capability& rhs); Slave_reporting_capability& operator=(const Slave_reporting_capability& rhs); }; #endif // RPL_REPORTING_H server/private/my_atomic_wrapper.h000064400000005753151031265040013425 0ustar00/* Copyright (c) 2020, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #pragma once #ifdef __cplusplus #include /** A wrapper for std::atomic, defaulting to std::memory_order_relaxed. When it comes to atomic loads or stores at std::memory_order_relaxed on IA-32 or AMD64, this wrapper is only introducing some constraints to the C++ compiler, to prevent some optimizations of loads or stores. On POWER and ARM, atomic loads and stores involve different instructions from normal loads and stores and will thus incur some overhead. Because atomic read-modify-write operations will always incur overhead, we intentionally do not define operator++(), operator--(), operator+=(), operator-=(), or similar, to make the overhead stand out in the users of this code. */ template class Atomic_relaxed { std::atomic m; public: Atomic_relaxed(const Atomic_relaxed &rhs) { m.store(rhs, std::memory_order_relaxed); } Atomic_relaxed(Type val) : m(val) {} Atomic_relaxed() = default; Type load(std::memory_order o= std::memory_order_relaxed) const { return m.load(o); } void store(Type i, std::memory_order o= std::memory_order_relaxed) { m.store(i, o); } operator Type() const { return m.load(); } Type operator=(const Type i) { store(i); return i; } Type operator=(const Atomic_relaxed &rhs) { return *this= Type{rhs}; } Type operator+=(const Type i) { return fetch_add(i); } Type fetch_add(const Type i, std::memory_order o= std::memory_order_relaxed) { return m.fetch_add(i, o); } Type fetch_sub(const Type i, std::memory_order o= std::memory_order_relaxed) { return m.fetch_sub(i, o); } Type fetch_xor(const Type i, std::memory_order o= std::memory_order_relaxed) { return m.fetch_xor(i, o); } Type fetch_and(const Type i, std::memory_order o= std::memory_order_relaxed) { return m.fetch_and(i, o); } Type fetch_or(const Type i, std::memory_order o= std::memory_order_relaxed) { return m.fetch_or(i, o); } bool compare_exchange_strong(Type& i1, const Type i2, std::memory_order o1= std::memory_order_relaxed, std::memory_order o2= std::memory_order_relaxed) { return m.compare_exchange_strong(i1, i2, o1, o2); } Type exchange(const Type i, std::memory_order o= std::memory_order_relaxed) { return m.exchange(i, o); } }; #endif /* __cplusplus */ server/private/table_cache.h000064400000010210151031265040012076 0ustar00#ifndef TABLE_CACHE_H_INCLUDED #define TABLE_CACHE_H_INCLUDED /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. Copyright (c) 2010, 2011 Monty Program Ab Copyright (C) 2013 Sergey Vojtovich and MariaDB Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ struct Share_free_tables { typedef I_P_List List; List list; /** Avoid false sharing between instances */ char pad[CPU_LEVEL1_DCACHE_LINESIZE]; }; struct TDC_element { uchar m_key[NAME_LEN + 1 + NAME_LEN + 1]; uint m_key_length; bool flushed; TABLE_SHARE *share; /** Protects ref_count, m_flush_tickets, all_tables, flushed, all_tables_refs. */ mysql_mutex_t LOCK_table_share; mysql_cond_t COND_release; TDC_element *next, **prev; /* Link to unused shares */ uint ref_count; /* How many TABLE objects uses this */ uint all_tables_refs; /* Number of refs to all_tables */ /** List of tickets representing threads waiting for the share to be flushed. */ Wait_for_flush_list m_flush_tickets; /* Doubly-linked (back-linked) lists of used and unused TABLE objects for this share. */ All_share_tables_list all_tables; /** Avoid false sharing between TDC_element and free_tables */ char pad[CPU_LEVEL1_DCACHE_LINESIZE]; Share_free_tables free_tables[1]; inline void wait_for_refs(uint my_refs); void flush(THD *thd, bool mark_flushed); void flush_unused(bool mark_flushed); }; extern ulong tdc_size; extern ulong tc_size; extern uint32 tc_instances; extern bool tdc_init(void); extern void tdc_start_shutdown(void); extern void tdc_deinit(void); extern ulong tdc_records(void); extern void tdc_purge(bool all); extern TDC_element *tdc_lock_share(THD *thd, const char *db, const char *table_name); extern void tdc_unlock_share(TDC_element *element); int tdc_share_is_cached(THD *thd, const char *db, const char *table_name); extern TABLE_SHARE *tdc_acquire_share(THD *thd, TABLE_LIST *tl, uint flags, TABLE **out_table= 0); extern void tdc_release_share(TABLE_SHARE *share); void tdc_remove_referenced_share(THD *thd, TABLE_SHARE *share); void tdc_remove_table(THD *thd, const char *db, const char *table_name); extern int tdc_wait_for_old_version(THD *thd, const char *db, const char *table_name, ulong wait_timeout, uint deadlock_weight); extern int tdc_iterate(THD *thd, my_hash_walk_action action, void *argument, bool no_dups= false); extern uint tc_records(void); int show_tc_active_instances(THD *thd, SHOW_VAR *var, void *buff, system_status_var *, enum enum_var_type scope); extern void tc_purge(); extern void tc_add_table(THD *thd, TABLE *table); extern void tc_release_table(TABLE *table); extern TABLE *tc_acquire_table(THD *thd, TDC_element *element); /** Create a table cache key for non-temporary table. @param key Buffer for key (must be at least NAME_LEN*2+2 bytes). @param db Database name. @param table_name Table name. @return Length of key. */ inline uint tdc_create_key(char *key, const char *db, const char *table_name) { /* In theory caller should ensure that both db and table_name are not longer than NAME_LEN bytes. In practice we play safe to avoid buffer overruns. */ return (uint) (strmake(strmake(key, db, NAME_LEN) + 1, table_name, NAME_LEN) - key + 1); } #endif /* TABLE_CACHE_H_INCLUDED */ server/private/sp_head.h000064400000175775151031265040011323 0ustar00/* -*- C++ -*- */ /* Copyright (c) 2002, 2011, Oracle and/or its affiliates. Copyright (c) 2020, 2022, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _SP_HEAD_H_ #define _SP_HEAD_H_ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif /* It is necessary to include set_var.h instead of item.h because there are dependencies on include order for set_var.h and item.h. This will be resolved later. */ #include "sql_class.h" // THD, set_var.h: THD #include "set_var.h" // Item #include "sp_pcontext.h" // sp_pcontext #include #include "sp.h" /** @defgroup Stored_Routines Stored Routines @ingroup Runtime_Environment @{ */ uint sp_get_flags_for_command(LEX *lex); class sp_instr; class sp_instr_opt_meta; class sp_instr_jump_if_not; /** Number of PSI_statement_info instruments for internal stored programs statements. */ #ifdef HAVE_PSI_INTERFACE void init_sp_psi_keys(void); #endif /*************************************************************************/ /** Stored_program_creation_ctx -- base class for creation context of stored programs (stored routines, triggers, events). */ class Stored_program_creation_ctx :public Default_object_creation_ctx { public: CHARSET_INFO *get_db_cl() { return m_db_cl; } public: virtual Stored_program_creation_ctx *clone(MEM_ROOT *mem_root) = 0; protected: Stored_program_creation_ctx(THD *thd) : Default_object_creation_ctx(thd), m_db_cl(thd->variables.collation_database) { } Stored_program_creation_ctx(CHARSET_INFO *client_cs, CHARSET_INFO *connection_cl, CHARSET_INFO *db_cl) : Default_object_creation_ctx(client_cs, connection_cl), m_db_cl(db_cl) { } protected: void change_env(THD *thd) const override { thd->variables.collation_database= m_db_cl; Default_object_creation_ctx::change_env(thd); } protected: /** db_cl stores the value of the database collation. Both character set and collation attributes are used. Database collation is included into the context because it defines the default collation for stored-program variables. */ CHARSET_INFO *m_db_cl; }; /*************************************************************************/ class sp_name : public Sql_alloc, public Database_qualified_name { public: bool m_explicit_name; /**< Prepend the db name? */ sp_name(const LEX_CSTRING *db, const LEX_CSTRING *name, bool use_explicit_name) : Database_qualified_name(db, name), m_explicit_name(use_explicit_name) { if (lower_case_table_names && m_db.length) m_db.length= my_casedn_str(files_charset_info, (char*) m_db.str); } /** Create temporary sp_name object from MDL key. Store in qname_buff */ sp_name(const MDL_key *key, char *qname_buff); ~sp_name() = default; }; bool check_routine_name(const LEX_CSTRING *ident); class sp_head :private Query_arena, public Database_qualified_name, public Sql_alloc { sp_head(const sp_head &)= delete; void operator=(sp_head &)= delete; protected: MEM_ROOT main_mem_root; #ifdef PROTECT_STATEMENT_MEMROOT /* The following data member is wholly for debugging purpose. It can be used for possible crash analysis to determine how many times the stored routine was executed before the mem_root marked read_only was requested for a memory chunk. Additionally, a value of this data member is output to the log with DBUG_PRINT. */ ulong executed_counter; #endif public: /** Possible values of m_flags */ enum { HAS_RETURN= 1, // For FUNCTIONs only: is set if has RETURN MULTI_RESULTS= 8, // Is set if a procedure with SELECT(s) CONTAINS_DYNAMIC_SQL= 16, // Is set if a procedure with PREPARE/EXECUTE IS_INVOKED= 32, // Is set if this sp_head is being used HAS_SET_AUTOCOMMIT_STMT= 64,// Is set if a procedure with 'set autocommit' /* Is set if a procedure with COMMIT (implicit or explicit) | ROLLBACK */ HAS_COMMIT_OR_ROLLBACK= 128, LOG_SLOW_STATEMENTS= 256, // Used by events LOG_GENERAL_LOG= 512, // Used by events HAS_SQLCOM_RESET= 1024, HAS_SQLCOM_FLUSH= 2048, /** Marks routines that directly (i.e. not by calling other routines) change tables. Note that this flag is set automatically based on type of statements used in the stored routine and is different from routine characteristic provided by user in a form of CONTAINS SQL, READS SQL DATA, MODIFIES SQL DATA clauses. The latter are accepted by parser but pretty much ignored after that. We don't rely on them: a) for compatibility reasons. b) because in CONTAINS SQL case they don't provide enough information anyway. */ MODIFIES_DATA= 4096, /* Marks routines that have column type references: DECLARE a t1.a%TYPE; */ HAS_COLUMN_TYPE_REFS= 8192, /* Set if has FETCH GROUP NEXT ROW instr. Used to ensure that only functions with AGGREGATE keyword use the instr. */ HAS_AGGREGATE_INSTR= 16384 }; sp_package *m_parent; const Sp_handler *m_handler; uint m_flags; // Boolean attributes of a stored routine /** Instrumentation interface for SP. */ PSI_sp_share *m_sp_share; Column_definition m_return_field_def; /**< This is used for FUNCTIONs only. */ const char *m_tmp_query; ///< Temporary pointer to sub query string private: /* Private to guarantee that m_chistics.comment is properly set to: - a string which is alloced on this->mem_root - or (NULL,0) set_chistics() makes sure this. */ Sp_chistics m_chistics; void set_chistics(const st_sp_chistics &chistics); inline void set_chistics_agg_type(enum enum_sp_aggregate_type type) { m_chistics.agg_type= type; } public: sql_mode_t m_sql_mode; ///< For SHOW CREATE and execution bool m_explicit_name; /**< Prepend the db name? */ LEX_CSTRING m_qname; ///< db.name LEX_CSTRING m_params; LEX_CSTRING m_body; LEX_CSTRING m_body_utf8; LEX_CSTRING m_defstr; AUTHID m_definer; const st_sp_chistics &chistics() const { return m_chistics; } const LEX_CSTRING &comment() const { return m_chistics.comment; } void set_suid(enum_sp_suid_behaviour suid) { m_chistics.suid= suid; } enum_sp_suid_behaviour suid() const { return m_chistics.suid; } bool detistic() const { return m_chistics.detistic; } enum_sp_data_access daccess() const { return m_chistics.daccess; } enum_sp_aggregate_type agg_type() const { return m_chistics.agg_type; } /** Is this routine being executed? */ virtual bool is_invoked() const { return m_flags & IS_INVOKED; } /** Get the value of the SP cache version, as remembered when the routine was inserted into the cache. */ ulong sp_cache_version() const; /** Set the value of the SP cache version. */ void set_sp_cache_version(ulong version_arg) const { m_sp_cache_version= version_arg; } sp_rcontext *rcontext_create(THD *thd, Field *retval, List *args); sp_rcontext *rcontext_create(THD *thd, Field *retval, Item **args, uint arg_count); sp_rcontext *rcontext_create(THD *thd, Field *retval, Row_definition_list *list, bool switch_security_ctx); bool eq_routine_spec(const sp_head *) const; private: /** Version of the stored routine cache at the moment when the routine was added to it. Is used only for functions and procedures, not used for triggers or events. When sp_head is created, its version is 0. When it's added to the cache, the version is assigned the global value 'Cversion'. If later on Cversion is incremented, we know that the routine is obsolete and should not be used -- sp_cache_flush_obsolete() will purge it. */ mutable ulong m_sp_cache_version; Stored_program_creation_ctx *m_creation_ctx; /** Boolean combination of (1<clone(mem_root); } longlong m_created; longlong m_modified; /** Recursion level of the current SP instance. The levels are numbered from 0 */ ulong m_recursion_level; /** A list of diferent recursion level instances for the same procedure. For every recursion level we have a sp_head instance. This instances connected in the list. The list ordered by increasing recursion level (m_recursion_level). */ sp_head *m_next_cached_sp; /** Pointer to the first element of the above list */ sp_head *m_first_instance; /** Pointer to the first free (non-INVOKED) routine in the list of cached instances for this SP. This pointer is set only for the first SP in the list of instences (see above m_first_cached_sp pointer). The pointer equal to 0 if we have no free instances. For non-first instance value of this pointer meanless (point to itself); */ sp_head *m_first_free_instance; /** Pointer to the last element in the list of instances of the SP. For non-first instance value of this pointer meanless (point to itself); */ sp_head *m_last_cached_sp; /** Set containing names of stored routines used by this routine. Note that unlike elements of similar set for statement elements of this set are not linked in one list. Because of this we are able save memory by using for this set same objects that are used in 'sroutines' sets for statements of which this stored routine consists. */ HASH m_sroutines; // Pointers set during parsing const char *m_param_begin; const char *m_param_end; private: /* A pointer to the body start inside the cpp buffer. Used only during parsing. Should be removed eventually. The affected functions/methods should be fixed to get the cpp body start as a parameter, rather than through this member. */ const char *m_cpp_body_begin; public: /* Security context for stored routine which should be run under definer privileges. */ Security_context m_security_ctx; /** List of all items (Item_trigger_field objects) representing fields in old/new version of row in trigger. We use this list for checking whenever all such fields are valid at trigger creation time and for binding these fields to TABLE object at table open (although for latter pointer to table being opened is probably enough). */ SQL_I_List m_trg_table_fields; protected: sp_head(MEM_ROOT *mem_root, sp_package *parent, const Sp_handler *handler, enum_sp_aggregate_type agg_type); virtual ~sp_head(); public: static void destroy(sp_head *sp); static sp_head *create(sp_package *parent, const Sp_handler *handler, enum_sp_aggregate_type agg_type); /// Initialize after we have reset mem_root void init(LEX *lex); /** Copy sp name from parser. */ void init_sp_name(const sp_name *spname); /** Set the body-definition start position. */ void set_body_start(THD *thd, const char *cpp_body_start); /** Set the statement-definition (body-definition) end position. */ void set_stmt_end(THD *thd, const char *cpp_body_end); bool execute_trigger(THD *thd, const LEX_CSTRING *db_name, const LEX_CSTRING *table_name, GRANT_INFO *grant_info); bool execute_function(THD *thd, Item **args, uint argcount, Field *return_fld, sp_rcontext **nctx, Query_arena *call_arena); bool execute_procedure(THD *thd, List *args); static void show_create_routine_get_fields(THD *thd, const Sp_handler *sph, List *fields); bool show_create_routine(THD *thd, const Sp_handler *sph); MEM_ROOT *get_main_mem_root() { return &main_mem_root; } int add_instr(sp_instr *instr); bool add_instr_jump(THD *thd, sp_pcontext *spcont); bool add_instr_jump(THD *thd, sp_pcontext *spcont, uint dest); bool add_instr_jump_forward_with_backpatch(THD *thd, sp_pcontext *spcont, sp_label *lab); bool add_instr_jump_forward_with_backpatch(THD *thd, sp_pcontext *spcont) { return add_instr_jump_forward_with_backpatch(thd, spcont, spcont->last_label()); } bool add_instr_freturn(THD *thd, sp_pcontext *spcont, Item *item, LEX *lex); bool add_instr_preturn(THD *thd, sp_pcontext *spcont); Item *adjust_assignment_source(THD *thd, Item *val, Item *val2); /** @param thd - the current thd @param spcont - the current parse context @param spv - the SP variable @param val - the value to be assigned to the variable @param lex - the LEX that was used to create "val" @param responsible_to_free_lex - if the generated sp_instr_set should free "lex". @retval true - on error @retval false - on success */ bool set_local_variable(THD *thd, sp_pcontext *spcont, const Sp_rcontext_handler *rh, sp_variable *spv, Item *val, LEX *lex, bool responsible_to_free_lex); bool set_local_variable_row_field(THD *thd, sp_pcontext *spcont, const Sp_rcontext_handler *rh, sp_variable *spv, uint field_idx, Item *val, LEX *lex); bool set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont, const Sp_rcontext_handler *rh, sp_variable *spv, const LEX_CSTRING *field_name, Item *val, LEX *lex); bool check_package_routine_end_name(const LEX_CSTRING &end_name) const; bool check_standalone_routine_end_name(const sp_name *end_name) const; bool check_group_aggregate_instructions_function() const; bool check_group_aggregate_instructions_forbid() const; bool check_group_aggregate_instructions_require() const; private: /** Generate a code to set a single cursor parameter variable. @param thd - current thd, for mem_root allocations. @param param_spcont - the context of the parameter block @param idx - the index of the parameter @param prm - the actual parameter (contains information about the assignment source expression Item, its free list, and its LEX) */ bool add_set_cursor_param_variable(THD *thd, sp_pcontext *param_spcont, uint idx, sp_assignment_lex *prm) { DBUG_ASSERT(idx < param_spcont->context_var_count()); sp_variable *spvar= param_spcont->get_context_variable(idx); /* add_instr() gets free_list from m_thd->free_list. Initialize it before the set_local_variable() call. */ DBUG_ASSERT(m_thd->free_list == NULL); m_thd->free_list= prm->get_free_list(); if (set_local_variable(thd, param_spcont, &sp_rcontext_handler_local, spvar, prm->get_item(), prm, true)) return true; /* Safety: The item and its free_list are now fully owned by the sp_instr_set instance, created by set_local_variable(). The sp_instr_set instance is now responsible for freeing the item and the free_list. Reset the "item" and the "free_list" members of "prm", to avoid double pointers to the same objects from "prm" and from the sp_instr_set instance. */ prm->set_item_and_free_list(NULL, NULL); return false; } /** Generate a code to set all cursor parameter variables. This method is called only when parameters exists, and the number of formal parameters matches the number of actual parameters. See also comments to add_open_cursor(). */ bool add_set_cursor_param_variables(THD *thd, sp_pcontext *param_spcont, List *parameters) { DBUG_ASSERT(param_spcont->context_var_count() == parameters->elements); sp_assignment_lex *prm; List_iterator li(*parameters); for (uint idx= 0; (prm= li++); idx++) { if (add_set_cursor_param_variable(thd, param_spcont, idx, prm)) return true; } return false; } /** Generate a code to set all cursor parameter variables for a FOR LOOP, e.g.: FOR index IN cursor(1,2,3) @param */ bool add_set_for_loop_cursor_param_variables(THD *thd, sp_pcontext *param_spcont, sp_assignment_lex *param_lex, Item_args *parameters); public: /** Generate a code for an "OPEN cursor" statement. @param thd - current thd, for mem_root allocations @param spcont - the context of the cursor @param offset - the offset of the cursor @param param_spcont - the context of the cursor parameter block @param parameters - the list of the OPEN actual parameters The caller must make sure that the number of local variables in "param_spcont" (formal parameters) matches the number of list elements in "parameters" (actual parameters). NULL in either of them means 0 parameters. */ bool add_open_cursor(THD *thd, sp_pcontext *spcont, uint offset, sp_pcontext *param_spcont, List *parameters); /** Generate an initiation code for a CURSOR FOR LOOP, e.g.: FOR index IN cursor -- cursor without parameters FOR index IN cursor(1,2,3) -- cursor with parameters The code generated by this method does the following during SP run-time: - Sets all cursor parameter vartiables from "parameters" - Initializes the index ROW-type variable from the cursor (the structure is copied from the cursor to the index variable) - The cursor gets opened - The first records is fetched from the cursor to the variable "index". @param thd - the current thread (for mem_root and error reporting) @param spcont - the current parse context @param index - the loop "index" ROW-type variable @param pcursor - the cursor @param coffset - the cursor offset @param param_lex - the LEX that owns Items in "parameters" @param parameters - the cursor parameters Item array @retval true - on error (EOM) @retval false - on success */ bool add_for_loop_open_cursor(THD *thd, sp_pcontext *spcont, sp_variable *index, const sp_pcursor *pcursor, uint coffset, sp_assignment_lex *param_lex, Item_args *parameters); /** Returns true if any substatement in the routine directly (not through another routine) modifies data/changes table. @sa Comment for MODIFIES_DATA flag. */ bool modifies_data() const { return m_flags & MODIFIES_DATA; } inline uint instructions() { return m_instr.elements; } inline sp_instr * last_instruction() { sp_instr *i; get_dynamic(&m_instr, (uchar*)&i, m_instr.elements-1); return i; } bool replace_instr_to_nop(THD *thd, uint ip); /* Resets lex in 'thd' and keeps a copy of the old one. @todo Conflicting comment in sp_head.cc */ bool reset_lex(THD *thd); bool reset_lex(THD *thd, sp_lex_local *sublex); /** Merge two LEX instances. @param oldlex - the upper level LEX we're going to restore to. @param sublex - the local lex that have just parsed some substatement. @returns - false on success, true on error (e.g. failed to merge the routine list or the table list). This method is shared by: - restore_lex(), when the old LEX is popped by sp_head::m_lex.pop() - THD::restore_from_local_lex_to_old_lex(), when the old LEX is stored in the caller's local variable. */ bool merge_lex(THD *thd, LEX *oldlex, LEX *sublex); /** Restores lex in 'thd' from our copy, but keeps some status from the one in 'thd', like ptr, tables, fields, etc. @todo Conflicting comment in sp_head.cc */ bool restore_lex(THD *thd) { DBUG_ENTER("sp_head::restore_lex"); /* There is no a need to free the current thd->lex here. - In the majority of the cases restore_lex() is called on success and thd->lex does not need to be deleted. - In cases when restore_lex() is called on error, e.g. from sp_create_assignment_instr(), thd->lex is already linked to some sp_instr_xxx (using sp_lex_keeper). Note, we don't get to here in case of a syntax error when the current thd->lex is not yet completely initialized and linked. It gets automatically deleted by the Bison %destructor in sql_yacc.yy. */ LEX *oldlex= (LEX *) m_lex.pop(); if (!oldlex) DBUG_RETURN(false); // Nothing to restore // This restores thd->lex and thd->stmt_lex DBUG_RETURN(thd->restore_from_local_lex_to_old_lex(oldlex)); } /** Iterate through the LEX stack from the top (the newest) to the bottom (the oldest) and find the one that contains a non-zero spname. @returns - the address of spname, or NULL of no spname found. */ const sp_name *find_spname_recursive() { uint count= m_lex.elements; for (uint i= 0; i < count; i++) { const LEX *tmp= m_lex.elem(count - i - 1); if (tmp->spname) return tmp->spname; } return NULL; } /// Put the instruction on the backpatch list, associated with the label. int push_backpatch(THD *thd, sp_instr *, sp_label *); int push_backpatch_goto(THD *thd, sp_pcontext *ctx, sp_label *lab); /// Update all instruction with this label in the backpatch list to /// the current position. void backpatch(sp_label *); void backpatch_goto(THD *thd, sp_label *, sp_label *); /// Check for unresolved goto label bool check_unresolved_goto(); /// Start a new cont. backpatch level. If 'i' is NULL, the level is just incr. int new_cont_backpatch(sp_instr_opt_meta *i); /// Add an instruction to the current level int add_cont_backpatch(sp_instr_opt_meta *i); /// Backpatch (and pop) the current level to the current position. void do_cont_backpatch(); /// Add cpush instructions for all cursors declared in the current frame bool sp_add_instr_cpush_for_cursors(THD *thd, sp_pcontext *pcontext); const LEX_CSTRING *name() const { return &m_name; } char *create_string(THD *thd, ulong *lenp); Field *create_result_field(uint field_max_length, const LEX_CSTRING *field_name, TABLE *table) const; /** Check and prepare an instance of Column_definition for field creation (fill all necessary attributes), for variables, parameters and function return values. @param[in] thd Thread handle @param[in] lex Yacc parsing context @param[out] field_def An instance of create_field to be filled @retval false on success @retval true on error */ bool fill_field_definition(THD *thd, Column_definition *field_def) { const Type_handler *h= field_def->type_handler(); return h->Column_definition_fix_attributes(field_def) || field_def->sp_prepare_create_field(thd, mem_root); } bool row_fill_field_definitions(THD *thd, Row_definition_list *row) { /* Prepare all row fields. This will (among other things) - convert VARCHAR lengths from character length to octet length - calculate interval lengths for SET and ENUM */ List_iterator it(*row); for (Spvar_definition *def= it++; def; def= it++) { if (fill_spvar_definition(thd, def)) return true; } return false; } /** Check and prepare a Column_definition for a variable or a parameter. */ bool fill_spvar_definition(THD *thd, Column_definition *def) { if (fill_field_definition(thd, def)) return true; def->pack_flag|= FIELDFLAG_MAYBE_NULL; return false; } bool fill_spvar_definition(THD *thd, Column_definition *def, LEX_CSTRING *name) { def->field_name= *name; return fill_spvar_definition(thd, def); } private: /** Set a column type reference for a parameter definition */ void fill_spvar_using_type_reference(sp_variable *spvar, Qualified_column_ident *ref) { spvar->field_def.set_column_type_ref(ref); spvar->field_def.field_name= spvar->name; m_flags|= sp_head::HAS_COLUMN_TYPE_REFS; } void fill_spvar_using_table_rowtype_reference(THD *thd, sp_variable *spvar, Table_ident *ref) { spvar->field_def.set_table_rowtype_ref(ref); spvar->field_def.field_name= spvar->name; fill_spvar_definition(thd, &spvar->field_def); m_flags|= sp_head::HAS_COLUMN_TYPE_REFS; } public: bool spvar_fill_row(THD *thd, sp_variable *spvar, Row_definition_list *def); bool spvar_fill_type_reference(THD *thd, sp_variable *spvar, const LEX_CSTRING &table, const LEX_CSTRING &column); bool spvar_fill_type_reference(THD *thd, sp_variable *spvar, const LEX_CSTRING &db, const LEX_CSTRING &table, const LEX_CSTRING &column); bool spvar_fill_table_rowtype_reference(THD *thd, sp_variable *spvar, const LEX_CSTRING &table); bool spvar_fill_table_rowtype_reference(THD *thd, sp_variable *spvar, const LEX_CSTRING &db, const LEX_CSTRING &table); void set_c_chistics(const st_sp_chistics &chistics); void set_info(longlong created, longlong modified, const st_sp_chistics &chistics, sql_mode_t sql_mode); void set_definer(const char *definer, size_t definerlen) { AUTHID tmp; tmp.parse(definer, definerlen); m_definer.copy(mem_root, &tmp.user, &tmp.host); } void set_definer(const LEX_CSTRING *user_name, const LEX_CSTRING *host_name) { m_definer.copy(mem_root, user_name, host_name); } void reset_thd_mem_root(THD *thd); void restore_thd_mem_root(THD *thd); /** Optimize the code. */ void optimize(); /** Helper used during flow analysis during code optimization. See the implementation of opt_mark(). @param ip the instruction to add to the leads list @param leads the list of remaining paths to explore in the graph that represents the code, during flow analysis. */ void add_mark_lead(uint ip, List *leads); inline sp_instr * get_instr(uint i) { sp_instr *ip; if (i < m_instr.elements) get_dynamic(&m_instr, (uchar*)&ip, i); else ip= NULL; return ip; } #ifdef PROTECT_STATEMENT_MEMROOT int has_all_instrs_executed(); void reset_instrs_executed_counter(); #endif /* Add tables used by routine to the table list. */ bool add_used_tables_to_table_list(THD *thd, TABLE_LIST ***query_tables_last_ptr, TABLE_LIST *belong_to_view); /** Check if this stored routine contains statements disallowed in a stored function or trigger, and set an appropriate error message if this is the case. */ bool is_not_allowed_in_function(const char *where) { if (m_flags & CONTAINS_DYNAMIC_SQL) my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "Dynamic SQL"); else if (m_flags & MULTI_RESULTS) my_error(ER_SP_NO_RETSET, MYF(0), where); else if (m_flags & HAS_SET_AUTOCOMMIT_STMT) my_error(ER_SP_CANT_SET_AUTOCOMMIT, MYF(0)); else if (m_flags & HAS_COMMIT_OR_ROLLBACK) my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); else if (m_flags & HAS_SQLCOM_RESET) my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "RESET"); else if (m_flags & HAS_SQLCOM_FLUSH) my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH"); return MY_TEST(m_flags & (CONTAINS_DYNAMIC_SQL | MULTI_RESULTS | HAS_SET_AUTOCOMMIT_STMT | HAS_COMMIT_OR_ROLLBACK | HAS_SQLCOM_RESET | HAS_SQLCOM_FLUSH)); } #ifndef DBUG_OFF int show_routine_code(THD *thd); #endif /* This method is intended for attributes of a routine which need to propagate upwards to the Query_tables_list of the caller (when a property of a sp_head needs to "taint" the calling statement). */ void propagate_attributes(Query_tables_list *prelocking_ctx) { DBUG_ENTER("sp_head::propagate_attributes"); /* If this routine needs row-based binary logging, the entire top statement too (we cannot switch from statement-based to row-based only for this routine, as in statement-based the top-statement may be binlogged and the substatements not). */ DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x", prelocking_ctx->get_stmt_unsafe_flags())); DBUG_PRINT("info", ("sp_head(%p=%s)->unsafe_flags: 0x%x", this, name()->str, unsafe_flags)); prelocking_ctx->set_stmt_unsafe_flags(unsafe_flags); DBUG_VOID_RETURN; } sp_pcontext *get_parse_context() { return m_pcont; } /* Check EXECUTE access: - in case of a standalone rotuine, for the routine itself - in case of a package routine, for the owner package body */ bool check_execute_access(THD *thd) const; virtual sp_package *get_package() { return NULL; } virtual void init_psi_share(); protected: MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root THD *m_thd; ///< Set if we have reset mem_root sp_pcontext *m_pcont; ///< Parse context List m_lex; ///< Temp. store for the other lex DYNAMIC_ARRAY m_instr; ///< The "instructions" enum backpatch_instr_type { GOTO, CPOP, HPOP }; typedef struct { sp_label *lab; sp_instr *instr; backpatch_instr_type instr_type; } bp_t; List m_backpatch; ///< Instructions needing backpatching List m_backpatch_goto; // Instructions needing backpatching (for goto) /** We need a special list for backpatching of instructions with a continue destination (in the case of a continue handler catching an error in the test), since it would otherwise interfere with the normal backpatch mechanism - e.g. jump_if_not instructions have two different destinations which are to be patched differently. Since these occur in a more restricted way (always the same "level" in the code), we don't need the label. */ List m_cont_backpatch; uint m_cont_level; // The current cont. backpatch level /** Multi-set representing optimized list of tables to be locked by this routine. Does not include tables which are used by invoked routines. @note For prelocking-free SPs this multiset is constructed too. We do so because the same instance of sp_head may be called both in prelocked mode and in non-prelocked mode. */ HASH m_sptabs; bool execute(THD *thd, bool merge_da_on_success); /** Perform a forward flow analysis in the generated code. Mark reachable instructions, for the optimizer. */ void opt_mark(); /** Merge the list of tables used by query into the multi-set of tables used by routine. */ bool merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check); /// Put the instruction on the a backpatch list, associated with the label. int push_backpatch(THD *thd, sp_instr *, sp_label *, List *list, backpatch_instr_type itype); }; // class sp_head : public Sql_alloc class sp_package: public sp_head { bool validate_public_routines(THD *thd, sp_package *spec); bool validate_private_routines(THD *thd); public: class LexList: public List { public: LexList() { elements= 0; } // Find a package routine by a non qualified name LEX *find(const LEX_CSTRING &name, enum_sp_type type); // Find a package routine by a package-qualified name, e.g. 'pkg.proc' LEX *find_qualified(const LEX_CSTRING &name, enum_sp_type type); // Check if a routine with the given qualified name already exists bool check_dup_qualified(const LEX_CSTRING &name, const Sp_handler *sph) { if (!find_qualified(name, sph->type())) return false; my_error(ER_SP_ALREADY_EXISTS, MYF(0), sph->type_str(), name.str); return true; } bool check_dup_qualified(const sp_head *sp) { return check_dup_qualified(sp->m_name, sp->m_handler); } void cleanup(); }; /* The LEX for a new package subroutine is initially assigned to m_current_routine. After scanning parameters, return type and chistics, the parser detects if we have a declaration or a definition, e.g.: PROCEDURE p1(a INT); vs PROCEDURE p1(a INT) AS BEGIN NULL; END; (i.e. either semicolon or the "AS" keyword) m_current_routine is then added either to m_routine_implementations, or m_routine_declarations, and then m_current_routine is set to NULL. */ LEX *m_current_routine; LexList m_routine_implementations; LexList m_routine_declarations; LEX *m_top_level_lex; sp_rcontext *m_rcontext; uint m_invoked_subroutine_count; bool m_is_instantiated; bool m_is_cloning_routine; private: sp_package(MEM_ROOT *mem_root, LEX *top_level_lex, const sp_name *name, const Sp_handler *sph); ~sp_package(); public: static sp_package *create(LEX *top_level_lex, const sp_name *name, const Sp_handler *sph); bool add_routine_declaration(LEX *lex) { return m_routine_declarations.check_dup_qualified(lex->sphead) || m_routine_declarations.push_back(lex, &main_mem_root); } bool add_routine_implementation(LEX *lex) { return m_routine_implementations.check_dup_qualified(lex->sphead) || m_routine_implementations.push_back(lex, &main_mem_root); } sp_package *get_package() override { return this; } void init_psi_share() override; bool is_invoked() const override { /* Cannot flush a package out of the SP cache when: - its initialization block is running - one of its subroutine is running */ return sp_head::is_invoked() || m_invoked_subroutine_count > 0; } sp_variable *find_package_variable(const LEX_CSTRING *name) const { /* sp_head::m_pcont is a special level for routine parameters. Variables declared inside CREATE PACKAGE BODY reside in m_children.at(0). */ sp_pcontext *ctx= m_pcont->child_context(0); return ctx ? ctx->find_variable(name, true) : NULL; } bool validate_after_parser(THD *thd); bool instantiate_if_needed(THD *thd); }; class sp_lex_cursor: public sp_lex_local, public Query_arena { public: sp_lex_cursor(THD *thd, const LEX *oldlex, MEM_ROOT *mem_root_arg) :sp_lex_local(thd, oldlex), Query_arena(mem_root_arg, STMT_INITIALIZED_FOR_SP) { } sp_lex_cursor(THD *thd, const LEX *oldlex) :sp_lex_local(thd, oldlex), Query_arena(thd->lex->sphead->get_main_mem_root(), STMT_INITIALIZED_FOR_SP) { } ~sp_lex_cursor() { free_items(); } bool cleanup_stmt(bool /*restore_set_statement_vars*/) override { return false; } Query_arena *query_arena() override { return this; } bool validate() { DBUG_ASSERT(sql_command == SQLCOM_SELECT); if (result) { my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0)); return true; } return false; } bool stmt_finalize(THD *thd) { if (validate()) return true; sp_lex_in_use= true; free_list= thd->free_list; thd->free_list= NULL; return false; } }; // // "Instructions"... // class sp_instr :public Query_arena, public Sql_alloc { sp_instr(const sp_instr &); /**< Prevent use of these */ void operator=(sp_instr &); public: uint marked; uint m_ip; ///< My index sp_pcontext *m_ctx; ///< My parse context uint m_lineno; /// Should give each a name or type code for debugging purposes? sp_instr(uint ip, sp_pcontext *ctx) :Query_arena(0, STMT_INITIALIZED_FOR_SP), marked(0), m_ip(ip), m_ctx(ctx) #ifdef PROTECT_STATEMENT_MEMROOT , m_has_been_run(NON_RUN) #endif {} virtual ~sp_instr() { free_items(); } /** Execute this instruction @param thd Thread handle @param[out] nextp index of the next instruction to execute. (For most instructions this will be the instruction following this one). Note that this parameter is undefined in case of errors, use get_cont_dest() to find the continuation instruction for CONTINUE error handlers. @retval 0 on success, @retval other if some error occurred */ virtual int execute(THD *thd, uint *nextp) = 0; /** Execute open_and_lock_tables() for this statement. Open and lock the tables used by this statement, as a pre-requisite to execute the core logic of this instruction with exec_core(). @param thd the current thread @param tables the list of tables to open and lock @return zero on success, non zero on failure. */ int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables); /** Get the continuation destination of this instruction. @return the continuation destination */ virtual uint get_cont_dest() const; /* Execute core function of instruction after all preparations (e.g. setting of proper LEX, saving part of the thread context have been done). Should be implemented for instructions using expressions or whole statements (thus having to have own LEX). Used in concert with sp_lex_keeper class and its descendants (there are none currently). */ virtual int exec_core(THD *thd, uint *nextp); virtual void print(String *str) = 0; virtual void backpatch(uint dest, sp_pcontext *dst_ctx) {} /** Mark this instruction as reachable during optimization and return the index to the next instruction. Jump instruction will add their destination to the leads list. */ virtual uint opt_mark(sp_head *sp, List *leads) { marked= 1; return m_ip+1; } /** Short-cut jumps to jumps during optimization. This is used by the jump instructions' opt_mark() methods. 'start' is the starting point, used to prevent the mark sweep from looping for ever. Return the end destination. */ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) { return m_ip; } /** Inform the instruction that it has been moved during optimization. Most instructions will simply update its index, but jump instructions must also take care of their destination pointers. Forward jumps get pushed to the backpatch list 'ibp'. */ virtual void opt_move(uint dst, List *ibp) { m_ip= dst; } virtual PSI_statement_info* get_psi_info() = 0; #ifdef PROTECT_STATEMENT_MEMROOT bool has_been_run() const { return m_has_been_run == RUN; } void mark_as_qc_used() { m_has_been_run= QC; } void mark_as_run() { if (m_has_been_run == QC) m_has_been_run= NON_RUN; // answer was from WC => not really executed else m_has_been_run= RUN; } void mark_as_not_run() { m_has_been_run= NON_RUN; } private: enum {NON_RUN, QC, RUN} m_has_been_run; #endif }; // class sp_instr : public Sql_alloc /** Auxilary class to which instructions delegate responsibility for handling LEX and preparations before executing statement or calculating complex expression. Exist mainly to avoid having double hierarchy between instruction classes. @todo Add ability to not store LEX and do any preparations if expression used is simple. */ class sp_lex_keeper { /** Prevent use of these */ sp_lex_keeper(const sp_lex_keeper &); void operator=(sp_lex_keeper &); public: sp_lex_keeper(LEX *lex, bool lex_resp) : m_lex(lex), m_lex_resp(lex_resp), lex_query_tables_own_last(NULL) { lex->sp_lex_in_use= TRUE; } virtual ~sp_lex_keeper(); /** Prepare execution of instruction using LEX, if requested check whenever we have read access to tables used and open/lock them, call instruction's exec_core() method, perform cleanup afterwards. @todo Conflicting comment in sp_head.cc */ int reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables, sp_instr* instr); int cursor_reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables, sp_instr *instr); inline uint sql_command() const { return (uint)m_lex->sql_command; } void disable_query_cache() { m_lex->safe_to_cache_query= 0; } private: LEX *m_lex; /** Indicates whenever this sp_lex_keeper instance responsible for LEX deletion. */ bool m_lex_resp; /* Support for being able to execute this statement in two modes: a) inside prelocked mode set by the calling procedure or its ancestor. b) outside of prelocked mode, when this statement enters/leaves prelocked mode itself. */ /** List of additional tables this statement needs to lock when it enters/leaves prelocked mode on its own. */ TABLE_LIST *prelocking_tables; /** The value m_lex->query_tables_own_last should be set to this when the statement enters/leaves prelocked mode on its own. */ TABLE_LIST **lex_query_tables_own_last; }; /** Call out to some prepared SQL statement. */ class sp_instr_stmt : public sp_instr { sp_instr_stmt(const sp_instr_stmt &); /**< Prevent use of these */ void operator=(sp_instr_stmt &); public: LEX_STRING m_query; ///< For thd->query sp_instr_stmt(uint ip, sp_pcontext *ctx, LEX *lex) : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE) { m_query.str= 0; m_query.length= 0; } virtual ~sp_instr_stmt() = default; int execute(THD *thd, uint *nextp) override; int exec_core(THD *thd, uint *nextp) override; void print(String *str) override; private: sp_lex_keeper m_lex_keeper; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_stmt : public sp_instr class sp_instr_set : public sp_instr { sp_instr_set(const sp_instr_set &); /**< Prevent use of these */ void operator=(sp_instr_set &); public: sp_instr_set(uint ip, sp_pcontext *ctx, const Sp_rcontext_handler *rh, uint offset, Item *val, LEX *lex, bool lex_resp) : sp_instr(ip, ctx), m_rcontext_handler(rh), m_offset(offset), m_value(val), m_lex_keeper(lex, lex_resp) {} virtual ~sp_instr_set() = default; int execute(THD *thd, uint *nextp) override; int exec_core(THD *thd, uint *nextp) override; void print(String *str) override; protected: sp_rcontext *get_rcontext(THD *thd) const; const Sp_rcontext_handler *m_rcontext_handler; uint m_offset; ///< Frame offset Item *m_value; sp_lex_keeper m_lex_keeper; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_set : public sp_instr /* This class handles assignments of a ROW fields: DECLARE rec ROW (a INT,b INT); SET rec.a= 10; */ class sp_instr_set_row_field : public sp_instr_set { sp_instr_set_row_field(const sp_instr_set_row_field &); // Prevent use of this void operator=(sp_instr_set_row_field &); uint m_field_offset; public: sp_instr_set_row_field(uint ip, sp_pcontext *ctx, const Sp_rcontext_handler *rh, uint offset, uint field_offset, Item *val, LEX *lex, bool lex_resp) : sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp), m_field_offset(field_offset) {} virtual ~sp_instr_set_row_field() = default; int exec_core(THD *thd, uint *nextp) override; void print(String *str) override; }; // class sp_instr_set_field : public sp_instr_set /** This class handles assignment instructions like this: DECLARE CURSOR cur IS SELECT * FROM t1; rec cur%ROWTYPE; BEGIN rec.column1:= 10; -- This instruction END; The idea is that during sp_rcontext::create() we do not know the extact structure of "rec". It gets resolved at run time, during the corresponding sp_instr_cursor_copy_struct::exec_core(). So sp_instr_set_row_field_by_name searches for ROW fields by name, while sp_instr_set_row_field (see above) searches for ROW fields by index. */ class sp_instr_set_row_field_by_name : public sp_instr_set { // Prevent use of this sp_instr_set_row_field_by_name(const sp_instr_set_row_field &); void operator=(sp_instr_set_row_field_by_name &); const LEX_CSTRING m_field_name; public: sp_instr_set_row_field_by_name(uint ip, sp_pcontext *ctx, const Sp_rcontext_handler *rh, uint offset, const LEX_CSTRING &field_name, Item *val, LEX *lex, bool lex_resp) : sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp), m_field_name(field_name) {} virtual ~sp_instr_set_row_field_by_name() = default; int exec_core(THD *thd, uint *nextp) override; void print(String *str) override; }; // class sp_instr_set_field_by_name : public sp_instr_set /** Set NEW/OLD row field value instruction. Used in triggers. */ class sp_instr_set_trigger_field : public sp_instr { sp_instr_set_trigger_field(const sp_instr_set_trigger_field &); void operator=(sp_instr_set_trigger_field &); public: sp_instr_set_trigger_field(uint ip, sp_pcontext *ctx, Item_trigger_field *trg_fld, Item *val, LEX *lex) : sp_instr(ip, ctx), trigger_field(trg_fld), value(val), m_lex_keeper(lex, TRUE) {} virtual ~sp_instr_set_trigger_field() = default; int execute(THD *thd, uint *nextp) override; int exec_core(THD *thd, uint *nextp) override; void print(String *str) override; private: Item_trigger_field *trigger_field; Item *value; sp_lex_keeper m_lex_keeper; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_trigger_field : public sp_instr /** An abstract class for all instructions with destinations that needs to be updated by the optimizer. Even if not all subclasses will use both the normal destination and the continuation destination, we put them both here for simplicity. */ class sp_instr_opt_meta : public sp_instr { public: uint m_dest; ///< Where we will go uint m_cont_dest; ///< Where continue handlers will go sp_instr_opt_meta(uint ip, sp_pcontext *ctx) : sp_instr(ip, ctx), m_dest(0), m_cont_dest(0), m_optdest(0), m_cont_optdest(0) {} sp_instr_opt_meta(uint ip, sp_pcontext *ctx, uint dest) : sp_instr(ip, ctx), m_dest(dest), m_cont_dest(0), m_optdest(0), m_cont_optdest(0) {} virtual ~sp_instr_opt_meta() = default; virtual void set_destination(uint old_dest, uint new_dest) = 0; uint get_cont_dest() const override; protected: sp_instr *m_optdest; ///< Used during optimization sp_instr *m_cont_optdest; ///< Used during optimization }; // class sp_instr_opt_meta : public sp_instr class sp_instr_jump : public sp_instr_opt_meta { sp_instr_jump(const sp_instr_jump &); /**< Prevent use of these */ void operator=(sp_instr_jump &); public: sp_instr_jump(uint ip, sp_pcontext *ctx) : sp_instr_opt_meta(ip, ctx) {} sp_instr_jump(uint ip, sp_pcontext *ctx, uint dest) : sp_instr_opt_meta(ip, ctx, dest) {} virtual ~sp_instr_jump() = default; int execute(THD *thd, uint *nextp) override; void print(String *str) override; uint opt_mark(sp_head *sp, List *leads) override; uint opt_shortcut_jump(sp_head *sp, sp_instr *start) override; void opt_move(uint dst, List *ibp) override; void backpatch(uint dest, sp_pcontext *dst_ctx) override { /* Calling backpatch twice is a logic flaw in jump resolution. */ DBUG_ASSERT(m_dest == 0); m_dest= dest; } /** Update the destination; used by the optimizer. */ void set_destination(uint old_dest, uint new_dest) override { if (m_dest == old_dest) m_dest= new_dest; } public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_jump : public sp_instr_opt_meta class sp_instr_jump_if_not : public sp_instr_jump { sp_instr_jump_if_not(const sp_instr_jump_if_not &); /**< Prevent use of these */ void operator=(sp_instr_jump_if_not &); public: sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex) : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE) {} sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex) : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE) {} virtual ~sp_instr_jump_if_not() = default; int execute(THD *thd, uint *nextp) override; int exec_core(THD *thd, uint *nextp) override; void print(String *str) override; uint opt_mark(sp_head *sp, List *leads) override; /** Override sp_instr_jump's shortcut; we stop here */ uint opt_shortcut_jump(sp_head *sp, sp_instr *start) override { return m_ip; } void opt_move(uint dst, List *ibp) override; void set_destination(uint old_dest, uint new_dest) override { sp_instr_jump::set_destination(old_dest, new_dest); if (m_cont_dest == old_dest) m_cont_dest= new_dest; } private: Item *m_expr; ///< The condition sp_lex_keeper m_lex_keeper; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_jump_if_not : public sp_instr_jump class sp_instr_preturn : public sp_instr { sp_instr_preturn(const sp_instr_preturn &); /**< Prevent use of these */ void operator=(sp_instr_preturn &); public: sp_instr_preturn(uint ip, sp_pcontext *ctx) : sp_instr(ip, ctx) {} virtual ~sp_instr_preturn() = default; int execute(THD *thd, uint *nextp) override; void print(String *str) override; uint opt_mark(sp_head *sp, List *leads) override { marked= 1; return UINT_MAX; } public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_preturn : public sp_instr class sp_instr_freturn : public sp_instr { sp_instr_freturn(const sp_instr_freturn &); /**< Prevent use of these */ void operator=(sp_instr_freturn &); public: sp_instr_freturn(uint ip, sp_pcontext *ctx, Item *val, const Type_handler *handler, LEX *lex) : sp_instr(ip, ctx), m_value(val), m_type_handler(handler), m_lex_keeper(lex, TRUE) {} virtual ~sp_instr_freturn() = default; int execute(THD *thd, uint *nextp) override; int exec_core(THD *thd, uint *nextp) override; void print(String *str) override; uint opt_mark(sp_head *sp, List *leads) override { marked= 1; return UINT_MAX; } protected: Item *m_value; const Type_handler *m_type_handler; sp_lex_keeper m_lex_keeper; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_freturn : public sp_instr class sp_instr_hpush_jump : public sp_instr_jump { sp_instr_hpush_jump(const sp_instr_hpush_jump &); /**< Prevent use of these */ void operator=(sp_instr_hpush_jump &); public: sp_instr_hpush_jump(uint ip, sp_pcontext *ctx, sp_handler *handler) :sp_instr_jump(ip, ctx), m_handler(handler), m_opt_hpop(0), m_frame(ctx->current_var_count()) { DBUG_ASSERT(m_handler->condition_values.elements == 0); } virtual ~sp_instr_hpush_jump() { m_handler->condition_values.empty(); m_handler= NULL; } int execute(THD *thd, uint *nextp) override; void print(String *str) override; uint opt_mark(sp_head *sp, List *leads) override; /** Override sp_instr_jump's shortcut; we stop here. */ uint opt_shortcut_jump(sp_head *sp, sp_instr *start) override { return m_ip; } void backpatch(uint dest, sp_pcontext *dst_ctx) override { DBUG_ASSERT(!m_dest || !m_opt_hpop); if (!m_dest) m_dest= dest; else m_opt_hpop= dest; } void add_condition(sp_condition_value *condition_value) { m_handler->condition_values.push_back(condition_value); } sp_handler *get_handler() { return m_handler; } private: /// Handler. sp_handler *m_handler; /// hpop marking end of handler scope. uint m_opt_hpop; // This attribute is needed for SHOW PROCEDURE CODE only (i.e. it's needed in // debug version only). It's used in print(). uint m_frame; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_hpush_jump : public sp_instr_jump class sp_instr_hpop : public sp_instr { sp_instr_hpop(const sp_instr_hpop &); /**< Prevent use of these */ void operator=(sp_instr_hpop &); public: sp_instr_hpop(uint ip, sp_pcontext *ctx, uint count) : sp_instr(ip, ctx), m_count(count) {} virtual ~sp_instr_hpop() = default; void update_count(uint count) { m_count= count; } int execute(THD *thd, uint *nextp) override; void print(String *str) override; private: uint m_count; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_hpop : public sp_instr class sp_instr_hreturn : public sp_instr_jump { sp_instr_hreturn(const sp_instr_hreturn &); /**< Prevent use of these */ void operator=(sp_instr_hreturn &); public: sp_instr_hreturn(uint ip, sp_pcontext *ctx) :sp_instr_jump(ip, ctx), m_frame(ctx->current_var_count()) {} virtual ~sp_instr_hreturn() = default; int execute(THD *thd, uint *nextp) override; void print(String *str) override; /* This instruction will not be short cut optimized. */ uint opt_shortcut_jump(sp_head *sp, sp_instr *start) override { return m_ip; } uint opt_mark(sp_head *sp, List *leads) override; private: uint m_frame; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_hreturn : public sp_instr_jump /** This is DECLARE CURSOR */ class sp_instr_cpush : public sp_instr, public sp_cursor { sp_instr_cpush(const sp_instr_cpush &); /**< Prevent use of these */ void operator=(sp_instr_cpush &); public: sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex, uint offset) : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE), m_cursor(offset) {} virtual ~sp_instr_cpush() = default; int execute(THD *thd, uint *nextp) override; void print(String *str) override; /** This call is used to cleanup the instruction when a sensitive cursor is closed. For now stored procedures always use materialized cursors and the call is not used. */ bool cleanup_stmt(bool /*restore_set_statement_vars*/) override { return false; } private: sp_lex_keeper m_lex_keeper; uint m_cursor; /**< Frame offset (for debugging) */ public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_cpush : public sp_instr class sp_instr_cpop : public sp_instr { sp_instr_cpop(const sp_instr_cpop &); /**< Prevent use of these */ void operator=(sp_instr_cpop &); public: sp_instr_cpop(uint ip, sp_pcontext *ctx, uint count) : sp_instr(ip, ctx), m_count(count) {} virtual ~sp_instr_cpop() = default; void update_count(uint count) { m_count= count; } int execute(THD *thd, uint *nextp) override; void print(String *str) override; private: uint m_count; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_cpop : public sp_instr class sp_instr_copen : public sp_instr { sp_instr_copen(const sp_instr_copen &); /**< Prevent use of these */ void operator=(sp_instr_copen &); public: sp_instr_copen(uint ip, sp_pcontext *ctx, uint c) : sp_instr(ip, ctx), m_cursor(c) {} virtual ~sp_instr_copen() = default; int execute(THD *thd, uint *nextp) override; int exec_core(THD *thd, uint *nextp) override; void print(String *str) override; private: uint m_cursor; ///< Stack index public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_copen : public sp_instr_stmt /** Initialize the structure of a cursor%ROWTYPE variable from the LEX containing the cursor SELECT statement. */ class sp_instr_cursor_copy_struct: public sp_instr { /**< Prevent use of these */ sp_instr_cursor_copy_struct(const sp_instr_cursor_copy_struct &); void operator=(sp_instr_cursor_copy_struct &); sp_lex_keeper m_lex_keeper; uint m_cursor; uint m_var; public: sp_instr_cursor_copy_struct(uint ip, sp_pcontext *ctx, uint coffs, sp_lex_cursor *lex, uint voffs) : sp_instr(ip, ctx), m_lex_keeper(lex, FALSE), m_cursor(coffs), m_var(voffs) {} virtual ~sp_instr_cursor_copy_struct() = default; int execute(THD *thd, uint *nextp) override; int exec_core(THD *thd, uint *nextp) override; void print(String *str) override; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; class sp_instr_cclose : public sp_instr { sp_instr_cclose(const sp_instr_cclose &); /**< Prevent use of these */ void operator=(sp_instr_cclose &); public: sp_instr_cclose(uint ip, sp_pcontext *ctx, uint c) : sp_instr(ip, ctx), m_cursor(c) {} virtual ~sp_instr_cclose() = default; int execute(THD *thd, uint *nextp) override; void print(String *str) override; private: uint m_cursor; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_cclose : public sp_instr class sp_instr_cfetch : public sp_instr { sp_instr_cfetch(const sp_instr_cfetch &); /**< Prevent use of these */ void operator=(sp_instr_cfetch &); public: sp_instr_cfetch(uint ip, sp_pcontext *ctx, uint c, bool error_on_no_data) : sp_instr(ip, ctx), m_cursor(c), m_error_on_no_data(error_on_no_data) { m_varlist.empty(); } virtual ~sp_instr_cfetch() = default; int execute(THD *thd, uint *nextp) override; void print(String *str) override; void add_to_varlist(sp_variable *var) { m_varlist.push_back(var); } private: uint m_cursor; List m_varlist; bool m_error_on_no_data; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_cfetch : public sp_instr /* This class is created for the special fetch instruction FETCH GROUP NEXT ROW, used in the user-defined aggregate functions */ class sp_instr_agg_cfetch : public sp_instr { sp_instr_agg_cfetch(const sp_instr_cfetch &); /**< Prevent use of these */ void operator=(sp_instr_cfetch &); public: sp_instr_agg_cfetch(uint ip, sp_pcontext *ctx) : sp_instr(ip, ctx){} virtual ~sp_instr_agg_cfetch() = default; int execute(THD *thd, uint *nextp) override; void print(String *str) override; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_agg_cfetch : public sp_instr class sp_instr_error : public sp_instr { sp_instr_error(const sp_instr_error &); /**< Prevent use of these */ void operator=(sp_instr_error &); public: sp_instr_error(uint ip, sp_pcontext *ctx, int errcode) : sp_instr(ip, ctx), m_errcode(errcode) {} virtual ~sp_instr_error() = default; int execute(THD *thd, uint *nextp) override; void print(String *str) override; uint opt_mark(sp_head *sp, List *leads) override { marked= 1; return UINT_MAX; } private: int m_errcode; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_error : public sp_instr class sp_instr_set_case_expr : public sp_instr_opt_meta { public: sp_instr_set_case_expr(uint ip, sp_pcontext *ctx, uint case_expr_id, Item *case_expr, LEX *lex) : sp_instr_opt_meta(ip, ctx), m_case_expr_id(case_expr_id), m_case_expr(case_expr), m_lex_keeper(lex, TRUE) {} virtual ~sp_instr_set_case_expr() = default; int execute(THD *thd, uint *nextp) override; int exec_core(THD *thd, uint *nextp) override; void print(String *str) override; uint opt_mark(sp_head *sp, List *leads) override; void opt_move(uint dst, List *ibp) override; void set_destination(uint old_dest, uint new_dest) override { if (m_cont_dest == old_dest) m_cont_dest= new_dest; } private: uint m_case_expr_id; Item *m_case_expr; sp_lex_keeper m_lex_keeper; public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; }; // class sp_instr_set_case_expr : public sp_instr_opt_meta bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access); #ifndef NO_EMBEDDED_ACCESS_CHECKS bool sp_change_security_context(THD *thd, sp_head *sp, Security_context **backup); void sp_restore_security_context(THD *thd, Security_context *backup); bool set_routine_security_ctx(THD *thd, sp_head *sp, Security_context **save_ctx); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ TABLE_LIST * sp_add_to_query_tables(THD *thd, LEX *lex, const LEX_CSTRING *db, const LEX_CSTRING *name, thr_lock_type locktype, enum_mdl_type mdl_type); /** @} (end of group Stored_Routines) */ #endif /* _SP_HEAD_H_ */ server/private/service_versions.h000064400000004001151031265040013255 0ustar00/* Copyright (c) 2009, 2010, Oracle and/or its affiliates. Copyright (c) 2012, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef _WIN32 #define SERVICE_VERSION __declspec(dllexport) void * #else #define SERVICE_VERSION void * #endif #define VERSION_debug_sync 0x1000 #define VERSION_kill_statement 0x1000 #define VERSION_base64 0x0100 #define VERSION_encryption 0x0300 #define VERSION_encryption_scheme 0x0100 #define VERSION_logger 0x0100 #define VERSION_my_crypt 0x0100 #define VERSION_my_md5 0x0100 #define VERSION_my_print_error 0x0100 #define VERSION_my_sha1 0x0101 #define VERSION_my_sha2 0x0100 #define VERSION_my_snprintf 0x0100 #define VERSION_progress_report 0x0100 #define VERSION_thd_alloc 0x0200 #define VERSION_thd_autoinc 0x0100 #define VERSION_thd_error_context 0x0200 #define VERSION_thd_rnd 0x0100 #define VERSION_thd_specifics 0x0100 #define VERSION_thd_timezone 0x0100 #define VERSION_thd_wait 0x0100 #define VERSION_wsrep 0x0500 #define VERSION_json 0x0100 #define VERSION_sql_service 0x0102 #define VERSION_thd_mdl 0x0100 #define VERSION_print_check_msg 0x0100 server/private/item_func.h000064400000413204151031265040011647 0ustar00#ifndef ITEM_FUNC_INCLUDED #define ITEM_FUNC_INCLUDED /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2009, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Function items used by mysql */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #ifdef HAVE_IEEEFP_H extern "C" /* Bug in BSDI include file */ { #include } #endif #include "sql_udf.h" // udf_handler #include "my_decimal.h" // string2my_decimal #include extern int st_append_json(String *s, CHARSET_INFO *json_cs, const uchar *js, uint js_len); class Item_func :public Item_func_or_sum { void sync_with_sum_func_and_with_field(List &list); protected: virtual bool check_arguments() const { return check_argument_types_scalar(0, arg_count); } bool check_argument_types_like_args0() const; bool check_argument_types_scalar(uint start, uint end) const; bool check_argument_types_traditional_scalar(uint start, uint end) const; bool check_argument_types_or_binary(const Type_handler *handler, uint start, uint end) const; bool check_argument_types_can_return_int(uint start, uint end) const; bool check_argument_types_can_return_real(uint start, uint end) const; bool check_argument_types_can_return_str(uint start, uint end) const; bool check_argument_types_can_return_text(uint start, uint end) const; bool check_argument_types_can_return_date(uint start, uint end) const; bool check_argument_types_can_return_time(uint start, uint end) const; void print_cast_temporal(String *str, enum_query_type query_type); void print_schema_qualified_name(String *to, const LEX_CSTRING &schema_name, const LEX_CSTRING &function_name) const { // e.g. oracle_schema.func() to->append(schema_name); to->append('.'); to->append(function_name); } void print_sql_mode_qualified_name(String *to, enum_query_type query_type, const LEX_CSTRING &function_name) const { const Schema *func_schema= schema(); if (!func_schema || func_schema == Schema::find_implied(current_thd)) to->append(function_name); else print_schema_qualified_name(to, func_schema->name(), function_name); } void print_sql_mode_qualified_name(String *to, enum_query_type query_type) const { return print_sql_mode_qualified_name(to, query_type, func_name_cstring()); } public: // Print an error message for a builtin-schema qualified function call static void wrong_param_count_error(const LEX_CSTRING &schema_name, const LEX_CSTRING &func_name); table_map not_null_tables_cache= 0; enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC, GE_FUNC,GT_FUNC,FT_FUNC, LIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC, COND_AND_FUNC, COND_OR_FUNC, XOR_FUNC, BETWEEN, IN_FUNC, MULT_EQUAL_FUNC, INTERVAL_FUNC, ISNOTNULLTEST_FUNC, SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC, SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC, SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC, SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING, SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN, SP_RELATE_FUNC, NOT_FUNC, NOT_ALL_FUNC, TEMPTABLE_ROWID, NOW_FUNC, NOW_UTC_FUNC, SYSDATE_FUNC, TRIG_COND_FUNC, SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC, NEG_FUNC, GSYSVAR_FUNC, IN_OPTIMIZER_FUNC, DYNCOL_FUNC, JSON_EXTRACT_FUNC, JSON_VALID_FUNC, ROWNUM_FUNC, CASE_SEARCHED_FUNC, // Used by ColumnStore/Spider CASE_SIMPLE_FUNC, // Used by ColumnStore/spider, }; /* A function bitmap. Useful when some operation needs to be applied only to certain functions. For now we only need to distinguish some comparison predicates. */ enum Bitmap : ulonglong { BITMAP_NONE= 0, BITMAP_EQ= 1ULL << EQ_FUNC, BITMAP_EQUAL= 1ULL << EQUAL_FUNC, BITMAP_NE= 1ULL << NE_FUNC, BITMAP_LT= 1ULL << LT_FUNC, BITMAP_LE= 1ULL << LE_FUNC, BITMAP_GE= 1ULL << GE_FUNC, BITMAP_GT= 1ULL << GT_FUNC, BITMAP_LIKE= 1ULL << LIKE_FUNC, BITMAP_BETWEEN= 1ULL << BETWEEN, BITMAP_IN= 1ULL << IN_FUNC, BITMAP_MULT_EQUAL= 1ULL << MULT_EQUAL_FUNC, BITMAP_OTHER= 1ULL << 63, BITMAP_ALL= 0xFFFFFFFFFFFFFFFFULL, BITMAP_ANY_EQUALITY= BITMAP_EQ | BITMAP_EQUAL | BITMAP_MULT_EQUAL, BITMAP_EXCEPT_ANY_EQUALITY= BITMAP_ALL & ~BITMAP_ANY_EQUALITY, }; ulonglong bitmap_bit() const { Functype type= functype(); return 1ULL << (type > 63 ? 63 : type); } static scalar_comparison_op functype_to_scalar_comparison_op(Functype type) { switch (type) { case EQ_FUNC: return SCALAR_CMP_EQ; case EQUAL_FUNC: return SCALAR_CMP_EQUAL; case LT_FUNC: return SCALAR_CMP_LT; case LE_FUNC: return SCALAR_CMP_LE; case GE_FUNC: return SCALAR_CMP_GE; case GT_FUNC: return SCALAR_CMP_GT; default: break; } DBUG_ASSERT(0); return SCALAR_CMP_EQ; } enum Type type() const override { return FUNC_ITEM; } virtual enum Functype functype() const { return UNKNOWN_FUNC; } Item_func(THD *thd): Item_func_or_sum(thd) { DBUG_ASSERT(with_flags == item_with_t::NONE); with_flags= item_with_t::NONE; } Item_func(THD *thd, Item *a): Item_func_or_sum(thd, a) { with_flags= a->with_flags; } Item_func(THD *thd, Item *a, Item *b): Item_func_or_sum(thd, a, b) { with_flags= a->with_flags | b->with_flags; } Item_func(THD *thd, Item *a, Item *b, Item *c): Item_func_or_sum(thd, a, b, c) { with_flags|= a->with_flags | b->with_flags | c->with_flags; } Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d): Item_func_or_sum(thd, a, b, c, d) { with_flags= a->with_flags | b->with_flags | c->with_flags | d->with_flags; } Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e): Item_func_or_sum(thd, a, b, c, d, e) { with_flags= (a->with_flags | b->with_flags | c->with_flags | d->with_flags | e->with_flags); } Item_func(THD *thd, List &list): Item_func_or_sum(thd, list) { set_arguments(thd, list); } // Constructor used for Item_cond_and/or (see Item comment) Item_func(THD *thd, Item_func *item): Item_func_or_sum(thd, item), not_null_tables_cache(item->not_null_tables_cache) { } bool fix_fields(THD *, Item **ref) override; void cleanup() override { Item_func_or_sum::cleanup(); used_tables_and_const_cache_init(); } void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; void quick_fix_field() override; table_map not_null_tables() const override; void update_used_tables() override { used_tables_and_const_cache_init(); used_tables_and_const_cache_update_and_join(arg_count, args); } COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) override; SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) override { DBUG_ENTER("Item_func::get_mm_tree"); DBUG_RETURN(const_item() ? get_mm_tree_for_const(param) : NULL); } bool eq(const Item *item, bool binary_cmp) const override; virtual Item *key_item() const { return args[0]; } void set_arguments(THD *thd, List &list) { Item_args::set_arguments(thd, list); sync_with_sum_func_and_with_field(list); list.empty(); // Fields are used } void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, uint flags) override; void print(String *str, enum_query_type query_type) override; void print_op(String *str, enum_query_type query_type); void print_args(String *str, uint from, enum_query_type query_type) const; void print_args_parenthesized(String *str, enum_query_type query_type) const { str->append('('); print_args(str, 0, query_type); str->append(')'); } bool is_null() override { update_null_value(); return null_value; } String *val_str_from_val_str_ascii(String *str, String *str2); void signal_divide_by_null(); friend class udf_handler; Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) override { return tmp_table_field_from_field_type(root, table); } Item *get_tmp_table_item(THD *thd) override; void fix_char_length_ulonglong(ulonglong max_char_length_arg) { ulonglong max_result_length= max_char_length_arg * collation.collation->mbmaxlen; if (max_result_length >= MAX_BLOB_WIDTH) { max_length= MAX_BLOB_WIDTH; set_maybe_null(); } else max_length= (uint32) max_result_length; } Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override; Item* compile(THD *thd, Item_analyzer analyzer, uchar **arg_p, Item_transformer transformer, uchar *arg_t) override; void traverse_cond(Cond_traverser traverser, void * arg, traverse_order order) override; bool eval_not_null_tables(void *opt_arg) override; bool find_not_null_fields(table_map allowed) override; // bool is_expensive_processor(void *arg); // virtual bool is_expensive() { return 0; } inline void raise_numeric_overflow(const char *type_name) { char buf[256]; String str(buf, sizeof(buf), system_charset_info); str.length(0); print(&str, QT_NO_DATA_EXPANSION); my_error(ER_DATA_OUT_OF_RANGE, MYF(0), type_name, str.c_ptr_safe()); } inline double raise_float_overflow() { raise_numeric_overflow("DOUBLE"); return 0.0; } inline longlong raise_integer_overflow() { raise_numeric_overflow(unsigned_flag ? "BIGINT UNSIGNED": "BIGINT"); return 0; } inline int raise_decimal_overflow() { raise_numeric_overflow("DECIMAL"); return E_DEC_OVERFLOW; } /** Throw an error if the input double number is not finite, i.e. is either +/-INF or NAN. */ inline double check_float_overflow(double value) { return std::isfinite(value) ? value : raise_float_overflow(); } /** Throw an error if the input BIGINT value represented by the (longlong value, bool unsigned flag) pair cannot be returned by the function, i.e. is not compatible with this Item's unsigned_flag. */ inline longlong check_integer_overflow(longlong value, bool val_unsigned) { return check_integer_overflow(Longlong_hybrid(value, val_unsigned)); } // Check if the value is compatible with Item::unsigned_flag. inline longlong check_integer_overflow(const Longlong_hybrid &sval) { Longlong_null res= sval.val_int(unsigned_flag); return res.is_null() ? raise_integer_overflow() : res.value(); } // Check if the value is compatible with Item::unsigned_flag. longlong check_integer_overflow(const ULonglong_hybrid &uval) { Longlong_null res= uval.val_int(unsigned_flag); return res.is_null() ? raise_integer_overflow() : res.value(); } /** Throw an error if the error code of a DECIMAL operation is E_DEC_OVERFLOW. */ inline int check_decimal_overflow(int error) { return (error == E_DEC_OVERFLOW) ? raise_decimal_overflow() : error; } bool has_timestamp_args() { DBUG_ASSERT(fixed()); for (uint i= 0; i < arg_count; i++) { if (args[i]->type() == Item::FIELD_ITEM && args[i]->field_type() == MYSQL_TYPE_TIMESTAMP) return TRUE; } return FALSE; } bool has_date_args() { DBUG_ASSERT(fixed()); for (uint i= 0; i < arg_count; i++) { if (args[i]->type() == Item::FIELD_ITEM && (args[i]->field_type() == MYSQL_TYPE_DATE || args[i]->field_type() == MYSQL_TYPE_DATETIME)) return TRUE; } return FALSE; } bool has_time_args() { DBUG_ASSERT(fixed()); for (uint i= 0; i < arg_count; i++) { if (args[i]->type() == Item::FIELD_ITEM && (args[i]->field_type() == MYSQL_TYPE_TIME || args[i]->field_type() == MYSQL_TYPE_DATETIME)) return TRUE; } return FALSE; } bool has_datetime_args() { DBUG_ASSERT(fixed()); for (uint i= 0; i < arg_count; i++) { if (args[i]->type() == Item::FIELD_ITEM && args[i]->field_type() == MYSQL_TYPE_DATETIME) return TRUE; } return FALSE; } Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { /* By default only substitution for a field whose two different values are never equal is allowed in the arguments of a function. This is overruled for the direct arguments of comparison functions. */ Item_args::propagate_equal_fields(thd, Context_identity(), cond); return this; } bool has_rand_bit() { return used_tables() & RAND_TABLE_BIT; } bool excl_dep_on_table(table_map tab_map) override { if (used_tables() & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)) return false; return !(used_tables() & ~tab_map) || Item_args::excl_dep_on_table(tab_map); } bool excl_dep_on_grouping_fields(st_select_lex *sel) override { if (has_rand_bit() || with_subquery()) return false; return Item_args::excl_dep_on_grouping_fields(sel); } bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override { return Item_args::excl_dep_on_in_subq_left_part(subq_pred); } /* We assume the result of any function that has a TIMESTAMP argument to be timezone-dependent, since a TIMESTAMP value in both numeric and string contexts is interpreted according to the current timezone. The only exception is UNIX_TIMESTAMP() which returns the internal representation of a TIMESTAMP argument verbatim, and thus does not depend on the timezone. */ bool check_valid_arguments_processor(void *bool_arg) override { return has_timestamp_args(); } bool find_function_processor (void *arg) override { return functype() == *(Functype *) arg; } void no_rows_in_result() override { for (uint i= 0; i < arg_count; i++) { args[i]->no_rows_in_result(); } } void restore_to_before_no_rows_in_result() override { for (uint i= 0; i < arg_count; i++) { args[i]->restore_to_before_no_rows_in_result(); } } void convert_const_compared_to_int_field(THD *thd); Item_func *get_item_func() override { return this; } bool is_simplified_cond_processor(void *) override { return const_item() && !val_bool(); } }; class Item_real_func :public Item_func { public: Item_real_func(THD *thd): Item_func(thd) { collation= DTCollation_numeric(); } Item_real_func(THD *thd, Item *a): Item_func(thd, a) { collation= DTCollation_numeric(); } Item_real_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b) { collation= DTCollation_numeric(); } Item_real_func(THD *thd, List &list): Item_func(thd, list) { collation= DTCollation_numeric(); } String *val_str(String*str) override; my_decimal *val_decimal(my_decimal *decimal_value) override; longlong val_int() override { DBUG_ASSERT(fixed()); return Converter_double_to_longlong(val_real(), unsigned_flag).result(); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_real(thd, ltime, fuzzydate); } const Type_handler *type_handler() const override { return &type_handler_double; } bool fix_length_and_dec() override { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); return FALSE; } }; /** Functions whose returned field type is determined at fix_fields() time. */ class Item_hybrid_func: public Item_func, public Type_handler_hybrid_field_type { protected: bool fix_attributes(Item **item, uint nitems); public: Item_hybrid_func(THD *thd): Item_func(thd) { } Item_hybrid_func(THD *thd, Item *a): Item_func(thd, a) { } Item_hybrid_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b) { } Item_hybrid_func(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b, c) { } Item_hybrid_func(THD *thd, List &list): Item_func(thd, list) { } Item_hybrid_func(THD *thd, Item_hybrid_func *item) :Item_func(thd, item), Type_handler_hybrid_field_type(item) { } const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } void fix_length_and_dec_long_or_longlong(uint char_length, bool unsigned_arg) { collation= DTCollation_numeric(); unsigned_flag= unsigned_arg; max_length= char_length; set_handler(Type_handler::type_handler_long_or_longlong(char_length, unsigned_arg)); } void fix_length_and_dec_ulong_or_ulonglong_by_nbits(uint nbits) { uint digits= Type_handler_bit::Bit_decimal_notation_int_digits_by_nbits(nbits); collation= DTCollation_numeric(); unsigned_flag= true; max_length= digits; if (nbits > 32) set_handler(&type_handler_ulonglong); else set_handler(&type_handler_ulong); } }; class Item_handled_func: public Item_func { public: class Handler { public: virtual ~Handler() = default; virtual String *val_str(Item_handled_func *, String *) const= 0; virtual String *val_str_ascii(Item_handled_func *, String *) const= 0; virtual double val_real(Item_handled_func *) const= 0; virtual longlong val_int(Item_handled_func *) const= 0; virtual my_decimal *val_decimal(Item_handled_func *, my_decimal *) const= 0; virtual bool get_date(THD *thd, Item_handled_func *, MYSQL_TIME *, date_mode_t fuzzydate) const= 0; virtual bool val_native(THD *thd, Item_handled_func *, Native *to) const { DBUG_ASSERT(0); to->length(0); return true; } virtual const Type_handler * return_type_handler(const Item_handled_func *item) const= 0; virtual const Type_handler * type_handler_for_create_select(const Item_handled_func *item) const { return return_type_handler(item); } virtual bool fix_length_and_dec(Item_handled_func *) const= 0; }; class Handler_str: public Handler { public: String *val_str_ascii(Item_handled_func *item, String *str) const override { return item->Item::val_str_ascii(str); } double val_real(Item_handled_func *item) const override { DBUG_ASSERT(item->fixed()); StringBuffer<64> tmp; String *res= item->val_str(&tmp); return res ? item->double_from_string_with_check(res) : 0.0; } longlong val_int(Item_handled_func *item) const override { DBUG_ASSERT(item->fixed()); StringBuffer<22> tmp; String *res= item->val_str(&tmp); return res ? item->longlong_from_string_with_check(res) : 0; } my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const override { return item->val_decimal_from_string(to); } bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzydate) const override { return item->get_date_from_string(thd, to, fuzzydate); } }; /** Abstract class for functions returning TIME, DATE, DATETIME or string values, whose data type depends on parameters and is set at fix_fields time. */ class Handler_temporal: public Handler { public: String *val_str(Item_handled_func *item, String *to) const override { StringBuffer ascii_buf; return item->val_str_from_val_str_ascii(to, &ascii_buf); } }; /** Abstract class for functions returning strings, which are generated from get_date() results, when get_date() can return different MYSQL_TIMESTAMP_XXX per row. */ class Handler_temporal_string: public Handler_temporal { public: const Type_handler *return_type_handler(const Item_handled_func *) const override { return &type_handler_string; } const Type_handler * type_handler_for_create_select(const Item_handled_func *item) const override { return return_type_handler(item)->type_handler_for_tmp_table(item); } double val_real(Item_handled_func *item) const override { return Temporal_hybrid(item).to_double(); } longlong val_int(Item_handled_func *item) const override { return Temporal_hybrid(item).to_longlong(); } my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const override { return Temporal_hybrid(item).to_decimal(to); } String *val_str_ascii(Item_handled_func *item, String *to) const override { return Temporal_hybrid(item).to_string(to, item->decimals); } }; class Handler_date: public Handler_temporal { public: const Type_handler *return_type_handler(const Item_handled_func *) const override { return &type_handler_newdate; } bool fix_length_and_dec(Item_handled_func *item) const override { item->fix_attributes_date(); return false; } double val_real(Item_handled_func *item) const override { return Date(item).to_double(); } longlong val_int(Item_handled_func *item) const override { return Date(item).to_longlong(); } my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const override { return Date(item).to_decimal(to); } String *val_str_ascii(Item_handled_func *item, String *to) const override { return Date(item).to_string(to); } }; class Handler_time: public Handler_temporal { public: const Type_handler *return_type_handler(const Item_handled_func *) const override { return &type_handler_time2; } double val_real(Item_handled_func *item) const override { return Time(item).to_double(); } longlong val_int(Item_handled_func *item) const override { return Time(item).to_longlong(); } my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const override { return Time(item).to_decimal(to); } String *val_str_ascii(Item_handled_func *item, String *to) const override { return Time(item).to_string(to, item->decimals); } bool val_native(THD *thd, Item_handled_func *item, Native *to) const override { return Time(thd, item).to_native(to, item->decimals); } }; class Handler_datetime: public Handler_temporal { public: const Type_handler *return_type_handler(const Item_handled_func *) const override { return &type_handler_datetime2; } double val_real(Item_handled_func *item) const override { return Datetime(item).to_double(); } longlong val_int(Item_handled_func *item) const override { return Datetime(item).to_longlong(); } my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const override { return Datetime(item).to_decimal(to); } String *val_str_ascii(Item_handled_func *item, String *to) const override { return Datetime(item).to_string(to, item->decimals); } }; class Handler_int: public Handler { public: String *val_str(Item_handled_func *item, String *to) const override { longlong nr= val_int(item); if (item->null_value) return 0; to->set_int(nr, item->unsigned_flag, item->collation.collation); return to; } String *val_str_ascii(Item_handled_func *item, String *to) const override { return item->Item::val_str_ascii(to); } double val_real(Item_handled_func *item) const override { return item->unsigned_flag ? (double) ((ulonglong) val_int(item)) : (double) val_int(item); } my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const override { return item->val_decimal_from_int(to); } bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzydate) const override { return item->get_date_from_int(thd, to, fuzzydate); } longlong val_int(Item_handled_func *item) const override { Longlong_null tmp= to_longlong_null(item); item->null_value= tmp.is_null(); return tmp.value(); } virtual Longlong_null to_longlong_null(Item_handled_func *item) const= 0; }; class Handler_slong: public Handler_int { public: const Type_handler *return_type_handler(const Item_handled_func *item) const override { return &type_handler_slong; } bool fix_length_and_dec(Item_handled_func *item) const override { item->unsigned_flag= false; item->collation= DTCollation_numeric(); item->fix_char_length(11); return false; } }; class Handler_slong2: public Handler_slong { public: bool fix_length_and_dec(Item_handled_func *func) const override { bool rc= Handler_slong::fix_length_and_dec(func); func->max_length= 2; return rc; } }; class Handler_ulonglong: public Handler_int { public: const Type_handler *return_type_handler(const Item_handled_func *item) const override { return &type_handler_ulonglong; } bool fix_length_and_dec(Item_handled_func *item) const override { item->unsigned_flag= true; item->collation= DTCollation_numeric(); item->fix_char_length(21); return false; } }; protected: const Handler *m_func_handler; public: Item_handled_func(THD *thd, Item *a) :Item_func(thd, a), m_func_handler(NULL) { } Item_handled_func(THD *thd, Item *a, Item *b) :Item_func(thd, a, b), m_func_handler(NULL) { } void set_func_handler(const Handler *handler) { m_func_handler= handler; } const Type_handler *type_handler() const override { return m_func_handler->return_type_handler(this); } Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) override { DBUG_ASSERT(fixed()); const Type_handler *h= m_func_handler->type_handler_for_create_select(this); return h->make_and_init_table_field(root, &name, Record_addr(maybe_null()), *this, table); } String *val_str(String *to) override { return m_func_handler->val_str(this, to); } String *val_str_ascii(String *to) override { return m_func_handler->val_str_ascii(this, to); } double val_real() override { return m_func_handler->val_real(this); } longlong val_int() override { return m_func_handler->val_int(this); } my_decimal *val_decimal(my_decimal *to) override { return m_func_handler->val_decimal(this, to); } bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) override { return m_func_handler->get_date(thd, this, to, fuzzydate); } bool val_native(THD *thd, Native *to) override { return m_func_handler->val_native(thd, this, to); } }; /** Functions that at fix_fields() time determine the returned field type, trying to preserve the exact data type of the arguments. The descendants have to implement "native" value methods, i.e. str_op(), date_op(), int_op(), real_op(), decimal_op(). fix_fields() chooses which of the above value methods will be used during execution time, according to the returned field type. For example, if fix_fields() determines that the returned value type is MYSQL_TYPE_LONG, then: - int_op() is chosen as the execution time native method. - val_int() returns the result of int_op() as is. - all other methods, i.e. val_real(), val_decimal(), val_str(), get_date(), call int_op() first, then convert the result to the requested data type. */ class Item_func_hybrid_field_type: public Item_hybrid_func { /* Helper methods to make sure that the result of decimal_op(), str_op() and date_op() is properly synched with null_value. */ bool date_op_with_null_check(THD *thd, MYSQL_TIME *ltime) { bool rc= date_op(thd, ltime, date_mode_t(0)); DBUG_ASSERT(!rc ^ null_value); return rc; } bool time_op_with_null_check(THD *thd, MYSQL_TIME *ltime) { bool rc= time_op(thd, ltime); DBUG_ASSERT(!rc ^ null_value); DBUG_ASSERT(rc || ltime->time_type == MYSQL_TIMESTAMP_TIME); return rc; } String *str_op_with_null_check(String *str) { String *res= str_op(str); DBUG_ASSERT((res != NULL) ^ null_value); return res; } public: // Value methods that involve no conversion String *val_str_from_str_op(String *str) { return str_op_with_null_check(&str_value); } longlong val_int_from_int_op() { return int_op(); } double val_real_from_real_op() { return real_op(); } // Value methods that involve conversion String *val_str_from_real_op(String *str); String *val_str_from_int_op(String *str); String *val_str_from_date_op(String *str); String *val_str_from_time_op(String *str); my_decimal *val_decimal_from_str_op(my_decimal *dec); my_decimal *val_decimal_from_real_op(my_decimal *dec); my_decimal *val_decimal_from_int_op(my_decimal *dec); my_decimal *val_decimal_from_date_op(my_decimal *dec); my_decimal *val_decimal_from_time_op(my_decimal *dec); longlong val_int_from_str_op(); longlong val_int_from_real_op(); longlong val_int_from_date_op(); longlong val_int_from_time_op(); double val_real_from_str_op(); double val_real_from_date_op(); double val_real_from_time_op(); double val_real_from_int_op(); public: Item_func_hybrid_field_type(THD *thd): Item_hybrid_func(thd) { collation= DTCollation_numeric(); } Item_func_hybrid_field_type(THD *thd, Item *a): Item_hybrid_func(thd, a) { collation= DTCollation_numeric(); } Item_func_hybrid_field_type(THD *thd, Item *a, Item *b): Item_hybrid_func(thd, a, b) { collation= DTCollation_numeric(); } Item_func_hybrid_field_type(THD *thd, Item *a, Item *b, Item *c): Item_hybrid_func(thd, a, b, c) { collation= DTCollation_numeric(); } Item_func_hybrid_field_type(THD *thd, List &list): Item_hybrid_func(thd, list) { collation= DTCollation_numeric(); } double val_real() override { DBUG_ASSERT(fixed()); return Item_func_hybrid_field_type::type_handler()-> Item_func_hybrid_field_type_val_real(this); } longlong val_int() override { DBUG_ASSERT(!is_cond()); DBUG_ASSERT(fixed()); return Item_func_hybrid_field_type::type_handler()-> Item_func_hybrid_field_type_val_int(this); } my_decimal *val_decimal(my_decimal *dec) override { DBUG_ASSERT(fixed()); return Item_func_hybrid_field_type::type_handler()-> Item_func_hybrid_field_type_val_decimal(this, dec); } String *val_str(String*str) override { DBUG_ASSERT(fixed()); String *res= Item_func_hybrid_field_type::type_handler()-> Item_func_hybrid_field_type_val_str(this, str); DBUG_ASSERT(null_value == (res == NULL)); return res; } bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode) override { DBUG_ASSERT(fixed()); return Item_func_hybrid_field_type::type_handler()-> Item_func_hybrid_field_type_get_date_with_warn(thd, this, to, mode); } bool val_native(THD *thd, Native *to) override { DBUG_ASSERT(fixed()); return native_op(thd, to); } /** @brief Performs the operation that this functions implements when the result type is INT. @return The result of the operation. */ virtual longlong int_op()= 0; Longlong_null to_longlong_null_op() { longlong nr= int_op(); /* C++ does not guarantee the order of parameter evaluation, so to make sure "null_value" is passed to the constructor after the int_op() call, int_op() is caled on a separate line. */ return Longlong_null(nr, null_value); } Longlong_hybrid_null to_longlong_hybrid_null_op() { return Longlong_hybrid_null(to_longlong_null_op(), unsigned_flag); } /** @brief Performs the operation that this functions implements when the result type is REAL. @return The result of the operation. */ virtual double real_op()= 0; Double_null to_double_null_op() { // val_real() must be caleed on a separate line. See to_longlong_null() double nr= real_op(); return Double_null(nr, null_value); } /** @brief Performs the operation that this functions implements when the result type is DECIMAL. @param A pointer where the DECIMAL value will be allocated. @return - 0 If the result is NULL - The same pointer it was given, with the area initialized to the result of the operation. */ virtual my_decimal *decimal_op(my_decimal *)= 0; /** @brief Performs the operation that this functions implements when the result type is a string type. @return The result of the operation. */ virtual String *str_op(String *)= 0; /** @brief Performs the operation that this functions implements when field type is DATETIME or DATE. @return The result of the operation. */ virtual bool date_op(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate)= 0; /** @brief Performs the operation that this functions implements when field type is TIME. @return The result of the operation. */ virtual bool time_op(THD *thd, MYSQL_TIME *res)= 0; virtual bool native_op(THD *thd, Native *native)= 0; }; /* This class resembles SQL standard CASE-alike expressions: CASE and its abbreviations COALESCE, NULLIF, IFNULL, IF. ::= | */ class Item_func_case_expression: public Item_func_hybrid_field_type { public: Item_func_case_expression(THD *thd) :Item_func_hybrid_field_type(thd) { } Item_func_case_expression(THD *thd, Item *a) :Item_func_hybrid_field_type(thd, a) { } Item_func_case_expression(THD *thd, Item *a, Item *b) :Item_func_hybrid_field_type(thd, a, b) { } Item_func_case_expression(THD *thd, Item *a, Item *b, Item *c) :Item_func_hybrid_field_type(thd, a, b, c) { } Item_func_case_expression(THD *thd, List &list): Item_func_hybrid_field_type(thd, list) { } bool find_not_null_fields(table_map allowed) override { return false; } }; class Item_func_numhybrid: public Item_func_hybrid_field_type { protected: inline void fix_decimals() { DBUG_ASSERT(result_type() == DECIMAL_RESULT); if (decimals == NOT_FIXED_DEC) set_if_smaller(decimals, max_length - 1); } public: Item_func_numhybrid(THD *thd): Item_func_hybrid_field_type(thd) { } Item_func_numhybrid(THD *thd, Item *a): Item_func_hybrid_field_type(thd, a) { } Item_func_numhybrid(THD *thd, Item *a, Item *b): Item_func_hybrid_field_type(thd, a, b) { } Item_func_numhybrid(THD *thd, Item *a, Item *b, Item *c): Item_func_hybrid_field_type(thd, a, b, c) { } Item_func_numhybrid(THD *thd, List &list): Item_func_hybrid_field_type(thd, list) { } String *str_op(String *str) override { DBUG_ASSERT(0); return 0; } bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { DBUG_ASSERT(0); return true; } bool time_op(THD *thd, MYSQL_TIME *ltime) override { DBUG_ASSERT(0); return true; } bool native_op(THD *thd, Native *to) override { DBUG_ASSERT(0); return true; } }; /* function where type of result detected by first argument */ class Item_func_num1: public Item_func_numhybrid { public: Item_func_num1(THD *thd, Item *a): Item_func_numhybrid(thd, a) {} Item_func_num1(THD *thd, Item *a, Item *b): Item_func_numhybrid(thd, a, b) {} bool check_partition_func_processor(void *int_arg) override { return FALSE; } bool check_vcol_func_processor(void *arg) override { return FALSE; } }; /* Base class for operations like '+', '-', '*' */ class Item_num_op :public Item_func_numhybrid { protected: bool check_arguments() const override { return false; // Checked by aggregate_for_num_op() } public: Item_num_op(THD *thd, Item *a, Item *b): Item_func_numhybrid(thd, a, b) {} virtual void result_precision()= 0; void print(String *str, enum_query_type query_type) override { print_op(str, query_type); } bool fix_type_handler(const Type_aggregator *aggregator); void fix_length_and_dec_double() { aggregate_numeric_attributes_real(args, arg_count); max_length= float_length(decimals); } void fix_length_and_dec_decimal() { unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag; result_precision(); fix_decimals(); } void fix_length_and_dec_int() { unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag; result_precision(); decimals= 0; set_handler(type_handler_long_or_longlong()); } void fix_length_and_dec_temporal(bool downcast_decimal_to_int) { set_handler(&type_handler_newdecimal); fix_length_and_dec_decimal(); if (decimals == 0 && downcast_decimal_to_int) set_handler(type_handler_long_or_longlong()); } bool need_parentheses_in_default() override { return true; } }; class Item_int_func :public Item_func { public: /* QQ: shouldn't 20 characters be enough: Max unsigned = 18,446,744,073,709,551,615 = 20 digits, 20 characters Max signed = 9,223,372,036,854,775,807 = 19 digits, 19 characters Min signed = -9,223,372,036,854,775,808 = 19 digits, 20 characters */ Item_int_func(THD *thd): Item_func(thd) { collation= DTCollation_numeric(); fix_char_length(21); } Item_int_func(THD *thd, Item *a): Item_func(thd, a) { collation= DTCollation_numeric(); fix_char_length(21); } Item_int_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b) { collation= DTCollation_numeric(); fix_char_length(21); } Item_int_func(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b, c) { collation= DTCollation_numeric(); fix_char_length(21); } Item_int_func(THD *thd, Item *a, Item *b, Item *c, Item *d): Item_func(thd, a, b, c, d) { collation= DTCollation_numeric(); fix_char_length(21); } Item_int_func(THD *thd, List &list): Item_func(thd, list) { collation= DTCollation_numeric(); fix_char_length(21); } Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) { collation= DTCollation_numeric(); } double val_real() override; String *val_str(String*str) override; my_decimal *val_decimal(my_decimal *decimal_value) override { return val_decimal_from_int(decimal_value); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_int(thd, ltime, fuzzydate); } const Type_handler *type_handler() const override= 0; bool fix_length_and_dec() override { return FALSE; } }; class Item_long_func: public Item_int_func { public: Item_long_func(THD *thd): Item_int_func(thd) { } Item_long_func(THD *thd, Item *a): Item_int_func(thd, a) {} Item_long_func(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} Item_long_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} Item_long_func(THD *thd, List &list): Item_int_func(thd, list) { } Item_long_func(THD *thd, Item_long_func *item) :Item_int_func(thd, item) {} const Type_handler *type_handler() const override { if (unsigned_flag) return &type_handler_ulong; return &type_handler_slong; } bool fix_length_and_dec() override { max_length= 11; return FALSE; } }; class Item_long_ge0_func: public Item_int_func { public: Item_long_ge0_func(THD *thd): Item_int_func(thd) { } Item_long_ge0_func(THD *thd, Item *a): Item_int_func(thd, a) {} Item_long_ge0_func(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} Item_long_ge0_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} Item_long_ge0_func(THD *thd, List &list): Item_int_func(thd, list) { } Item_long_ge0_func(THD *thd, Item_long_ge0_func *item) :Item_int_func(thd, item) {} const Type_handler *type_handler() const override { DBUG_ASSERT(!unsigned_flag); return &type_handler_slong_ge0; } bool fix_length_and_dec() override { max_length= 10; return FALSE; } }; class Item_func_hash: public Item_int_func { public: Item_func_hash(THD *thd, List &item): Item_int_func(thd, item) {} longlong val_int() override; bool fix_length_and_dec() override; const Type_handler *type_handler() const override { return &type_handler_slong; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("") }; return name; } }; class Item_func_hash_mariadb_100403: public Item_func_hash { public: Item_func_hash_mariadb_100403(THD *thd, List &item) :Item_func_hash(thd, item) {} longlong val_int() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("") }; return name; } }; class Item_longlong_func: public Item_int_func { public: Item_longlong_func(THD *thd): Item_int_func(thd) { } Item_longlong_func(THD *thd, Item *a): Item_int_func(thd, a) {} Item_longlong_func(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} Item_longlong_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} Item_longlong_func(THD *thd, Item *a, Item *b, Item *c, Item *d): Item_int_func(thd, a, b, c, d) {} Item_longlong_func(THD *thd, List &list): Item_int_func(thd, list) { } Item_longlong_func(THD *thd, Item_longlong_func *item) :Item_int_func(thd, item) {} const Type_handler *type_handler() const override { if (unsigned_flag) return &type_handler_ulonglong; return &type_handler_slonglong; } }; class Cursor_ref { protected: LEX_CSTRING m_cursor_name; uint m_cursor_offset; class sp_cursor *get_open_cursor_or_error(); Cursor_ref(const LEX_CSTRING *name, uint offset) :m_cursor_name(*name), m_cursor_offset(offset) { } void print_func(String *str, const LEX_CSTRING &func_name); }; class Item_func_cursor_rowcount: public Item_longlong_func, public Cursor_ref { public: Item_func_cursor_rowcount(THD *thd, const LEX_CSTRING *name, uint offset) :Item_longlong_func(thd), Cursor_ref(name, offset) { set_maybe_null(); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("%ROWCOUNT") }; return name; } longlong val_int() override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), arg, VCOL_SESSION_FUNC); } void print(String *str, enum_query_type query_type) override { return Cursor_ref::print_func(str, func_name_cstring()); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_connection_id :public Item_long_func { longlong value; public: Item_func_connection_id(THD *thd): Item_long_func(thd) { unsigned_flag=1; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("connection_id") }; return name; } bool fix_length_and_dec() override; bool fix_fields(THD *thd, Item **ref) override; longlong val_int() override { DBUG_ASSERT(fixed()); return value; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_signed :public Item_int_func { public: Item_func_signed(THD *thd, Item *a): Item_int_func(thd, a) { unsigned_flag= 0; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("cast_as_signed") }; return name; } const Type_handler *type_handler() const override { return Type_handler::type_handler_long_or_longlong(max_char_length(), false); } longlong val_int() override { longlong value= args[0]->val_int_signed_typecast(); null_value= args[0]->null_value; return value; } void fix_length_and_dec_double() { fix_char_length(MAX_BIGINT_WIDTH); } void fix_length_and_dec_sint_ge0() { uint32 digits= args[0]->decimal_precision(); DBUG_ASSERT(digits > 0); DBUG_ASSERT(digits <= MY_INT64_NUM_DECIMAL_DIGITS); fix_char_length(digits + (unsigned_flag ? 0 : 1/*sign*/)); } void fix_length_and_dec_generic() { uint32 char_length= MY_MIN(args[0]->max_char_length(), MY_INT64_NUM_DECIMAL_DIGITS); /* args[0]->max_char_length() can return 0. Reserve max_length to fit at least one character for one digit, plus one character for the sign (if signed). */ set_if_bigger(char_length, 1U + (unsigned_flag ? 0 : 1)); fix_char_length(char_length); } void fix_length_and_dec_string() { /* For strings, use decimal_int_part() instead of max_char_length(). This is important for Item_hex_hybrid: SELECT CAST(0x1FFFFFFFF AS SIGNED); Length is 5, decimal_int_part() is 13. */ uint32 char_length= MY_MIN(args[0]->decimal_int_part(), MY_INT64_NUM_DECIMAL_DIGITS); set_if_bigger(char_length, 1U + (unsigned_flag ? 0 : 1)); fix_char_length(char_length); } bool fix_length_and_dec() override { return args[0]->type_handler()->Item_func_signed_fix_length_and_dec(this); } void print(String *str, enum_query_type query_type) override; decimal_digits_t decimal_precision() const override { return args[0]->decimal_precision(); } bool need_parentheses_in_default() override { return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_unsigned :public Item_func_signed { public: Item_func_unsigned(THD *thd, Item *a): Item_func_signed(thd, a) { unsigned_flag= 1; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("cast_as_unsigned") }; return name; } const Type_handler *type_handler() const override { if (max_char_length() <= MY_INT32_NUM_DECIMAL_DIGITS - 1) return &type_handler_ulong; return &type_handler_ulonglong; } longlong val_int() override { longlong value= args[0]->val_int_unsigned_typecast(); null_value= args[0]->null_value; return value; } bool fix_length_and_dec() override { return args[0]->type_handler()->Item_func_unsigned_fix_length_and_dec(this); } decimal_digits_t decimal_precision() const override { return max_length; } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_decimal_typecast :public Item_func { my_decimal decimal_value; public: Item_decimal_typecast(THD *thd, Item *a, uint len, decimal_digits_t dec) :Item_func(thd, a) { decimals= dec; collation= DTCollation_numeric(); fix_char_length(my_decimal_precision_to_length_no_truncation(len, dec, unsigned_flag)); } String *val_str(String *str) override { return VDec(this).to_string(str); } double val_real() override { return VDec(this).to_double(); } longlong val_int() override { return VDec(this).to_longlong(unsigned_flag); } my_decimal *val_decimal(my_decimal*) override; bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode) override { return decimal_to_datetime_with_warn(thd, VDec(this).ptr(), to, mode, NULL, NULL); } const Type_handler *type_handler() const override { return &type_handler_newdecimal; } void fix_length_and_dec_generic() {} bool fix_length_and_dec() override { return args[0]->type_handler()->Item_decimal_typecast_fix_length_and_dec(this); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("decimal_typecast") }; return name; } void print(String *str, enum_query_type query_type) override; bool need_parentheses_in_default() override { return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_real_typecast: public Item_real_func { protected: double val_real_with_truncate(double max_value); public: Item_real_typecast(THD *thd, Item *a, uint len, uint dec) :Item_real_func(thd, a) { decimals= (uint8) dec; max_length= (uint32) len; } bool need_parentheses_in_default() override { return true; } void print(String *str, enum_query_type query_type) override; void fix_length_and_dec_generic() { set_maybe_null(); } }; class Item_float_typecast :public Item_real_typecast { public: Item_float_typecast(THD *thd, Item *a) :Item_real_typecast(thd, a, MAX_FLOAT_STR_LENGTH, NOT_FIXED_DEC) { } const Type_handler *type_handler() const override { return &type_handler_float; } bool fix_length_and_dec() override { return args[0]->type_handler()->Item_float_typecast_fix_length_and_dec(this); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("float_typecast") }; return name; } double val_real() override { return (double) (float) val_real_with_truncate(FLT_MAX); } String *val_str(String*str) override { Float nr(Item_float_typecast::val_real()); if (null_value) return 0; nr.to_string(str, decimals); return str; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_double_typecast :public Item_real_typecast { public: Item_double_typecast(THD *thd, Item *a, uint len, uint dec): Item_real_typecast(thd, a, len, dec) { } bool fix_length_and_dec() override { return args[0]->type_handler()->Item_double_typecast_fix_length_and_dec(this); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("double_typecast") }; return name; } double val_real() override { return val_real_with_truncate(DBL_MAX); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_additive_op :public Item_num_op { public: Item_func_additive_op(THD *thd, Item *a, Item *b): Item_num_op(thd, a, b) {} void result_precision() override; bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} }; class Item_func_plus :public Item_func_additive_op { public: Item_func_plus(THD *thd, Item *a, Item *b): Item_func_additive_op(thd, a, b) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("+") }; return name; } enum precedence precedence() const override { return ADD_PRECEDENCE; } bool fix_length_and_dec() override; longlong int_op() override; double real_op() override; my_decimal *decimal_op(my_decimal *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_minus :public Item_func_additive_op { bool m_depends_on_sql_mode_no_unsigned_subtraction; public: Item_func_minus(THD *thd, Item *a, Item *b): Item_func_additive_op(thd, a, b), m_depends_on_sql_mode_no_unsigned_subtraction(false) { } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("-") }; return name; } enum precedence precedence() const override { return ADD_PRECEDENCE; } Sql_mode_dependency value_depends_on_sql_mode() const override; longlong int_op() override; double real_op() override; my_decimal *decimal_op(my_decimal *) override; bool fix_length_and_dec() override; void fix_unsigned_flag(); void fix_length_and_dec_double() { Item_func_additive_op::fix_length_and_dec_double(); fix_unsigned_flag(); } void fix_length_and_dec_decimal() { Item_func_additive_op::fix_length_and_dec_decimal(); fix_unsigned_flag(); } void fix_length_and_dec_int() { Item_func_additive_op::fix_length_and_dec_int(); fix_unsigned_flag(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_mul :public Item_num_op { public: Item_func_mul(THD *thd, Item *a, Item *b): Item_num_op(thd, a, b) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("*") }; return name; } enum precedence precedence() const override { return MUL_PRECEDENCE; } longlong int_op() override; double real_op() override; my_decimal *decimal_op(my_decimal *) override; void result_precision() override; bool fix_length_and_dec() override; bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_div :public Item_num_op { public: uint prec_increment; Item_func_div(THD *thd, Item *a, Item *b): Item_num_op(thd, a, b) {} longlong int_op() override { DBUG_ASSERT(0); return 0; } double real_op() override; my_decimal *decimal_op(my_decimal *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("/") }; return name; } enum precedence precedence() const override { return MUL_PRECEDENCE; } bool fix_length_and_dec() override; void fix_length_and_dec_double(); void fix_length_and_dec_int(); void result_precision() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_int_div :public Item_int_func { public: Item_func_int_div(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("DIV") }; return name; } enum precedence precedence() const override { return MUL_PRECEDENCE; } const Type_handler *type_handler() const override { return type_handler_long_or_longlong(); } bool fix_length_and_dec() override; void print(String *str, enum_query_type query_type) override { print_op(str, query_type); } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool need_parentheses_in_default() override { return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_mod :public Item_num_op { public: Item_func_mod(THD *thd, Item *a, Item *b): Item_num_op(thd, a, b) {} longlong int_op() override; double real_op() override; my_decimal *decimal_op(my_decimal *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("MOD") }; return name; } enum precedence precedence() const override { return MUL_PRECEDENCE; } void result_precision() override; bool fix_length_and_dec() override; void fix_length_and_dec_double() { Item_num_op::fix_length_and_dec_double(); unsigned_flag= args[0]->unsigned_flag; } void fix_length_and_dec_decimal() { result_precision(); fix_decimals(); } void fix_length_and_dec_int() { result_precision(); DBUG_ASSERT(decimals == 0); set_handler(type_handler_long_or_longlong()); } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_neg :public Item_func_num1 { public: Item_func_neg(THD *thd, Item *a): Item_func_num1(thd, a) {} double real_op() override; longlong int_op() override; my_decimal *decimal_op(my_decimal *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("-") }; return name; } enum Functype functype() const override { return NEG_FUNC; } enum precedence precedence() const override { return NEG_PRECEDENCE; } void print(String *str, enum_query_type query_type) override { str->append(func_name_cstring()); args[0]->print_parenthesised(str, query_type, precedence()); } void fix_length_and_dec_int(); void fix_length_and_dec_double(); void fix_length_and_dec_decimal(); bool fix_length_and_dec() override; decimal_digits_t decimal_precision() const override { return args[0]->decimal_precision(); } bool need_parentheses_in_default() override { return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_abs :public Item_func_num1 { public: Item_func_abs(THD *thd, Item *a): Item_func_num1(thd, a) {} double real_op() override; longlong int_op() override; my_decimal *decimal_op(my_decimal *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("abs") }; return name; } void fix_length_and_dec_int(); void fix_length_and_dec_sint_ge0(); void fix_length_and_dec_double(); void fix_length_and_dec_decimal(); bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; // A class to handle logarithmic and trigonometric functions class Item_dec_func :public Item_real_func { bool check_arguments() const override { return check_argument_types_can_return_real(0, arg_count); } public: Item_dec_func(THD *thd, Item *a): Item_real_func(thd, a) {} Item_dec_func(THD *thd, Item *a, Item *b): Item_real_func(thd, a, b) {} bool fix_length_and_dec() override { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); set_maybe_null(); return FALSE; } }; class Item_func_exp :public Item_dec_func { public: Item_func_exp(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("exp") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_ln :public Item_dec_func { public: Item_func_ln(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("ln") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_log :public Item_dec_func { public: Item_func_log(THD *thd, Item *a): Item_dec_func(thd, a) {} Item_func_log(THD *thd, Item *a, Item *b): Item_dec_func(thd, a, b) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("log") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_log2 :public Item_dec_func { public: Item_func_log2(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("log2") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_log10 :public Item_dec_func { public: Item_func_log10(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("log10") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_sqrt :public Item_dec_func { public: Item_func_sqrt(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("sqrt") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_pow :public Item_dec_func { public: Item_func_pow(THD *thd, Item *a, Item *b): Item_dec_func(thd, a, b) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("pow") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_acos :public Item_dec_func { public: Item_func_acos(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("acos") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_asin :public Item_dec_func { public: Item_func_asin(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("asin") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_atan :public Item_dec_func { public: Item_func_atan(THD *thd, Item *a): Item_dec_func(thd, a) {} Item_func_atan(THD *thd, Item *a, Item *b): Item_dec_func(thd, a, b) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("atan") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_cos :public Item_dec_func { public: Item_func_cos(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("cos") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_sin :public Item_dec_func { public: Item_func_sin(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("sin") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_tan :public Item_dec_func { public: Item_func_tan(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("tan") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_cot :public Item_dec_func { public: Item_func_cot(THD *thd, Item *a): Item_dec_func(thd, a) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("cot") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_int_val :public Item_func_hybrid_field_type { public: Item_func_int_val(THD *thd, Item *a): Item_func_hybrid_field_type(thd, a) {} bool check_partition_func_processor(void *int_arg) override { return FALSE; } bool check_vcol_func_processor(void *arg) override { return FALSE; } virtual decimal_round_mode round_mode() const= 0; void fix_length_and_dec_double(); void fix_length_and_dec_int_or_decimal(); void fix_length_and_dec_time() { fix_attributes_time(0); set_handler(&type_handler_time2); } void fix_length_and_dec_datetime() { fix_attributes_datetime(0); set_handler(&type_handler_datetime2); // Thinks like CEILING(TIMESTAMP'0000-01-01 23:59:59.9') returns NULL set_maybe_null(); } bool fix_length_and_dec() override; String *str_op(String *str) override { DBUG_ASSERT(0); return 0; } bool native_op(THD *thd, Native *to) override; }; class Item_func_ceiling :public Item_func_int_val { public: Item_func_ceiling(THD *thd, Item *a): Item_func_int_val(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("ceiling") }; return name; } decimal_round_mode round_mode() const override { return CEILING; } longlong int_op() override; double real_op() override; my_decimal *decimal_op(my_decimal *) override; bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool time_op(THD *thd, MYSQL_TIME *ltime) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_floor :public Item_func_int_val { public: Item_func_floor(THD *thd, Item *a): Item_func_int_val(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("floor") }; return name; } decimal_round_mode round_mode() const override { return FLOOR; } longlong int_op() override; double real_op() override; my_decimal *decimal_op(my_decimal *) override; bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool time_op(THD *thd, MYSQL_TIME *ltime) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* This handles round and truncate */ class Item_func_round :public Item_func_hybrid_field_type { bool truncate; void fix_length_and_dec_decimal(uint decimals_to_set); void fix_length_and_dec_double(uint decimals_to_set); bool test_if_length_can_increase(); public: Item_func_round(THD *thd, Item *a, Item *b, bool trunc_arg) :Item_func_hybrid_field_type(thd, a, b), truncate(trunc_arg) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING truncate_name= {STRING_WITH_LEN("truncate") }; static LEX_CSTRING round_name= {STRING_WITH_LEN("round") }; return truncate ? truncate_name : round_name; } double real_op() override; longlong int_op() override; my_decimal *decimal_op(my_decimal *) override; bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool time_op(THD *thd, MYSQL_TIME *ltime) override; bool native_op(THD *thd, Native *to) override; String *str_op(String *str) override { DBUG_ASSERT(0); return NULL; } void fix_arg_decimal(); void fix_arg_int(const Type_handler *preferred, const Type_std_attributes *preferred_attributes, bool use_decimal_on_length_increase); void fix_arg_slong_ge0(); void fix_arg_hex_hybrid(); void fix_arg_double(); void fix_arg_time(); void fix_arg_datetime(); void fix_arg_temporal(const Type_handler *h, uint int_part_length); bool fix_length_and_dec() override { /* We don't want to translate ENUM/SET to CHAR here. So let's real_type_handler(), not type_handler(). */ return args[0]->real_type_handler()->Item_func_round_fix_length_and_dec(this); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_rand :public Item_real_func { struct my_rnd_struct *rand; bool first_eval; // TRUE if val_real() is called 1st time bool check_arguments() const override { return check_argument_types_can_return_int(0, arg_count); } void seed_random (Item * val); public: Item_func_rand(THD *thd, Item *a): Item_real_func(thd, a), rand(0), first_eval(TRUE) {} Item_func_rand(THD *thd): Item_real_func(thd) {} double val_real() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("rand") }; return name; } bool const_item() const override { return 0; } void update_used_tables() override; bool fix_fields(THD *thd, Item **ref) override; void cleanup() override { first_eval= TRUE; Item_real_func::cleanup(); } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_rownum final :public Item_longlong_func { /* This points to a variable that contains the number of rows accpted so far in the result set */ ha_rows *accepted_rows; SELECT_LEX *select; public: Item_func_rownum(THD *thd); longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("rownum") }; return name; } enum Functype functype() const override { return ROWNUM_FUNC; } void update_used_tables() override {} bool const_item() const override { return 0; } void fix_after_optimize(THD *thd) override; bool fix_length_and_dec() override { unsigned_flag= 1; used_tables_cache= RAND_TABLE_BIT; const_item_cache=0; set_maybe_null(); return FALSE; } void cleanup() override { Item_longlong_func::cleanup(); /* Ensure we don't point to freed memory */ accepted_rows= 0; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } bool check_handler_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return 0; } /* This function is used in insert, update and delete */ void store_pointer_to_row_counter(ha_rows *row_counter) { accepted_rows= row_counter; } }; void fix_rownum_pointers(THD *thd, SELECT_LEX *select_lex, ha_rows *ptr); class Item_func_sign :public Item_long_func { bool check_arguments() const override { return args[0]->check_type_can_return_real(func_name_cstring()); } public: Item_func_sign(THD *thd, Item *a): Item_long_func(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("sign") }; return name; } decimal_digits_t decimal_precision() const override { return 1; } bool fix_length_and_dec() override { fix_char_length(2); return FALSE; } longlong val_int() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_units :public Item_real_func { LEX_CSTRING name; double mul,add; bool check_arguments() const override { return check_argument_types_can_return_real(0, arg_count); } public: Item_func_units(THD *thd, char *name_arg, Item *a, double mul_arg, double add_arg): Item_real_func(thd, a), mul(mul_arg), add(add_arg) { name.str= name_arg; name.length= strlen(name_arg); } double val_real() override; LEX_CSTRING func_name_cstring() const override { return name; } bool fix_length_and_dec() override { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /** Item_func_min_max does not derive from Item_func_hybrid_field_type because the way how its methods val_xxx() and get_date() work depend not only by its arguments, but also on the context in which LEAST() and GREATEST() appear. For example, using Item_func_min_max in a CAST like this: CAST(LEAST('11','2') AS SIGNED) forces Item_func_min_max to compare the arguments as numbers rather than strings. Perhaps this should be changed eventually (see MDEV-5893). */ class Item_func_min_max :public Item_hybrid_func { String tmp_value; int cmp_sign; protected: bool check_arguments() const override { return false; // Checked by aggregate_for_min_max() } bool fix_attributes(Item **item, uint nitems); public: Item_func_min_max(THD *thd, List &list, int cmp_sign_arg): Item_hybrid_func(thd, list), cmp_sign(cmp_sign_arg) {} String *val_str_native(String *str); double val_real_native(); longlong val_int_native(); longlong val_uint_native(); my_decimal *val_decimal_native(my_decimal *); bool get_date_native(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); bool get_time_native(THD *thd, MYSQL_TIME *res); double val_real() override { DBUG_ASSERT(fixed()); return Item_func_min_max::type_handler()-> Item_func_min_max_val_real(this); } longlong val_int() override { DBUG_ASSERT(fixed()); return Item_func_min_max::type_handler()-> Item_func_min_max_val_int(this); } String *val_str(String *str) override { DBUG_ASSERT(fixed()); return Item_func_min_max::type_handler()-> Item_func_min_max_val_str(this, str); } my_decimal *val_decimal(my_decimal *dec) override { DBUG_ASSERT(fixed()); return Item_func_min_max::type_handler()-> Item_func_min_max_val_decimal(this, dec); } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override { DBUG_ASSERT(fixed()); return Item_func_min_max::type_handler()-> Item_func_min_max_get_date(thd, this, res, fuzzydate); } bool val_native(THD *thd, Native *to) override; void aggregate_attributes_real(Item **items, uint nitems) { /* Aggregating attributes for the double data type for LEAST/GREATEST is almost the same with aggregating for CASE-alike hybrid functions, (CASE..THEN, COALESCE, IF, etc). There is one notable difference though, when a numeric argument is mixed with a string argument: - CASE-alike functions return a string data type in such cases COALESCE(10,'x') -> VARCHAR(2) = '10' - LEAST/GREATEST returns double: GREATEST(10,'10e4') -> DOUBLE = 100000 As the string argument can represent a number in the scientific notation, like in the example above, max_length of the result can be longer than max_length of the arguments. To handle this properly, max_length is additionally assigned to the result of float_length(decimals). */ Item_func::aggregate_attributes_real(items, nitems); max_length= float_length(decimals); } bool fix_length_and_dec() override { if (aggregate_for_min_max(func_name_cstring(), args, arg_count)) return true; fix_attributes(args, arg_count); return false; } }; class Item_func_min :public Item_func_min_max { public: Item_func_min(THD *thd, List &list): Item_func_min_max(thd, list, 1) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("least") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_max :public Item_func_min_max { public: Item_func_max(THD *thd, List &list): Item_func_min_max(thd, list, -1) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("greatest") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Objects of this class are used for ROLLUP queries to wrap up each constant item referred to in GROUP BY list. */ class Item_func_rollup_const :public Item_func { public: Item_func_rollup_const(THD *thd, Item *a): Item_func(thd, a) { name= a->name; } double val_real() override { return val_real_from_item(args[0]); } longlong val_int() override { return val_int_from_item(args[0]); } String *val_str(String *str) override { return val_str_from_item(args[0], str); } bool val_native(THD *thd, Native *to) override { return val_native_from_item(thd, args[0], to); } my_decimal *val_decimal(my_decimal *dec) override { return val_decimal_from_item(args[0], dec); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_item(thd, args[0], ltime, fuzzydate); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("rollup_const") }; return name; } bool const_item() const override { return 0; } const Type_handler *type_handler() const override { return args[0]->type_handler(); } bool fix_length_and_dec() override { Type_std_attributes::set(*args[0]); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_long_func_length: public Item_long_func { bool check_arguments() const override { return args[0]->check_type_can_return_str(func_name_cstring()); } public: Item_long_func_length(THD *thd, Item *a): Item_long_func(thd, a) {} bool fix_length_and_dec() override { max_length=10; return FALSE; } }; class Item_func_octet_length :public Item_long_func_length { String value; public: Item_func_octet_length(THD *thd, Item *a): Item_long_func_length(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("octet_length") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_bit_length :public Item_longlong_func { String value; public: Item_func_bit_length(THD *thd, Item *a): Item_longlong_func(thd, a) {} bool fix_length_and_dec() override { max_length= 11; // 0x100000000*8 = 34,359,738,368 return FALSE; } longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("bit_length") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_char_length :public Item_long_func_length { String value; public: Item_func_char_length(THD *thd, Item *a): Item_long_func_length(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("char_length") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_coercibility :public Item_long_func { longlong m_cached_collation_derivation; bool check_arguments() const override { return args[0]->check_type_can_return_str(func_name_cstring()); } public: Item_func_coercibility(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("coercibility") }; return name; } bool fix_length_and_dec() override; bool eval_not_null_tables(void *) override { not_null_tables_cache= 0; return false; } bool find_not_null_fields(table_map allowed) override { return false; } Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { return this; } bool const_item() const override { return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } table_map used_tables() const override { return 0; } }; /* In the corner case LOCATE could return (4,294,967,296 + 1), which would not fit into Item_long_func range. But string lengths are limited with max_allowed_packet, which cannot be bigger than 1024*1024*1024. */ class Item_func_locate :public Item_long_func { bool check_arguments() const override { return check_argument_types_can_return_str(0, 2) || (arg_count > 2 && args[2]->check_type_can_return_int(func_name_cstring())); } String value1,value2; DTCollation cmp_collation; public: Item_func_locate(THD *thd, Item *a, Item *b) :Item_long_func(thd, a, b) {} Item_func_locate(THD *thd, Item *a, Item *b, Item *c) :Item_long_func(thd, a, b, c) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("locate") }; return name; } longlong val_int() override; bool fix_length_and_dec() override { max_length= MY_INT32_NUM_DECIMAL_DIGITS; return agg_arg_charsets_for_comparison(cmp_collation, args, 2); } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_field :public Item_long_func { String value,tmp; Item_result cmp_type; DTCollation cmp_collation; public: Item_func_field(THD *thd, List &list): Item_long_func(thd, list) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("field") }; return name; } bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_ascii :public Item_long_func { bool check_arguments() const override { return check_argument_types_can_return_str(0, arg_count); } String value; public: Item_func_ascii(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("ascii") }; return name; } bool fix_length_and_dec() override { max_length=3; return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_ord :public Item_long_func { bool check_arguments() const override { return args[0]->check_type_can_return_str(func_name_cstring()); } String value; public: Item_func_ord(THD *thd, Item *a): Item_long_func(thd, a) {} bool fix_length_and_dec() override { fix_char_length(7); return FALSE; } longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("ord") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_find_in_set :public Item_long_func { bool check_arguments() const override { return check_argument_types_can_return_str(0, 2); } String value,value2; uint enum_value; ulonglong enum_bit; DTCollation cmp_collation; public: Item_func_find_in_set(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b), enum_value(0) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("find_in_set") }; return name; } bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */ class Item_func_bit_operator: public Item_handled_func { bool check_arguments() const override { return check_argument_types_can_return_int(0, arg_count); } protected: bool fix_length_and_dec_op1_std(const Handler *ha_int, const Handler *ha_dec) { set_func_handler(args[0]->cmp_type() == INT_RESULT ? ha_int : ha_dec); return m_func_handler->fix_length_and_dec(this); } bool fix_length_and_dec_op2_std(const Handler *ha_int, const Handler *ha_dec) { set_func_handler(args[0]->cmp_type() == INT_RESULT && args[1]->cmp_type() == INT_RESULT ? ha_int : ha_dec); return m_func_handler->fix_length_and_dec(this); } public: Item_func_bit_operator(THD *thd, Item *a) :Item_handled_func(thd, a) {} Item_func_bit_operator(THD *thd, Item *a, Item *b) :Item_handled_func(thd, a, b) {} void print(String *str, enum_query_type query_type) override { print_op(str, query_type); } bool need_parentheses_in_default() override { return true; } }; class Item_func_bit_or :public Item_func_bit_operator { public: Item_func_bit_or(THD *thd, Item *a, Item *b) :Item_func_bit_operator(thd, a, b) {} bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("|") }; return name; } enum precedence precedence() const override { return BITOR_PRECEDENCE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_bit_and :public Item_func_bit_operator { public: Item_func_bit_and(THD *thd, Item *a, Item *b) :Item_func_bit_operator(thd, a, b) {} bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("&") }; return name; } enum precedence precedence() const override { return BITAND_PRECEDENCE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_bit_count :public Item_handled_func { bool check_arguments() const override { return args[0]->check_type_can_return_int(func_name_cstring()); } public: Item_func_bit_count(THD *thd, Item *a): Item_handled_func(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("bit_count") }; return name; } bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_shift_left :public Item_func_bit_operator { public: Item_func_shift_left(THD *thd, Item *a, Item *b) :Item_func_bit_operator(thd, a, b) {} bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("<<") }; return name; } enum precedence precedence() const override { return SHIFT_PRECEDENCE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_shift_right :public Item_func_bit_operator { public: Item_func_shift_right(THD *thd, Item *a, Item *b) :Item_func_bit_operator(thd, a, b) {} bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN(">>") }; return name; } enum precedence precedence() const override { return SHIFT_PRECEDENCE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_bit_neg :public Item_func_bit_operator { public: Item_func_bit_neg(THD *thd, Item *a): Item_func_bit_operator(thd, a) {} bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("~") }; return name; } enum precedence precedence() const override { return NEG_PRECEDENCE; } void print(String *str, enum_query_type query_type) override { str->append(func_name_cstring()); args[0]->print_parenthesised(str, query_type, precedence()); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_last_insert_id :public Item_longlong_func { bool check_arguments() const override { return check_argument_types_can_return_int(0, arg_count); } public: Item_func_last_insert_id(THD *thd): Item_longlong_func(thd) {} Item_func_last_insert_id(THD *thd, Item *a): Item_longlong_func(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("last_insert_id") }; return name; } bool fix_length_and_dec() override { unsigned_flag= true; if (arg_count) max_length= args[0]->max_length; return FALSE; } bool fix_fields(THD *thd, Item **ref) override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_benchmark :public Item_long_func { bool check_arguments() const override { return args[0]->check_type_can_return_int(func_name_cstring()) || args[1]->check_type_scalar(func_name_cstring()); } public: Item_func_benchmark(THD *thd, Item *count_expr, Item *expr): Item_long_func(thd, count_expr, expr) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("benchmark") }; return name; } bool fix_length_and_dec() override { max_length=1; base_flags&= ~item_base_t::MAYBE_NULL; return FALSE; } void print(String *str, enum_query_type query_type) override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; void item_func_sleep_init(void); void item_func_sleep_free(void); class Item_func_sleep :public Item_long_func { bool check_arguments() const override { return args[0]->check_type_can_return_real(func_name_cstring()); } public: Item_func_sleep(THD *thd, Item *a): Item_long_func(thd, a) {} bool fix_length_and_dec() override { fix_char_length(1); return FALSE; } bool const_item() const override { return 0; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("sleep") }; return name; } table_map used_tables() const override { return used_tables_cache | RAND_TABLE_BIT; } bool is_expensive() override { return 1; } longlong val_int() override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #ifdef HAVE_DLOPEN class Item_udf_func :public Item_func { /** Mark "this" as non-deterministic if it uses no tables and is not a constant at the same time. */ void set_non_deterministic_if_needed() { if (!const_item_cache && !used_tables_cache) used_tables_cache= RAND_TABLE_BIT; } protected: udf_handler udf; bool is_expensive_processor(void *arg) override { return TRUE; } class VDec_udf: public Dec_ptr_and_buffer { public: VDec_udf(Item_udf_func *func, udf_handler *udf) { my_bool tmp_null_value; m_ptr= udf->val_decimal(&tmp_null_value, &m_buffer); DBUG_ASSERT(is_null() == (tmp_null_value != 0)); func->null_value= is_null(); } }; public: Item_udf_func(THD *thd, udf_func *udf_arg): Item_func(thd), udf(udf_arg) {} Item_udf_func(THD *thd, udf_func *udf_arg, List &list): Item_func(thd, list), udf(udf_arg) {} LEX_CSTRING func_name_cstring() const override { const char *tmp= udf.name(); return { tmp, strlen(tmp) }; } enum Functype functype() const override { return UDF_FUNC; } bool fix_fields(THD *thd, Item **ref) override { DBUG_ASSERT(fixed() == 0); bool res= udf.fix_fields(thd, this, arg_count, args); set_non_deterministic_if_needed(); base_flags|= item_base_t::FIXED; return res; } void fix_num_length_and_dec(); void update_used_tables() override { /* TODO: Make a member in UDF_INIT and return if a UDF is deterministic or not. Currently UDF_INIT has a member (const_item) that is an in/out parameter to the init() call. The code in udf_handler::fix_fields also duplicates the arguments handling code in Item_func::fix_fields(). The lack of information if a UDF is deterministic makes writing a correct update_used_tables() for UDFs impossible. One solution to this would be : - Add a is_deterministic member of UDF_INIT - (optionally) deprecate the const_item member of UDF_INIT - Take away the duplicate code from udf_handler::fix_fields() and make Item_udf_func call Item_func::fix_fields() to process its arguments as for any other function. - Store the deterministic flag returned by _init into the udf_handler. - Don't implement Item_udf_func::fix_fields, implement Item_udf_func::fix_length_and_dec() instead (similar to non-UDF functions). - Override Item_func::update_used_tables to call Item_func::update_used_tables() and add a RAND_TABLE_BIT to the result of Item_func::update_used_tables() if the UDF is non-deterministic. - (optionally) rename RAND_TABLE_BIT to NONDETERMINISTIC_BIT to better describe its usage. The above would require a change of the UDF API. Until that change is done here's how the current code works: We call Item_func::update_used_tables() only when we know that the function depends on real non-const tables and is deterministic. This can be done only because we know that the optimizer will call update_used_tables() only when there's possibly a new const table. So update_used_tables() can only make a Item_func more constant than it is currently. That's why we don't need to do anything if a function is guaranteed to return non-constant (it's non-deterministic) or is already a const. */ if ((used_tables_cache & ~PSEUDO_TABLE_BITS) && !(used_tables_cache & RAND_TABLE_BIT)) { Item_func::update_used_tables(); set_non_deterministic_if_needed(); } } void cleanup() override; bool eval_not_null_tables(void *opt_arg) override { not_null_tables_cache= 0; return 0; } bool find_not_null_fields(table_map allowed) override { return false; } bool is_expensive() override { return 1; } void print(String *str, enum_query_type query_type) override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_NON_DETERMINISTIC); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } bool excl_dep_on_grouping_fields(st_select_lex *sel) override { return false; } }; class Item_func_udf_float :public Item_udf_func { public: Item_func_udf_float(THD *thd, udf_func *udf_arg): Item_udf_func(thd, udf_arg) {} Item_func_udf_float(THD *thd, udf_func *udf_arg, List &list): Item_udf_func(thd, udf_arg, list) {} longlong val_int() override { DBUG_ASSERT(fixed()); return Converter_double_to_longlong(Item_func_udf_float::val_real(), unsigned_flag).result(); } my_decimal *val_decimal(my_decimal *dec_buf) override { double res=val_real(); if (null_value) return NULL; double2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf); return dec_buf; } double val_real() override; String *val_str(String *str) override; const Type_handler *type_handler() const override { return &type_handler_double; } bool fix_length_and_dec() override { fix_num_length_and_dec(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_udf_int :public Item_udf_func { public: Item_func_udf_int(THD *thd, udf_func *udf_arg): Item_udf_func(thd, udf_arg) {} Item_func_udf_int(THD *thd, udf_func *udf_arg, List &list): Item_udf_func(thd, udf_arg, list) {} longlong val_int() override; double val_real() override { return (double) Item_func_udf_int::val_int(); } my_decimal *val_decimal(my_decimal *decimal_value) override { return val_decimal_from_int(decimal_value); } String *val_str(String *str) override; const Type_handler *type_handler() const override { if (unsigned_flag) return &type_handler_ulonglong; return &type_handler_slonglong; } bool fix_length_and_dec() override { decimals= 0; max_length= 21; return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_udf_decimal :public Item_udf_func { public: Item_func_udf_decimal(THD *thd, udf_func *udf_arg): Item_udf_func(thd, udf_arg) {} Item_func_udf_decimal(THD *thd, udf_func *udf_arg, List &list): Item_udf_func(thd, udf_arg, list) {} longlong val_int() override { return VDec_udf(this, &udf).to_longlong(unsigned_flag); } double val_real() override { return VDec_udf(this, &udf).to_double(); } my_decimal *val_decimal(my_decimal *) override; String *val_str(String *str) override { return VDec_udf(this, &udf).to_string_round(str, decimals); } const Type_handler *type_handler() const override { return &type_handler_newdecimal; } bool fix_length_and_dec() override { fix_num_length_and_dec(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_udf_str :public Item_udf_func { public: Item_func_udf_str(THD *thd, udf_func *udf_arg): Item_udf_func(thd, udf_arg) {} Item_func_udf_str(THD *thd, udf_func *udf_arg, List &list): Item_udf_func(thd, udf_arg, list) {} String *val_str(String *) override; double val_real() override { int err_not_used; char *end_not_used; String *res; res= val_str(&str_value); return res ? res->charset()->strntod((char*) res->ptr(), res->length(), &end_not_used, &err_not_used) : 0.0; } longlong val_int() override { int err_not_used; String *res; res=val_str(&str_value); return res ? res->charset()->strntoll(res->ptr(),res->length(),10, (char**) 0, &err_not_used) : (longlong) 0; } my_decimal *val_decimal(my_decimal *dec_buf) override { String *res=val_str(&str_value); if (!res) return NULL; string2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf); return dec_buf; } const Type_handler *type_handler() const override { return string_type_handler(); } bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #else /* Dummy functions to get yy_*.cc files compiled */ class Item_func_udf_float :public Item_real_func { public: Item_func_udf_float(THD *thd, udf_func *udf_arg): Item_real_func(thd) {} Item_func_udf_float(THD *thd, udf_func *udf_arg, List &list): Item_real_func(thd, list) {} double val_real() { DBUG_ASSERT(fixed()); return 0.0; } }; class Item_func_udf_int :public Item_int_func { public: Item_func_udf_int(THD *thd, udf_func *udf_arg): Item_int_func(thd) {} Item_func_udf_int(THD *thd, udf_func *udf_arg, List &list): Item_int_func(thd, list) {} const Type_handler *type_handler() const override { return &type_handler_slonglong; } longlong val_int() { DBUG_ASSERT(fixed()); return 0; } }; class Item_func_udf_decimal :public Item_int_func { public: Item_func_udf_decimal(THD *thd, udf_func *udf_arg): Item_int_func(thd) {} Item_func_udf_decimal(THD *thd, udf_func *udf_arg, List &list): Item_int_func(thd, list) {} const Type_handler *type_handler() const override { return &type_handler_slonglong; } my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed()); return 0; } }; class Item_func_udf_str :public Item_func { public: Item_func_udf_str(THD *thd, udf_func *udf_arg): Item_func(thd) {} Item_func_udf_str(THD *thd, udf_func *udf_arg, List &list): Item_func(thd, list) {} String *val_str(String *) { DBUG_ASSERT(fixed()); null_value=1; return 0; } double val_real() { DBUG_ASSERT(fixed()); null_value= 1; return 0.0; } longlong val_int() { DBUG_ASSERT(fixed()); null_value=1; return 0; } bool fix_length_and_dec() override { base_flags|= item_base_t::MAYBE_NULL; max_length=0; return FALSE; } }; #endif /* HAVE_DLOPEN */ void mysql_ull_cleanup(THD *thd); void mysql_ull_set_explicit_lock_duration(THD *thd); class Item_func_lock :public Item_long_func { public: Item_func_lock(THD *thd): Item_long_func(thd) { } Item_func_lock(THD *thd, Item *a): Item_long_func(thd, a) {} Item_func_lock(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} table_map used_tables() const override { return used_tables_cache | RAND_TABLE_BIT; } bool const_item() const override { return 0; } bool is_expensive() override { return 1; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } }; class Item_func_get_lock final :public Item_func_lock { bool check_arguments() const override { return args[0]->check_type_general_purpose_string(func_name_cstring()) || args[1]->check_type_can_return_real(func_name_cstring()); } String value; public: Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_func_lock(thd, a, b) {} longlong val_int() override final; LEX_CSTRING func_name_cstring() const override final { static LEX_CSTRING name= {STRING_WITH_LEN("get_lock") }; return name; } bool fix_length_and_dec() override { max_length= 1; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override final { return get_item_copy(thd, this); } }; class Item_func_release_all_locks final :public Item_func_lock { public: Item_func_release_all_locks(THD *thd): Item_func_lock(thd) { unsigned_flag= 1; } longlong val_int() override final; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("release_all_locks") }; return name; } Item *do_get_copy(THD *thd) const override final { return get_item_copy(thd, this); } }; class Item_func_release_lock final :public Item_func_lock { bool check_arguments() const override { return args[0]->check_type_general_purpose_string(func_name_cstring()); } String value; public: Item_func_release_lock(THD *thd, Item *a): Item_func_lock(thd, a) {} longlong val_int() override final; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("release_lock") }; return name; } bool fix_length_and_dec() override { max_length= 1; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override final { return get_item_copy(thd, this); } }; /* replication functions */ class Item_master_pos_wait :public Item_longlong_func { bool check_arguments() const override { return args[0]->check_type_general_purpose_string(func_name_cstring()) || args[1]->check_type_can_return_int(func_name_cstring()) || (arg_count > 2 && args[2]->check_type_can_return_int(func_name_cstring())) || (arg_count > 3 && args[3]->check_type_general_purpose_string(func_name_cstring())); } String value; public: Item_master_pos_wait(THD *thd, Item *a, Item *b) :Item_longlong_func(thd, a, b) {} Item_master_pos_wait(THD *thd, Item *a, Item *b, Item *c): Item_longlong_func(thd, a, b, c) {} Item_master_pos_wait(THD *thd, Item *a, Item *b, Item *c, Item *d): Item_longlong_func(thd, a, b, c, d) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("master_pos_wait") }; return name; } bool fix_length_and_dec() override { max_length=21; set_maybe_null(); return FALSE; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_master_gtid_wait :public Item_long_func { bool check_arguments() const override { return args[0]->check_type_general_purpose_string(func_name_cstring()) || (arg_count > 1 && args[1]->check_type_can_return_real(func_name_cstring())); } String value; public: Item_master_gtid_wait(THD *thd, Item *a) :Item_long_func(thd, a) {} Item_master_gtid_wait(THD *thd, Item *a, Item *b) :Item_long_func(thd, a, b) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("master_gtid_wait") }; return name; } bool fix_length_and_dec() override { max_length=2; return FALSE; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Handling of user definable variables */ class user_var_entry; /** A class to set and get user variables */ class Item_func_user_var :public Item_hybrid_func { protected: user_var_entry *m_var_entry; public: LEX_CSTRING name; // keep it public Item_func_user_var(THD *thd, const LEX_CSTRING *a) :Item_hybrid_func(thd), m_var_entry(NULL), name(*a) { } Item_func_user_var(THD *thd, const LEX_CSTRING *a, Item *b) :Item_hybrid_func(thd, b), m_var_entry(NULL), name(*a) { } Item_func_user_var(THD *thd, Item_func_user_var *item) :Item_hybrid_func(thd, item), m_var_entry(item->m_var_entry), name(item->name) { } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { DBUG_ASSERT(fixed()); return create_tmp_field_ex_from_handler(root, table, src, param, type_handler()); } Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) override { return create_table_field_from_handler(root, table); } bool check_vcol_func_processor(void *arg) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } }; class Item_func_set_user_var :public Item_func_user_var { /* The entry_thread_id variable is used: 1) to skip unnecessary updates of the entry field (see above); 2) to reset the entry field that was initialized in the other thread (for example, an item tree of a trigger that updates user variables may be shared between several connections, and the entry_thread_id field prevents updates of one connection user variables from a concurrent connection calling the same trigger that initially updated some user variable it the first connection context). */ my_thread_id entry_thread_id; String value; my_decimal decimal_buff; bool null_item; union { longlong vint; double vreal; String *vstr; my_decimal *vdec; } save_result; public: Item_func_set_user_var(THD *thd, const LEX_CSTRING *a, Item *b): Item_func_user_var(thd, a, b), entry_thread_id(0) {} Item_func_set_user_var(THD *thd, Item_func_set_user_var *item) :Item_func_user_var(thd, item), entry_thread_id(item->entry_thread_id), value(item->value), decimal_buff(item->decimal_buff), null_item(item->null_item), save_result(item->save_result) {} enum Functype functype() const override { return SUSERVAR_FUNC; } double val_real() override; longlong val_int() override; String *val_str(String *str) override; my_decimal *val_decimal(my_decimal *) override; double val_result() override; longlong val_int_result() override; bool val_bool_result() override; String *str_result(String *str) override; my_decimal *val_decimal_result(my_decimal *) override; bool is_null_result() override; bool update_hash(void *ptr, size_t length, const Type_handler *th, CHARSET_INFO *cs); bool send(Protocol *protocol, st_value *buffer) override; void make_send_field(THD *thd, Send_field *tmp_field) override; bool check(bool use_result_field); void save_item_result(Item *item); bool update(); bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override; void print(String *str, enum_query_type query_type) override; enum precedence precedence() const override { return ASSIGN_PRECEDENCE; } void print_as_stmt(String *str, enum_query_type query_type); LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("set_user_var") }; return name; } int save_in_field(Field *field, bool no_conversions, bool can_use_result_field); int save_in_field(Field *field, bool no_conversions) override { return save_in_field(field, no_conversions, 1); } void save_org_in_field(Field *field, fast_field_copier data __attribute__ ((__unused__))) override { (void) save_in_field(field, 1, 0); } bool register_field_in_read_map(void *arg) override; bool register_field_in_bitmap(void *arg) override; bool set_entry(THD *thd, bool create_if_not_exists); void cleanup() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } bool excl_dep_on_table(table_map tab_map) override { return false; } }; class Item_func_get_user_var :public Item_func_user_var, private Settable_routine_parameter { public: Item_func_get_user_var(THD *thd, const LEX_CSTRING *a): Item_func_user_var(thd, a) {} enum Functype functype() const override { return GUSERVAR_FUNC; } LEX_CSTRING get_name() { return name; } double val_real() override; longlong val_int() override; my_decimal *val_decimal(my_decimal*) override; String *val_str(String* str) override; bool fix_length_and_dec() override; void print(String *str, enum_query_type query_type) override; /* We must always return variables as strings to guard against selects of type select @t1:=1,@t1,@t:="hello",@t from foo where (@t1:= t2.b) */ LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("get_user_var") }; return name; } bool const_item() const override; table_map used_tables() const override { return const_item() ? 0 : RAND_TABLE_BIT; } bool eq(const Item *item, bool binary_cmp) const override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } private: bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; public: Settable_routine_parameter *get_settable_routine_parameter() override { return this; } }; /* This item represents user variable used as out parameter (e.g in LOAD DATA), and it is supposed to be used only for this purprose. So it is simplified a lot. Actually you should never obtain its value. The only two reasons for this thing being an Item is possibility to store it in List and desire to place this code somewhere near other functions working with user variables. */ class Item_user_var_as_out_param :public Item_fixed_hybrid, public Load_data_outvar { LEX_CSTRING org_name; user_var_entry *entry; public: Item_user_var_as_out_param(THD *thd, const LEX_CSTRING *a) :Item_fixed_hybrid(thd) { DBUG_ASSERT(a->length < UINT_MAX32); org_name= *a; set_name(thd, a->str, a->length, system_charset_info); } Load_data_outvar *get_load_data_outvar() override { return this; } bool load_data_set_null(THD *thd, const Load_data_param *param) override { set_null_value(param->charset()); return false; } bool load_data_set_no_data(THD *thd, const Load_data_param *param) override { set_null_value(param->charset()); return false; } bool load_data_set_value(THD *thd, const char *pos, uint length, const Load_data_param *param) override { set_value(pos, length, param->charset()); return false; } void load_data_print_for_log_event(THD *thd, String *to) const override; bool load_data_add_outvar(THD *thd, Load_data_param *param) const override { return param->add_outvar_user_var(thd); } uint load_data_fixed_length() const override { return 0; } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { DBUG_ASSERT(0); return NULL; } /* We should return something different from FIELD_ITEM here */ enum Type type() const override { return CONST_ITEM;} double val_real() override; longlong val_int() override; String *val_str(String *str) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; my_decimal *val_decimal(my_decimal *decimal_buffer) override; /* fix_fields() binds variable name with its entry structure */ bool fix_fields(THD *thd, Item **ref) override; void set_null_value(CHARSET_INFO* cs); void set_value(const char *str, uint length, CHARSET_INFO* cs); const Type_handler *type_handler() const override { return &type_handler_double; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /* A system variable */ #define GET_SYS_VAR_CACHE_LONG 1 #define GET_SYS_VAR_CACHE_DOUBLE 2 #define GET_SYS_VAR_CACHE_STRING 4 class Item_func_get_system_var :public Item_func { sys_var *var; enum_var_type var_type, orig_var_type; LEX_CSTRING component; longlong cached_llval; double cached_dval; String cached_strval; bool cached_null_value; query_id_t used_query_id; uchar cache_present; public: Item_func_get_system_var(THD *thd, sys_var *var_arg, enum_var_type var_type_arg, LEX_CSTRING *component_arg, const char *name_arg, size_t name_len_arg); enum Functype functype() const override { return GSYSVAR_FUNC; } void update_null_value() override; bool fix_length_and_dec() override; void print(String *str, enum_query_type query_type) override; bool const_item() const override { return true; } table_map used_tables() const override { return 0; } const Type_handler *type_handler() const override; double val_real() override; longlong val_int() override; String* val_str(String*) override; my_decimal *val_decimal(my_decimal *dec_buf) override { return val_decimal_from_real(dec_buf); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } /* TODO: fix to support views */ LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("get_system_var") }; return name; } /** Indicates whether this system variable is written to the binlog or not. Variables are written to the binlog as part of "status_vars" in Query_log_event, as an Intvar_log_event, or a Rand_log_event. @return true if the variable is written to the binlog, false otherwise. */ bool is_written_to_binlog(); bool eq(const Item *item, bool binary_cmp) const override; void cleanup() override; bool check_vcol_func_processor(void *arg) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* for fulltext search */ class Item_func_match :public Item_real_func { public: uint key, match_flags; bool join_key; DTCollation cmp_collation; FT_INFO *ft_handler; TABLE *table; Item_func_match *master; // for master-slave optimization Item *concat_ws; // Item_func_concat_ws String value; // value of concat_ws String search_value; // key_item()'s value converted to cmp_collation Item_func_match(THD *thd, List &a, uint b): Item_real_func(thd, a), key(0), match_flags(b), join_key(0), ft_handler(0), table(0), master(0), concat_ws(0) { } void cleanup() override { DBUG_ENTER("Item_func_match::cleanup"); Item_real_func::cleanup(); if (!master && ft_handler) ft_handler->please->close_search(ft_handler); ft_handler= 0; concat_ws= 0; table= 0; // required by Item_func_match::eq() DBUG_VOID_RETURN; } bool is_expensive_processor(void *arg) override { return TRUE; } enum Functype functype() const override { return FT_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("match") }; return name; } bool eval_not_null_tables(void *opt_arg) override { not_null_tables_cache= 0; return 0; } bool find_not_null_fields(table_map allowed) override { return false; } bool fix_fields(THD *thd, Item **ref) override; bool eq(const Item *, bool binary_cmp) const override; /* The following should be safe, even if we compare doubles */ longlong val_int() override { DBUG_ASSERT(fixed()); return val_real() != 0.0; } double val_real() override; void print(String *str, enum_query_type query_type) override; bool fix_index(); bool init_search(THD *thd, bool no_order); bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("match ... against()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return nullptr; } private: /** Check whether storage engine for given table, allows FTS Boolean search on non-indexed columns. @todo A flag should be added to the extended fulltext API so that it may be checked whether search on non-indexed columns are supported. Currently, it is not possible to check for such a flag since @c this->ft_handler is not yet set when this function is called. The current hack is to assume that search on non-indexed columns are supported for engines that does not support the extended fulltext API (e.g., MyISAM), while it is not supported for other engines (e.g., InnoDB) @param table_arg Table for which storage engine to check @retval true if BOOLEAN search on non-indexed columns is supported @retval false otherwise */ bool allows_search_on_non_indexed_columns(TABLE* table_arg) { // Only Boolean search may support non_indexed columns if (!(match_flags & FT_BOOL)) return false; DBUG_ASSERT(table_arg && table_arg->file); // Assume that if extended fulltext API is not supported, // non-indexed columns are allowed. This will be true for MyISAM. if ((table_arg->file->ha_table_flags() & HA_CAN_FULLTEXT_EXT) == 0) return true; return false; } }; class Item_func_bit_xor : public Item_func_bit_operator { public: Item_func_bit_xor(THD *thd, Item *a, Item *b) :Item_func_bit_operator(thd, a, b) {} bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("^") }; return name; } enum precedence precedence() const override { return BITXOR_PRECEDENCE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_is_free_lock :public Item_long_func { bool check_arguments() const override { return args[0]->check_type_general_purpose_string(func_name_cstring()); } String value; public: Item_func_is_free_lock(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("is_free_lock") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=1; set_maybe_null(); return FALSE; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_is_used_lock :public Item_long_func { bool check_arguments() const override { return args[0]->check_type_general_purpose_string(func_name_cstring()); } String value; public: Item_func_is_used_lock(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("is_used_lock") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=10; set_maybe_null(); return FALSE; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; struct Lex_cast_type_st: public Lex_length_and_dec_st { private: const Type_handler *m_type_handler; public: void set(const Type_handler *handler, const char *length, const char *dec) { m_type_handler= handler; Lex_length_and_dec_st::set(length, dec); } void set(const Type_handler *handler, Lex_length_and_dec_st length_and_dec) { m_type_handler= handler; Lex_length_and_dec_st::operator=(length_and_dec); } void set(const Type_handler *handler, const char *length) { set(handler, length, 0); } void set(const Type_handler *handler) { set(handler, 0, 0); } const Type_handler *type_handler() const { return m_type_handler; } Item *create_typecast_item(THD *thd, Item *item, CHARSET_INFO *cs= NULL) const { return m_type_handler-> create_typecast_item(thd, item, Type_cast_attributes(length(), dec(), cs)); } Item *create_typecast_item_or_error(THD *thd, Item *item, CHARSET_INFO *cs= NULL) const; }; class Item_func_row_count :public Item_longlong_func { public: Item_func_row_count(THD *thd): Item_longlong_func(thd) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("row_count") }; return name; } bool fix_length_and_dec() override { decimals= 0; base_flags&= ~item_base_t::MAYBE_NULL; return FALSE; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* * * Stored FUNCTIONs * */ class Item_func_sp :public Item_func, public Item_sp { private: const Sp_handler *m_handler; bool execute(); protected: bool is_expensive_processor(void *arg) override { return is_expensive(); } bool check_arguments() const override { // sp_prepare_func_item() checks that the number of columns is correct return false; } public: Item_func_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name, const Sp_handler *sph); Item_func_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name, const Sp_handler *sph, List &list); virtual ~Item_func_sp() = default; void update_used_tables() override; void cleanup() override; LEX_CSTRING func_name_cstring() const override; const Type_handler *type_handler() const override; Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override; Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) override { return result_type() != STRING_RESULT ? sp_result_field : create_table_field_from_handler(root, table); } void make_send_field(THD *thd, Send_field *tmp_field) override; longlong val_int() override { if (execute()) return (longlong) 0; return sp_result_field->val_int(); } double val_real() override { if (execute()) return 0.0; return sp_result_field->val_real(); } my_decimal *val_decimal(my_decimal *dec_buf) override { if (execute()) return NULL; return sp_result_field->val_decimal(dec_buf); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { if (execute()) return true; return sp_result_field->get_date(ltime, fuzzydate); } String *val_str(String *str) override { String buf; char buff[20]; buf.set(buff, 20, str->charset()); buf.length(0); if (execute()) return NULL; /* result_field will set buf pointing to internal buffer of the resul_field. Due to this it will change any time when SP is executed. In order to prevent occasional corruption of returned value, we make here a copy. */ sp_result_field->val_str(&buf); str->copy(buf); return str; } bool val_native(THD *thd, Native *to) override { if (execute()) return true; return (null_value= sp_result_field->val_native(to)); } void update_null_value() override { execute(); } bool change_context_processor(void *cntx) override { context= (Name_resolution_context *)cntx; return FALSE; } enum Functype functype() const override { return FUNC_SP; } bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec(void) override; bool is_expensive() override; inline Field *get_sp_result_field() { return sp_result_field; } const sp_name *get_sp_name() const { return m_name; } bool check_vcol_func_processor(void *arg) override; bool limit_index_condition_pushdown_processor(void *opt_arg) override { return TRUE; } Item *do_get_copy(THD *thd) const override { return 0; } bool eval_not_null_tables(void *opt_arg) override { not_null_tables_cache= 0; return 0; } bool excl_dep_on_grouping_fields(st_select_lex *sel) override { return false; } bool find_not_null_fields(table_map allowed) override { return false; } }; class Item_func_found_rows :public Item_longlong_func { public: Item_func_found_rows(THD *thd): Item_longlong_func(thd) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("found_rows") }; return name; } bool fix_length_and_dec() override { decimals= 0; base_flags&= ~item_base_t::MAYBE_NULL; return FALSE; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_oracle_sql_rowcount :public Item_longlong_func { public: Item_func_oracle_sql_rowcount(THD *thd): Item_longlong_func(thd) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("SQL%ROWCOUNT") }; return name; } void print(String *str, enum_query_type query_type) override { str->append(func_name_cstring()); } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_sqlcode: public Item_long_func { public: Item_func_sqlcode(THD *thd): Item_long_func(thd) { } longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("SQLCODE") }; return name; } void print(String *str, enum_query_type query_type) override { str->append(func_name_cstring()); } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } bool fix_length_and_dec() override { base_flags&= ~item_base_t::MAYBE_NULL; null_value= false; max_length= 11; return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; void uuid_short_init(); ulonglong server_uuid_value(); class Item_func_uuid_short :public Item_longlong_func { public: Item_func_uuid_short(THD *thd): Item_longlong_func(thd) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("uuid_short") }; return name; } longlong val_int() override; bool const_item() const override { return false; } bool fix_length_and_dec() override { max_length= 21; unsigned_flag=1; return FALSE; } table_map used_tables() const override { return RAND_TABLE_BIT; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_NON_DETERMINISTIC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_last_value :public Item_func { protected: Item *last_value; public: Item_func_last_value(THD *thd, List &list): Item_func(thd, list) {} double val_real() override; longlong val_int() override; String *val_str(String *) override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool val_native(THD *thd, Native *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("last_value") }; return name; } const Type_handler *type_handler() const override { return last_value->type_handler(); } bool eval_not_null_tables(void *) override { not_null_tables_cache= 0; return 0; } bool find_not_null_fields(table_map allowed) override { return false; } bool const_item() const override { return 0; } void evaluate_sideeffects(); void update_used_tables() override { Item_func::update_used_tables(); copy_flags(last_value, item_base_t::MAYBE_NULL); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Implementation for sequences: NEXT VALUE FOR sequence and NEXTVAL() */ class Item_func_nextval :public Item_longlong_func { protected: TABLE_LIST *table_list; TABLE *table; bool check_access(THD *, privilege_t); public: Item_func_nextval(THD *thd, TABLE_LIST *table_list_arg): Item_longlong_func(thd), table_list(table_list_arg) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("nextval") }; return name; } bool fix_fields(THD *thd, Item **ref) override { /* Don't check privileges, if it's parse_vcol_defs() */ return (table_list->table && check_sequence_privileges(thd)) || Item_longlong_func::fix_fields(thd, ref); } bool check_sequence_privileges(void *thd) override { return check_access((THD*)thd, INSERT_ACL | SELECT_ACL); } bool fix_length_and_dec() override { unsigned_flag= 0; max_length= MAX_BIGINT_WIDTH; set_maybe_null(); /* In case of errors */ return FALSE; } /* update_table() function must be called during the value function as in case of DEFAULT the sequence table may not yet be open while fix_fields() are called */ void update_table() { if (!(table= table_list->table)) { /* If nextval was used in DEFAULT then next_local points to the table_list used by to open the sequence table */ table= table_list->next_local->table; } } bool const_item() const override { return 0; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } void print(String *str, enum_query_type query_type) override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_NEXTVAL); } }; /* Implementation for sequences: LASTVAL(sequence), PostgreSQL style */ class Item_func_lastval :public Item_func_nextval { public: Item_func_lastval(THD *thd, TABLE_LIST *table_list_arg): Item_func_nextval(thd, table_list_arg) {} bool check_sequence_privileges(void *thd) override { return check_access((THD*)thd, SELECT_ACL); } longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("lastval") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Implementation for sequences: SETVAL(sequence), PostgreSQL style */ class Item_func_setval :public Item_func_nextval { longlong nextval; ulonglong round; bool is_used; public: Item_func_setval(THD *thd, TABLE_LIST *table_list_arg, longlong nextval_arg, ulonglong round_arg, bool is_used_arg) : Item_func_nextval(thd, table_list_arg), nextval(nextval_arg), round(round_arg), is_used(is_used_arg) {} bool check_sequence_privileges(void *thd) override { return check_access((THD*)thd, INSERT_ACL); } longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("setval") }; return name; } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; Item *get_system_var(THD *thd, enum_var_type var_type, const LEX_CSTRING *name, const LEX_CSTRING *component); extern bool check_reserved_words(const LEX_CSTRING *name); double my_double_round(double value, longlong dec, bool dec_unsigned, bool truncate); extern bool volatile mqh_used; bool update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length, const Type_handler *th, CHARSET_INFO *cs); #endif /* ITEM_FUNC_INCLUDED */ server/private/event_scheduler.h000064400000006332151031265040013055 0ustar00#ifndef _EVENT_SCHEDULER_H_ #define _EVENT_SCHEDULER_H_ /* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @addtogroup Event_Scheduler @{ */ /** @file Declarations of the scheduler thread class and related functionality. This file is internal to Event_Scheduler module. Please do not include it directly. All public declarations of Event_Scheduler module are in events.h and event_data_objects.h. */ class Event_queue; class Event_job_data; class Event_db_repository; class Event_queue_element_for_exec; class Events; class THD; void pre_init_event_thread(THD* thd); bool post_init_event_thread(THD* thd); void deinit_event_thread(THD *thd); class Event_worker_thread { public: static void init(Event_db_repository *db_repository_arg) { db_repository= db_repository_arg; } void run(THD *thd, Event_queue_element_for_exec *event); private: void print_warnings(THD *thd, Event_job_data *et); static Event_db_repository *db_repository; }; class Event_scheduler { public: Event_scheduler(Event_queue *event_queue_arg); ~Event_scheduler(); /* State changing methods follow */ bool start(int *err_no); bool stop(); /* Need to be public because has to be called from the function passed to pthread_create. */ bool run(THD *thd); /* Information retrieving methods follow */ bool is_running(); void dump_internal_status(); private: uint workers_count(); /* helper functions */ bool execute_top(Event_queue_element_for_exec *event_name); /* helper functions for working with mutexes & conditionals */ void lock_data(const char *func, uint line); void unlock_data(const char *func, uint line); void cond_wait(THD *thd, struct timespec *abstime, const PSI_stage_info *stage, const char *src_func, const char *src_file, uint src_line); mysql_mutex_t LOCK_scheduler_state; enum enum_state { INITIALIZED = 0, RUNNING, STOPPING }; /* This is the current status of the life-cycle of the scheduler. */ enum enum_state state; THD *scheduler_thd; mysql_cond_t COND_state; Event_queue *queue; uint mutex_last_locked_at_line; uint mutex_last_unlocked_at_line; const char* mutex_last_locked_in_func; const char* mutex_last_unlocked_in_func; bool mutex_scheduler_data_locked; bool waiting_on_cond; ulonglong started_events; private: /* Prevent use of these */ Event_scheduler(const Event_scheduler &); void operator=(Event_scheduler &); }; /** @} (End of group Event_Scheduler) */ #endif /* _EVENT_SCHEDULER_H_ */ server/private/wsrep_schema.h000064400000011517151031265040012357 0ustar00/* Copyright (C) 2015-2024 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef WSREP_SCHEMA_H #define WSREP_SCHEMA_H /* wsrep-lib */ #include "wsrep_types.h" #include "mysqld.h" #include "wsrep_mysqld.h" /* Forward decls */ class THD; class Relay_log_info; struct TABLE; struct TABLE_LIST; struct st_mysql_lex_string; typedef struct st_mysql_lex_string LEX_STRING; class Gtid_log_event; /** Name of the table in `wsrep_schema_str` used for storing streaming replication data. In an InnoDB full format, e.g. "database/tablename". */ extern const char* wsrep_sr_table_name_full; class Wsrep_schema { public: Wsrep_schema(); ~Wsrep_schema(); /* Initialize wsrep schema. Storage engines must be running before calling this function. */ int init(); /* Store wsrep view info into wsrep schema. */ int store_view(THD*, const Wsrep_view& view); /* Restore view info from stable storage. */ Wsrep_view restore_view(THD* thd, const Wsrep_id& own_id) const; /** Append transaction fragment to fragment storage. Transaction must have been started for THD before this call. In order to make changes durable, transaction must be committed separately after this call. @param thd THD object @param server_id Wsrep server identifier @param transaction_id Transaction identifier @param flags Flags for the fragment @param data Fragment data buffer @return Zero in case of success, non-zero on failure. */ int append_fragment(THD* thd, const wsrep::id& server_id, wsrep::transaction_id transaction_id, wsrep::seqno seqno, int flags, const wsrep::const_buffer& data); /** Update existing fragment meta data. The fragment must have been inserted before using append_fragment(). @param thd THD object @param ws_meta Wsrep meta data @return Zero in case of success, non-zero on failure. */ int update_fragment_meta(THD* thd, const wsrep::ws_meta& ws_meta); /** Remove fragments from storage. This method must be called inside active transaction. Fragment removal will be committed once the transaction commits. @param thd Pointer to THD object @param server_id Identifier of the running server @param transaction_id Identifier of the current transaction @param fragments Vector of fragment seqnos to be removed */ int remove_fragments(THD* thd, const wsrep::id& server_id, wsrep::transaction_id transaction_id, const std::vector& fragments); /** Replay a transaction from stored fragments. The caller must have started a transaction for a thd. @param thd Pointer to THD object @param ws_meta Write set meta data for commit fragment. @param fragments Vector of fragments to be replayed @return Zero on success, non-zero on failure. */ int replay_transaction(THD* thd, Relay_log_info* rli, const wsrep::ws_meta& ws_meta, const std::vector& fragments); /** Recover streaming transactions from SR table. This method should be called after storage enignes are initialized. It will scan SR table and replay found streaming transactions. @param orig_thd The THD object of the calling thread. @return Zero on success, non-zero on failure. */ int recover_sr_transactions(THD* orig_thd); /** Store GTID-event to mysql.gtid_slave_pos table. @param thd The THD object of the calling thread. @param gtid GTID event from binlog. @return Zero on success, non-zero on failure. */ int store_gtid_event(THD* thd, const Gtid_log_event *gtid); private: /* Non-copyable */ Wsrep_schema(const Wsrep_schema&); Wsrep_schema& operator=(const Wsrep_schema&); }; extern Wsrep_schema* wsrep_schema; extern LEX_CSTRING WSREP_LEX_SCHEMA; extern LEX_CSTRING WSREP_LEX_STREAMING; extern LEX_CSTRING WSREP_LEX_CLUSTER; extern LEX_CSTRING WSREP_LEX_MEMBERS; #endif /* !WSREP_SCHEMA_H */ server/private/wsrep_applier.h000064400000005217151031265040012553 0ustar00/* Copyright 2013-2019 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef WSREP_APPLIER_H #define WSREP_APPLIER_H #include "sql_class.h" // THD class #include "rpl_rli.h" // Relay_log_info #include "log_event.h" // Format_description_log_event int wsrep_apply_events(THD* thd, Relay_log_info* rli, const void* events_buf, size_t buf_len); /* Applier error codes, when nothing better is available. */ #define WSREP_RET_SUCCESS 0 // Success #define WSREP_ERR_GENERIC 1 // When in doubt (MySQL default error code) #define WSREP_ERR_BAD_EVENT 2 // Can't parse event #define WSREP_ERR_NOT_FOUND 3 // Key. table, schema not found #define WSREP_ERR_EXISTS 4 // Key, table, schema already exists #define WSREP_ERR_WRONG_TYPE 5 // Incompatible data type #define WSREP_ERR_FAILED 6 // Operation failed for some internal reason #define WSREP_ERR_ABORTED 7 // Operation was aborted externally /* Loops over THD diagnostic area and concatenates all error messages * and error codes to a single continuous buffer to create a unique * but consistent failure signature which provider can use for voting * between the nodes in the cluster. * * @param thd THD context * @param dst buffer to store the signature * @param include_msg whether to use MySQL error message in addition to * MySQL error code. Note that in the case of a TOI * operation the message may be not consistent between * the nodes e.g. due to a different client locale setting * and should be omitted */ void wsrep_store_error(const THD* thd, wsrep::mutable_buffer& buf, bool include_msg); class Format_description_log_event; void wsrep_set_apply_format(THD*, Format_description_log_event*); Format_description_log_event* wsrep_get_apply_format(THD* thd); #endif /* WSREP_APPLIER_H */ server/private/my_nosys.h000064400000002636151031265040011561 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Header to remove use of my_functions in functions where we need speed and where calls to posix functions should work */ #ifndef _my_nosys_h #define _my_nosys_h #ifdef __cplusplus extern "C" { #endif #ifndef __MY_NOSYS__ #define __MY_NOSYS__ #ifndef HAVE_STDLIB_H #include #endif #undef my_read #undef my_write #undef my_seek #define my_read(a,b,c,d) my_quick_read(a,b,c,d) #define my_write(a,b,c,d) my_quick_write(a,b,c) extern size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count, myf myFlags); extern size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count); #endif /* __MY_NOSYS__ */ #ifdef __cplusplus } #endif #endif server/private/log_event.h000064400000554052151031265040011667 0ustar00/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. Copyright (c) 2009, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @addtogroup Replication @{ @file @brief Binary log event definitions. This includes generic code common to all types of log events, as well as specific code for each type of log event. */ #ifndef _log_event_h #define _log_event_h #if defined(USE_PRAGMA_INTERFACE) && defined(MYSQL_SERVER) #pragma interface /* gcc class implementation */ #endif #include #include "rpl_constants.h" #include #include #include #include #include #ifdef MYSQL_CLIENT #include "sql_const.h" #include "rpl_utility.h" #include "hash.h" #include "rpl_tblmap.h" #include "sql_string.h" #endif #ifdef MYSQL_SERVER #include "rpl_record.h" #include "rpl_reporting.h" #include "sql_class.h" /* THD */ #endif #include "rpl_gtid.h" #include "log_event_data_type.h" /* Forward declarations */ #ifndef MYSQL_CLIENT class String; #endif #define PREFIX_SQL_LOAD "SQL_LOAD-" #define LONG_FIND_ROW_THRESHOLD 60 /* seconds */ /** Either assert or return an error. In debug build, the condition will be checked, but in non-debug builds, the error code given will be returned instead. @param COND Condition to check @param ERRNO Error number to return in non-debug builds */ #ifdef DBUG_OFF #define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \ do { if (!(COND)) return ERRNO; } while (0) #else #define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \ DBUG_ASSERT(COND) #endif #define LOG_READ_EOF -1 #define LOG_READ_BOGUS -2 #define LOG_READ_IO -3 #define LOG_READ_MEM -5 #define LOG_READ_TRUNC -6 #define LOG_READ_TOO_LARGE -7 #define LOG_READ_CHECKSUM_FAILURE -8 #define LOG_READ_DECRYPT -9 #define LOG_EVENT_OFFSET 4 /* 3 is MySQL 4.x; 4 is MySQL 5.0.0. Compared to version 3, version 4 has: - a different Start_log_event, which includes info about the binary log (sizes of headers); this info is included for better compatibility if the master's MySQL version is different from the slave's. - all events have a unique ID (the triplet (server_id, timestamp at server start, other) to be sure an event is not executed more than once in a multimaster setup, example: M1 / \ v v M2 M3 \ / v v S if a query is run on M1, it will arrive twice on S, so we need that S remembers the last unique ID it has processed, to compare and know if the event should be skipped or not. Example of ID: we already have the server id (4 bytes), plus: timestamp_when_the_master_started (4 bytes), a counter (a sequence number which increments every time we write an event to the binlog) (3 bytes). Q: how do we handle when the counter is overflowed and restarts from 0 ? - Query and Load (Create or Execute) events may have a more precise timestamp (with microseconds), number of matched/affected/warnings rows and fields of session variables: SQL_MODE, FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, SQL_AUTO_IS_NULL, the collations and charsets, the PASSWORD() version (old/new/...). */ #define BINLOG_VERSION 4 /* We could have used SERVER_VERSION_LENGTH, but this introduces an obscure dependency - if somebody decided to change SERVER_VERSION_LENGTH this would break the replication protocol */ #define ST_SERVER_VER_LEN 50 /* These are flags and structs to handle all the LOAD DATA INFILE options (LINES TERMINATED etc). */ /* These are flags and structs to handle all the LOAD DATA INFILE options (LINES TERMINATED etc). DUMPFILE_FLAG is probably useless (DUMPFILE is a clause of SELECT, not of LOAD DATA). */ #define DUMPFILE_FLAG 0x1 #define OPT_ENCLOSED_FLAG 0x2 #define REPLACE_FLAG 0x4 #define IGNORE_FLAG 0x8 #define FIELD_TERM_EMPTY 0x1 #define ENCLOSED_EMPTY 0x2 #define LINE_TERM_EMPTY 0x4 #define LINE_START_EMPTY 0x8 #define ESCAPED_EMPTY 0x10 #define NUM_LOAD_DELIM_STRS 5 /* The following is the max table_map_id. This is limited by that we are using 6 bytes for it in replication */ #define MAX_TABLE_MAP_ID ((1ULL << (6*8)) -1) /***************************************************************************** MySQL Binary Log This log consists of events. Each event has a fixed-length header, possibly followed by a variable length data body. The data body consists of an optional fixed length segment (post-header) and an optional variable length segment. See the #defines below for the format specifics. The events which really update data are Query_log_event, Execute_load_query_log_event and old Load_log_event and Execute_load_log_event events (Execute_load_query is used together with Begin_load_query and Append_block events to replicate LOAD DATA INFILE. Create_file/Append_block/Execute_load (which includes Load_log_event) were used to replicate LOAD DATA before the 5.0.3). ****************************************************************************/ #define LOG_EVENT_HEADER_LEN 19 /* the fixed header length */ #define OLD_HEADER_LEN 13 /* the fixed header length in 3.23 */ /* Fixed header length, where 4.x and 5.0 agree. That is, 5.0 may have a longer header (it will for sure when we have the unique event's ID), but at least the first 19 bytes are the same in 4.x and 5.0. So when we have the unique event's ID, LOG_EVENT_HEADER_LEN will be something like 26, but LOG_EVENT_MINIMAL_HEADER_LEN will remain 19. */ #define LOG_EVENT_MINIMAL_HEADER_LEN 19 /* event-specific post-header sizes */ // where 3.23, 4.x and 5.0 agree #define QUERY_HEADER_MINIMAL_LEN (4 + 4 + 1 + 2) // where 5.0 differs: 2 for len of N-bytes vars. #define QUERY_HEADER_LEN (QUERY_HEADER_MINIMAL_LEN + 2) #define STOP_HEADER_LEN 0 #define LOAD_HEADER_LEN (4 + 4 + 4 + 1 +1 + 4) #define SLAVE_HEADER_LEN 0 #define START_V3_HEADER_LEN (2 + ST_SERVER_VER_LEN + 4) #define ROTATE_HEADER_LEN 8 // this is FROZEN (the Rotate post-header is frozen) #define INTVAR_HEADER_LEN 0 #define CREATE_FILE_HEADER_LEN 4 #define APPEND_BLOCK_HEADER_LEN 4 #define EXEC_LOAD_HEADER_LEN 4 #define DELETE_FILE_HEADER_LEN 4 #define NEW_LOAD_HEADER_LEN LOAD_HEADER_LEN #define RAND_HEADER_LEN 0 #define USER_VAR_HEADER_LEN 0 #define FORMAT_DESCRIPTION_HEADER_LEN (START_V3_HEADER_LEN+1+LOG_EVENT_TYPES) #define XID_HEADER_LEN 0 #define BEGIN_LOAD_QUERY_HEADER_LEN APPEND_BLOCK_HEADER_LEN #define ROWS_HEADER_LEN_V1 8 #define TABLE_MAP_HEADER_LEN 8 #define EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN (4 + 4 + 4 + 1) #define EXECUTE_LOAD_QUERY_HEADER_LEN (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN) #define INCIDENT_HEADER_LEN 2 #define HEARTBEAT_HEADER_LEN 0 #define IGNORABLE_HEADER_LEN 0 #define ROWS_HEADER_LEN_V2 10 #define ANNOTATE_ROWS_HEADER_LEN 0 #define BINLOG_CHECKPOINT_HEADER_LEN 4 #define GTID_HEADER_LEN 19 #define GTID_LIST_HEADER_LEN 4 #define START_ENCRYPTION_HEADER_LEN 0 #define XA_PREPARE_HEADER_LEN 0 /* Max number of possible extra bytes in a replication event compared to a packet (i.e. a query) sent from client to master; First, an auxiliary log_event status vars estimation: */ #define MAX_SIZE_LOG_EVENT_STATUS (1 + 4 /* type, flags2 */ + \ 1 + 8 /* type, sql_mode */ + \ 1 + 1 + 255 /* type, length, catalog */ + \ 1 + 4 /* type, auto_increment */ + \ 1 + 6 /* type, charset */ + \ 1 + 1 + 255 /* type, length, time_zone */ + \ 1 + 2 /* type, lc_time_names_number */ + \ 1 + 2 /* type, charset_database_number */ + \ 1 + 8 /* type, table_map_for_update */ + \ 1 + 4 /* type, master_data_written */ + \ 1 + 3 /* type, sec_part of NOW() */ + \ 1 + 16 + 1 + 60/* type, user_len, user, host_len, host */) #define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \ LOG_EVENT_HEADER_LEN + /* write_header */ \ QUERY_HEADER_LEN + /* write_data */ \ EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN + /*write_post_header_for_derived */ \ MAX_SIZE_LOG_EVENT_STATUS + /* status */ \ NAME_LEN + 1) /* The new option is added to handle large packets that are sent from the master to the slave. It is used to increase the thd(max_allowed) for both the DUMP thread on the master and the SQL/IO thread on the slave. */ #define MAX_MAX_ALLOWED_PACKET (1024*1024*1024) /* Event header offsets; these point to places inside the fixed header. */ #define EVENT_TYPE_OFFSET 4 #define SERVER_ID_OFFSET 5 #define EVENT_LEN_OFFSET 9 #define LOG_POS_OFFSET 13 #define FLAGS_OFFSET 17 /* start event post-header (for v3 and v4) */ #define ST_BINLOG_VER_OFFSET 0 #define ST_SERVER_VER_OFFSET 2 #define ST_CREATED_OFFSET (ST_SERVER_VER_OFFSET + ST_SERVER_VER_LEN) #define ST_COMMON_HEADER_LEN_OFFSET (ST_CREATED_OFFSET + 4) /* slave event post-header (this event is never written) */ #define SL_MASTER_PORT_OFFSET 8 #define SL_MASTER_POS_OFFSET 0 #define SL_MASTER_HOST_OFFSET 10 /* query event post-header */ #define Q_THREAD_ID_OFFSET 0 #define Q_EXEC_TIME_OFFSET 4 #define Q_DB_LEN_OFFSET 8 #define Q_ERR_CODE_OFFSET 9 #define Q_STATUS_VARS_LEN_OFFSET 11 #define Q_DATA_OFFSET QUERY_HEADER_LEN /* these are codes, not offsets; not more than 256 values (1 byte). */ #define Q_FLAGS2_CODE 0 #define Q_SQL_MODE_CODE 1 /* Q_CATALOG_CODE is catalog with end zero stored; it is used only by MySQL 5.0.x where 0<=x<=3. We have to keep it to be able to replicate these old masters. */ #define Q_CATALOG_CODE 2 #define Q_AUTO_INCREMENT 3 #define Q_CHARSET_CODE 4 #define Q_TIME_ZONE_CODE 5 /* Q_CATALOG_NZ_CODE is catalog withOUT end zero stored; it is used by MySQL 5.0.x where x>=4. Saves one byte in every Query_log_event in binlog, compared to Q_CATALOG_CODE. The reason we didn't simply re-use Q_CATALOG_CODE is that then a 5.0.3 slave of this 5.0.x (x>=4) master would crash (segfault etc) because it would expect a 0 when there is none. */ #define Q_CATALOG_NZ_CODE 6 #define Q_LC_TIME_NAMES_CODE 7 #define Q_CHARSET_DATABASE_CODE 8 #define Q_TABLE_MAP_FOR_UPDATE_CODE 9 #define Q_MASTER_DATA_WRITTEN_CODE 10 #define Q_INVOKER 11 #define Q_HRNOW 128 #define Q_XID 129 /* Intvar event post-header */ /* Intvar event data */ #define I_TYPE_OFFSET 0 #define I_VAL_OFFSET 1 /* Rand event data */ #define RAND_SEED1_OFFSET 0 #define RAND_SEED2_OFFSET 8 /* User_var event data */ #define UV_VAL_LEN_SIZE 4 #define UV_VAL_IS_NULL 1 #define UV_VAL_TYPE_SIZE 1 #define UV_NAME_LEN_SIZE 4 #define UV_CHARSET_NUMBER_SIZE 4 /* Load event post-header */ #define L_THREAD_ID_OFFSET 0 #define L_EXEC_TIME_OFFSET 4 #define L_SKIP_LINES_OFFSET 8 #define L_TBL_LEN_OFFSET 12 #define L_DB_LEN_OFFSET 13 #define L_NUM_FIELDS_OFFSET 14 #define L_SQL_EX_OFFSET 18 #define L_DATA_OFFSET LOAD_HEADER_LEN /* Rotate event post-header */ #define R_POS_OFFSET 0 #define R_IDENT_OFFSET 8 /* CF to DF handle LOAD DATA INFILE */ /* CF = "Create File" */ #define CF_FILE_ID_OFFSET 0 #define CF_DATA_OFFSET CREATE_FILE_HEADER_LEN /* AB = "Append Block" */ #define AB_FILE_ID_OFFSET 0 #define AB_DATA_OFFSET APPEND_BLOCK_HEADER_LEN /* EL = "Execute Load" */ #define EL_FILE_ID_OFFSET 0 /* DF = "Delete File" */ #define DF_FILE_ID_OFFSET 0 /* TM = "Table Map" */ #define TM_MAPID_OFFSET 0 #define TM_FLAGS_OFFSET 6 /* RW = "RoWs" */ #define RW_MAPID_OFFSET 0 #define RW_FLAGS_OFFSET 6 #define RW_VHLEN_OFFSET 8 #define RW_V_TAG_LEN 1 #define RW_V_EXTRAINFO_TAG 0 /* ELQ = "Execute Load Query" */ #define ELQ_FILE_ID_OFFSET QUERY_HEADER_LEN #define ELQ_FN_POS_START_OFFSET ELQ_FILE_ID_OFFSET + 4 #define ELQ_FN_POS_END_OFFSET ELQ_FILE_ID_OFFSET + 8 #define ELQ_DUP_HANDLING_OFFSET ELQ_FILE_ID_OFFSET + 12 /* 4 bytes which all binlogs should begin with */ #define BINLOG_MAGIC (const uchar*) "\xfe\x62\x69\x6e" /* The 2 flags below were useless : - the first one was never set - the second one was set in all Rotate events on the master, but not used for anything useful. So they are now removed and their place may later be reused for other flags. Then one must remember that Rotate events in 4.x have LOG_EVENT_FORCED_ROTATE_F set, so one should not rely on the value of the replacing flag when reading a Rotate event. I keep the defines here just to remember what they were. */ #ifdef TO_BE_REMOVED #define LOG_EVENT_TIME_F 0x1 #define LOG_EVENT_FORCED_ROTATE_F 0x2 #endif /* This flag only makes sense for Format_description_log_event. It is set when the event is written, and *reset* when a binlog file is closed (yes, it's the only case when MySQL modifies already written part of binlog). Thus it is a reliable indicator that binlog was closed correctly. (Stop_log_event is not enough, there's always a small chance that mysqld crashes in the middle of insert and end of the binlog would look like a Stop_log_event). This flag is used to detect a restart after a crash, and to provide "unbreakable" binlog. The problem is that on a crash storage engines rollback automatically, while binlog does not. To solve this we use this flag and automatically append ROLLBACK to every non-closed binlog (append virtually, on reading, file itself is not changed). If this flag is found, mysqlbinlog simply prints "ROLLBACK" Replication master does not abort on binlog corruption, but takes it as EOF, and replication slave forces a rollback in this case. Note, that old binlogs does not have this flag set, so we get a a backward-compatible behaviour. */ #define LOG_EVENT_BINLOG_IN_USE_F 0x1 /** @def LOG_EVENT_THREAD_SPECIFIC_F If the query depends on the thread (for example: TEMPORARY TABLE). Currently this is used by mysqlbinlog to know it must print SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it for every query but this would be slow). */ #define LOG_EVENT_THREAD_SPECIFIC_F 0x4 /** @def LOG_EVENT_SUPPRESS_USE_F Suppress the generation of 'USE' statements before the actual statement. This flag should be set for any events that does not need the current database set to function correctly. Most notable cases are 'CREATE DATABASE' and 'DROP DATABASE'. This flags should only be used in exceptional circumstances, since it introduce a significant change in behaviour regarding the replication logic together with the flags --binlog-do-db and --replicated-do-db. */ #define LOG_EVENT_SUPPRESS_USE_F 0x8 /* Note: this is a place holder for the flag LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F (0x10), which is not used any more, please do not reused this value for other flags. */ /** @def LOG_EVENT_ARTIFICIAL_F Artificial events are created arbitrarily and not written to binary log These events should not update the master log position when slave SQL thread executes them. */ #define LOG_EVENT_ARTIFICIAL_F 0x20 /** @def LOG_EVENT_RELAY_LOG_F Events with this flag set are created by slave IO thread and written to relay log */ #define LOG_EVENT_RELAY_LOG_F 0x40 /** @def LOG_EVENT_IGNORABLE_F For an event, 'e', carrying a type code, that a slave, 's', does not recognize, 's' will check 'e' for LOG_EVENT_IGNORABLE_F, and if the flag is set, then 'e' is ignored. Otherwise, 's' acknowledges that it has found an unknown event in the relay log. */ #define LOG_EVENT_IGNORABLE_F 0x80 /** @def LOG_EVENT_ACCEPT_OWN_F Flag sets by the semisync slave for accepting the same server_id ("own") events which the slave must not have in its state. Typically such events were never committed by their originator (this server) and discared at its semisync-slave recovery. */ #define LOG_EVENT_ACCEPT_OWN_F 0x4000 /** @def LOG_EVENT_SKIP_REPLICATION_F Flag set by application creating the event (with @@skip_replication); the slave will skip replication of such events if --replicate-events-marked-for-skip is not set to REPLICATE. This is a MariaDB flag; we allocate it from the end of the available values to reduce risk of conflict with new MySQL flags. */ #define LOG_EVENT_SKIP_REPLICATION_F 0x8000 /** @def OPTIONS_WRITTEN_TO_BIN_LOG OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must be written to the binlog. OPTIONS_WRITTEN_TO_BIN_LOG could be written into the Format_description_log_event, so that if later we don't want to replicate a variable we did replicate, or the contrary, it's doable. But it should not be too hard to deduct the value of OPTIONS_WRITTEN_TO_BIN_LOG from the master's version. This is done in deduct_options_written_to_bin_log(). You *must* update it, when changing the definition below. */ #define OPTIONS_WRITTEN_TO_BIN_LOG (OPTION_EXPLICIT_DEF_TIMESTAMP |\ OPTION_AUTO_IS_NULL | OPTION_NO_FOREIGN_KEY_CHECKS | \ OPTION_RELAXED_UNIQUE_CHECKS | OPTION_NOT_AUTOCOMMIT | OPTION_IF_EXISTS) #define CHECKSUM_CRC32_SIGNATURE_LEN 4 /** defined statically while there is just one alg implemented */ #define BINLOG_CHECKSUM_LEN CHECKSUM_CRC32_SIGNATURE_LEN #define BINLOG_CHECKSUM_ALG_DESC_LEN 1 /* 1 byte checksum alg descriptor */ /* These are capability numbers for MariaDB slave servers. Newer MariaDB slaves set this to inform the master about their capabilities. This allows the master to decide which events it can send to the slave without breaking replication on old slaves that maybe do not understand all events from newer masters. As new releases are backwards compatible, a given capability implies also all capabilities with smaller number. Older MariaDB slaves and other MySQL slave servers do not set this, so they are recorded with capability 0. */ /* MySQL or old MariaDB slave with no announced capability. */ #define MARIA_SLAVE_CAPABILITY_UNKNOWN 0 /* MariaDB >= 5.3, which understands ANNOTATE_ROWS_EVENT. */ #define MARIA_SLAVE_CAPABILITY_ANNOTATE 1 /* MariaDB >= 5.5. This version has the capability to tolerate events omitted from the binlog stream without breaking replication (MySQL slaves fail because they mis-compute the offsets into the master's binlog). */ #define MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES 2 /* MariaDB >= 10.0, which knows about binlog_checkpoint_log_event. */ #define MARIA_SLAVE_CAPABILITY_BINLOG_CHECKPOINT 3 /* MariaDB >= 10.0.1, which knows about global transaction id events. */ #define MARIA_SLAVE_CAPABILITY_GTID 4 /* Our capability. */ #define MARIA_SLAVE_CAPABILITY_MINE MARIA_SLAVE_CAPABILITY_GTID /* When the size of 'log_pos' within Heartbeat_log_event exceeds UINT32_MAX it cannot be accommodated in common_header, as 'log_pos' is of 4 bytes size. In such cases, sub_header, of size 8 bytes will hold larger 'log_pos' value. */ #define HB_SUB_HEADER_LEN 8 /** @enum Log_event_type Enumeration type for the different types of log events. */ enum Log_event_type { /* Every time you update this enum (when you add a type), you have to fix Format_description_log_event::Format_description_log_event(). */ UNKNOWN_EVENT= 0, START_EVENT_V3= 1, QUERY_EVENT= 2, STOP_EVENT= 3, ROTATE_EVENT= 4, INTVAR_EVENT= 5, LOAD_EVENT= 6, SLAVE_EVENT= 7, CREATE_FILE_EVENT= 8, APPEND_BLOCK_EVENT= 9, EXEC_LOAD_EVENT= 10, DELETE_FILE_EVENT= 11, /* NEW_LOAD_EVENT is like LOAD_EVENT except that it has a longer sql_ex, allowing multibyte TERMINATED BY etc; both types share the same class (Load_log_event) */ NEW_LOAD_EVENT= 12, RAND_EVENT= 13, USER_VAR_EVENT= 14, FORMAT_DESCRIPTION_EVENT= 15, XID_EVENT= 16, BEGIN_LOAD_QUERY_EVENT= 17, EXECUTE_LOAD_QUERY_EVENT= 18, TABLE_MAP_EVENT = 19, /* These event numbers were used for 5.1.0 to 5.1.15 and are therefore obsolete. */ PRE_GA_WRITE_ROWS_EVENT = 20, PRE_GA_UPDATE_ROWS_EVENT = 21, PRE_GA_DELETE_ROWS_EVENT = 22, /* These event numbers are used from 5.1.16 until mysql-5.6.6, and in MariaDB */ WRITE_ROWS_EVENT_V1 = 23, UPDATE_ROWS_EVENT_V1 = 24, DELETE_ROWS_EVENT_V1 = 25, /* Something out of the ordinary happened on the master */ INCIDENT_EVENT= 26, /* Heartbeat event to be send by master at its idle time to ensure master's online status to slave */ HEARTBEAT_LOG_EVENT= 27, /* In some situations, it is necessary to send over ignorable data to the slave: data that a slave can handle in case there is code for handling it, but which can be ignored if it is not recognized. These mysql-5.6 events are not recognized (and ignored) by MariaDB */ IGNORABLE_LOG_EVENT= 28, ROWS_QUERY_LOG_EVENT= 29, /* Version 2 of the Row events, generated only by mysql-5.6.6+ */ WRITE_ROWS_EVENT = 30, UPDATE_ROWS_EVENT = 31, DELETE_ROWS_EVENT = 32, /* MySQL 5.6 GTID events, ignored by MariaDB */ GTID_LOG_EVENT= 33, ANONYMOUS_GTID_LOG_EVENT= 34, PREVIOUS_GTIDS_LOG_EVENT= 35, /* MySQL 5.7 events, ignored by MariaDB */ TRANSACTION_CONTEXT_EVENT= 36, VIEW_CHANGE_EVENT= 37, /* not ignored */ XA_PREPARE_LOG_EVENT= 38, /** Extension of UPDATE_ROWS_EVENT, allowing partial values according to binlog_row_value_options. */ PARTIAL_UPDATE_ROWS_EVENT = 39, TRANSACTION_PAYLOAD_EVENT = 40, HEARTBEAT_LOG_EVENT_V2 = 41, /* Add new events here - right above this comment! Existing events (except ENUM_END_EVENT) should never change their numbers */ /* New MySQL/Sun events are to be added right above this comment */ MYSQL_EVENTS_END, MARIA_EVENTS_BEGIN= 160, /* New Maria event numbers start from here */ ANNOTATE_ROWS_EVENT= 160, /* Binlog checkpoint event. Used for XA crash recovery on the master, not used in replication. A binlog checkpoint event specifies a binlog file such that XA crash recovery can start from that file - and it is guaranteed to find all XIDs that are prepared in storage engines but not yet committed. */ BINLOG_CHECKPOINT_EVENT= 161, /* Gtid event. For global transaction ID, used to start a new event group, instead of the old BEGIN query event, and also to mark stand-alone events. */ GTID_EVENT= 162, /* Gtid list event. Logged at the start of every binlog, to record the current replication state. This consists of the last GTID seen for each replication domain. */ GTID_LIST_EVENT= 163, START_ENCRYPTION_EVENT= 164, /* Compressed binlog event. Note that the order between WRITE/UPDATE/DELETE events is significant; this is so that we can convert from the compressed to the uncompressed event type with (type-WRITE_ROWS_COMPRESSED_EVENT + WRITE_ROWS_EVENT) and similar for _V1. */ QUERY_COMPRESSED_EVENT = 165, WRITE_ROWS_COMPRESSED_EVENT_V1 = 166, UPDATE_ROWS_COMPRESSED_EVENT_V1 = 167, DELETE_ROWS_COMPRESSED_EVENT_V1 = 168, WRITE_ROWS_COMPRESSED_EVENT = 169, UPDATE_ROWS_COMPRESSED_EVENT = 170, DELETE_ROWS_COMPRESSED_EVENT = 171, /* Add new MariaDB events here - right above this comment! */ ENUM_END_EVENT /* end marker */ }; /* Bit flags for what has been writing to cache. Used to discard logs with table map events but not row events and nothing else important. This is stored by cache. */ enum enum_logged_status { LOGGED_TABLE_MAP= 1, LOGGED_ROW_EVENT= 2, LOGGED_NO_DATA= 4, LOGGED_CRITICAL= 8 }; static inline bool LOG_EVENT_IS_QUERY(enum Log_event_type type) { return type == QUERY_EVENT || type == QUERY_COMPRESSED_EVENT; } static inline bool LOG_EVENT_IS_WRITE_ROW(enum Log_event_type type) { return type == WRITE_ROWS_EVENT || type == WRITE_ROWS_EVENT_V1 || type == WRITE_ROWS_COMPRESSED_EVENT || type == WRITE_ROWS_COMPRESSED_EVENT_V1; } static inline bool LOG_EVENT_IS_UPDATE_ROW(enum Log_event_type type) { return type == UPDATE_ROWS_EVENT || type == UPDATE_ROWS_EVENT_V1 || type == UPDATE_ROWS_COMPRESSED_EVENT || type == UPDATE_ROWS_COMPRESSED_EVENT_V1; } static inline bool LOG_EVENT_IS_DELETE_ROW(enum Log_event_type type) { return type == DELETE_ROWS_EVENT || type == DELETE_ROWS_EVENT_V1 || type == DELETE_ROWS_COMPRESSED_EVENT || type == DELETE_ROWS_COMPRESSED_EVENT_V1; } static inline bool LOG_EVENT_IS_ROW_COMPRESSED(enum Log_event_type type) { return type == WRITE_ROWS_COMPRESSED_EVENT || type == WRITE_ROWS_COMPRESSED_EVENT_V1 || type == UPDATE_ROWS_COMPRESSED_EVENT || type == UPDATE_ROWS_COMPRESSED_EVENT_V1 || type == DELETE_ROWS_COMPRESSED_EVENT || type == DELETE_ROWS_COMPRESSED_EVENT_V1; } static inline bool LOG_EVENT_IS_ROW_V2(enum Log_event_type type) { return (type >= WRITE_ROWS_EVENT && type <= DELETE_ROWS_EVENT) || (type >= WRITE_ROWS_COMPRESSED_EVENT && type <= DELETE_ROWS_COMPRESSED_EVENT); } /* The number of types we handle in Format_description_log_event (UNKNOWN_EVENT is not to be handled, it does not exist in binlogs, it does not have a format). */ #define LOG_EVENT_TYPES (ENUM_END_EVENT-1) enum Int_event_type { INVALID_INT_EVENT = 0, LAST_INSERT_ID_EVENT = 1, INSERT_ID_EVENT = 2 }; #ifdef MYSQL_SERVER class String; class MYSQL_BIN_LOG; class THD; #endif class Format_description_log_event; class Relay_log_info; class binlog_cache_data; bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, FILE *file); #ifdef MYSQL_CLIENT enum enum_base64_output_mode { BASE64_OUTPUT_NEVER= 0, BASE64_OUTPUT_AUTO= 1, BASE64_OUTPUT_UNSPEC= 2, BASE64_OUTPUT_DECODE_ROWS= 3, /* insert new output modes here */ BASE64_OUTPUT_MODE_COUNT }; bool copy_event_cache_to_string_and_reinit(IO_CACHE *cache, LEX_STRING *to); /* A structure for mysqlbinlog to know how to print events This structure is passed to the event's print() methods, There are two types of settings stored here: 1. Last db, flags2, sql_mode etc comes from the last printed event. They are stored so that only the necessary USE and SET commands are printed. 2. Other information on how to print the events, e.g. short_form, hexdump_from. These are not dependent on the last event. */ typedef struct st_print_event_info { /* Settings for database, sql_mode etc that comes from the last event that was printed. We cache these so that we don't have to print them if they are unchanged. */ char db[FN_REFLEN+1]; // TODO: make this a LEX_STRING when thd->db is char charset[6]; // 3 variables, each of them storable in 2 bytes char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH]; char delimiter[16]; sql_mode_t sql_mode; /* must be same as THD.variables.sql_mode */ my_thread_id thread_id; ulonglong row_events; ulong auto_increment_increment, auto_increment_offset; uint lc_time_names_number; uint charset_database_number; uint verbose; uchar gtid_ev_flags2; uint32 flags2; uint32 server_id; uint32 domain_id; uint8 common_header_len; enum_base64_output_mode base64_output_mode; my_off_t hexdump_from; table_mapping m_table_map; table_mapping m_table_map_ignored; bool flags2_inited; bool sql_mode_inited; bool charset_inited; bool thread_id_printed; bool server_id_printed; bool domain_id_printed; bool allow_parallel; bool allow_parallel_printed; bool found_row_event; bool print_row_count; static const uint max_delimiter_size= 16; /* Settings on how to print the events */ bool short_form; /* This is set whenever a Format_description_event is printed. Later, when an event is printed in base64, this flag is tested: if no Format_description_event has been seen, it is unsafe to print the base64 event, so an error message is generated. */ bool printed_fd_event; /* Track when @@skip_replication changes so we need to output a SET statement for it. */ bool skip_replication; bool print_table_metadata; /* These two caches are used by the row-based replication events to collect the header information and the main body of the events making up a statement. */ IO_CACHE head_cache; IO_CACHE body_cache; IO_CACHE tail_cache; #ifdef WHEN_FLASHBACK_REVIEW_READY /* Storing the SQL for reviewing */ IO_CACHE review_sql_cache; #endif FILE *file; st_print_event_info(); ~st_print_event_info() { close_cached_file(&head_cache); close_cached_file(&body_cache); close_cached_file(&tail_cache); #ifdef WHEN_FLASHBACK_REVIEW_READY close_cached_file(&review_sql_cache); #endif } bool init_ok() /* tells if construction was successful */ { return my_b_inited(&head_cache) && my_b_inited(&body_cache) #ifdef WHEN_FLASHBACK_REVIEW_READY && my_b_inited(&review_sql_cache) #endif ; } void flush_for_error() { if (!copy_event_cache_to_file_and_reinit(&head_cache, file)) copy_event_cache_to_file_and_reinit(&body_cache, file); fflush(file); } my_bool is_xa_trans(); } PRINT_EVENT_INFO; #endif // MYSQL_CLIENT /** This class encapsulates writing of Log_event objects to IO_CACHE. Automatically calculates the checksum and encrypts the data, if necessary. */ class Log_event_writer { /* Log_event_writer is updated when ctx is set */ int (Log_event_writer::*encrypt_or_write)(const uchar *pos, size_t len); public: ulonglong bytes_written; void *ctx; ///< Encryption context or 0 if no encryption is needed uint checksum_len; int write(Log_event *ev); int write_header(uchar *pos, size_t len); int write_data(const uchar *pos, size_t len); int write_footer(); my_off_t pos() { return my_b_safe_tell(file); } void add_status(enum_logged_status status); void set_incident(); void set_encrypted_writer() { encrypt_or_write= &Log_event_writer::encrypt_and_write; } Log_event_writer(IO_CACHE *file_arg, binlog_cache_data *cache_data_arg, Binlog_crypt_data *cr= 0) :encrypt_or_write(&Log_event_writer::write_internal), bytes_written(0), ctx(0), file(file_arg), cache_data(cache_data_arg), crypto(cr) { } private: IO_CACHE *file; binlog_cache_data *cache_data; /** Placeholder for event checksum while writing to binlog. */ ha_checksum crc; /** Encryption data (key, nonce). Only used if ctx != 0. */ Binlog_crypt_data *crypto; /** Event length to be written into the next encrypted block */ uint event_len; int write_internal(const uchar *pos, size_t len); int encrypt_and_write(const uchar *pos, size_t len); int maybe_write_event_len(uchar *pos, size_t len); }; /** the struct aggregates two parameters that identify an event uniquely in scope of communication of a particular master and slave couple. I.e there can not be 2 events from the same staying connected master which have the same coordinates. @note Such identifier is not yet unique generally as the event originating master is resettable. Also the crashed master can be replaced with some other. */ typedef struct event_coordinates { char * file_name; // binlog file name (directories stripped) my_off_t pos; // event's position in the binlog file } LOG_POS_COORD; /** @class Log_event This is the abstract base class for binary log events. @section Log_event_binary_format Binary Format Any @c Log_event saved on disk consists of the following three components. - Common-Header - Post-Header - Body The Common-Header, documented in the table @ref Table_common_header "below", always has the same form and length within one version of MySQL. Each event type specifies a format and length of the Post-Header. The length of the Common-Header is the same for all events of the same type. The Body may be of different format and length even for different events of the same type. The binary formats of Post-Header and Body are documented separately in each subclass. The binary format of Common-Header is as follows.
Common-Header
Name Format Description
timestamp 4 byte unsigned integer The time when the query started, in seconds since 1970.
type 1 byte enumeration See enum #Log_event_type.
server_id 4 byte unsigned integer Server ID of the server that created the event.
total_size 4 byte unsigned integer The total size of this event, in bytes. In other words, this is the sum of the sizes of Common-Header, Post-Header, and Body.
master_position 4 byte unsigned integer The position of the next event in the master binary log, in bytes from the beginning of the file. In a binlog that is not a relay log, this is just the position of the next event, in bytes from the beginning of the file. In a relay log, this is the position of the next event in the master's binlog.
flags 2 byte bitfield See Log_event::flags.
Summing up the numbers above, we see that the total size of the common header is 19 bytes. @subsection Log_event_format_of_atomic_primitives Format of Atomic Primitives - All numbers, whether they are 16-, 24-, 32-, or 64-bit numbers, are stored in little endian, i.e., the least significant byte first, unless otherwise specified. @anchor packed_integer - Some events use a special format for efficient representation of unsigned integers, called Packed Integer. A Packed Integer has the capacity of storing up to 8-byte integers, while small integers still can use 1, 3, or 4 bytes. The value of the first byte determines how to read the number, according to the following table:
Format of Packed Integer
First byte Format
0-250 The first byte is the number (in the range 0-250), and no more bytes are used.
252 Two more bytes are used. The number is in the range 251-0xffff.
253 Three more bytes are used. The number is in the range 0xffff-0xffffff.
254 Eight more bytes are used. The number is in the range 0xffffff-0xffffffffffffffff.
- Strings are stored in various formats. The format of each string is documented separately. */ class Log_event { public: /** Enumeration of what kinds of skipping (and non-skipping) that can occur when the slave executes an event. @see shall_skip @see do_shall_skip */ enum enum_skip_reason { /** Don't skip event. */ EVENT_SKIP_NOT, /** Skip event by ignoring it. This means that the slave skip counter will not be changed. */ EVENT_SKIP_IGNORE, /** Skip event and decrease skip counter. */ EVENT_SKIP_COUNT }; enum enum_event_cache_type { EVENT_INVALID_CACHE, /* If possible the event should use a non-transactional cache before being flushed to the binary log. This means that it must be flushed right after its correspondent statement is completed. */ EVENT_STMT_CACHE, /* The event should use a transactional cache before being flushed to the binary log. This means that it must be flushed upon commit or rollback. */ EVENT_TRANSACTIONAL_CACHE, /* The event must be written directly to the binary log without going through a cache. */ EVENT_NO_CACHE, /** If there is a need for different types, introduce them before this. */ EVENT_CACHE_COUNT }; /* The following type definition is to be used whenever data is placed and manipulated in a common buffer. Use this typedef for buffers that contain data containing binary and character data. */ typedef unsigned char Byte; /* The offset in the log where this event originally appeared (it is preserved in relay logs, making SHOW SLAVE STATUS able to print coordinates of the event in the master's binlog). Note: when a transaction is written by the master to its binlog (wrapped in BEGIN/COMMIT) the log_pos of all the queries it contains is the one of the BEGIN (this way, when one does SHOW SLAVE STATUS it sees the offset of the BEGIN, which is logical as rollback may occur), except the COMMIT query which has its real offset. */ my_off_t log_pos; /* A temp buffer for read_log_event; it is later analysed according to the event's type, and its content is distributed in the event-specific fields. */ uchar *temp_buf; /* TRUE <=> this event 'owns' temp_buf and should call my_free() when done with it */ bool event_owns_temp_buf; /* Timestamp on the master(for debugging and replication of NOW()/TIMESTAMP). It is important for queries and LOAD DATA INFILE. This is set at the event's creation time, except for Query and Load (et al.) events where this is set at the query's execution time, which guarantees good replication (otherwise, we could have a query and its event with different timestamps). */ my_time_t when; ulong when_sec_part; /* The number of seconds the query took to run on the master. */ ulong exec_time; /* Number of bytes written by write() function */ size_t data_written; /* The master's server id (is preserved in the relay log; used to prevent from infinite loops in circular replication). */ uint32 server_id; /** Some 16 flags. See the definitions above for LOG_EVENT_TIME_F, LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, LOG_EVENT_SUPPRESS_USE_F, and LOG_EVENT_SKIP_REPLICATION_F for notes. */ uint16 flags; enum_event_cache_type cache_type; /** A storage to cache the global system variable's value. Handling of a separate event will be governed its member. */ ulong slave_exec_mode; Log_event_writer *writer; #ifdef MYSQL_SERVER THD* thd; Log_event(); Log_event(THD* thd_arg, uint16 flags_arg, bool is_transactional); /* init_show_field_list() prepares the column names and types for the output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG EVENTS. */ static void init_show_field_list(THD *thd, List* field_list); #ifdef HAVE_REPLICATION int net_send(Protocol *protocol, const char* log_name, my_off_t pos); /* pack_info() is used by SHOW BINLOG EVENTS; as print() it prepares and sends a string to display to the user, so it resembles print(). */ virtual void pack_info(Protocol *protocol); #endif /* HAVE_REPLICATION */ virtual const char* get_db() { return thd ? thd->db.str : 0; } #else Log_event() : temp_buf(0), when(0), flags(0) {} ha_checksum crc; /* print*() functions are used by mysqlbinlog */ virtual bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0; bool print_timestamp(IO_CACHE* file, time_t *ts = 0); bool print_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info, bool is_more); bool print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info, bool do_print_encoded); #endif /* MYSQL_SERVER */ /* The following code used for Flashback */ #ifdef MYSQL_CLIENT my_bool is_flashback; my_bool need_flashback_review; String output_buf; // Storing the event output #ifdef WHEN_FLASHBACK_REVIEW_READY String m_review_dbname; String m_review_tablename; void set_review_dbname(const char *name) { if (name) { m_review_dbname.free(); m_review_dbname.append(name); } } void set_review_tablename(const char *name) { if (name) { m_review_tablename.free(); m_review_tablename.append(name); } } const char *get_review_dbname() const { return m_review_dbname.ptr(); } const char *get_review_tablename() const { return m_review_tablename.ptr(); } #endif #endif /* read_log_event() functions read an event from a binlog or relay log; used by SHOW BINLOG EVENTS, the binlog_dump thread on the master (reads master's binlog), the slave IO thread (reads the event sent by binlog_dump), the slave SQL thread (reads the event from the relay log). If mutex is 0, the read will proceed without mutex. We need the description_event to be able to parse the event (to know the post-header's size); in fact in read_log_event we detect the event's type, then call the specific event's constructor and pass description_event as an argument. */ static Log_event* read_log_event(IO_CACHE* file, int *out_error, const Format_description_log_event *description_event, my_bool crc_check, my_bool print_errors= 1); /** Reads an event from a binlog or relay log. Used by the dump thread this method reads the event into a raw buffer without parsing it. @Note If mutex is 0, the read will proceed without mutex. @Note If a log name is given than the method will check if the given binlog is still active. @param[in] file log file to be read @param[out] packet packet to hold the event @param[in] checksum_alg_arg verify the event checksum using this algorithm (or don't if it's use BINLOG_CHECKSUM_ALG_OFF) @retval 0 success @retval LOG_READ_EOF end of file, nothing was read @retval LOG_READ_BOGUS malformed event @retval LOG_READ_IO io error while reading @retval LOG_READ_MEM packet memory allocation failed @retval LOG_READ_TRUNC only a partial event could be read @retval LOG_READ_TOO_LARGE event too large */ static int read_log_event(IO_CACHE* file, String* packet, const Format_description_log_event *fdle, enum enum_binlog_checksum_alg checksum_alg_arg); /* The value is set by caller of FD constructor and Log_event::write_header() for the rest. In the FD case it's propagated into the last byte of post_header_len[] at FD::write(). On the slave side the value is assigned from post_header_len[last] of the last seen FD event. */ enum enum_binlog_checksum_alg checksum_alg; static void *operator new(size_t size) { extern PSI_memory_key key_memory_log_event; return my_malloc(key_memory_log_event, size, MYF(MY_WME|MY_FAE)); } static void operator delete(void *ptr, size_t) { my_free(ptr); } /* Placement version of the above operators */ static void *operator new(size_t, void* ptr) { return ptr; } static void operator delete(void*, void*) { } #ifdef MYSQL_SERVER bool write_header(size_t event_data_length); bool write_data(const uchar *buf, size_t data_length) { return writer->write_data(buf, data_length); } bool write_data(const char *buf, size_t data_length) { return write_data((uchar*)buf, data_length); } bool write_footer() { return writer->write_footer(); } my_bool need_checksum(); virtual bool write() { return write_header(get_data_size()) || write_data_header() || write_data_body() || write_footer(); } virtual bool write_data_header() { return 0; } virtual bool write_data_body() { return 0; } /* Return start of query time or current time */ inline my_time_t get_time() { THD *tmp_thd; if (when) return when; if (thd) { when= thd->start_time; when_sec_part= thd->start_time_sec_part; return when; } /* thd will only be 0 here at time of log creation */ if ((tmp_thd= current_thd)) { when= tmp_thd->start_time; when_sec_part= tmp_thd->start_time_sec_part; return when; } my_hrtime_t hrtime= my_hrtime(); when= hrtime_to_my_time(hrtime); when_sec_part= hrtime_sec_part(hrtime); return when; } #endif virtual Log_event_type get_type_code() = 0; virtual enum_logged_status logged_status() { return LOGGED_CRITICAL; } virtual bool is_valid() const = 0; virtual my_off_t get_header_len(my_off_t len) { return len; } void set_artificial_event() { flags |= LOG_EVENT_ARTIFICIAL_F; } void set_relay_log_event() { flags |= LOG_EVENT_RELAY_LOG_F; } bool is_artificial_event() const { return flags & LOG_EVENT_ARTIFICIAL_F; } bool is_relay_log_event() const { return flags & LOG_EVENT_RELAY_LOG_F; } inline bool use_trans_cache() const { return (cache_type == Log_event::EVENT_TRANSACTIONAL_CACHE); } inline void set_direct_logging() { cache_type = Log_event::EVENT_NO_CACHE; } inline bool use_direct_logging() { return (cache_type == Log_event::EVENT_NO_CACHE); } Log_event(const uchar *buf, const Format_description_log_event *description_event); virtual ~Log_event() { free_temp_buf();} void register_temp_buf(uchar* buf, bool must_free) { temp_buf= buf; event_owns_temp_buf= must_free; } void free_temp_buf() { if (temp_buf) { if (event_owns_temp_buf) my_free(temp_buf); temp_buf = 0; } } /* Get event length for simple events. For complicated events the length is calculated during write() */ virtual int get_data_size() { return 0;} static Log_event* read_log_event(const uchar *buf, uint event_len, const char **error, const Format_description_log_event *description_event, my_bool crc_check, my_bool print_errors= 1); /** Returns the human readable name of the given event type. */ static const char* get_type_str(Log_event_type type); /** Returns the human readable name of this event's type. */ const char* get_type_str(); #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) /** Apply the event to the database. This function represents the public interface for applying an event. @see do_apply_event */ int apply_event(rpl_group_info *rgi) { int res; THD_STAGE_INFO(thd, stage_apply_event); res= do_apply_event(rgi); THD_STAGE_INFO(thd, stage_after_apply_event); return res; } /** Update the relay log position. This function represents the public interface for "stepping over" the event and will update the relay log information. @see do_update_pos */ int update_pos(rpl_group_info *rgi) { return do_update_pos(rgi); } /** Decide if the event shall be skipped, and the reason for skipping it. @see do_shall_skip */ enum_skip_reason shall_skip(rpl_group_info *rgi) { return do_shall_skip(rgi); } /* Check if an event is non-final part of a stand-alone event group, such as Intvar_log_event (such events should be processed as part of the following event group, not individually). See also is_part_of_group() */ static bool is_part_of_group(enum Log_event_type ev_type) { switch (ev_type) { case GTID_EVENT: case INTVAR_EVENT: case RAND_EVENT: case USER_VAR_EVENT: case TABLE_MAP_EVENT: case ANNOTATE_ROWS_EVENT: return true; case DELETE_ROWS_EVENT: case UPDATE_ROWS_EVENT: case WRITE_ROWS_EVENT: /* ToDo: also check for non-final Rows_log_event (though such events are usually in a BEGIN-COMMIT group). */ default: return false; } } /* Same as above, but works on the object. In addition this is true for all rows event except the last one. */ virtual bool is_part_of_group() { return 0; } static bool is_group_event(enum Log_event_type ev_type) { switch (ev_type) { case START_EVENT_V3: case STOP_EVENT: case ROTATE_EVENT: case SLAVE_EVENT: case FORMAT_DESCRIPTION_EVENT: case INCIDENT_EVENT: case HEARTBEAT_LOG_EVENT: case BINLOG_CHECKPOINT_EVENT: case GTID_LIST_EVENT: case START_ENCRYPTION_EVENT: return false; default: return true; } } protected: /** Helper function to ignore an event w.r.t. the slave skip counter. This function can be used inside do_shall_skip() for functions that cannot end a group. If the slave skip counter is 1 when seeing such an event, the event shall be ignored, the counter left intact, and processing continue with the next event. A typical usage is: @code enum_skip_reason do_shall_skip(rpl_group_info *rgi) { return continue_group(rgi); } @endcode @return Skip reason */ enum_skip_reason continue_group(rpl_group_info *rgi); /** Primitive to apply an event to the database. This is where the change to the database is made. @note The primitive is protected instead of private, since there is a hierarchy of actions to be performed in some cases. @see Format_description_log_event::do_apply_event() @param rli Pointer to relay log info structure @retval 0 Event applied successfully @retval errno Error code if event application failed */ virtual int do_apply_event(rpl_group_info *rgi) { return 0; /* Default implementation does nothing */ } /** Advance relay log coordinates. This function is called to advance the relay log coordinates to just after the event. It is essential that both the relay log coordinate and the group log position is updated correctly, since this function is used also for skipping events. Normally, each implementation of do_update_pos() shall: - Update the event position to refer to the position just after the event. - Update the group log position to refer to the position just after the event if the event is last in a group @param rli Pointer to relay log info structure @retval 0 Coordinates changed successfully @retval errno Error code if advancing failed (usually just 1). Observe that handler errors are returned by the do_apply_event() function, and not by this one. */ virtual int do_update_pos(rpl_group_info *rgi); /** Decide if this event shall be skipped or not and the reason for skipping it. The default implementation decide that the event shall be skipped if either: - the server id of the event is the same as the server id of the server and rli->replicate_same_server_id is true, or - if rli->slave_skip_counter is greater than zero. @see do_apply_event @see do_update_pos @retval Log_event::EVENT_SKIP_NOT The event shall not be skipped and should be applied. @retval Log_event::EVENT_SKIP_IGNORE The event shall be skipped by just ignoring it, i.e., the slave skip counter shall not be changed. This happends if, for example, the originating server id of the event is the same as the server id of the slave. @retval Log_event::EVENT_SKIP_COUNT The event shall be skipped because the slave skip counter was non-zero. The caller shall decrease the counter by one. */ virtual enum_skip_reason do_shall_skip(rpl_group_info *rgi); #endif }; /* One class for each type of event. Two constructors for each class: - one to create the event for logging (when the server acts as a master), called after an update to the database is done, which accepts parameters like the query, the database, the options for LOAD DATA INFILE... - one to create the event from a packet (when the server acts as a slave), called before reproducing the update, which accepts parameters (like a buffer). Used to read from the master, from the relay log, and in mysqlbinlog. This constructor must be format-tolerant. */ /** @class Query_log_event A @c Query_log_event is created for each query that modifies the database, unless the query is logged row-based. @section Query_log_event_binary_format Binary format See @ref Log_event_binary_format "Binary format for log events" for a general discussion and introduction to the binary format of binlog events. The Post-Header has five components:
Post-Header for Query_log_event
Name Format Description
slave_proxy_id 4 byte unsigned integer An integer identifying the client thread that issued the query. The id is unique per server. (Note, however, that two threads on different servers may have the same slave_proxy_id.) This is used when a client thread creates a temporary table local to the client. The slave_proxy_id is used to distinguish temporary tables that belong to different clients.
exec_time 4 byte unsigned integer The time from when the query started to when it was logged in the binlog, in seconds.
db_len 1 byte integer The length of the name of the currently selected database.
error_code 2 byte unsigned integer Error code generated by the master. If the master fails, the slave will fail with the same error code, except for the error codes ER_DB_CREATE_EXISTS == 1007 and ER_DB_DROP_EXISTS == 1008.
status_vars_len 2 byte unsigned integer The length of the status_vars block of the Body, in bytes. See @ref query_log_event_status_vars "below".
The Body has the following components:
Body for Query_log_event
Name Format Description
@anchor query_log_event_status_vars status_vars status_vars_len bytes Zero or more status variables. Each status variable consists of one byte identifying the variable stored, followed by the value of the variable. The possible variables are listed separately in the table @ref Table_query_log_event_status_vars "below". MySQL always writes events in the order defined below; however, it is capable of reading them in any order.
db db_len+1 The currently selected database, as a null-terminated string. (The trailing zero is redundant since the length is already known; it is db_len from Post-Header.)
query variable length string without trailing zero, extending to the end of the event (determined by the length field of the Common-Header) The SQL query.
The following table lists the status variables that may appear in the status_vars field. @anchor Table_query_log_event_status_vars
Status variables for Query_log_event
Status variable 1 byte identifier Format Description
flags2 Q_FLAGS2_CODE == 0 4 byte bitfield The flags in @c thd->options, binary AND-ed with @c OPTIONS_WRITTEN_TO_BIN_LOG. The @c thd->options bitfield contains options for "SELECT". @c OPTIONS_WRITTEN identifies those options that need to be written to the binlog (not all do). These flags correspond to the SQL variables SQL_AUTO_IS_NULL, FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and AUTOCOMMIT, documented in the "SET Syntax" section of the MySQL Manual. This field is always written to the binlog in version >= 5.0, and never written in version < 5.0.
sql_mode Q_SQL_MODE_CODE == 1 8 byte bitfield The @c sql_mode variable. See the section "SQL Modes" in the MySQL manual, and see sql_priv.h for a list of the possible flags. Currently (2007-10-04), the following flags are available:
    MODE_REAL_AS_FLOAT==0x1
    MODE_PIPES_AS_CONCAT==0x2
    MODE_ANSI_QUOTES==0x4
    MODE_IGNORE_SPACE==0x8
    MODE_IGNORE_BAD_TABLE_OPTIONS==0x10
    MODE_ONLY_FULL_GROUP_BY==0x20
    MODE_NO_UNSIGNED_SUBTRACTION==0x40
    MODE_NO_DIR_IN_CREATE==0x80
    MODE_POSTGRESQL==0x100
    MODE_ORACLE==0x200
    MODE_MSSQL==0x400
    MODE_DB2==0x800
    MODE_MAXDB==0x1000
    MODE_NO_KEY_OPTIONS==0x2000
    MODE_NO_TABLE_OPTIONS==0x4000
    MODE_NO_FIELD_OPTIONS==0x8000
    MODE_MYSQL323==0x10000
    MODE_MYSQL323==0x20000
    MODE_MYSQL40==0x40000
    MODE_ANSI==0x80000
    MODE_NO_AUTO_VALUE_ON_ZERO==0x100000
    MODE_NO_BACKSLASH_ESCAPES==0x200000
    MODE_STRICT_TRANS_TABLES==0x400000
    MODE_STRICT_ALL_TABLES==0x800000
    MODE_NO_ZERO_IN_DATE==0x1000000
    MODE_NO_ZERO_DATE==0x2000000
    MODE_INVALID_DATES==0x4000000
    MODE_ERROR_FOR_DIVISION_BY_ZERO==0x8000000
    MODE_TRADITIONAL==0x10000000
    MODE_NO_AUTO_CREATE_USER==0x20000000
    MODE_HIGH_NOT_PRECEDENCE==0x40000000
    MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000
    
All these flags are replicated from the server. However, all flags except @c MODE_NO_DIR_IN_CREATE are honored by the slave; the slave always preserves its old value of @c MODE_NO_DIR_IN_CREATE. For a rationale, see comment in @c Query_log_event::do_apply_event in @c log_event.cc. This field is always written to the binlog.
catalog Q_CATALOG_NZ_CODE == 6 Variable-length string: the length in bytes (1 byte) followed by the characters (at most 255 bytes) Stores the client's current catalog. Every database belongs to a catalog, the same way that every table belongs to a database. Currently, there is only one catalog, "std". This field is written if the length of the catalog is > 0; otherwise it is not written.
auto_increment Q_AUTO_INCREMENT == 3 two 2 byte unsigned integers, totally 2+2=4 bytes The two variables auto_increment_increment and auto_increment_offset, in that order. For more information, see "System variables" in the MySQL manual. This field is written if auto_increment > 1. Otherwise, it is not written.
charset Q_CHARSET_CODE == 4 three 2 byte unsigned integers, totally 2+2+2=6 bytes The three variables character_set_client, collation_connection, and collation_server, in that order. character_set_client is a code identifying the character set and collation used by the client to encode the query. collation_connection identifies the character set and collation that the master converts the query to when it receives it; this is useful when comparing literal strings. collation_server is the default character set and collation used when a new database is created. See also "Connection Character Sets and Collations" in the MySQL 5.1 manual. All three variables are codes identifying a (character set, collation) pair. To see which codes map to which pairs, run the query "SELECT id, character_set_name, collation_name FROM COLLATIONS". Cf. Q_CHARSET_DATABASE_CODE below. This field is always written.
time_zone Q_TIME_ZONE_CODE == 5 Variable-length string: the length in bytes (1 byte) followed by the characters (at most 255 bytes). The time_zone of the master. See also "System Variables" and "MySQL Server Time Zone Support" in the MySQL manual. This field is written if the length of the time zone string is > 0; otherwise, it is not written.
lc_time_names_number Q_LC_TIME_NAMES_CODE == 7 2 byte integer A code identifying a table of month and day names. The mapping from codes to languages is defined in @c sql_locale.cc. This field is written if it is not 0, i.e., if the locale is not en_US.
charset_database_number Q_CHARSET_DATABASE_CODE == 8 2 byte integer The value of the collation_database system variable (in the source code stored in @c thd->variables.collation_database), which holds the code for a (character set, collation) pair as described above (see Q_CHARSET_CODE). collation_database was used in old versions (???WHEN). Its value was loaded when issuing a "use db" query and could be changed by issuing a "SET collation_database=xxx" query. It used to affect the "LOAD DATA INFILE" and "CREATE TABLE" commands. In newer versions, "CREATE TABLE" has been changed to take the character set from the database of the created table, rather than the character set of the current database. This makes a difference when creating a table in another database than the current one. "LOAD DATA INFILE" has not yet changed to do this, but there are plans to eventually do it, and to make collation_database read-only. This field is written if it is not 0.
table_map_for_update Q_TABLE_MAP_FOR_UPDATE_CODE == 9 8 byte integer The value of the table map that is to be updated by the multi-table update query statement. Every bit of this variable represents a table, and is set to 1 if the corresponding table is to be updated by this statement. The value of this variable is set when executing a multi-table update statement and used by slave to apply filter rules without opening all the tables on slave. This is required because some tables may not exist on slave because of the filter rules.
@subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions * Status vars were introduced in version 5.0. To read earlier versions correctly, check the length of the Post-Header. * The status variable Q_CATALOG_CODE == 2 existed in MySQL 5.0.x, where 0<=x<=3. It was identical to Q_CATALOG_CODE, except that the string had a trailing '\0'. The '\0' was removed in 5.0.4 since it was redundant (the string length is stored before the string). The Q_CATALOG_CODE will never be written by a new master, but can still be understood by a new slave. * See Q_CHARSET_DATABASE_CODE in the table above. * When adding new status vars, please don't forget to update the MAX_SIZE_LOG_EVENT_STATUS, and update function code_name */ class Query_log_event: public Log_event { LEX_CSTRING user; LEX_CSTRING host; protected: Log_event::Byte* data_buf; public: const char* query; const char* catalog; const char* db; /* If we already know the length of the query string we pass it with q_len, so we would not have to call strlen() otherwise, set it to 0, in which case, we compute it with strlen() */ uint32 q_len; uint32 db_len; uint16 error_code; my_thread_id thread_id; /* For events created by Query_log_event::do_apply_event (and Load_log_event::do_apply_event()) we need the *original* thread id, to be able to log the event with the original (=master's) thread id (fix for BUG#1686). */ ulong slave_proxy_id; /* Binlog format 3 and 4 start to differ (as far as class members are concerned) from here. */ uint catalog_len; // <= 255 char; 0 means uninited /* We want to be able to store a variable number of N-bit status vars: (generally N=32; but N=64 for SQL_MODE) a user may want to log the number of affected rows (for debugging) while another does not want to lose 4 bytes in this. The storage on disk is the following: status_vars_len is part of the post-header, status_vars are in the variable-length part, after the post-header, before the db & query. status_vars on disk is a sequence of pairs (code, value) where 'code' means 'sql_mode', 'affected' etc. Sometimes 'value' must be a short string, so its first byte is its length. For now the order of status vars is: flags2 - sql_mode - catalog - autoinc - charset We should add the same thing to Load_log_event, but in fact LOAD DATA INFILE is going to be logged with a new type of event (logging of the plain text query), so Load_log_event would be frozen, so no need. The new way of logging LOAD DATA INFILE would use a derived class of Query_log_event, so automatically benefit from the work already done for status variables in Query_log_event. */ uint16 status_vars_len; /* 'flags2' is a second set of flags (on top of those in Log_event), for session variables. These are thd->options which is & against a mask (OPTIONS_WRITTEN_TO_BIN_LOG). flags2_inited helps make a difference between flags2==0 (3.23 or 4.x master, we don't know flags2, so use the slave server's global options) and flags2==0 (5.0 master, we know this has a meaning of flags all down which must influence the query). */ uint32 flags2_inited; bool sql_mode_inited; bool charset_inited; uint32 flags2; sql_mode_t sql_mode; ulong auto_increment_increment, auto_increment_offset; char charset[6]; uint time_zone_len; /* 0 means uninited */ const char *time_zone_str; uint lc_time_names_number; /* 0 means en_US */ uint charset_database_number; /* map for tables that will be updated for a multi-table update query statement, for other query statements, this will be zero. */ ulonglong table_map_for_update; /* Xid for the event, if such exists */ ulonglong xid; /* Holds the original length of a Query_log_event that comes from a master of version < 5.0 (i.e., binlog_version < 4). When the IO thread writes the relay log, it augments the Query_log_event with a Q_MASTER_DATA_WRITTEN_CODE status_var that holds the original event length. This field is initialized to non-zero in the SQL thread when it reads this augmented event. SQL thread does not write Q_MASTER_DATA_WRITTEN_CODE to the slave's server binlog. */ uint32 master_data_written; #ifdef MYSQL_SERVER Query_log_event(THD* thd_arg, const char* query_arg, size_t query_length, bool using_trans, bool direct, bool suppress_use, int error); const char* get_db() override { return db; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print_query_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info); bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif Query_log_event(); Query_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event, Log_event_type event_type); ~Query_log_event() { if (data_buf) my_free(data_buf); } Log_event_type get_type_code() override { return QUERY_EVENT; } static int dummy_event(String *packet, ulong ev_offset, enum enum_binlog_checksum_alg checksum_alg); static int begin_event(String *packet, ulong ev_offset, enum enum_binlog_checksum_alg checksum_alg); #ifdef MYSQL_SERVER bool write() override; virtual bool write_post_header_for_derived() { return FALSE; } #endif bool is_valid() const override { return query != 0; } /* Returns number of bytes additionally written to post header by derived events (so far it is only Execute_load_query event). */ virtual ulong get_post_header_size_for_derived() { return 0; } /* Writes derived event-specific part of post header. */ public: /* !!! Public in this patch to allow old usage */ #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; int do_apply_event(rpl_group_info *rgi) override; int do_apply_event(rpl_group_info *rgi, const char *query_arg, uint32 q_len_arg); static bool peek_is_commit_rollback(const uchar *event_start, size_t event_len, enum enum_binlog_checksum_alg checksum_alg); #endif /* HAVE_REPLICATION */ /* If true, the event always be applied by slave SQL thread or be printed by mysqlbinlog */ bool is_trans_keyword(bool is_xa) { /* Before the patch for bug#50407, The 'SAVEPOINT and ROLLBACK TO' queries input by user was written into log events directly. So the keywords can be written in both upper case and lower case together, strncasecmp is used to check both cases. they also could be binlogged with comments in the front of these keywords. for examples: / * bla bla * / SAVEPOINT a; / * bla bla * / ROLLBACK TO a; but we don't handle these cases and after the patch, both quiries are binlogged in upper case with no comments. */ return is_xa ? !strncasecmp(query, C_STRING_WITH_LEN("XA ")) : (!strncmp(query, "BEGIN", q_len) || !strncmp(query, "COMMIT", q_len) || !strncasecmp(query, "SAVEPOINT", 9) || !strncasecmp(query, "ROLLBACK", 8)); } virtual bool is_begin() { return !strcmp(query, "BEGIN"); } virtual bool is_commit() { return !strcmp(query, "COMMIT"); } virtual bool is_rollback() { return !strcmp(query, "ROLLBACK"); } }; class Query_compressed_log_event:public Query_log_event{ protected: Log_event::Byte* query_buf; // point to the uncompressed query public: Query_compressed_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event, Log_event_type event_type); ~Query_compressed_log_event() { if (query_buf) my_free(query_buf); } Log_event_type get_type_code() override { return QUERY_COMPRESSED_EVENT; } /* the min length of log_bin_compress_min_len is 10, means that Begin/Commit/Rollback would never be compressed! */ bool is_begin() override { return false; } bool is_commit() override { return false; } bool is_rollback() override { return false; } #ifdef MYSQL_SERVER Query_compressed_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans, bool direct, bool suppress_use, int error); bool write() override; #endif }; /***************************************************************************** sql_ex_info struct ****************************************************************************/ struct sql_ex_info { const char* field_term; const char* enclosed; const char* line_term; const char* line_start; const char* escaped; int cached_new_format= -1; uint8 field_term_len= 0, enclosed_len= 0, line_term_len= 0, line_start_len= 0, escaped_len= 0; char opt_flags; char empty_flags= 0; // store in new format even if old is possible void force_new_format() { cached_new_format = 1;} int data_size() { return (new_format() ? field_term_len + enclosed_len + line_term_len + line_start_len + escaped_len + 6 : 7); } bool write_data(Log_event_writer *writer); const uchar *init(const uchar *buf, const uchar* buf_end, bool use_new_format); bool new_format() { return ((cached_new_format != -1) ? cached_new_format : (cached_new_format=(field_term_len > 1 || enclosed_len > 1 || line_term_len > 1 || line_start_len > 1 || escaped_len > 1))); } }; /** @class Load_log_event This log event corresponds to a "LOAD DATA INFILE" SQL query on the following form: @verbatim (1) USE db; (2) LOAD DATA [CONCURRENT] [LOCAL] INFILE 'file_name' (3) [REPLACE | IGNORE] (4) INTO TABLE 'table_name' (5) [FIELDS (6) [TERMINATED BY 'field_term'] (7) [[OPTIONALLY] ENCLOSED BY 'enclosed'] (8) [ESCAPED BY 'escaped'] (9) ] (10) [LINES (11) [TERMINATED BY 'line_term'] (12) [LINES STARTING BY 'line_start'] (13) ] (14) [IGNORE skip_lines LINES] (15) (field_1, field_2, ..., field_n)@endverbatim @section Load_log_event_binary_format Binary Format The Post-Header consists of the following six components.
Post-Header for Load_log_event
Name Format Description
slave_proxy_id 4 byte unsigned integer An integer identifying the client thread that issued the query. The id is unique per server. (Note, however, that two threads on different servers may have the same slave_proxy_id.) This is used when a client thread creates a temporary table local to the client. The slave_proxy_id is used to distinguish temporary tables that belong to different clients.
exec_time 4 byte unsigned integer The time from when the query started to when it was logged in the binlog, in seconds.
skip_lines 4 byte unsigned integer The number on line (14) above, if present, or 0 if line (14) is left out.
table_name_len 1 byte unsigned integer The length of 'table_name' on line (4) above.
db_len 1 byte unsigned integer The length of 'db' on line (1) above.
num_fields 4 byte unsigned integer The number n of fields on line (15) above.
The Body contains the following components.
Body of Load_log_event
Name Format Description
sql_ex variable length Describes the part of the query on lines (3) and (5)–(13) above. More precisely, it stores the five strings (on lines) field_term (6), enclosed (7), escaped (8), line_term (11), and line_start (12); as well as a bitfield indicating the presence of the keywords REPLACE (3), IGNORE (3), and OPTIONALLY (7). The data is stored in one of two formats, called "old" and "new". The type field of Common-Header determines which of these two formats is used: type LOAD_EVENT means that the old format is used, and type NEW_LOAD_EVENT means that the new format is used. When MySQL writes a Load_log_event, it uses the new format if at least one of the five strings is two or more bytes long. Otherwise (i.e., if all strings are 0 or 1 bytes long), the old format is used. The new and old format differ in the way the five strings are stored.
  • In the new format, the strings are stored in the order field_term, enclosed, escaped, line_term, line_start. Each string consists of a length (1 byte), followed by a sequence of characters (0-255 bytes). Finally, a boolean combination of the following flags is stored in 1 byte: REPLACE_FLAG==0x4, IGNORE_FLAG==0x8, and OPT_ENCLOSED_FLAG==0x2. If a flag is set, it indicates the presence of the corresponding keyword in the SQL query.
  • In the old format, we know that each string has length 0 or 1. Therefore, only the first byte of each string is stored. The order of the strings is the same as in the new format. These five bytes are followed by the same 1 byte bitfield as in the new format. Finally, a 1 byte bitfield called empty_flags is stored. The low 5 bits of empty_flags indicate which of the five strings have length 0. For each of the following flags that is set, the corresponding string has length 0; for the flags that are not set, the string has length 1: FIELD_TERM_EMPTY==0x1, ENCLOSED_EMPTY==0x2, LINE_TERM_EMPTY==0x4, LINE_START_EMPTY==0x8, ESCAPED_EMPTY==0x10.
Thus, the size of the new format is 6 bytes + the sum of the sizes of the five strings. The size of the old format is always 7 bytes.
field_lens num_fields 1 byte unsigned integers An array of num_fields integers representing the length of each field in the query. (num_fields is from the Post-Header).
fields num_fields null-terminated strings An array of num_fields null-terminated strings, each representing a field in the query. (The trailing zero is redundant, since the length are stored in the num_fields array.) The total length of all strings equals to the sum of all field_lens, plus num_fields bytes for all the trailing zeros.
table_name null-terminated string of length table_len+1 bytes The 'table_name' from the query, as a null-terminated string. (The trailing zero is actually redundant since the table_len is known from Post-Header.)
db null-terminated string of length db_len+1 bytes The 'db' from the query, as a null-terminated string. (The trailing zero is actually redundant since the db_len is known from Post-Header.)
file_name variable length string without trailing zero, extending to the end of the event (determined by the length field of the Common-Header) The 'file_name' from the query.
@subsection Load_log_event_notes_on_previous_versions Notes on Previous Versions This event type is understood by current versions, but only generated by MySQL 3.23 and earlier. */ class Load_log_event: public Log_event { private: protected: int copy_log_event(const uchar *buf, ulong event_len, int body_offset, const Format_description_log_event* description_event); public: bool print_query(THD *thd, bool need_db, const char *cs, String *buf, my_off_t *fn_start, my_off_t *fn_end, const char *qualify_db); my_thread_id thread_id; ulong slave_proxy_id; uint32 table_name_len; /* No need to have a catalog, as these events can only come from 4.x. TODO: this may become false if Dmitri pushes his new LOAD DATA INFILE in 5.0 only (not in 4.x). */ uint32 db_len; uint32 fname_len; uint32 num_fields; const char* fields; const uchar* field_lens; uint32 field_block_len; const char* table_name; const char* db; const char* fname; uint32 skip_lines; sql_ex_info sql_ex; bool local_fname; /** Indicates that this event corresponds to LOAD DATA CONCURRENT, @note Since Load_log_event event coming from the binary log lacks information whether LOAD DATA on master was concurrent or not, this flag is only set to TRUE for an auxiliary Load_log_event object which is used in mysql_load() to re-construct LOAD DATA statement from function parameters, for logging. */ bool is_concurrent; /* fname doesn't point to memory inside Log_event::temp_buf */ void set_fname_outside_temp_buf(const char *afname, size_t alen) { fname= afname; fname_len= (uint)alen; local_fname= TRUE; } /* fname doesn't point to memory inside Log_event::temp_buf */ int check_fname_outside_temp_buf() { return local_fname; } #ifdef MYSQL_SERVER String field_lens_buf; String fields_buf; Load_log_event(THD* thd, const sql_exchange* ex, const char* db_arg, const char* table_name_arg, List& fields_arg, bool is_concurrent_arg, enum enum_duplicates handle_dup, bool ignore, bool using_trans); void set_fields(const char* db, List &fields_arg, Name_resolution_context *context); const char* get_db() override { return db; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; bool print(FILE* file, PRINT_EVENT_INFO* print_event_info, bool commented); #endif /* Note that for all the events related to LOAD DATA (Load_log_event, Create_file/Append/Exec/Delete, we pass description_event; however as logging of LOAD DATA is going to be changed in 4.1 or 5.0, this is only used for the common_header_len (post_header_len will not be changed). */ Load_log_event(const uchar *buf, uint event_len, const Format_description_log_event* description_event); ~Load_log_event() = default; Log_event_type get_type_code() override { return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT; } #ifdef MYSQL_SERVER bool write_data_header() override; bool write_data_body() override; #endif bool is_valid() const override { return table_name != 0; } int get_data_size() override { return (table_name_len + db_len + 2 + fname_len + LOAD_HEADER_LEN + sql_ex.data_size() + field_block_len + num_fields); } public: /* !!! Public in this patch to allow old usage */ #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override { return do_apply_event(thd->slave_net,rgi,0); } int do_apply_event(NET *net, rpl_group_info *rgi, bool use_rli_only_for_errors); #endif }; /** @class Start_log_event_v3 Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and 4.x). Format_description_log_event derives from Start_log_event_v3; it is the Start_log_event of binlog format 4 (MySQL 5.0), that is, the event that describes the other events' Common-Header/Post-Header lengths. This event is sent by MySQL 5.0 whenever it starts sending a new binlog if the requested position is >4 (otherwise if ==4 the event will be sent naturally). @section Start_log_event_v3_binary_format Binary Format */ class Start_log_event_v3: public Log_event { public: /* If this event is at the start of the first binary log since server startup 'created' should be the timestamp when the event (and the binary log) was created. In the other case (i.e. this event is at the start of a binary log created by FLUSH LOGS or automatic rotation), 'created' should be 0. This "trick" is used by MySQL >=4.0.14 slaves to know whether they must drop stale temporary tables and whether they should abort unfinished transaction. Note that when 'created'!=0, it is always equal to the event's timestamp; indeed Start_log_event is written only in log.cc where the first constructor below is called, in which 'created' is set to 'when'. So in fact 'created' is a useless variable. When it is 0 we can read the actual value from timestamp ('when') and when it is non-zero we can read the same value from timestamp ('when'). Conclusion: - we use timestamp to print when the binlog was created. - we use 'created' only to know if this is a first binlog or not. In 3.23.57 we did not pay attention to this identity, so mysqlbinlog in 3.23.57 does not print 'created the_date' if created was zero. This is now fixed. */ time_t created; uint16 binlog_version; char server_version[ST_SERVER_VER_LEN]; /* We set this to 1 if we don't want to have the created time in the log, which is the case when we rollover to a new log. */ bool dont_set_created; #ifdef MYSQL_SERVER Start_log_event_v3(); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else Start_log_event_v3() = default; bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif Start_log_event_v3(const uchar *buf, uint event_len, const Format_description_log_event* description_event); ~Start_log_event_v3() = default; Log_event_type get_type_code() override { return START_EVENT_V3;} my_off_t get_header_len(my_off_t l __attribute__((unused))) override { return LOG_EVENT_MINIMAL_HEADER_LEN; } #ifdef MYSQL_SERVER bool write() override; #endif bool is_valid() const override { return server_version[0] != 0; } int get_data_size() override { return START_V3_HEADER_LEN; //no variable-sized part } protected: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info*) override { /* Events from ourself should be skipped, but they should not decrease the slave skip counter. */ if (this->server_id == global_system_variables.server_id) return Log_event::EVENT_SKIP_IGNORE; else return Log_event::EVENT_SKIP_NOT; } #endif }; /** @class Start_encryption_log_event Start_encryption_log_event marks the beginning of encrypted data (all events after this event are encrypted). It contains the cryptographic scheme used for the encryption as well as any data required to decrypt (except the actual key). For binlog cryptoscheme 1: key version, and nonce for iv generation. */ class Start_encryption_log_event : public Log_event { public: #ifdef MYSQL_SERVER Start_encryption_log_event(uint crypto_scheme_arg, uint key_version_arg, const uchar* nonce_arg) : crypto_scheme(crypto_scheme_arg), key_version(key_version_arg) { cache_type = EVENT_NO_CACHE; DBUG_ASSERT(crypto_scheme == 1); memcpy(nonce, nonce_arg, BINLOG_NONCE_LENGTH); } bool write_data_body() override { uchar scheme_buf= crypto_scheme; uchar key_version_buf[BINLOG_KEY_VERSION_LENGTH]; int4store(key_version_buf, key_version); return write_data(&scheme_buf, sizeof(scheme_buf)) || write_data(key_version_buf, sizeof(key_version_buf)) || write_data(nonce, BINLOG_NONCE_LENGTH); } #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif Start_encryption_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); bool is_valid() const override { return crypto_scheme == 1; } Log_event_type get_type_code() override { return START_ENCRYPTION_EVENT; } int get_data_size() override { return BINLOG_CRYPTO_SCHEME_LENGTH + BINLOG_KEY_VERSION_LENGTH + BINLOG_NONCE_LENGTH; } uint crypto_scheme; uint key_version; uchar nonce[BINLOG_NONCE_LENGTH]; protected: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info* rgi) override; int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info* rgi) override { return Log_event::EVENT_SKIP_NOT; } #endif }; class Version { protected: uchar m_ver[3]; int cmp(const Version &other) const { return memcmp(m_ver, other.m_ver, 3); } public: Version() { m_ver[0]= m_ver[1]= m_ver[2]= '\0'; } Version(uchar v0, uchar v1, uchar v2) { m_ver[0]= v0; m_ver[1]= v1; m_ver[2]= v2; } Version(const char *version, const char **endptr); const uchar& operator [] (size_t i) const { DBUG_ASSERT(i < 3); return m_ver[i]; } bool operator<(const Version &other) const { return cmp(other) < 0; } bool operator>(const Version &other) const { return cmp(other) > 0; } bool operator<=(const Version &other) const { return cmp(other) <= 0; } bool operator>=(const Version &other) const { return cmp(other) >= 0; } }; /** @class Format_description_log_event For binlog version 4. This event is saved by threads which read it, as they need it for future use (to decode the ordinary events). @section Format_description_log_event_binary_format Binary Format */ class Format_description_log_event: public Start_log_event_v3 { public: /* The size of the fixed header which _all_ events have (for binlogs written by this version, this is equal to LOG_EVENT_HEADER_LEN), except FORMAT_DESCRIPTION_EVENT and ROTATE_EVENT (those have a header of size LOG_EVENT_MINIMAL_HEADER_LEN). */ uint8 common_header_len; uint8 number_of_event_types; /* The list of post-headers' lengths followed by the checksum alg description byte */ uint8 *post_header_len; class master_version_split: public Version { public: enum {KIND_MYSQL, KIND_MARIADB}; int kind; master_version_split() :kind(KIND_MARIADB) { } master_version_split(const char *version); bool version_is_valid() const { /* It is invalid only when all version numbers are 0 */ return !(m_ver[0] == 0 && m_ver[1] == 0 && m_ver[2] == 0); } }; master_version_split server_version_split; const uint8 *event_type_permutation; uint32 options_written_to_bin_log; Format_description_log_event(uint8 binlog_ver, const char* server_ver=0); Format_description_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); ~Format_description_log_event() { my_free(post_header_len); } Log_event_type get_type_code() override { return FORMAT_DESCRIPTION_EVENT;} #ifdef MYSQL_SERVER bool write() override; #endif bool header_is_valid() const { return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN : LOG_EVENT_MINIMAL_HEADER_LEN)) && (post_header_len != NULL)); } bool is_valid() const override { return header_is_valid() && server_version_split.version_is_valid(); } int get_data_size() override { /* The vector of post-header lengths is considered as part of the post-header, because in a given version it never changes (contrary to the query in a Query_log_event). */ return FORMAT_DESCRIPTION_HEADER_LEN; } Binlog_crypt_data crypto_data; bool start_decryption(Start_encryption_log_event* sele); void copy_crypto_data(const Format_description_log_event* o) { crypto_data= o->crypto_data; } void reset_crypto() { crypto_data.scheme= 0; } void calc_server_version_split(); void deduct_options_written_to_bin_log(); static bool is_version_before_checksum(const master_version_split *version_split); protected: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; #endif }; /** @class Intvar_log_event An Intvar_log_event will be created just before a Query_log_event, if the query uses one of the variables LAST_INSERT_ID or INSERT_ID. Each Intvar_log_event holds the value of one of these variables. @section Intvar_log_event_binary_format Binary Format The Post-Header for this event type is empty. The Body has two components:
Body for Intvar_log_event
Name Format Description
type 1 byte enumeration One byte identifying the type of variable stored. Currently, two identifiers are supported: LAST_INSERT_ID_EVENT==1 and INSERT_ID_EVENT==2.
value 8 byte unsigned integer The value of the variable.
*/ class Intvar_log_event: public Log_event { public: ulonglong val; uchar type; #ifdef MYSQL_SERVER Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg, bool using_trans, bool direct) :Log_event(thd_arg,0,using_trans),val(val_arg),type(type_arg) { if (direct) cache_type= Log_event::EVENT_NO_CACHE; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif Intvar_log_event(const uchar *buf, const Format_description_log_event *description_event); ~Intvar_log_event() = default; Log_event_type get_type_code() override { return INTVAR_EVENT;} const char* get_var_type_name(); int get_data_size() override { return 9; /* sizeof(type) + sizeof(val) */;} #ifdef MYSQL_SERVER bool write() override; #ifdef HAVE_REPLICATION bool is_part_of_group() override { return 1; } #endif #endif bool is_valid() const override { return 1; } private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; #endif }; /** @class Rand_log_event Logs random seed used by the next RAND(), and by PASSWORD() in 4.1.0. 4.1.1 does not need it (it's repeatable again) so this event needn't be written in 4.1.1 for PASSWORD() (but the fact that it is written is just a waste, it does not cause bugs). The state of the random number generation consists of 128 bits, which are stored internally as two 64-bit numbers. @section Rand_log_event_binary_format Binary Format The Post-Header for this event type is empty. The Body has two components:
Body for Rand_log_event
Name Format Description
seed1 8 byte unsigned integer 64 bit random seed1.
seed2 8 byte unsigned integer 64 bit random seed2.
*/ class Rand_log_event: public Log_event { public: ulonglong seed1; ulonglong seed2; #ifdef MYSQL_SERVER Rand_log_event(THD* thd_arg, ulonglong seed1_arg, ulonglong seed2_arg, bool using_trans, bool direct) :Log_event(thd_arg,0,using_trans),seed1(seed1_arg),seed2(seed2_arg) { if (direct) cache_type= Log_event::EVENT_NO_CACHE; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif Rand_log_event(const uchar *buf, const Format_description_log_event *description_event); ~Rand_log_event() = default; Log_event_type get_type_code() override { return RAND_EVENT;} int get_data_size() override { return 16; /* sizeof(ulonglong) * 2*/ } #ifdef MYSQL_SERVER bool write() override; #ifdef HAVE_REPLICATION bool is_part_of_group() override { return 1; } #endif #endif bool is_valid() const override { return 1; } private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; #endif }; class Xid_apply_log_event: public Log_event { public: #ifdef MYSQL_SERVER Xid_apply_log_event(THD* thd_arg): Log_event(thd_arg, 0, TRUE) {} #endif Xid_apply_log_event(const uchar *buf, const Format_description_log_event *description_event): Log_event(buf, description_event) {} ~Xid_apply_log_event() {} bool is_valid() const override { return 1; } private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) virtual int do_commit()= 0; int do_apply_event(rpl_group_info *rgi) override; int do_record_gtid(THD *thd, rpl_group_info *rgi, bool in_trans, void **out_hton, bool force_err= false); enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; virtual const char* get_query()= 0; #endif }; /** @class Xid_log_event Logs xid of the transaction-to-be-committed in the 2pc protocol. Has no meaning in replication, slaves ignore it. @section Xid_log_event_binary_format Binary Format */ #ifdef MYSQL_CLIENT typedef ulonglong my_xid; // this line is the same as in handler.h #endif class Xid_log_event: public Xid_apply_log_event { public: my_xid xid; #ifdef MYSQL_SERVER Xid_log_event(THD* thd_arg, my_xid x, bool direct): Xid_apply_log_event(thd_arg), xid(x) { if (direct) cache_type= Log_event::EVENT_NO_CACHE; } #ifdef HAVE_REPLICATION const char* get_query() override { return "COMMIT /* implicit, from Xid_log_event */"; } void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif Xid_log_event(const uchar *buf, const Format_description_log_event *description_event); ~Xid_log_event() = default; Log_event_type get_type_code() override { return XID_EVENT;} int get_data_size() override { return sizeof(xid); } #ifdef MYSQL_SERVER bool write() override; #endif private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_commit() override; #endif }; /** @class XA_prepare_log_event Similar to Xid_log_event except that - it is specific to XA transaction - it carries out the prepare logics rather than the final committing when @c one_phase member is off. The latter option is only for compatibility with the upstream. From the groupping perspective the event finalizes the current "prepare" group that is started with Gtid_log_event similarly to the regular replicated transaction. */ /** Function serializes XID which is characterized by by four last arguments of the function. Serialized XID is presented in valid hex format and is returned to the caller in a buffer pointed by the first argument. The buffer size provived by the caller must be not less than 8 + 2 * XIDDATASIZE + 4 * sizeof(XID::formatID) + 1, see {MYSQL_,}XID definitions. @param buf pointer to a buffer allocated for storing serialized data @param fmt formatID value @param gln gtrid_length value @param bln bqual_length value @param dat data value @return the value of the buffer pointer */ inline char *serialize_xid(char *buf, long fmt, long gln, long bln, const char *dat) { int i; char *c= buf; /* Build a string consisting of the hex format representation of XID as passed through fmt,gln,bln,dat argument: X'hex11hex12...hex1m',X'hex21hex22...hex2n',11 and store it into buf. */ c[0]= 'X'; c[1]= '\''; c+= 2; for (i= 0; i < gln; i++) { c[0]=_dig_vec_lower[((uchar*) dat)[i] >> 4]; c[1]=_dig_vec_lower[((uchar*) dat)[i] & 0x0f]; c+= 2; } c[0]= '\''; c[1]= ','; c[2]= 'X'; c[3]= '\''; c+= 4; for (; i < gln + bln; i++) { c[0]=_dig_vec_lower[((uchar*) dat)[i] >> 4]; c[1]=_dig_vec_lower[((uchar*) dat)[i] & 0x0f]; c+= 2; } c[0]= '\''; sprintf(c+1, ",%lu", fmt); return buf; } /* The size of the string containing serialized Xid representation is computed as a sum of eight as the number of formatting symbols (X'',X'',) plus 2 x XIDDATASIZE (2 due to hex format), plus space for decimal digits of XID::formatID, plus one for 0x0. */ static const uint ser_buf_size= 8 + 2 * MYSQL_XIDDATASIZE + 4 * sizeof(long) + 1; struct event_mysql_xid_t : MYSQL_XID { char buf[ser_buf_size]; char *serialize() { return serialize_xid(buf, formatID, gtrid_length, bqual_length, data); } }; #ifndef MYSQL_CLIENT struct event_xid_t : XID { char buf[ser_buf_size]; char *serialize(char *buf_arg) { return serialize_xid(buf_arg, formatID, gtrid_length, bqual_length, data); } char *serialize() { return serialize(buf); } }; #endif class XA_prepare_log_event: public Xid_apply_log_event { protected: /* Constant contributor to subheader in write() by members of XID struct. */ static const int xid_subheader_no_data= 12; event_mysql_xid_t m_xid; void *xid; bool one_phase; public: #ifdef MYSQL_SERVER XA_prepare_log_event(THD* thd_arg, XID *xid_arg, bool one_phase_arg): Xid_apply_log_event(thd_arg), xid(xid_arg), one_phase(one_phase_arg) { cache_type= Log_event::EVENT_NO_CACHE; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif XA_prepare_log_event(const uchar *buf, const Format_description_log_event *description_event); ~XA_prepare_log_event() {} Log_event_type get_type_code() override { return XA_PREPARE_LOG_EVENT; } bool is_valid() const override { return m_xid.formatID != -1; } int get_data_size() override { return xid_subheader_no_data + m_xid.gtrid_length + m_xid.bqual_length; } #ifdef MYSQL_SERVER bool write() override; #endif private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) char query[sizeof("XA COMMIT ONE PHASE") + 1 + ser_buf_size]; int do_commit() override; const char* get_query() override { sprintf(query, (one_phase ? "XA COMMIT %s ONE PHASE" : "XA PREPARE %s"), m_xid.serialize()); return query; } #endif }; /** @class User_var_log_event Every time a query uses the value of a user variable, a User_var_log_event is written before the Query_log_event, to set the user variable. @section User_var_log_event_binary_format Binary Format */ class User_var_log_event: public Log_event, public Log_event_data_type { public: const char *name; size_t name_len; const char *val; size_t val_len; bool is_null; #ifdef MYSQL_SERVER bool deferred; query_id_t query_id; User_var_log_event(THD* thd_arg, const char *name_arg, size_t name_len_arg, const char *val_arg, size_t val_len_arg, const Log_event_data_type &data_type, bool using_trans, bool direct) :Log_event(thd_arg, 0, using_trans), Log_event_data_type(data_type), name(name_arg), name_len(name_len_arg), val(val_arg), val_len(val_len_arg), deferred(false) { is_null= !val; if (direct) cache_type= Log_event::EVENT_NO_CACHE; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif User_var_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); ~User_var_log_event() = default; Log_event_type get_type_code() override { return USER_VAR_EVENT;} #ifdef MYSQL_SERVER bool write() override; /* Getter and setter for deferred User-event. Returns true if the event is not applied directly and which case the applier adjusts execution path. */ bool is_deferred() { return deferred; } /* In case of the deferred applying the variable instance is flagged and the parsing time query id is stored to be used at applying time. */ void set_deferred(query_id_t qid) { deferred= true; query_id= qid; } #ifdef HAVE_REPLICATION bool is_part_of_group() override { return 1; } #endif #endif bool is_valid() const override { return name != 0; } private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; #endif }; /** @class Stop_log_event @section Stop_log_event_binary_format Binary Format The Post-Header and Body for this event type are empty; it only has the Common-Header. */ class Stop_log_event: public Log_event { public: #ifdef MYSQL_SERVER Stop_log_event() :Log_event() {} #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif Stop_log_event(const uchar *buf, const Format_description_log_event *description_event): Log_event(buf, description_event) {} ~Stop_log_event() = default; Log_event_type get_type_code() override { return STOP_EVENT;} bool is_valid() const override { return 1; } private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override { /* Events from ourself should be skipped, but they should not decrease the slave skip counter. */ if (this->server_id == global_system_variables.server_id) return Log_event::EVENT_SKIP_IGNORE; else return Log_event::EVENT_SKIP_NOT; } #endif }; /** @class Rotate_log_event This will be deprecated when we move to using sequence ids. @section Rotate_log_event_binary_format Binary Format The Post-Header has one component:
Post-Header for Rotate_log_event
Name Format Description
position 8 byte integer The position within the binlog to rotate to.
The Body has one component:
Body for Rotate_log_event
Name Format Description
new_log variable length string without trailing zero, extending to the end of the event (determined by the length field of the Common-Header) Name of the binlog to rotate to.
*/ class Rotate_log_event: public Log_event { public: enum { DUP_NAME= 2, // if constructor should dup the string argument RELAY_LOG=4 // rotate event for relay log }; const char *new_log_ident; ulonglong pos; uint ident_len; uint flags; #ifdef MYSQL_SERVER Rotate_log_event(const char* new_log_ident_arg, uint ident_len_arg, ulonglong pos_arg, uint flags); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif Rotate_log_event(const uchar *buf, uint event_len, const Format_description_log_event* description_event); ~Rotate_log_event() { if (flags & DUP_NAME) my_free((void*) new_log_ident); } Log_event_type get_type_code() override { return ROTATE_EVENT;} my_off_t get_header_len(my_off_t l __attribute__((unused))) override { return LOG_EVENT_MINIMAL_HEADER_LEN; } int get_data_size() override { return ident_len + ROTATE_HEADER_LEN;} bool is_valid() const override { return new_log_ident != 0; } #ifdef MYSQL_SERVER bool write() override; #endif private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; #endif }; class Binlog_checkpoint_log_event: public Log_event { public: char *binlog_file_name; uint binlog_file_len; #ifdef MYSQL_SERVER Binlog_checkpoint_log_event(const char *binlog_file_name_arg, uint binlog_file_len_arg); #ifdef HAVE_REPLICATION void pack_info(Protocol *protocol) override; #endif #else bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif Binlog_checkpoint_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); ~Binlog_checkpoint_log_event() { my_free(binlog_file_name); } Log_event_type get_type_code() override { return BINLOG_CHECKPOINT_EVENT;} int get_data_size() override { return binlog_file_len + BINLOG_CHECKPOINT_HEADER_LEN;} bool is_valid() const override { return binlog_file_name != 0; } #ifdef MYSQL_SERVER bool write() override; #ifdef HAVE_REPLICATION enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; #endif #endif }; /** @class Gtid_log_event This event is logged as part of every event group to give the global transaction id (GTID) of that group. It replaces the BEGIN query event used in earlier versions to begin most event groups, but is also used for events that used to be stand-alone. @section Gtid_log_event_binary_format Binary Format The binary format for Gtid_log_event has 6 extra reserved bytes to make the length a total of 19 byte (+ 19 bytes of header in common with all events). This is just the minimal size for a BEGIN query event, which makes it easy to replace this event with such BEGIN event to remain compatible with old slave servers.
Post-Header
Name Format Description
seq_no 8 byte unsigned integer increasing id within one server_id. Starts at 1, holes in the sequence may occur
domain_id 4 byte unsigned integer Replication domain id, identifying independent replication streams>
flags 1 byte bitfield Bit 0 set indicates stand-alone event (no terminating COMMIT) Bit 1 set indicates group commit, and that commit id exists Bit 2 set indicates a transactional event group (can be safely rolled back). Bit 3 set indicates that user allowed optimistic parallel apply (the @@SESSION.replicate_allow_parallel value was true at commit). Bit 4 set indicates that this transaction encountered a row (or other) lock wait during execution.
Reserved (no group commit) / commit id (group commit) (see flags bit 1) 6 bytes / 8 bytes Reserved bytes, set to 0. Maybe be used for future expansion (no group commit). OR commit id, same for all GTIDs in the same group commit (see flags bit 1).
The Body of Gtid_log_event is empty. The total event size is 19 bytes + the normal 19 bytes common-header. */ class Gtid_log_event: public Log_event { public: uint64 seq_no; uint64 commit_id; uint32 domain_id; #ifdef MYSQL_SERVER event_xid_t xid; #else event_mysql_xid_t xid; #endif uchar flags2; uint flags_extra; // more flags area placed after the regular flags2's one /* Number of engine participants in transaction minus 1. When zero the event does not contain that information. */ uint8 extra_engines; /* Flags2. */ /* FL_STANDALONE is set when there is no terminating COMMIT event. */ static const uchar FL_STANDALONE= 1; /* FL_GROUP_COMMIT_ID is set when event group is part of a group commit on the master. Groups with same commit_id are part of the same group commit. */ static const uchar FL_GROUP_COMMIT_ID= 2; /* FL_TRANSACTIONAL is set for an event group that can be safely rolled back (no MyISAM, eg.). */ static const uchar FL_TRANSACTIONAL= 4; /* FL_ALLOW_PARALLEL reflects the (negation of the) value of @@SESSION.skip_parallel_replication at the time of commit. */ static const uchar FL_ALLOW_PARALLEL= 8; /* FL_WAITED is set if a row lock wait (or other wait) is detected during the execution of the transaction. */ static const uchar FL_WAITED= 16; /* FL_DDL is set for event group containing DDL. */ static const uchar FL_DDL= 32; /* FL_PREPARED_XA is set for XA transaction. */ static const uchar FL_PREPARED_XA= 64; /* FL_"COMMITTED or ROLLED-BACK"_XA is set for XA transaction. */ static const uchar FL_COMPLETED_XA= 128; /* Flags_extra. */ /* FL_EXTRA_MULTI_ENGINE is set for event group comprising a transaction involving multiple storage engines. No flag and extra data are added to the event when the transaction involves only one engine. */ static const uchar FL_EXTRA_MULTI_ENGINE= 1; #ifdef MYSQL_SERVER Gtid_log_event(THD *thd_arg, uint64 seq_no, uint32 domain_id, bool standalone, uint16 flags, bool is_transactional, uint64 commit_id, bool has_xid= false, bool is_ro_1pc= false); #ifdef HAVE_REPLICATION void pack_info(Protocol *protocol) override; int do_apply_event(rpl_group_info *rgi) override; int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; #endif #else bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif Gtid_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); ~Gtid_log_event() = default; Log_event_type get_type_code() override { return GTID_EVENT; } enum_logged_status logged_status() override { return LOGGED_NO_DATA; } int get_data_size() override { return GTID_HEADER_LEN + ((flags2 & FL_GROUP_COMMIT_ID) ? 2 : 0); } bool is_valid() const override { /* seq_no is set to 0 if the structure of a serialized GTID event does not align with that as indicated by flags and extra_flags. */ return seq_no != 0; } #ifdef MYSQL_SERVER bool write() override; static int make_compatible_event(String *packet, bool *need_dummy_event, ulong ev_offset, enum enum_binlog_checksum_alg checksum_alg); static bool peek(const uchar *event_start, size_t event_len, enum enum_binlog_checksum_alg checksum_alg, uint32 *domain_id, uint32 *server_id, uint64 *seq_no, uchar *flags2, const Format_description_log_event *fdev); #endif }; /** @class Gtid_list_log_event This event is logged at the start of every binlog file to record the current replication state: the last global transaction id (GTID) applied on the server within each replication domain. It consists of a list of GTIDs, one for each replication domain ever seen on the server. @section Gtid_list_log_event_binary_format Binary Format
Post-Header
Name Format Description
count 4 byte unsigned integer The lower 28 bits are the number of GTIDs. The upper 4 bits are flags bits.
Body
Name Format Description
domain_id 4 byte unsigned integer Replication domain id of one GTID
server_id 4 byte unsigned integer Server id of one GTID
seq_no 8 byte unsigned integer sequence number of one GTID
The three elements in the body repeat COUNT times to form the GTID list. At the time of writing, only two flag bit are in use. Bit 28 of `count' is used for flag FLAG_UNTIL_REACHED, which is sent in a Gtid_list event from the master to the slave to indicate that the START SLAVE UNTIL master_gtid_pos=xxx condition has been reached. (This flag is only sent in "fake" events generated on the fly, it is not written into the binlog). */ class Gtid_list_log_event: public Log_event { public: uint32 count; uint32 gl_flags; struct rpl_gtid *list; uint64 *sub_id_list; static const uint element_size= 4+4+8; /* Upper bits stored in 'count'. See comment above */ enum gtid_flags { FLAG_UNTIL_REACHED= (1<<28), FLAG_IGN_GTIDS= (1<<29), }; #ifdef MYSQL_SERVER Gtid_list_log_event(rpl_binlog_state *gtid_set, uint32 gl_flags); Gtid_list_log_event(slave_connection_state *gtid_set, uint32 gl_flags); #ifdef HAVE_REPLICATION void pack_info(Protocol *protocol) override; #endif #else bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif Gtid_list_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); ~Gtid_list_log_event() { my_free(list); my_free(sub_id_list); } Log_event_type get_type_code() override { return GTID_LIST_EVENT; } int get_data_size() override { /* Replacing with dummy event, needed for older slaves, requires a minimum of 6 bytes in the body. */ return (count==0 ? GTID_LIST_HEADER_LEN+2 : GTID_LIST_HEADER_LEN+count*element_size); } bool is_valid() const override { return list != NULL; } #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) bool to_packet(String *packet); bool write() override; int do_apply_event(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; #endif static bool peek(const char *event_start, size_t event_len, enum enum_binlog_checksum_alg checksum_alg, rpl_gtid **out_gtid_list, uint32 *out_list_len, const Format_description_log_event *fdev); }; /* the classes below are for the new LOAD DATA INFILE logging */ /** @class Create_file_log_event @section Create_file_log_event_binary_format Binary Format */ class Create_file_log_event: public Load_log_event { protected: /* Pretend we are Load event, so we can write out just our Load part - used on the slave when writing event out to SQL_LOAD-*.info file */ bool fake_base; public: uchar *block; const uchar *event_buf; uint block_len; uint file_id; bool inited_from_old; #ifdef MYSQL_SERVER Create_file_log_event(THD* thd, sql_exchange* ex, const char* db_arg, const char* table_name_arg, List& fields_arg, bool is_concurrent_arg, enum enum_duplicates handle_dup, bool ignore, uchar* block_arg, uint block_len_arg, bool using_trans); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; bool print(FILE* file, PRINT_EVENT_INFO* print_event_info, bool enable_local); #endif Create_file_log_event(const uchar *buf, uint event_len, const Format_description_log_event* description_event); ~Create_file_log_event() { my_free((void*) event_buf); } Log_event_type get_type_code() override { return fake_base ? Load_log_event::get_type_code() : CREATE_FILE_EVENT; } int get_data_size() override { return (fake_base ? Load_log_event::get_data_size() : Load_log_event::get_data_size() + 4 + 1 + block_len); } bool is_valid() const override { return inited_from_old || block != 0; } #ifdef MYSQL_SERVER bool write_data_header() override; bool write_data_body() override; /* Cut out Create_file extensions and write it as Load event - used on the slave */ bool write_base(); #endif private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; #endif }; /** @class Append_block_log_event @section Append_block_log_event_binary_format Binary Format */ class Append_block_log_event: public Log_event { public: uchar* block; uint block_len; uint file_id; /* 'db' is filled when the event is created in mysql_load() (the event needs to have a 'db' member to be well filtered by binlog-*-db rules). 'db' is not written to the binlog (it's not used by Append_block_log_event::write()), so it can't be read in the Append_block_log_event(const uchar *buf, int event_len) constructor. In other words, 'db' is used only for filtering by binlog-*-db rules. Create_file_log_event is different: it's 'db' (which is inherited from Load_log_event) is written to the binlog and can be re-read. */ const char* db; #ifdef MYSQL_SERVER Append_block_log_event(THD* thd, const char* db_arg, uchar* block_arg, uint block_len_arg, bool using_trans); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; virtual int get_create_or_append() const; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif Append_block_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); ~Append_block_log_event() = default; Log_event_type get_type_code() override { return APPEND_BLOCK_EVENT;} int get_data_size() override { return block_len + APPEND_BLOCK_HEADER_LEN ;} bool is_valid() const override { return block != 0; } #ifdef MYSQL_SERVER bool write() override; const char* get_db() override { return db; } #endif private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; #endif }; /** @class Delete_file_log_event @section Delete_file_log_event_binary_format Binary Format */ class Delete_file_log_event: public Log_event { public: uint file_id; const char* db; /* see comment in Append_block_log_event */ #ifdef MYSQL_SERVER Delete_file_log_event(THD* thd, const char* db_arg, bool using_trans); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; bool print(FILE* file, PRINT_EVENT_INFO* print_event_info, bool enable_local); #endif Delete_file_log_event(const uchar *buf, uint event_len, const Format_description_log_event* description_event); ~Delete_file_log_event() = default; Log_event_type get_type_code() override { return DELETE_FILE_EVENT;} int get_data_size() override { return DELETE_FILE_HEADER_LEN ;} bool is_valid() const override { return file_id != 0; } #ifdef MYSQL_SERVER bool write() override; const char* get_db() override { return db; } #endif private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; #endif }; /** @class Execute_load_log_event @section Delete_file_log_event_binary_format Binary Format */ class Execute_load_log_event: public Log_event { public: uint file_id; const char* db; /* see comment in Append_block_log_event */ #ifdef MYSQL_SERVER Execute_load_log_event(THD* thd, const char* db_arg, bool using_trans); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; #endif Execute_load_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); ~Execute_load_log_event() = default; Log_event_type get_type_code() override { return EXEC_LOAD_EVENT;} int get_data_size() override { return EXEC_LOAD_HEADER_LEN ;} bool is_valid() const override { return file_id != 0; } #ifdef MYSQL_SERVER bool write() override; const char* get_db() override { return db; } #endif private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; #endif }; /** @class Begin_load_query_log_event Event for the first block of file to be loaded, its only difference from Append_block event is that this event creates or truncates existing file before writing data. @section Begin_load_query_log_event_binary_format Binary Format */ class Begin_load_query_log_event: public Append_block_log_event { public: #ifdef MYSQL_SERVER Begin_load_query_log_event(THD* thd_arg, const char *db_arg, uchar* block_arg, uint block_len_arg, bool using_trans); #ifdef HAVE_REPLICATION Begin_load_query_log_event(THD* thd); int get_create_or_append() const override; #endif /* HAVE_REPLICATION */ #endif Begin_load_query_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); ~Begin_load_query_log_event() = default; Log_event_type get_type_code() override { return BEGIN_LOAD_QUERY_EVENT; } private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; #endif }; /* Elements of this enum describe how LOAD DATA handles duplicates. */ enum enum_load_dup_handling { LOAD_DUP_ERROR= 0, LOAD_DUP_IGNORE, LOAD_DUP_REPLACE }; /** @class Execute_load_query_log_event Event responsible for LOAD DATA execution, it similar to Query_log_event but before executing the query it substitutes original filename in LOAD DATA query with name of temporary file. @section Execute_load_query_log_event_binary_format Binary Format */ class Execute_load_query_log_event: public Query_log_event { public: uint file_id; // file_id of temporary file uint fn_pos_start; // pointer to the part of the query that should // be substituted uint fn_pos_end; // pointer to the end of this part of query /* We have to store type of duplicate handling explicitly, because for LOAD DATA it also depends on LOCAL option. And this part of query will be rewritten during replication so this information may be lost... */ enum_load_dup_handling dup_handling; #ifdef MYSQL_SERVER Execute_load_query_log_event(THD* thd, const char* query_arg, ulong query_length, uint fn_pos_start_arg, uint fn_pos_end_arg, enum_load_dup_handling dup_handling_arg, bool using_trans, bool direct, bool suppress_use, int errcode); #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol) override; #endif /* HAVE_REPLICATION */ #else bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; /* Prints the query as LOAD DATA LOCAL and with rewritten filename */ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info, const char *local_fname); #endif Execute_load_query_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); ~Execute_load_query_log_event() = default; Log_event_type get_type_code() override { return EXECUTE_LOAD_QUERY_EVENT; } bool is_valid() const override { return Query_log_event::is_valid() && file_id != 0; } ulong get_post_header_size_for_derived() override; #ifdef MYSQL_SERVER bool write_post_header_for_derived() override; #endif private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; #endif }; #ifdef MYSQL_CLIENT /** @class Unknown_log_event @section Unknown_log_event_binary_format Binary Format */ class Unknown_log_event: public Log_event { public: enum { UNKNOWN, ENCRYPTED } what; /* Even if this is an unknown event, we still pass description_event to Log_event's ctor, this way we can extract maximum information from the event's header (the unique ID for example). */ Unknown_log_event(const uchar *buf, const Format_description_log_event *description_event): Log_event(buf, description_event), what(UNKNOWN) {} /* constructor for hopelessly corrupted events */ Unknown_log_event(): Log_event(), what(ENCRYPTED) {} ~Unknown_log_event() = default; bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) override; Log_event_type get_type_code() override { return UNKNOWN_EVENT;} bool is_valid() const override { return 1; } }; #endif char *str_to_hex(char *to, const char *from, size_t len); /** @class Annotate_rows_log_event In row-based mode, if binlog_annotate_row_events = ON, each group of Table_map_log_events is preceded by an Annotate_rows_log_event which contains the query which caused the subsequent rows operations. The Annotate_rows_log_event has no post-header and its body contains the corresponding query (without trailing zero). Note. The query length is to be calculated as a difference between the whole event length and the common header length. */ class Annotate_rows_log_event: public Log_event { public: #ifndef MYSQL_CLIENT Annotate_rows_log_event(THD*, bool using_trans, bool direct); #endif Annotate_rows_log_event(const uchar *buf, uint event_len, const Format_description_log_event*); ~Annotate_rows_log_event(); int get_data_size() override; Log_event_type get_type_code() override; enum_logged_status logged_status() override { return LOGGED_NO_DATA; } bool is_valid() const override; #ifndef MYSQL_CLIENT #ifdef HAVE_REPLICATION bool is_part_of_group() override { return 1; } #endif bool write_data_header() override; bool write_data_body() override; #endif #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) void pack_info(Protocol*) override; #endif #ifdef MYSQL_CLIENT bool print(FILE*, PRINT_EVENT_INFO*) override; #endif #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) private: int do_apply_event(rpl_group_info *rgi) override; int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info*) override; #endif private: char *m_query_txt; uint m_query_len; char *m_save_thd_query_txt; uint m_save_thd_query_len; bool m_saved_thd_query; bool m_used_query_txt; }; /** @class Table_map_log_event In row-based mode, every row operation event is preceded by a Table_map_log_event which maps a table definition to a number. The table definition consists of database name, table name, and column definitions. @section Table_map_log_event_binary_format Binary Format The Post-Header has the following components:
Post-Header for Table_map_log_event
Name Format Description
table_id 6 bytes unsigned integer The number that identifies the table.
flags 2 byte bitfield Reserved for future use; currently always 0.
The Body has the following components:
Body for Table_map_log_event
Name Format Description
database_name one byte string length, followed by null-terminated string The name of the database in which the table resides. The name is represented as a one byte unsigned integer representing the number of bytes in the name, followed by length bytes containing the database name, followed by a terminating 0 byte. (Note the redundancy in the representation of the length.)
table_name one byte string length, followed by null-terminated string The name of the table, encoded the same way as the database name above.
column_count @ref packed_integer "Packed Integer" The number of columns in the table, represented as a packed variable-length integer.
column_type List of column_count 1 byte enumeration values The type of each column in the table, listed from left to right. Each byte is mapped to a column type according to the enumeration type enum_field_types defined in mysql_com.h. The mapping of types to numbers is listed in the table @ref Table_table_map_log_event_column_types "below" (along with description of the associated metadata field).
metadata_length @ref packed_integer "Packed Integer" The length of the following metadata block
metadata list of metadata for each column For each column from left to right, a chunk of data who's length and semantics depends on the type of the column. The length and semantics for the metadata for each column are listed in the table @ref Table_table_map_log_event_column_types "below".
null_bits column_count bits, rounded up to nearest byte For each column, a bit indicating whether data in the column can be NULL or not. The number of bytes needed for this is int((column_count+7)/8). The flag for the first column from the left is in the least-significant bit of the first byte, the second is in the second least significant bit of the first byte, the ninth is in the least significant bit of the second byte, and so on.
optional metadata fields optional metadata fields are stored in Type, Length, Value(TLV) format. Type takes 1 byte. Length is a packed integer value. Values takes Length bytes. There are some optional metadata defined. They are listed in the table @ref Table_table_map_event_optional_metadata. Optional metadata fields follow null_bits. Whether binlogging an optional metadata is decided by the server. The order is not defined, so they can be binlogged in any order.
The table below lists all column types, along with the numerical identifier for it and the size and interpretation of meta-data used to describe the type. @anchor Table_table_map_log_event_column_types
Table_map_log_event column types: numerical identifier and metadata
Name Identifier Size of metadata in bytes Description of metadata
MYSQL_TYPE_DECIMAL0 0 No column metadata.
MYSQL_TYPE_TINY1 0 No column metadata.
MYSQL_TYPE_SHORT2 0 No column metadata.
MYSQL_TYPE_LONG3 0 No column metadata.
MYSQL_TYPE_FLOAT4 1 byte 1 byte unsigned integer, representing the "pack_length", which is equal to sizeof(float) on the server from which the event originates.
MYSQL_TYPE_DOUBLE5 1 byte 1 byte unsigned integer, representing the "pack_length", which is equal to sizeof(double) on the server from which the event originates.
MYSQL_TYPE_NULL6 0 No column metadata.
MYSQL_TYPE_TIMESTAMP7 0 No column metadata.
MYSQL_TYPE_LONGLONG8 0 No column metadata.
MYSQL_TYPE_INT249 0 No column metadata.
MYSQL_TYPE_DATE10 0 No column metadata.
MYSQL_TYPE_TIME11 0 No column metadata.
MYSQL_TYPE_DATETIME12 0 No column metadata.
MYSQL_TYPE_YEAR13 0 No column metadata.
MYSQL_TYPE_NEWDATE14 This enumeration value is only used internally and cannot exist in a binlog.
MYSQL_TYPE_VARCHAR15 2 bytes 2 byte unsigned integer representing the maximum length of the string.
MYSQL_TYPE_BIT16 2 bytes A 1 byte unsigned int representing the length in bits of the bitfield (0 to 64), followed by a 1 byte unsigned int representing the number of bytes occupied by the bitfield. The number of bytes is either int((length+7)/8) or int(length/8).
MYSQL_TYPE_NEWDECIMAL246 2 bytes A 1 byte unsigned int representing the precision, followed by a 1 byte unsigned int representing the number of decimals.
MYSQL_TYPE_ENUM247 This enumeration value is only used internally and cannot exist in a binlog.
MYSQL_TYPE_SET248 This enumeration value is only used internally and cannot exist in a binlog.
MYSQL_TYPE_TINY_BLOB249 This enumeration value is only used internally and cannot exist in a binlog.
MYSQL_TYPE_MEDIUM_BLOB250 This enumeration value is only used internally and cannot exist in a binlog.
MYSQL_TYPE_LONG_BLOB251 This enumeration value is only used internally and cannot exist in a binlog.
MYSQL_TYPE_BLOB252 1 byte The pack length, i.e., the number of bytes needed to represent the length of the blob: 1, 2, 3, or 4.
MYSQL_TYPE_VAR_STRING253 2 bytes This is used to store both strings and enumeration values. The first byte is a enumeration value storing the real type, which may be either MYSQL_TYPE_VAR_STRING or MYSQL_TYPE_ENUM. The second byte is a 1 byte unsigned integer representing the field size, i.e., the number of bytes needed to store the length of the string.
MYSQL_TYPE_STRING254 2 bytes The first byte is always MYSQL_TYPE_VAR_STRING (i.e., 253). The second byte is the field size, i.e., the number of bytes in the representation of size of the string: 3 or 4.
MYSQL_TYPE_GEOMETRY255 1 byte The pack length, i.e., the number of bytes needed to represent the length of the geometry: 1, 2, 3, or 4.
The table below lists all optional metadata types, along with the numerical identifier for it and the size and interpretation of meta-data used to describe the type. @anchor Table_table_map_event_optional_metadata
Table_map_event optional metadata types: numerical identifier and metadata. Optional metadata fields are stored in TLV fields. Format of values are described in this table.
Type Description Format
SIGNEDNESS signedness of numeric colums. This is included for all values of binlog_row_metadata. For each numeric column, a bit indicates whether the numeric colunm has unsigned flag. 1 means it is unsigned. The number of bytes needed for this is int((column_count + 7) / 8). The order is the same as the order of column_type field.
DEFAULT_CHARSET Charsets of character columns. It has a default charset for the case that most of character columns have same charset and the most used charset is binlogged as default charset.Collation numbers are binlogged for identifying charsets. They are stored in packed length format. Either DEFAULT_CHARSET or COLUMN_CHARSET is included for all values of binlog_row_metadata. Default charset's collation is logged first. The charsets which are not same to default charset are logged following default charset. They are logged as column index and charset collation number pair sequence. The column index is counted only in all character columns. The order is same to the order of column_type field.
COLUMN_CHARSET Charsets of character columns. For the case that most of columns have different charsets, this field is logged. It is never logged with DEFAULT_CHARSET together. Either DEFAULT_CHARSET or COLUMN_CHARSET is included for all values of binlog_row_metadata. It is a collation number sequence for all character columns.
COLUMN_NAME Names of columns. This is only included if binlog_row_metadata=FULL. A sequence of column names. For each column name, 1 byte for the string length in bytes is followed by a string without null terminator.
SET_STR_VALUE The string values of SET columns. This is only included if binlog_row_metadata=FULL. For each SET column, a pack_length representing the value count is followed by a sequence of length and string pairs. length is the byte count in pack_length format. The string has no null terminator.
ENUM_STR_VALUE The string values is ENUM columns. This is only included if binlog_row_metadata=FULL. The format is the same as SET_STR_VALUE.
GEOMETRY_TYPE The real type of geometry columns. This is only included if binlog_row_metadata=FULL. A sequence of real type of geometry columns are stored in pack_length format.
SIMPLE_PRIMARY_KEY The primary key without any prefix. This is only included if binlog_row_metadata=FULL and there is a primary key where every key part covers an entire column. A sequence of column indexes. The indexes are stored in pack_length format.
PRIMARY_KEY_WITH_PREFIX The primary key with some prefix. It doesn't appear together with SIMPLE_PRIMARY_KEY. This is only included if binlog_row_metadata=FULL and there is a primary key where some key part covers a prefix of the column. A sequence of column index and prefix length pairs. Both column index and prefix length are in pack_length format. Prefix length 0 means that the whole column value is used.
ENUM_AND_SET_DEFAULT_CHARSET Charsets of ENUM and SET columns. It has the same layout as DEFAULT_CHARSET. If there are SET or ENUM columns and binlog_row_metadata=FULL, exactly one of ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET appears (the encoder chooses the representation that uses the least amount of space). Otherwise, none of them appears. The same format as for DEFAULT_CHARSET, except it counts ENUM and SET columns rather than character columns.
ENUM_AND_SET_COLUMN_CHARSET Charsets of ENUM and SET columns. It has the same layout as COLUMN_CHARSET. If there are SET or ENUM columns and binlog_row_metadata=FULL, exactly one of ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET appears (the encoder chooses the representation that uses the least amount of space). Otherwise, none of them appears. The same format as for COLUMN_CHARSET, except it counts ENUM and SET columns rather than character columns.
*/ class Table_map_log_event : public Log_event { public: /* Constants */ enum { TYPE_CODE = TABLE_MAP_EVENT }; /** Enumeration of the errors that can be returned. */ enum enum_error { ERR_OPEN_FAILURE = -1, /**< Failure to open table */ ERR_OK = 0, /**< No error */ ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */ ERR_OUT_OF_MEM = 2, /**< Out of memory */ ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */ ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */ }; enum enum_flag { /* Nothing here right now, but the flags support is there in preparation for changes that are coming. Need to add a constant to make it compile under HP-UX: aCC does not like empty enumerations. */ ENUM_FLAG_COUNT }; typedef uint16 flag_set; /** DEFAULT_CHARSET and COLUMN_CHARSET don't appear together, and ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET don't appear together. They are just alternative ways to pack character set information. When binlogging, it logs character sets in the way that occupies least storage. SIMPLE_PRIMARY_KEY and PRIMARY_KEY_WITH_PREFIX don't appear together. SIMPLE_PRIMARY_KEY is for the primary keys which only use whole values of pk columns. PRIMARY_KEY_WITH_PREFIX is for the primary keys which just use part value of pk columns. */ enum Optional_metadata_field_type { SIGNEDNESS = 1, // UNSIGNED flag of numeric columns DEFAULT_CHARSET, /* Character set of string columns, optimized to minimize space when many columns have the same charset. */ COLUMN_CHARSET, /* Character set of string columns, optimized to minimize space when columns have many different charsets. */ COLUMN_NAME, SET_STR_VALUE, // String value of SET columns ENUM_STR_VALUE, // String value of ENUM columns GEOMETRY_TYPE, // Real type of geometry columns SIMPLE_PRIMARY_KEY, // Primary key without prefix PRIMARY_KEY_WITH_PREFIX, // Primary key with prefix ENUM_AND_SET_DEFAULT_CHARSET, /* Character set of enum and set columns, optimized to minimize space when many columns have the same charset. */ ENUM_AND_SET_COLUMN_CHARSET, /* Character set of enum and set columns, optimized to minimize space when many columns have the same charset. */ }; /** Metadata_fields organizes m_optional_metadata into a structured format which is easy to access. */ // Values for binlog_row_metadata sysvar enum enum_binlog_row_metadata { BINLOG_ROW_METADATA_NO_LOG= 0, BINLOG_ROW_METADATA_MINIMAL= 1, BINLOG_ROW_METADATA_FULL= 2 }; struct Optional_metadata_fields { typedef std::pair uint_pair; typedef std::vector str_vector; struct Default_charset { Default_charset() : default_charset(0) {} bool empty() const { return default_charset == 0; } // Default charset for the columns which are not in charset_pairs. unsigned int default_charset; /* The uint_pair means . */ std::vector charset_pairs; }; // Contents of DEFAULT_CHARSET field is converted into Default_charset. Default_charset m_default_charset; // Contents of ENUM_AND_SET_DEFAULT_CHARSET are converted into // Default_charset. Default_charset m_enum_and_set_default_charset; std::vector m_signedness; // Character set number of every string column std::vector m_column_charset; // Character set number of every ENUM or SET column. std::vector m_enum_and_set_column_charset; std::vector m_column_name; // each str_vector stores values of one enum/set column std::vector m_enum_str_value; std::vector m_set_str_value; std::vector m_geometry_type; /* The uint_pair means . Prefix length is 0 if whole column value is used. */ std::vector m_primary_key; /* It parses m_optional_metadata and populates into above variables. @param[in] optional_metadata points to the begin of optional metadata fields in table_map_event. @param[in] optional_metadata_len length of optional_metadata field. */ Optional_metadata_fields(unsigned char* optional_metadata, unsigned int optional_metadata_len); }; /** Print column metadata. Its format looks like: # Columns(colume_name type, colume_name type, ...) if colume_name field is not logged into table_map_log_event, then only type is printed. @@param[out] file the place where colume metadata is printed @@param[in] The metadata extracted from optional metadata fields */ void print_columns(IO_CACHE *file, const Optional_metadata_fields &fields); /** Print primary information. Its format looks like: # Primary Key(colume_name, column_name(prifix), ...) if colume_name field is not logged into table_map_log_event, then colume index is printed. @@param[out] file the place where primary key is printed @@param[in] The metadata extracted from optional metadata fields */ void print_primary_key(IO_CACHE *file, const Optional_metadata_fields &fields); /* Special constants representing sets of flags */ enum { TM_NO_FLAGS = 0U, TM_BIT_LEN_EXACT_F = (1U << 0), // MariaDB flags (we starts from the other end) TM_BIT_HAS_TRIGGERS_F= (1U << 14) }; flag_set get_flags(flag_set flag) const { return m_flags & flag; } #ifdef MYSQL_SERVER Table_map_log_event(THD *thd, TABLE *tbl, ulonglong tid, bool is_transactional); #endif #ifdef HAVE_REPLICATION Table_map_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); #endif ~Table_map_log_event(); #ifdef MYSQL_CLIENT table_def *create_table_def() { return new table_def(m_coltype, m_colcnt, m_field_metadata, m_field_metadata_size, m_null_bits, m_flags); } int rewrite_db(const char* new_name, size_t new_name_len, const Format_description_log_event*); #endif ulonglong get_table_id() const { return m_table_id; } const char *get_table_name() const { return m_tblnam; } const char *get_db_name() const { return m_dbnam; } Log_event_type get_type_code() override { return TABLE_MAP_EVENT; } enum_logged_status logged_status() override { return LOGGED_TABLE_MAP; } bool is_valid() const override { return m_memory != NULL; /* we check malloc */ } int get_data_size() override { return (uint) m_data_size; } #ifdef MYSQL_SERVER #ifdef HAVE_REPLICATION bool is_part_of_group() override { return 1; } #endif virtual int save_field_metadata(); bool write_data_header() override; bool write_data_body() override; const char *get_db() override { return m_dbnam; } #endif #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) void pack_info(Protocol *protocol) override; #endif #ifdef MYSQL_CLIENT bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; #endif #ifdef MYSQL_SERVER TABLE *m_table; Binlog_type_info *binlog_type_info_array; // Metadata fields buffer StringBuffer<1024> m_metadata_buf; /** Capture the optional metadata fields which should be logged into table_map_log_event and serialize them into m_metadata_buf. */ void init_metadata_fields(); bool init_signedness_field(); /** Capture and serialize character sets. Character sets for character columns (TEXT etc) and character sets for ENUM and SET columns are stored in different metadata fields. The reason is that TEXT character sets are included even when binlog_row_metadata=MINIMAL, whereas ENUM and SET character sets are included only when binlog_row_metadata=FULL. @param include_type Predicate to determine if a given Field object is to be included in the metadata field. @param default_charset_type Type code when storing in "default charset" format. (See comment above Table_maps_log_event in libbinlogevents/include/rows_event.h) @param column_charset_type Type code when storing in "column charset" format. (See comment above Table_maps_log_event in libbinlogevents/include/rows_event.h) */ bool init_charset_field(bool(* include_type)(Binlog_type_info *, Field *), Optional_metadata_field_type default_charset_type, Optional_metadata_field_type column_charset_type); bool init_column_name_field(); bool init_set_str_value_field(); bool init_enum_str_value_field(); bool init_geometry_type_field(); bool init_primary_key_field(); #endif #ifdef MYSQL_CLIENT class Charset_iterator; class Default_charset_iterator; class Column_charset_iterator; #endif char const *m_dbnam; size_t m_dblen; char const *m_tblnam; size_t m_tbllen; ulong m_colcnt; uchar *m_coltype; uchar *m_memory; ulonglong m_table_id; flag_set m_flags; size_t m_data_size; uchar *m_field_metadata; // buffer for field metadata /* The size of field metadata buffer set by calling save_field_metadata() */ ulong m_field_metadata_size; uchar *m_null_bits; uchar *m_meta_memory; unsigned int m_optional_metadata_len; unsigned char *m_optional_metadata; }; /** @class Rows_log_event Common base class for all row-containing log events. RESPONSIBILITIES Encode the common parts of all events containing rows, which are: - Write data header and data body to an IO_CACHE. - Provide an interface for adding an individual row to the event. @section Rows_log_event_binary_format Binary Format */ class Rows_log_event : public Log_event { public: /** Enumeration of the errors that can be returned. */ enum enum_error { ERR_OPEN_FAILURE = -1, /**< Failure to open table */ ERR_OK = 0, /**< No error */ ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */ ERR_OUT_OF_MEM = 2, /**< Out of memory */ ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */ ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */ }; /* These definitions allow you to combine the flags into an appropriate flag set using the normal bitwise operators. The implicit conversion from an enum-constant to an integer is accepted by the compiler, which is then used to set the real set of flags. */ enum enum_flag { /* Last event of a statement */ STMT_END_F = (1U << 0), /* Value of the OPTION_NO_FOREIGN_KEY_CHECKS flag in thd->options */ NO_FOREIGN_KEY_CHECKS_F = (1U << 1), /* Value of the OPTION_RELAXED_UNIQUE_CHECKS flag in thd->options */ RELAXED_UNIQUE_CHECKS_F = (1U << 2), /** Indicates that rows in this event are complete, that is contain values for all columns of the table. */ COMPLETE_ROWS_F = (1U << 3), /* Value of the OPTION_NO_CHECK_CONSTRAINT_CHECKS flag in thd->options */ NO_CHECK_CONSTRAINT_CHECKS_F = (1U << 7) }; typedef uint16 flag_set; /* Special constants representing sets of flags */ enum { RLE_NO_FLAGS = 0U }; virtual ~Rows_log_event(); void set_flags(flag_set flags_arg) { m_flags |= flags_arg; } void clear_flags(flag_set flags_arg) { m_flags &= ~flags_arg; } flag_set get_flags(flag_set flags_arg) const { return m_flags & flags_arg; } void update_flags() { int2store(temp_buf + m_flags_pos, m_flags); } Log_event_type get_type_code() override { return m_type; } /* Specific type (_V1 etc) */ enum_logged_status logged_status() override { return LOGGED_ROW_EVENT; } virtual Log_event_type get_general_type_code() = 0; /* General rows op type, no version */ #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) void pack_info(Protocol *protocol) override; #endif #ifdef MYSQL_CLIENT /* not for direct call, each derived has its own ::print() */ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override= 0; void change_to_flashback_event(PRINT_EVENT_INFO *print_event_info, uchar *rows_buff, Log_event_type ev_type); bool print_verbose(IO_CACHE *file, PRINT_EVENT_INFO *print_event_info); size_t print_verbose_one_row(IO_CACHE *file, table_def *td, PRINT_EVENT_INFO *print_event_info, MY_BITMAP *cols_bitmap, const uchar *ptr, const uchar *prefix, const my_bool no_fill_output= 0); // if no_fill_output=1, then print result is unnecessary size_t calc_row_event_length(table_def *td, PRINT_EVENT_INFO *print_event_info, MY_BITMAP *cols_bitmap, const uchar *value); void count_row_events(PRINT_EVENT_INFO *print_event_info); #endif #ifdef MYSQL_SERVER int add_row_data(uchar *data, size_t length) { return do_add_row_data(data,length); } #endif /* Member functions to implement superclass interface */ int get_data_size() override; MY_BITMAP const *get_cols() const { return &m_cols; } MY_BITMAP const *get_cols_ai() const { return &m_cols_ai; } size_t get_width() const { return m_width; } ulonglong get_table_id() const { return m_table_id; } #if defined(MYSQL_SERVER) /* This member function compares the table's read/write_set with this event's m_cols and m_cols_ai. Comparison takes into account what type of rows event is this: Delete, Write or Update, therefore it uses the correct m_cols[_ai] according to the event type code. Note that this member function should only be called for the following events: - Delete_rows_log_event - Write_rows_log_event - Update_rows_log_event @param[IN] table The table to compare this events bitmaps against. @return TRUE if sets match, FALSE otherwise. (following bitmap_cmp return logic). */ bool read_write_bitmaps_cmp(TABLE *table) { bool res= FALSE; switch (get_general_type_code()) { case DELETE_ROWS_EVENT: res= bitmap_cmp(get_cols(), table->read_set); break; case UPDATE_ROWS_EVENT: res= (bitmap_cmp(get_cols(), table->read_set) && bitmap_cmp(get_cols_ai(), table->rpl_write_set)); break; case WRITE_ROWS_EVENT: res= bitmap_cmp(get_cols(), table->rpl_write_set); break; default: /* We should just compare bitmaps for Delete, Write or Update rows events. */ DBUG_ASSERT(0); } return res; } #endif #ifdef MYSQL_SERVER bool write_data_header() override; bool write_data_body() override; virtual bool write_compressed(); const char *get_db() override { return m_table->s->db.str; } #ifdef HAVE_REPLICATION bool is_part_of_group() override { return get_flags(STMT_END_F) != 0; } #endif #endif /* Check that malloc() succeeded in allocating memory for the rows buffer and the COLS vector. Checking that an Update_rows_log_event is valid is done in the Update_rows_log_event::is_valid() function. */ bool is_valid() const override { return m_cols.bitmap; } uint m_row_count; /* The number of rows added to the event */ const uchar* get_extra_row_data() const { return m_extra_row_data; } #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) virtual uint8 get_trg_event_map()= 0; inline bool do_invoke_trigger() { return (slave_run_triggers_for_rbr && !master_had_triggers) || slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_ENFORCE; } #endif protected: /* The constructors are protected since you're supposed to inherit this class, not create instances of this class. */ #ifdef MYSQL_SERVER Rows_log_event(THD*, TABLE*, ulonglong table_id, MY_BITMAP const *cols, bool is_transactional, Log_event_type event_type); #endif Rows_log_event(const uchar *row_data, uint event_len, const Format_description_log_event *description_event); void uncompress_buf(); #ifdef MYSQL_CLIENT bool print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name); #endif #ifdef MYSQL_SERVER virtual int do_add_row_data(uchar *data, size_t length); #endif #ifdef MYSQL_SERVER TABLE *m_table; /* The table the rows belong to */ #endif ulonglong m_table_id; /* Table ID */ MY_BITMAP m_cols; /* Bitmap denoting columns available */ ulong m_width; /* The width of the columns bitmap */ /* Bitmap for columns available in the after image, if present. These fields are only available for Update_rows events. Observe that the width of both the before image COLS vector and the after image COLS vector is the same: the number of columns of the table on the master. */ MY_BITMAP m_cols_ai; ulong m_master_reclength; /* Length of record on master side */ /* Bit buffers in the same memory as the class */ my_bitmap_map m_bitbuf[128/(sizeof(my_bitmap_map)*8)]; my_bitmap_map m_bitbuf_ai[128/(sizeof(my_bitmap_map)*8)]; uchar *m_rows_buf; /* The rows in packed format */ uchar *m_rows_cur; /* One-after the end of the data */ uchar *m_rows_end; /* One-after the end of the allocated space */ size_t m_rows_before_size; /* The length before m_rows_buf */ size_t m_flags_pos; /* The position of the m_flags */ flag_set m_flags; /* Flags for row-level events */ Log_event_type m_type; /* Actual event type */ uchar *m_extra_row_data; /* Pointer to extra row data if any */ /* If non null, first byte is length */ bool m_vers_from_plain; /* helper functions */ #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) const uchar *m_curr_row; /* Start of the row being processed */ const uchar *m_curr_row_end; /* One-after the end of the current row */ uchar *m_key; /* Buffer to keep key value during searches */ KEY *m_key_info; /* Pointer to KEY info for m_key_nr */ uint m_key_nr; /* Key number */ bool master_had_triggers; /* set after tables opening */ /* RAII helper class to automatically handle the override/restore of thd->db when applying row events, so it will be visible in SHOW PROCESSLIST. If triggers will be invoked, their logic frees the current thread's db, so we use set_db() to use a copy of the table share's database. If not using triggers, the db is never freed, and we can reference the same memory owned by the table share. */ class Db_restore_ctx { private: THD *thd; LEX_CSTRING restore_db; bool db_copied; Db_restore_ctx(Rows_log_event *rev) : thd(rev->thd), restore_db(rev->thd->db) { TABLE *table= rev->m_table; if (table->triggers && rev->do_invoke_trigger()) { thd->reset_db(&null_clex_str); thd->set_db(&table->s->db); db_copied= true; } else { thd->reset_db(&table->s->db); db_copied= false; } } ~Db_restore_ctx() { if (db_copied) thd->set_db(&null_clex_str); thd->reset_db(&restore_db); } friend class Rows_log_event; }; int find_key(); // Find a best key to use in find_row() int find_row(rpl_group_info *); int write_row(rpl_group_info *, const bool); int update_sequence(); // Unpack the current row into m_table->record[0], but with // a different columns bitmap. int unpack_current_row(rpl_group_info *rgi, MY_BITMAP const *cols) { DBUG_ASSERT(m_table); ASSERT_OR_RETURN_ERROR(m_curr_row <= m_rows_end, HA_ERR_CORRUPT_EVENT); return ::unpack_row(rgi, m_table, m_width, m_curr_row, cols, &m_curr_row_end, &m_master_reclength, m_rows_end); } // Unpack the current row into m_table->record[0] int unpack_current_row(rpl_group_info *rgi) { DBUG_ASSERT(m_table); ASSERT_OR_RETURN_ERROR(m_curr_row <= m_rows_end, HA_ERR_CORRUPT_EVENT); return ::unpack_row(rgi, m_table, m_width, m_curr_row, &m_cols, &m_curr_row_end, &m_master_reclength, m_rows_end); } bool process_triggers(trg_event_type event, trg_action_time_type time_type, bool old_row_is_record1); /** Helper function to check whether there is an auto increment column on the table where the event is to be applied. @return true if there is an autoincrement field on the extra columns, false otherwise. */ inline bool is_auto_inc_in_extra_columns() { DBUG_ASSERT(m_table); return (m_table->next_number_field && m_table->next_number_field->field_index >= m_width); } #endif private: #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; int do_update_pos(rpl_group_info *rgi) override; enum_skip_reason do_shall_skip(rpl_group_info *rgi) override; /* Primitive to prepare for a sequence of row executions. DESCRIPTION Before doing a sequence of do_prepare_row() and do_exec_row() calls, this member function should be called to prepare for the entire sequence. Typically, this member function will allocate space for any buffers that are needed for the two member functions mentioned above. RETURN VALUE The member function will return 0 if all went OK, or a non-zero error code otherwise. */ virtual int do_before_row_operations(const Slave_reporting_capability *const log) = 0; /* Primitive to clean up after a sequence of row executions. DESCRIPTION After doing a sequence of do_prepare_row() and do_exec_row(), this member function should be called to clean up and release any allocated buffers. The error argument, if non-zero, indicates an error which happened during row processing before this function was called. In this case, even if function is successful, it should return the error code given in the argument. */ virtual int do_after_row_operations(const Slave_reporting_capability *const log, int error) = 0; /* Primitive to do the actual execution necessary for a row. DESCRIPTION The member function will do the actual execution needed to handle a row. The row is located at m_curr_row. When the function returns, m_curr_row_end should point at the next row (one byte after the end of the current row). RETURN VALUE 0 if execution succeeded, 1 if execution failed. */ virtual int do_exec_row(rpl_group_info *rli) = 0; #endif /* defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) */ friend class Old_rows_log_event; }; /** @class Write_rows_log_event Log row insertions and updates. The event contain several insert/update rows for a table. Note that each event contains only rows for one table. @section Write_rows_log_event_binary_format Binary Format */ class Write_rows_log_event : public Rows_log_event { public: enum { /* Support interface to THD::binlog_prepare_pending_rows_event */ TYPE_CODE = WRITE_ROWS_EVENT }; #if defined(MYSQL_SERVER) Write_rows_log_event(THD*, TABLE*, ulonglong table_id, bool is_transactional); #endif #ifdef HAVE_REPLICATION Write_rows_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); #endif #if defined(MYSQL_SERVER) static bool binlog_row_logging_function(THD *thd, TABLE *table, bool is_transactional, const uchar *before_record __attribute__((unused)), const uchar *after_record) { DBUG_ASSERT(!table->versioned(VERS_TRX_ID)); return thd->binlog_write_row(table, is_transactional, after_record); } #endif #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) uint8 get_trg_event_map() override; #endif private: Log_event_type get_general_type_code() override { return (Log_event_type)TYPE_CODE; } #ifdef MYSQL_CLIENT bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_before_row_operations(const Slave_reporting_capability *const) override; int do_after_row_operations(const Slave_reporting_capability *const,int) override; int do_exec_row(rpl_group_info *) override; #endif }; class Write_rows_compressed_log_event : public Write_rows_log_event { public: #if defined(MYSQL_SERVER) Write_rows_compressed_log_event(THD*, TABLE*, ulonglong table_id, bool is_transactional); bool write() override; #endif #ifdef HAVE_REPLICATION Write_rows_compressed_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); #endif private: #if defined(MYSQL_CLIENT) bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif }; /** @class Update_rows_log_event Log row updates with a before image. The event contain several update rows for a table. Note that each event contains only rows for one table. Also note that the row data consists of pairs of row data: one row for the old data and one row for the new data. @section Update_rows_log_event_binary_format Binary Format */ class Update_rows_log_event : public Rows_log_event { public: enum { /* Support interface to THD::binlog_prepare_pending_rows_event */ TYPE_CODE = UPDATE_ROWS_EVENT }; #ifdef MYSQL_SERVER Update_rows_log_event(THD*, TABLE*, ulonglong table_id, bool is_transactional); void init(MY_BITMAP const *cols); #endif virtual ~Update_rows_log_event(); #ifdef HAVE_REPLICATION Update_rows_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); #endif #ifdef MYSQL_SERVER static bool binlog_row_logging_function(THD *thd, TABLE *table, bool is_transactional, const uchar *before_record, const uchar *after_record) { DBUG_ASSERT(!table->versioned(VERS_TRX_ID)); return thd->binlog_update_row(table, is_transactional, before_record, after_record); } #endif bool is_valid() const override { return Rows_log_event::is_valid() && m_cols_ai.bitmap; } #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) uint8 get_trg_event_map() override; #endif protected: Log_event_type get_general_type_code() override { return (Log_event_type)TYPE_CODE; } #ifdef MYSQL_CLIENT bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_before_row_operations(const Slave_reporting_capability *const) override; int do_after_row_operations(const Slave_reporting_capability *const,int) override; int do_exec_row(rpl_group_info *) override; #endif /* defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) */ }; class Update_rows_compressed_log_event : public Update_rows_log_event { public: #if defined(MYSQL_SERVER) Update_rows_compressed_log_event(THD*, TABLE*, ulonglong table_id, bool is_transactional); bool write() override; #endif #ifdef HAVE_REPLICATION Update_rows_compressed_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); #endif private: #if defined(MYSQL_CLIENT) bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif }; /** @class Delete_rows_log_event Log row deletions. The event contain several delete rows for a table. Note that each event contains only rows for one table. RESPONSIBILITIES - Act as a container for rows that has been deleted on the master and should be deleted on the slave. COLLABORATION Row_writer Create the event and add rows to the event. Row_reader Extract the rows from the event. @section Delete_rows_log_event_binary_format Binary Format */ class Delete_rows_log_event : public Rows_log_event { public: enum { /* Support interface to THD::binlog_prepare_pending_rows_event */ TYPE_CODE = DELETE_ROWS_EVENT }; #ifdef MYSQL_SERVER Delete_rows_log_event(THD*, TABLE*, ulonglong, bool is_transactional); #endif #ifdef HAVE_REPLICATION Delete_rows_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); #endif #ifdef MYSQL_SERVER static bool binlog_row_logging_function(THD *thd, TABLE *table, bool is_transactional, const uchar *before_record, const uchar *after_record __attribute__((unused))) { DBUG_ASSERT(!table->versioned(VERS_TRX_ID)); return thd->binlog_delete_row(table, is_transactional, before_record); } #endif #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) uint8 get_trg_event_map() override; #endif protected: Log_event_type get_general_type_code() override { return (Log_event_type)TYPE_CODE; } #ifdef MYSQL_CLIENT bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_before_row_operations(const Slave_reporting_capability *const) override; int do_after_row_operations(const Slave_reporting_capability *const,int) override; int do_exec_row(rpl_group_info *) override; #endif }; class Delete_rows_compressed_log_event : public Delete_rows_log_event { public: #if defined(MYSQL_SERVER) Delete_rows_compressed_log_event(THD*, TABLE*, ulonglong, bool is_transactional); bool write() override; #endif #ifdef HAVE_REPLICATION Delete_rows_compressed_log_event(const uchar *buf, uint event_len, const Format_description_log_event *description_event); #endif private: #if defined(MYSQL_CLIENT) bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif }; #include "log_event_old.h" /** @class Incident_log_event Class representing an incident, an occurence out of the ordinary, that happened on the master. The event is used to inform the slave that something out of the ordinary happened on the master that might cause the database to be in an inconsistent state.
Incident event format
Symbol Format Description
INCIDENT 2 Incident number as an unsigned integer
MSGLEN 1 Message length as an unsigned integer
MESSAGE MSGLEN The message, if present. Not null terminated.
@section Delete_rows_log_event_binary_format Binary Format */ class Incident_log_event : public Log_event { public: #ifdef MYSQL_SERVER Incident_log_event(THD *thd_arg, Incident incident) : Log_event(thd_arg, 0, FALSE), m_incident(incident) { DBUG_ENTER("Incident_log_event::Incident_log_event"); DBUG_PRINT("enter", ("m_incident: %d", m_incident)); m_message.str= NULL; /* Just as a precaution */ m_message.length= 0; set_direct_logging(); /* Replicate the incident regardless of @@skip_replication. */ flags&= ~LOG_EVENT_SKIP_REPLICATION_F; DBUG_VOID_RETURN; } Incident_log_event(THD *thd_arg, Incident incident, const LEX_CSTRING *msg) : Log_event(thd_arg, 0, FALSE), m_incident(incident) { extern PSI_memory_key key_memory_Incident_log_event_message; DBUG_ENTER("Incident_log_event::Incident_log_event"); DBUG_PRINT("enter", ("m_incident: %d", m_incident)); m_message.length= 0; if (!(m_message.str= (char*) my_malloc(key_memory_Incident_log_event_message, msg->length + 1, MYF(MY_WME)))) { /* Mark this event invalid */ m_incident= INCIDENT_NONE; DBUG_VOID_RETURN; } strmake(m_message.str, msg->str, msg->length); m_message.length= msg->length; set_direct_logging(); /* Replicate the incident regardless of @@skip_replication. */ flags&= ~LOG_EVENT_SKIP_REPLICATION_F; DBUG_VOID_RETURN; } #endif #ifdef MYSQL_SERVER #ifdef HAVE_REPLICATION void pack_info(Protocol*) override; #endif bool write_data_header() override; bool write_data_body() override; #endif Incident_log_event(const uchar *buf, uint event_len, const Format_description_log_event *descr_event); virtual ~Incident_log_event(); #ifdef MYSQL_CLIENT bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) int do_apply_event(rpl_group_info *rgi) override; #endif Log_event_type get_type_code() override { return INCIDENT_EVENT; } bool is_valid() const override { return m_incident > INCIDENT_NONE && m_incident < INCIDENT_COUNT; } int get_data_size() override { return INCIDENT_HEADER_LEN + 1 + (uint) m_message.length; } private: const char *description() const; Incident m_incident; LEX_STRING m_message; }; /** @class Ignorable_log_event Base class for ignorable log events. Events deriving from this class can be safely ignored by slaves that cannot recognize them. Newer slaves, will be able to read and handle them. This has been designed to be an open-ended architecture, so adding new derived events shall not harm the old slaves that support ignorable log event mechanism (they will just ignore unrecognized ignorable events). @note The only thing that makes an event ignorable is that it has the LOG_EVENT_IGNORABLE_F flag set. It is not strictly necessary that ignorable event types derive from Ignorable_log_event; they may just as well derive from Log_event and pass LOG_EVENT_IGNORABLE_F as argument to the Log_event constructor. **/ class Ignorable_log_event : public Log_event { public: int number; const char *description; #ifndef MYSQL_CLIENT Ignorable_log_event(THD *thd_arg) :Log_event(thd_arg, LOG_EVENT_IGNORABLE_F, FALSE), number(0), description("internal") { DBUG_ENTER("Ignorable_log_event::Ignorable_log_event"); DBUG_VOID_RETURN; } #endif Ignorable_log_event(const uchar *buf, const Format_description_log_event *descr_event, const char *event_name); virtual ~Ignorable_log_event(); #ifndef MYSQL_CLIENT #ifdef HAVE_REPLICATION void pack_info(Protocol*) override; #endif #else bool print(FILE *file, PRINT_EVENT_INFO *print_event_info) override; #endif Log_event_type get_type_code() override { return IGNORABLE_LOG_EVENT; } bool is_valid() const override { return 1; } int get_data_size() override { return IGNORABLE_HEADER_LEN; } }; #ifdef MYSQL_CLIENT bool copy_cache_to_string_wrapped(IO_CACHE *body, LEX_STRING *to, bool do_wrap, const char *delimiter, bool is_verbose); bool copy_cache_to_file_wrapped(IO_CACHE *body, FILE *file, bool do_wrap, const char *delimiter, bool is_verbose); #endif #ifdef MYSQL_SERVER /***************************************************************************** Heartbeat Log Event class Replication event to ensure to slave that master is alive. The event is originated by master's dump thread and sent straight to slave without being logged. Slave itself does not store it in relay log but rather uses a data for immediate checks and throws away the event. Two members of the class log_ident and Log_event::log_pos comprise @see the event_coordinates instance. The coordinates that a heartbeat instance carries correspond to the last event master has sent from its binlog. ****************************************************************************/ class Heartbeat_log_event: public Log_event { public: uint8 hb_flags; Heartbeat_log_event(const uchar *buf, uint event_len, const Format_description_log_event* description_event); Log_event_type get_type_code() override { return HEARTBEAT_LOG_EVENT; } bool is_valid() const override { return (log_ident != NULL && ident_len <= FN_REFLEN-1 && log_pos >= BIN_LOG_HEADER_SIZE); } const uchar * get_log_ident() { return log_ident; } uint get_ident_len() { return ident_len; } private: uint ident_len; const uchar *log_ident; }; inline int Log_event_writer::write(Log_event *ev) { ev->writer= this; int res= ev->write(); IF_DBUG(ev->writer= 0,); // writer must be set before every Log_event::write add_status(ev->logged_status()); return res; } /** The function is called by slave applier in case there are active table filtering rules to force gathering events associated with Query-log-event into an array to execute them once the fate of the Query is determined for execution. */ bool slave_execute_deferred_events(THD *thd); #endif bool event_that_should_be_ignored(const uchar *buf); bool event_checksum_test(uchar *buf, ulong event_len, enum_binlog_checksum_alg alg); enum enum_binlog_checksum_alg get_checksum_alg(const uchar *buf, ulong len); extern TYPELIB binlog_checksum_typelib; #ifdef WITH_WSREP enum Log_event_type wsrep_peak_event(rpl_group_info *rgi, ulonglong* event_size); #endif /* WITH_WSREP */ /** @} (end of group Replication) */ int binlog_buf_compress(const uchar *src, uchar *dst, uint32 len, uint32 *comlen); int binlog_buf_uncompress(const uchar *src, uchar *dst, uint32 len, uint32 *newlen); uint32 binlog_get_compress_len(uint32 len); uint32 binlog_get_uncompress_len(const uchar *buf); int query_event_uncompress(const Format_description_log_event *description_event, bool contain_checksum, const uchar *src, ulong src_len, uchar *buf, ulong buf_size, bool* is_malloc, uchar **dst, ulong *newlen); int row_log_event_uncompress(const Format_description_log_event *description_event, bool contain_checksum, const uchar *src, ulong src_len, uchar* buf, ulong buf_size, bool *is_malloc, uchar **dst, ulong *newlen); #endif /* _log_event_h */ server/private/sp_rcontext.h000064400000033776151031265040012262 0ustar00/* -*- C++ -*- */ /* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _SP_RCONTEXT_H_ #define _SP_RCONTEXT_H_ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_class.h" // select_result_interceptor #include "sp_pcontext.h" // sp_condition_value /////////////////////////////////////////////////////////////////////////// // sp_rcontext declaration. /////////////////////////////////////////////////////////////////////////// class sp_cursor; class sp_lex_keeper; class sp_instr_cpush; class sp_instr_hpush_jump; class Query_arena; class sp_head; class Item_cache; class Virtual_tmp_table; /* This class is a runtime context of a Stored Routine. It is used in an execution and is intended to contain all dynamic objects (i.e. objects, which can be changed during execution), such as: - stored routine variables; - cursors; - handlers; Runtime context is used with sp_head class. sp_head class is intended to contain all static things, related to the stored routines (code, for example). sp_head instance creates runtime context for the execution of a stored routine. There is a parsing context (an instance of sp_pcontext class), which is used on parsing stage. However, now it contains some necessary for an execution things, such as definition of used stored routine variables. That's why runtime context needs a reference to the parsing context. */ class sp_rcontext : public Sql_alloc { public: /// Construct and properly initialize a new sp_rcontext instance. The static /// create-function is needed because we need a way to return an error from /// the constructor. /// /// @param thd Thread handle. /// @param root_parsing_ctx Top-level parsing context for this stored program. /// @param return_value_fld Field object to store the return value /// (for stored functions only). /// /// @return valid sp_rcontext object or NULL in case of OOM-error. static sp_rcontext *create(THD *thd, const sp_head *owner, const sp_pcontext *root_parsing_ctx, Field *return_value_fld, Row_definition_list &defs); ~sp_rcontext(); private: sp_rcontext(const sp_head *owner, const sp_pcontext *root_parsing_ctx, Field *return_value_fld, bool in_sub_stmt); // Prevent use of copying constructor and operator. sp_rcontext(const sp_rcontext &); void operator=(sp_rcontext &); public: /// This class stores basic information about SQL-condition, such as: /// - SQL error code; /// - error level; /// - SQLSTATE; /// - text message. /// /// It's used to organize runtime SQL-handler call stack. /// /// Standard Sql_condition class can not be used, because we don't always have /// an Sql_condition object for an SQL-condition in Diagnostics_area. /// /// Eventually, this class should be moved to sql_error.h, and be a part of /// standard SQL-condition processing (Diagnostics_area should contain an /// object for active SQL-condition, not just information stored in DA's /// fields). class Sql_condition_info : public Sql_alloc, public Sql_condition_identity { public: /// Text message. char *message; /// The constructor. /// /// @param _sql_condition The SQL condition. /// @param arena Query arena for SP Sql_condition_info(const Sql_condition *_sql_condition, Query_arena *arena) :Sql_condition_identity(*_sql_condition) { message= strdup_root(arena->mem_root, _sql_condition->get_message_text()); } }; private: /// This class represents a call frame of SQL-handler (one invocation of a /// handler). Basically, it's needed to store continue instruction pointer for /// CONTINUE SQL-handlers. class Handler_call_frame : public Sql_alloc { public: /// SQL-condition, triggered handler activation. const Sql_condition_info *sql_condition; /// Continue-instruction-pointer for CONTINUE-handlers. /// The attribute contains 0 for EXIT-handlers. uint continue_ip; /// The constructor. /// /// @param _sql_condition SQL-condition, triggered handler activation. /// @param _continue_ip Continue instruction pointer. Handler_call_frame(const Sql_condition_info *_sql_condition, uint _continue_ip) :sql_condition(_sql_condition), continue_ip(_continue_ip) { } }; public: /// Arena used to (re) allocate items on. E.g. reallocate INOUT/OUT /// SP-variables when they don't fit into prealloced items. This is common /// situation with String items. It is used mainly in sp_eval_func_item(). Query_arena *callers_arena; /// Flag to end an open result set before start executing an SQL-handler /// (if one is found). Otherwise the client will hang due to a violation /// of the client/server protocol. bool end_partial_result_set; bool pause_state; bool quit_func; uint instr_ptr; /// The stored program for which this runtime context is created. Used for /// checking if correct runtime context is used for variable handling, /// and to access the package run-time context. /// Also used by slow log. const sp_head *m_sp; ///////////////////////////////////////////////////////////////////////// // SP-variables. ///////////////////////////////////////////////////////////////////////// uint argument_count() const { return m_root_parsing_ctx->context_var_count(); } int set_variable(THD *thd, uint var_idx, Item **value); int set_variable_row_field(THD *thd, uint var_idx, uint field_idx, Item **value); int set_variable_row_field_by_name(THD *thd, uint var_idx, const LEX_CSTRING &field_name, Item **value); int set_variable_row(THD *thd, uint var_idx, List &items); int set_parameter(THD *thd, uint var_idx, Item **value) { DBUG_ASSERT(var_idx < argument_count()); return set_variable(thd, var_idx, value); } Item_field *get_variable(uint var_idx) const { return m_var_items[var_idx]; } Item **get_variable_addr(uint var_idx) const { return ((Item **) m_var_items.array()) + var_idx; } Item_field *get_parameter(uint var_idx) const { DBUG_ASSERT(var_idx < argument_count()); return get_variable(var_idx); } bool find_row_field_by_name_or_error(uint *field_idx, uint var_idx, const LEX_CSTRING &field_name); bool set_return_value(THD *thd, Item **return_value_item); bool is_return_value_set() const { return m_return_value_set; } ///////////////////////////////////////////////////////////////////////// // SQL-handlers. ///////////////////////////////////////////////////////////////////////// /// Push an sp_instr_hpush_jump instance to the handler call stack. /// /// @param entry The condition handler entry /// /// @return error flag. /// @retval false on success. /// @retval true on error. bool push_handler(sp_instr_hpush_jump *entry); /// Pop and delete given number of instances from the handler /// call stack. /// /// @param count Number of handler entries to pop & delete. void pop_handlers(size_t count); const Sql_condition_info *raised_condition() const { return m_handler_call_stack.elements() ? (*m_handler_call_stack.back())->sql_condition : NULL; } /// Handle current SQL condition (if any). /// /// This is the public-interface function to handle SQL conditions in /// stored routines. /// /// @param thd Thread handle. /// @param ip[out] Instruction pointer to the first handler /// instruction. /// @param cur_spi Current SP instruction. /// /// @retval true if an SQL-handler has been activated. That means, all of /// the following conditions are satisfied: /// - the SP-instruction raised SQL-condition(s), /// - and there is an SQL-handler to process at least one of those /// SQL-conditions, /// - and that SQL-handler has been activated. /// Note, that the return value has nothing to do with "error flag" /// semantics. /// /// @retval false otherwise. bool handle_sql_condition(THD *thd, uint *ip, const sp_instr *cur_spi); /// Remove latest call frame from the handler call stack. /// /// @param da Diagnostics area containing handled conditions. /// /// @return continue instruction pointer of the removed handler. uint exit_handler(Diagnostics_area *da); ///////////////////////////////////////////////////////////////////////// // Cursors. ///////////////////////////////////////////////////////////////////////// /// Push a cursor to the cursor stack. /// /// @param cursor The cursor /// void push_cursor(sp_cursor *cur); void pop_cursor(THD *thd); /// Pop and delete given number of sp_cursor instance from the cursor stack. /// /// @param count Number of cursors to pop & delete. void pop_cursors(THD *thd, size_t count); void pop_all_cursors(THD *thd) { pop_cursors(thd, m_ccount); } sp_cursor *get_cursor(uint i) const { return m_cstack[i]; } ///////////////////////////////////////////////////////////////////////// // CASE expressions. ///////////////////////////////////////////////////////////////////////// /// Set CASE expression to the specified value. /// /// @param thd Thread handler. /// @param case_expr_id The CASE expression identifier. /// @param case_expr_item The CASE expression value /// /// @return error flag. /// @retval false on success. /// @retval true on error. /// /// @note The idea is to reuse Item_cache for the expression of the one /// CASE statement. This optimization takes place when there is CASE /// statement inside of a loop. So, in other words, we will use the same /// object on each iteration instead of creating a new one for each /// iteration. /// /// TODO /// Hypothetically, a type of CASE expression can be different for each /// iteration. For instance, this can happen if the expression contains /// a session variable (something like @@VAR) and its type is changed /// from one iteration to another. /// /// In order to cope with this problem, we check type each time, when we /// use already created object. If the type does not match, we re-create /// Item. This also can (should?) be optimized. bool set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr); Item *get_case_expr(int case_expr_id) const { return m_case_expr_holders[case_expr_id]; } Item ** get_case_expr_addr(int case_expr_id) const { return (Item**) m_case_expr_holders.array() + case_expr_id; } private: /// Internal function to allocate memory for arrays. /// /// @param thd Thread handle. /// /// @return error flag: false on success, true in case of failure. bool alloc_arrays(THD *thd); /// Create and initialize a table to store SP-variables. /// /// param thd Thread handle. /// /// @return error flag. /// @retval false on success. /// @retval true on error. bool init_var_table(THD *thd, List &defs); /// Create and initialize an Item-adapter (Item_field) for each SP-var field. /// /// param thd Thread handle. /// /// @return error flag. /// @retval false on success. /// @retval true on error. bool init_var_items(THD *thd, List &defs); /// Create an instance of appropriate Item_cache class depending on the /// specified type in the callers arena. /// /// @note We should create cache items in the callers arena, as they are /// used between in several instructions. /// /// @param thd Thread handler. /// @param item Item to get the expression type. /// /// @return Pointer to valid object on success, or NULL in case of error. Item_cache *create_case_expr_holder(THD *thd, const Item *item) const; Virtual_tmp_table *virtual_tmp_table_for_row(uint idx); private: /// Top-level (root) parsing context for this runtime context. const sp_pcontext *m_root_parsing_ctx; /// Virtual table for storing SP-variables. Virtual_tmp_table *m_var_table; /// Collection of Item_field proxies, each of them points to the /// corresponding field in m_var_table. Bounds_checked_array m_var_items; /// This is a pointer to a field, which should contain return value for /// stored functions (only). For stored procedures, this pointer is NULL. Field *m_return_value_fld; /// Indicates whether the return value (in m_return_value_fld) has been /// set during execution. bool m_return_value_set; /// Flag to tell if the runtime context is created for a sub-statement. bool m_in_sub_stmt; /// Stack of visible handlers. Dynamic_array m_handlers; /// Stack of caught SQL conditions. Dynamic_array m_handler_call_stack; /// Stack of cursors. Bounds_checked_array m_cstack; /// Current number of cursors in m_cstack. uint m_ccount; /// Array of CASE expression holders. Bounds_checked_array m_case_expr_holders; }; // class sp_rcontext : public Sql_alloc #endif /* _SP_RCONTEXT_H_ */ server/private/sql_i_s.h000064400000020050151031265040011320 0ustar00#ifndef SQL_I_S_INCLUDED #define SQL_I_S_INCLUDED /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. Copyright (c) 2009, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "sql_const.h" // MAX_FIELD_VARCHARLENGTH #include "sql_basic_types.h" // enum_nullability #include "sql_string.h" // strlen, MY_CS_NAME_SIZE #include "lex_string.h" // LEX_CSTRING #include "mysql_com.h" // enum_field_types #include "my_time.h" // TIME_SECOND_PART_DIGITS #include "sql_type.h" // Type_handler_xxx struct TABLE_LIST; struct TABLE; typedef class Item COND; #ifdef MYSQL_CLIENT #error MYSQL_CLIENT must not be defined #endif // MYSQL_CLIENT bool schema_table_store_record(THD *thd, TABLE *table); COND *make_cond_for_info_schema(THD *thd, COND *cond, TABLE_LIST *table); enum enum_show_open_table { SKIP_OPEN_TABLE= 0U, // do not open table OPEN_FRM_ONLY= 1U, // open FRM file only OPEN_FULL_TABLE= 2U // open FRM,MYD, MYI files }; namespace Show { class Type { /** This denotes data type for the column. For the most part, there seems to be one entry in the enum for each SQL data type, although there seem to be a number of additional entries in the enum. */ const Type_handler *m_type_handler; /** For string-type columns, this is the maximum number of characters. Otherwise, it is the 'display-length' for the column. */ uint m_char_length; uint m_unsigned_flag; const Typelib *m_typelib; public: Type(const Type_handler *th, uint length, uint unsigned_flag, const Typelib *typelib= NULL) :m_type_handler(th), m_char_length(length), m_unsigned_flag(unsigned_flag), m_typelib(typelib) { } const Type_handler *type_handler() const { return m_type_handler; } uint char_length() const { return m_char_length; } decimal_digits_t decimal_precision() const { return (decimal_digits_t) ((m_char_length / 100) % 100); } decimal_digits_t decimal_scale() const { return (decimal_digits_t) (m_char_length % 10); } uint fsp() const { DBUG_ASSERT(m_char_length <= TIME_SECOND_PART_DIGITS); return m_char_length; } uint unsigned_flag() const { return m_unsigned_flag; } const Typelib *typelib() const { return m_typelib; } }; } // namespace Show class ST_FIELD_INFO: public Show::Type { protected: LEX_CSTRING m_name; // I_S column name enum_nullability m_nullability; // NULLABLE or NOT NULL LEX_CSTRING m_old_name; // SHOW column name enum_show_open_table m_open_method; public: ST_FIELD_INFO(const LEX_CSTRING &name, const Type &type, enum_nullability nullability, LEX_CSTRING &old_name, enum_show_open_table open_method) :Type(type), m_name(name), m_nullability(nullability), m_old_name(old_name), m_open_method(open_method) { } ST_FIELD_INFO(const char *name, const Type &type, enum_nullability nullability, const char *old_name, enum_show_open_table open_method) :Type(type), m_nullability(nullability), m_open_method(open_method) { m_name.str= name; m_name.length= safe_strlen(name); m_old_name.str= old_name; m_old_name.length= safe_strlen(old_name); } const LEX_CSTRING &name() const { return m_name; } bool nullable() const { return m_nullability == NULLABLE; } const LEX_CSTRING &old_name() const { return m_old_name; } enum_show_open_table open_method() const { return m_open_method; } bool end_marker() const { return m_name.str == NULL; } }; namespace Show { class Enum: public Type { public: Enum(const Typelib *typelib) :Type(&type_handler_enum, 0, false, typelib) { } }; class Blob: public Type { public: Blob(uint length) :Type(&type_handler_blob, length, false) { } }; class Varchar: public Type { public: Varchar(uint length) :Type(&type_handler_varchar, length, false) { DBUG_ASSERT(length * 3 <= MAX_FIELD_VARCHARLENGTH); } }; class Longtext: public Type { public: Longtext(uint length) :Type(&type_handler_varchar, length, false) { } }; class Yes_or_empty: public Varchar { public: Yes_or_empty(): Varchar(3) { } }; class Catalog: public Varchar { public: Catalog(): Varchar(FN_REFLEN) { } }; class Name: public Varchar { public: Name(): Varchar(NAME_CHAR_LEN) { } }; class Definer: public Varchar { public: Definer(): Varchar(DEFINER_CHAR_LENGTH) { } }; class Userhost: public Varchar { public: Userhost(): Varchar(USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 2) { } }; class CSName: public Varchar { public: CSName(): Varchar(MY_CS_NAME_SIZE) { } }; class SQLMode: public Varchar { public: SQLMode(): Varchar(32*256) { } }; class Datetime: public Type { public: Datetime(uint dec) :Type(&type_handler_datetime2, dec, false) { } }; class Decimal: public Type { public: Decimal(uint length) :Type(&type_handler_newdecimal, length, false) { } }; class ULonglong: public Type { public: ULonglong(uint length) :Type(&type_handler_ulonglong, length, true) { } ULonglong() :ULonglong(MY_INT64_NUM_DECIMAL_DIGITS) { } }; class ULong: public Type { public: ULong(uint length) :Type(&type_handler_ulong, length, true) { } ULong() :ULong(MY_INT32_NUM_DECIMAL_DIGITS) { } }; class SLonglong: public Type { public: SLonglong(uint length) :Type(&type_handler_slonglong, length, false) { } SLonglong() :SLonglong(MY_INT64_NUM_DECIMAL_DIGITS) { } }; class SLong: public Type { public: SLong(uint length) :Type(&type_handler_slong, length, false) { } SLong() :SLong(MY_INT32_NUM_DECIMAL_DIGITS) { } }; class SShort: public Type { public: SShort(uint length) :Type(&type_handler_sshort, length, false) { } }; class STiny: public Type { public: STiny(uint length) :Type(&type_handler_stiny, length, false) { } }; class Double: public Type { public: Double(uint length) :Type(&type_handler_double, length, false) { } }; class Float: public Type { public: Float(uint length) :Type(&type_handler_float, length, false) { } }; class Column: public ST_FIELD_INFO { public: Column(const char *name, const Type &type, enum_nullability nullability, const char *old_name, enum_show_open_table open_method= SKIP_OPEN_TABLE) :ST_FIELD_INFO(name, type, nullability, old_name, open_method) { } Column(const char *name, const Type &type, enum_nullability nullability, enum_show_open_table open_method= SKIP_OPEN_TABLE) :ST_FIELD_INFO(name, type, nullability, NullS, open_method) { } }; // End marker class CEnd: public Column { public: CEnd() :Column(NullS, Varchar(0), NOT_NULL, NullS, SKIP_OPEN_TABLE) { } }; } // namespace Show struct TABLE_LIST; typedef class Item COND; typedef struct st_schema_table { const char *table_name; ST_FIELD_INFO *fields_info; /* for FLUSH table_name */ int (*reset_table) (); /* Fill table with data */ int (*fill_table) (THD *thd, TABLE_LIST *tables, COND *cond); /* Handle fileds for old SHOW */ int (*old_format) (THD *thd, struct st_schema_table *schema_table); int (*process_table) (THD *thd, TABLE_LIST *tables, TABLE *table, bool res, const LEX_CSTRING *db_name, const LEX_CSTRING *table_name); int idx_field1, idx_field2; bool hidden; uint i_s_requested_object; /* the object we need to open(TABLE | VIEW) */ } ST_SCHEMA_TABLE; #endif // SQL_I_S_INCLUDED server/private/sql_type_geom.h000064400000045216151031265040012551 0ustar00#ifndef SQL_TYPE_GEOM_H_INCLUDED #define SQL_TYPE_GEOM_H_INCLUDED /* Copyright (c) 2015 MariaDB Foundation Copyright (c) 2019, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation #endif #include "mariadb.h" #include "sql_type.h" #ifdef HAVE_SPATIAL class Type_handler_geometry: public Type_handler_string_result { public: enum geometry_types { GEOM_GEOMETRY = 0, GEOM_POINT = 1, GEOM_LINESTRING = 2, GEOM_POLYGON = 3, GEOM_MULTIPOINT = 4, GEOM_MULTILINESTRING = 5, GEOM_MULTIPOLYGON = 6, GEOM_GEOMETRYCOLLECTION = 7 }; static bool check_type_geom_or_binary(const LEX_CSTRING &opname, const Item *item); static bool check_types_geom_or_binary(const LEX_CSTRING &opname, Item * const *args, uint start, uint end); static const Type_handler_geometry *type_handler_geom_by_type(uint type); LEX_CSTRING extended_metadata_data_type_name() const; public: virtual ~Type_handler_geometry() {} enum_field_types field_type() const override { return MYSQL_TYPE_GEOMETRY; } bool Item_append_extended_type_info(Send_field_extended_metadata *to, const Item *item) const override { LEX_CSTRING tmp= extended_metadata_data_type_name(); return tmp.length ? to->set_data_type_name(tmp) : false; } bool is_param_long_data_type() const override { return true; } uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override; const Type_collection *type_collection() const override; const Type_handler *type_handler_for_comparison() const override; virtual geometry_types geometry_type() const { return GEOM_GEOMETRY; } virtual Item *create_typecast_item(THD *thd, Item *item, const Type_cast_attributes &attr) const override; const Type_handler *type_handler_frm_unpack(const uchar *buffer) const override; bool is_binary_compatible_geom_super_type_for(const Type_handler_geometry *th) const { return geometry_type() == GEOM_GEOMETRY || geometry_type() == th->geometry_type(); } bool type_can_have_key_part() const override { return true; } bool subquery_type_allows_materialization(const Item *, const Item *, bool) const override { return false; // Materialization does not work with GEOMETRY columns } void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len) const override; bool Item_param_set_from_value(THD *thd, Item_param *param, const Type_all_attributes *attr, const st_value *value) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; Log_event_data_type user_var_log_event_data_type(uint charset_nr) const override { return Log_event_data_type(name().lex_cstring(), result_type(), charset_nr, false/*unsigned*/); } uint Column_definition_gis_options_image(uchar *buff, const Column_definition &def) const override; bool Column_definition_data_type_info_image(Binary_string *to, const Column_definition &def) const override { return false; } void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; bool Column_definition_attributes_frm_unpack(Column_definition_attributes *attr, TABLE_SHARE *share, const uchar *buffer, LEX_CUSTRING *gis_options) const override; bool Column_definition_fix_attributes(Column_definition *c) const override; void Column_definition_reuse_fix_attributes(THD *thd, Column_definition *c, const Field *field) const override; bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, Column_definition *c, handler *file, ulonglong table_flags, const Column_derived_attributes *derived_attr) const override; bool Column_definition_prepare_stage2(Column_definition *c, handler *file, ulonglong table_flags) const override; bool Key_part_spec_init_primary(Key_part_spec *part, const Column_definition &def, const handler *file) const override; bool Key_part_spec_init_unique(Key_part_spec *part, const Column_definition &def, const handler *file, bool *has_key_needed) const override; bool Key_part_spec_init_multiple(Key_part_spec *part, const Column_definition &def, const handler *file) const override; bool Key_part_spec_init_foreign(Key_part_spec *part, const Column_definition &def, const handler *file) const override; bool Key_part_spec_init_spatial(Key_part_spec *part, const Column_definition &def) const override; Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, const Record_addr &addr, const Type_all_attributes &attr, TABLE_SHARE *share) const override; Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, const Record_addr &addr, const Bit_addr &bit, const Column_definition_attributes *attr, uint32 flags) const override; bool can_return_int() const override { return false; } bool can_return_decimal() const override { return false; } bool can_return_real() const override { return false; } bool can_return_text() const override { return false; } bool can_return_date() const override { return false; } bool can_return_time() const override { return false; } bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *h, Type_all_attributes *attr, Item **items, uint nitems) const override; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override; bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const override; bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const override; bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const override; bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const override; bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const override; bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const override; bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const override; bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const override; bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *) const override; }; class Type_handler_point: public Type_handler_geometry { // Binary length of a POINT value: 4 byte SRID + 21 byte WKB POINT static uint octet_length() { return 25; } public: geometry_types geometry_type() const override { return GEOM_POINT; } Item *make_constructor_item(THD *thd, List *args) const override; bool Key_part_spec_init_primary(Key_part_spec *part, const Column_definition &def, const handler *file) const override; bool Key_part_spec_init_unique(Key_part_spec *part, const Column_definition &def, const handler *file, bool *has_key_needed) const override; bool Key_part_spec_init_multiple(Key_part_spec *part, const Column_definition &def, const handler *file) const override; bool Key_part_spec_init_foreign(Key_part_spec *part, const Column_definition &def, const handler *file) const override; }; class Type_handler_linestring: public Type_handler_geometry { public: geometry_types geometry_type() const override { return GEOM_LINESTRING; } Item *make_constructor_item(THD *thd, List *args) const override; }; class Type_handler_polygon: public Type_handler_geometry { public: geometry_types geometry_type() const override { return GEOM_POLYGON; } Item *make_constructor_item(THD *thd, List *args) const override; }; class Type_handler_multipoint: public Type_handler_geometry { public: geometry_types geometry_type() const override { return GEOM_MULTIPOINT; } Item *make_constructor_item(THD *thd, List *args) const override; }; class Type_handler_multilinestring: public Type_handler_geometry { public: geometry_types geometry_type() const override { return GEOM_MULTILINESTRING; } Item *make_constructor_item(THD *thd, List *args) const override; }; class Type_handler_multipolygon: public Type_handler_geometry { public: geometry_types geometry_type() const override { return GEOM_MULTIPOLYGON; } Item *make_constructor_item(THD *thd, List *args) const override; }; class Type_handler_geometrycollection: public Type_handler_geometry { public: geometry_types geometry_type() const override { return GEOM_GEOMETRYCOLLECTION; } Item *make_constructor_item(THD *thd, List *args) const override; }; extern Named_type_handler type_handler_geometry; extern Named_type_handler type_handler_point; extern Named_type_handler type_handler_linestring; extern Named_type_handler type_handler_polygon; extern Named_type_handler type_handler_multipoint; extern Named_type_handler type_handler_multilinestring; extern Named_type_handler type_handler_multipolygon; extern Named_type_handler type_handler_geometrycollection; class Type_collection_geometry: public Type_collection { const Type_handler *aggregate_common(const Type_handler *a, const Type_handler *b) const { if (a == b) return a; if (dynamic_cast(a) && dynamic_cast(b)) return &type_handler_geometry; return NULL; } const Type_handler *aggregate_if_null(const Type_handler *a, const Type_handler *b) const { return a == &type_handler_null ? b : b == &type_handler_null ? a : NULL; } const Type_handler *aggregate_if_long_blob(const Type_handler *a, const Type_handler *b) const { return a == &type_handler_long_blob ? &type_handler_long_blob : b == &type_handler_long_blob ? &type_handler_long_blob : NULL; } const Type_handler *aggregate_if_string(const Type_handler *a, const Type_handler *b) const; #ifndef DBUG_OFF bool init_aggregators(Type_handler_data *data, const Type_handler *geom) const; #endif public: bool init(Type_handler_data *data) override; const Type_handler *aggregate_for_result(const Type_handler *a, const Type_handler *b) const override; const Type_handler *aggregate_for_comparison(const Type_handler *a, const Type_handler *b) const override; const Type_handler *aggregate_for_min_max(const Type_handler *a, const Type_handler *b) const override; const Type_handler *aggregate_for_num_op(const Type_handler *a, const Type_handler *b) const override { return NULL; } }; extern Type_collection_geometry type_collection_geometry; const Type_handler * Type_collection_geometry_handler_by_name(const LEX_CSTRING &name); #include "field.h" class Field_geom :public Field_blob { const Type_handler_geometry *m_type_handler; public: uint srid; uint precision; enum storage_type { GEOM_STORAGE_WKB= 0, GEOM_STORAGE_BINARY= 1}; enum storage_type storage; Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, uint blob_pack_length, const Type_handler_geometry *gth, uint field_srid) :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share, blob_pack_length, &my_charset_bin), m_type_handler(gth) { srid= field_srid; } enum_conv_type rpl_conv_type_from(const Conv_source &source, const Relay_log_info *rli, const Conv_param ¶m) const override; enum ha_base_keytype key_type() const override { return HA_KEYTYPE_VARBINARY2; } const Type_handler *type_handler() const override { return m_type_handler; } const Type_handler_geometry *type_handler_geom() const { return m_type_handler; } void set_type_handler(const Type_handler_geometry *th) { m_type_handler= th; } enum_field_types type() const override { return MYSQL_TYPE_GEOMETRY; } enum_field_types real_type() const override { return MYSQL_TYPE_GEOMETRY; } Information_schema_character_attributes information_schema_character_attributes() const override { return Information_schema_character_attributes(); } void make_send_field(Send_field *to) override { Field_longstr::make_send_field(to); LEX_CSTRING tmp= m_type_handler->extended_metadata_data_type_name(); if (tmp.length) to->set_data_type_name(tmp); } Data_type_compatibility can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const override; void sql_type(String &str) const override; Copy_func *get_copy_func(const Field *from) const override { const Type_handler_geometry *fth= dynamic_cast(from->type_handler()); if (fth && m_type_handler->is_binary_compatible_geom_super_type_for(fth)) return get_identical_copy_func(); return do_conv_blob; } bool memcpy_field_possible(const Field *from) const override { const Type_handler_geometry *fth= dynamic_cast(from->type_handler()); return fth && m_type_handler->is_binary_compatible_geom_super_type_for(fth) && !table->copy_blobs; } bool is_equal(const Column_definition &new_field) const override; int store(const char *to, size_t length, CHARSET_INFO *charset) override; int store(double nr) override; int store(longlong nr, bool unsigned_val) override; int store_decimal(const my_decimal *) override; uint size_of() const override{ return sizeof(*this); } /** Key length is provided only to support hash joins. (compared byte for byte) Ex: SELECT .. FROM t1,t2 WHERE t1.field_geom1=t2.field_geom2. The comparison is not very relevant, as identical geometry might be represented differently, but we need to support it either way. */ uint32 key_length() const override{ return packlength; } uint get_key_image(uchar *buff,uint length, const uchar *ptr_arg, imagetype type_arg) const override; /** Non-nullable GEOMETRY types cannot have defaults, but the underlying blob must still be reset. */ int reset(void) override{ return Field_blob::reset() || !maybe_null(); } bool load_data_set_null(THD *thd) override; bool load_data_set_no_data(THD *thd, bool fixed_format) override; uint get_srid() const { return srid; } void print_key_value(String *out, uint32 length) override { out->append(STRING_WITH_LEN("unprintable_geometry_value")); } Binlog_type_info binlog_type_info() const override; }; #endif // HAVE_SPATIAL #endif // SQL_TYPE_GEOM_H_INCLUDED server/private/sql_expression_cache.h000064400000010407151031265040014075 0ustar00/* Copyright (c) 2010, 2011, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_EXPRESSION_CACHE_INCLUDED #define SQL_EXPRESSION_CACHE_INCLUDED #include "sql_select.h" /** Interface for expression cache @note Parameters of an expression cache interface are set on the creation of the cache. They are passed when a cache object of the implementation class is constructed. That's why they are not visible in this interface. */ extern ulong subquery_cache_miss, subquery_cache_hit; class Expression_cache :public Sql_alloc { public: enum result {ERROR, HIT, MISS}; Expression_cache()= default; virtual ~Expression_cache() = default; /** Shall check the presence of expression value in the cache for a given set of values of the expression parameters. Return the result of the expression if it's found in the cache. */ virtual result check_value(Item **value)= 0; /** Shall put the value of an expression for given set of its parameters into the expression cache */ virtual my_bool put_value(Item *value)= 0; /** Print cache parameters */ virtual void print(String *str, enum_query_type query_type)= 0; /** Is this cache initialized */ virtual bool is_inited()= 0; /** Initialize this cache */ virtual void init()= 0; /** Save this object's statistics into Expression_cache_tracker object */ virtual void update_tracker()= 0; }; struct st_table_ref; struct st_join_table; class Item_field; class Expression_cache_tracker :public Sql_alloc { public: enum expr_cache_state {UNINITED, STOPPED, OK}; Expression_cache_tracker(Expression_cache *c) : cache(c), hit(0), miss(0), state(UNINITED) {} private: // This can be NULL if the cache is already deleted Expression_cache *cache; public: ulong hit, miss; enum expr_cache_state state; static const char* state_str[3]; void set(ulong h, ulong m, enum expr_cache_state s) {hit= h; miss= m; state= s;} void detach_from_cache() { cache= NULL; } void fetch_current_stats() { if (cache) cache->update_tracker(); } }; /** Implementation of expression cache over a temporary table */ class Expression_cache_tmptable :public Expression_cache { public: Expression_cache_tmptable(THD *thd, List &dependants, Item *value); virtual ~Expression_cache_tmptable(); result check_value(Item **value) override; my_bool put_value(Item *value) override; void print(String *str, enum_query_type query_type) override; bool is_inited() override { return inited; }; void init() override; void set_tracker(Expression_cache_tracker *st) { tracker= st; update_tracker(); } void update_tracker() override { if (tracker) { tracker->set(hit, miss, (inited ? (cache_table ? Expression_cache_tracker::OK : Expression_cache_tracker::STOPPED) : Expression_cache_tracker::UNINITED)); } } private: void disable_cache(); /* tmp table parameters */ TMP_TABLE_PARAM cache_table_param; /* temporary table to store this cache */ TABLE *cache_table; /* Thread handle for the temporary table */ THD *table_thd; /* EXPALIN/ANALYZE statistics */ Expression_cache_tracker *tracker; /* TABLE_REF for index lookup */ struct st_table_ref ref; /* Cached result */ Item_field *cached_result; /* List of parameter items */ List &items; /* Value Item example */ Item *val; /* hit/miss counters */ ulong hit, miss; /* Set on if the object has been successfully initialized with init() */ bool inited; }; #endif /* SQL_EXPRESSION_CACHE_INCLUDED */ server/private/sql_digest.h000064400000007353151031265040012040 0ustar00/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_DIGEST_H #define SQL_DIGEST_H #include class String; #include "my_md5.h" #define MAX_DIGEST_STORAGE_SIZE (1024*1024) /** Structure to store token count/array for a statement on which digest is to be calculated. */ struct sql_digest_storage { bool m_full; uint m_byte_count; unsigned char m_md5[MD5_HASH_SIZE]; /** Character set number. */ uint m_charset_number; /** Token array. Token array is an array of bytes to store tokens received during parsing. Following is the way token array is formed. ... <non-id-token> <non-id-token> <id-token> <id_len> <id_text> ... For Example: SELECT * FROM T1; <SELECT_TOKEN> <*> <FROM_TOKEN> <ID_TOKEN> <2> <T1> @note Only the first @c m_byte_count bytes are initialized, out of @c m_token_array_length. */ unsigned char *m_token_array; /* Length of the token array to be considered for DIGEST_TEXT calculation. */ uint m_token_array_length; sql_digest_storage() { reset(NULL, 0); } inline void reset(unsigned char *token_array, size_t length) { m_token_array= token_array; m_token_array_length= (uint)length; reset(); } inline void reset() { m_full= false; m_byte_count= 0; m_charset_number= 0; memset(m_md5, 0, MD5_HASH_SIZE); } inline bool is_empty() { return (m_byte_count == 0); } inline void copy(const sql_digest_storage *from) { /* Keep in mind this is a dirty copy of something that may change, as the thread producing the digest is executing concurrently, without any lock enforced. */ uint byte_count_copy= m_token_array_length < from->m_byte_count ? m_token_array_length : from->m_byte_count; if (byte_count_copy > 0) { m_full= from->m_full; m_byte_count= byte_count_copy; m_charset_number= from->m_charset_number; memcpy(m_token_array, from->m_token_array, m_byte_count); memcpy(m_md5, from->m_md5, MD5_HASH_SIZE); } else { m_full= false; m_byte_count= 0; m_charset_number= 0; } } }; typedef struct sql_digest_storage sql_digest_storage; /** Compute a digest hash. @param digest_storage The digest @param [out] md5 The computed digest hash. This parameter is a buffer of size @c MD5_HASH_SIZE. */ void compute_digest_md5(const sql_digest_storage *digest_storage, unsigned char *md5); /** Compute a digest text. A 'digest text' is a textual representation of a query, where: - comments are removed, - non significant spaces are removed, - literal values are replaced with a special '?' marker, - lists of values are collapsed using a shorter notation @param digest_storage The digest @param [out] digest_text @param digest_text_length Size of @c digest_text. @param [out] truncated true if the text representation was truncated */ void compute_digest_text(const sql_digest_storage *digest_storage, String *digest_text); #endif server/private/wsrep_server_state.h000064400000004355151031265040013627 0ustar00/* Copyright 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WSREP_SERVER_STATE_H #define WSREP_SERVER_STATE_H /* wsrep-lib */ #include "wsrep/server_state.hpp" #include "wsrep/provider.hpp" /* implementation */ #include "wsrep_server_service.h" #include "wsrep_mutex.h" #include "wsrep_condition_variable.h" class Wsrep_server_state : public wsrep::server_state { public: static void init_once(const std::string& name, const std::string& incoming_address, const std::string& address, const std::string& working_dir, const wsrep::gtid& initial_position, int max_protocol_version); static void destroy(); static Wsrep_server_state& instance() { return *m_instance; } static bool is_inited() { return (m_instance != NULL); } static wsrep::provider& get_provider() { return instance().provider(); } static bool has_capability(int capability) { return (get_provider().capabilities() & capability); } static void handle_fatal_signal(); private: Wsrep_server_state(const std::string& name, const std::string& incoming_address, const std::string& address, const std::string& working_dir, const wsrep::gtid& initial_position, int max_protocol_version); ~Wsrep_server_state(); Wsrep_mutex m_mutex; Wsrep_condition_variable m_cond; Wsrep_server_service m_service; static Wsrep_server_state* m_instance; }; #endif // WSREP_SERVER_STATE_H server/private/rpl_injector.h000064400000022625151031265040012373 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef INJECTOR_H #define INJECTOR_H /* Pull in 'byte', 'my_off_t', and 'uint32' */ #include #include "rpl_constants.h" #include "table.h" /* TABLE */ /* Forward declarations */ class handler; class MYSQL_BIN_LOG; struct TABLE; /* Injector to inject rows into the MySQL server. The injector class is used to notify the MySQL server of new rows that have appeared outside of MySQL control. The original purpose of this is to allow clusters---which handle replication inside the cluster through other means---to insert new rows into binary log. Note, however, that the injector should be used whenever rows are altered in any manner that is outside of MySQL server visibility and which therefore are not seen by the MySQL server. */ class injector { public: /* Get an instance of the injector. DESCRIPTION The injector is a Singleton, so this static function return the available instance of the injector. RETURN VALUE A pointer to the available injector object. */ static injector *instance(); /* Delete the singleton instance (if allocated). Used during server shutdown. */ static void free_instance(); /* A transaction where rows can be added. DESCRIPTION The transaction class satisfy the **CopyConstructible** and **Assignable** requirements. Note that the transaction is *not* default constructible. */ class transaction { friend class injector; public: /* Convenience definitions */ typedef uchar* record_type; typedef uint32 server_id_type; /* Table reference. RESPONSIBILITY The class contains constructors to handle several forms of references to tables. The constructors can implicitly be used to construct references from, e.g., strings containing table names. EXAMPLE The class is intended to be used *by value*. Please, do not try to construct objects of this type using 'new'; instead construct an object, possibly a temporary object. For example: injector::transaction::table tbl(share->table, true); MY_BITMAP cols; my_bitmap_init(&cols, NULL, (i + 7) / 8, false); inj->write_row(::server_id, tbl, &cols, row_data); or MY_BITMAP cols; my_bitmap_init(&cols, NULL, (i + 7) / 8, false); inj->write_row(::server_id, injector::transaction::table(share->table, true), &cols, row_data); This will work, be more efficient, and have greater chance of inlining, not run the risk of losing pointers. COLLABORATION injector::transaction Provide a flexible interface to the representation of tables. */ class table { public: table(TABLE *table, bool is_transactional_arg) : m_table(table), m_is_transactional(is_transactional_arg) { } char const *db_name() const { return m_table->s->db.str; } char const *table_name() const { return m_table->s->table_name.str; } TABLE *get_table() const { return m_table; } bool is_transactional() const { return m_is_transactional; } private: TABLE *m_table; bool m_is_transactional; }; /* Binlog position as a structure. */ class binlog_pos { friend class transaction; public: char const *file_name() const { return m_file_name; } my_off_t file_pos() const { return m_file_pos; } private: char const *m_file_name; my_off_t m_file_pos; }; transaction() : m_thd(NULL) { } ~transaction(); /* Clear transaction, i.e., make calls to 'good()' return false. */ void clear() { m_thd= NULL; } /* Is the transaction in a good state? */ bool good() const { return m_thd != NULL; } /* Default assignment operator: standard implementation */ transaction& operator=(transaction t) { swap(t); return *this; } /* DESCRIPTION Register table for use within the transaction. All tables that are going to be used need to be registered before being used below. The member function will fail with an error if use_table() is called after any *_row() function has been called for the transaction. RETURN VALUE 0 All OK >0 Failure */ #ifdef TO_BE_DELETED int use_table(server_id_type sid, table tbl); #endif /* Commit a transaction. This member function will clean up after a sequence of *_row calls by, for example, releasing resource and unlocking files. */ int commit(); /* Get the position for the start of the transaction. Returns the position in the binary log of the first event in this transaction. If no event is yet written, the position where the event *will* be written is returned. This position is known, since a new_transaction() will lock the binary log and prevent any other writes to the binary log. */ binlog_pos start_pos() const; private: /* Only the injector may construct these object */ transaction(MYSQL_BIN_LOG *, THD *); void swap(transaction& o) { /* std::swap(m_start_pos, o.m_start_pos); */ { binlog_pos const tmp= m_start_pos; m_start_pos= o.m_start_pos; o.m_start_pos= tmp; } /* std::swap(m_thd, o.m_thd); */ { THD* const tmp= m_thd; m_thd= o.m_thd; o.m_thd= tmp; } { enum_state const tmp= m_state; m_state= o.m_state; o.m_state= tmp; } } enum enum_state { START_STATE, /* Start state */ TABLE_STATE, /* At least one table has been registered */ ROW_STATE, /* At least one row has been registered */ STATE_COUNT /* State count and sink state */ } m_state; /* Check and update the state. PARAMETER(S) target_state The state we are moving to: TABLE_STATE if we are writing a table and ROW_STATE if we are writing a row. DESCRIPTION The internal state will be updated to the target state if and only if it is a legal move. The only legal moves are: START_STATE -> START_STATE START_STATE -> TABLE_STATE TABLE_STATE -> TABLE_STATE TABLE_STATE -> ROW_STATE That is: - It is not possible to write any row before having written at least one table - It is not possible to write a table after at least one row has been written RETURN VALUE 0 All OK -1 Incorrect call sequence */ int check_state(enum_state const target_state) { #ifdef DBUG_TRACE static char const *state_name[] = { "START_STATE", "TABLE_STATE", "ROW_STATE", "STATE_COUNT" }; DBUG_PRINT("info", ("In state %s", state_name[m_state])); #endif DBUG_ASSERT(target_state <= STATE_COUNT); if (m_state <= target_state && target_state <= m_state + 1 && m_state < STATE_COUNT) m_state= target_state; else m_state= STATE_COUNT; return m_state == STATE_COUNT ? 1 : 0; } binlog_pos m_start_pos; THD *m_thd; }; /* Create a new transaction. This member function will prepare for a sequence of *_row calls by, for example, reserving resources and locking files. There are two overloaded alternatives: one returning a transaction by value and one using placement semantics. The following two calls are equivalent, with the exception that the latter will overwrite the transaction. injector::transaction trans1= inj->new_trans(thd); injector::transaction trans2; inj->new_trans(thd, &trans); */ transaction new_trans(THD *); void new_trans(THD *, transaction *); int record_incident(THD*, Incident incident); int record_incident(THD*, Incident incident, const LEX_CSTRING *message); private: explicit injector(); ~injector() = default; /* Nothing needs to be done */ injector(injector const&); /* You're not allowed to copy injector instances. */ }; #endif /* INJECTOR_H */ server/private/xa.h000064400000003465151031265040010312 0ustar00#ifndef XA_INCLUDED #define XA_INCLUDED /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2009, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ class XID_cache_element; enum xa_states { XA_ACTIVE= 0, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY, XA_NO_STATE }; struct XID_STATE { XID_cache_element *xid_cache_element; bool check_has_uncommitted_xa() const; bool is_explicit_XA() const { return xid_cache_element != 0; } void set_error(uint error); void set_rollback_only(); void er_xaer_rmfail() const; XID *get_xid() const; enum xa_states get_state_code() const; }; void xid_cache_init(void); void xid_cache_free(void); bool xid_cache_insert(XID *xid); bool xid_cache_insert(THD *thd, XID_STATE *xid_state, XID *xid); void xid_cache_delete(THD *thd, XID_STATE *xid_state); bool trans_xa_start(THD *thd); bool trans_xa_end(THD *thd); bool trans_xa_prepare(THD *thd); bool trans_xa_commit(THD *thd); bool trans_xa_rollback(THD *thd); bool trans_xa_detach(THD *thd); bool mysql_xa_recover(THD *thd); void xa_recover_get_fields(THD *thd, List *field_list, my_hash_walk_action *action); #endif /* XA_INCLUDED */ server/private/discover.h000064400000003042151031265040011507 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef DISCOVER_INCLUDED #define DISCOVER_INCLUDED int extension_based_table_discovery(MY_DIR *dirp, const char *ext, handlerton::discovered_list *tl); #ifdef MYSQL_SERVER int readfrm(const char *name, const uchar **data, size_t *length); int writefile(const char *path, const char *db, const char *table, bool tmp_table, const uchar *frmdata, size_t len); /* a helper to delete an frm file, given a path w/o .frm extension */ inline void deletefrm(const char *path) { char frm_name[FN_REFLEN]; strxnmov(frm_name, sizeof(frm_name)-1, path, reg_ext, NullS); mysql_file_delete(key_file_frm, frm_name, MYF(0)); } int ext_table_discovery_simple(MY_DIR *dirp, handlerton::discovered_list *result); #endif #endif /* DISCOVER_INCLUDED */ server/private/json_table.h000064400000022442151031265040012016 0ustar00#ifndef JSON_TABLE_INCLUDED #define JSON_TABLE_INCLUDED /* Copyright (c) 2020, MariaDB Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include class Json_table_column; /* The Json_table_nested_path represents the 'current nesting' level for a set of JSON_TABLE columns. Each column (Json_table_column instance) is linked with corresponding 'nested path' object and gets its piece of JSON to parse during the computation phase. The root 'nested_path' is always present as a part of Table_function_json_table, then other 'nested_paths' can be created and linked into a tree structure when new 'NESTED PATH' is met. The nested 'nested_paths' are linked with 'm_nested', the same-level 'nested_paths' are linked with 'm_next_nested'. So for instance JSON_TABLE( '...', '$[*]' COLUMNS( a INT PATH '$.a' , NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$', NESTED PATH '$.c[*]' COLUMNS(x INT PATH '$')), NESTED PATH '$.n[*]' COLUMNS (z INT PATH '$')) results in 4 'nested_path' created: root nested_b nested_c nested_n m_path '$[*]' '$.b[*]' '$.c[*]' '$.n[*] m_nested &nested_b &nested_c NULL NULL n_next_nested NULL &nested_n NULL NULL and 4 columns created: a b x z m_nest &root &nested_b &nested_c &nested_n */ class Json_table_nested_path : public Sql_alloc { public: json_path_t m_path; /* The JSON Path to get the rows from */ bool m_null; // TRUE <=> producing a NULL-complemented row. /*** Construction interface ***/ Json_table_nested_path(): m_null(TRUE), m_nested(NULL), m_next_nested(NULL) {} int set_path(THD *thd, const LEX_CSTRING &path); /*** Methods for performing a scan ***/ void scan_start(CHARSET_INFO *i_cs, const uchar *str, const uchar *end); int scan_next(); bool check_error(const char *str); /*** Members for getting the values we've scanned to ***/ const uchar *get_value() { return m_engine.value_begin; } const uchar *get_value_end() { return m_engine.s.str_end; } /* Counts the rows produced. Used by FOR ORDINALITY columns */ longlong m_ordinality_counter; int print(THD *thd, Field ***f, String *str, List_iterator_fast &it, Json_table_column **last_column); private: /* The head of the list of nested NESTED PATH statements. */ Json_table_nested_path *m_nested; /* in the above list items are linked with the */ Json_table_nested_path *m_next_nested; /*** Members describing NESTED PATH structure ***/ /* Parent nested path. The "root" path has this NULL */ Json_table_nested_path *m_parent; /*** Members describing current JSON Path scan state ***/ /* The JSON Parser and JSON Path evaluator */ json_engine_t m_engine; /* The path the parser is currently pointing to */ json_path_t m_cur_path; /* The child NESTED PATH we're currently scanning */ Json_table_nested_path *m_cur_nested; static bool column_in_this_or_nested(const Json_table_nested_path *p, const Json_table_column *jc); friend class Table_function_json_table; }; /* @brief Describes the column definition in JSON_TABLE(...) syntax. @detail Has methods for printing/handling errors but otherwise it's a static object. */ class Json_table_column : public Sql_alloc { public: enum enum_type { FOR_ORDINALITY, PATH, EXISTS_PATH }; enum enum_on_type { ON_EMPTY, ON_ERROR }; enum enum_on_response { RESPONSE_NOT_SPECIFIED, RESPONSE_ERROR, RESPONSE_NULL, RESPONSE_DEFAULT }; struct On_response { public: Json_table_column::enum_on_response m_response; Item *m_default; int respond(Json_table_column *jc, Field *f, uint error_num); int print(const char *name, String *str) const; bool specified() const { return m_response != RESPONSE_NOT_SPECIFIED; } }; enum_type m_column_type; bool m_format_json; json_path_t m_path; On_response m_on_error; On_response m_on_empty; Create_field *m_field; Json_table_nested_path *m_nest; CHARSET_INFO *m_explicit_cs; void set(enum_type ctype) { m_column_type= ctype; } int set(THD *thd, enum_type ctype, const LEX_CSTRING &path, CHARSET_INFO *cs); Json_table_column(Create_field *f, Json_table_nested_path *nest) : m_field(f), m_nest(nest), m_explicit_cs(NULL) { m_on_error.m_response= RESPONSE_NOT_SPECIFIED; m_on_empty.m_response= RESPONSE_NOT_SPECIFIED; } int print(THD *tnd, Field **f, String *str); }; /* Class represents the table function, the function that returns the table as a result so supposed to appear in the FROM list of the SELECT statement. At the moment there is only one such function JSON_TABLE, so the class named after it, but should be refactored into the hierarchy root if we create more of that functions. As the parser finds the table function in the list it creates an instance of Table_function_json_table storing it into the TABLE_LIST::table_function. Then the ha_json_table instance is created based on it in the create_table_for_function(). == Replication: whether JSON_TABLE is deterministic == In sql_yacc.yy, we set BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION whenever JSON_TABLE is used. The reasoning behind this is as follows: In the current MariaDB code, evaluation of JSON_TABLE is deterministic, that is, for a given input string JSON_TABLE will always produce the same set of rows in the same order. However one can think of JSON documents that one can consider indentical which will produce different output. In order to be feature-proof and withstand changes like: - sorting JSON object members by name (like MySQL does) - changing the way duplicate object members are handled we mark the function as SBR-unsafe. (If there is ever an issue with this, marking the function as SBR-safe is a non-intrusive change we will always be able to make) */ class Table_function_json_table : public Sql_alloc { public: /*** Basic properties of the original JSON_TABLE(...) ***/ Item *m_json; /* The JSON value to be parsed. */ /* The COLUMNS(...) part representation. */ Json_table_nested_path m_nested_path; /* The list of table column definitions. */ List m_columns; /*** Name resolution functions ***/ bool setup(THD *thd, TABLE_LIST *sql_table, SELECT_LEX *s_lex); int walk_items(Item_processor processor, bool walk_subquery, void *argument); /*** Functions for interaction with the Query Optimizer ***/ void fix_after_pullout(TABLE_LIST *sql_table, st_select_lex *new_parent, bool merge); void update_used_tables() { m_json->update_used_tables(); } table_map used_tables() const { return m_json->used_tables(); } bool join_cache_allowed() const { /* Can use join cache when we have an outside reference. If there's dependency on any other table or randomness, cannot use it. */ return !(used_tables() & ~OUTER_REF_TABLE_BIT); } void get_estimates(ha_rows *out_rows, double *scan_time, double *startup_cost); int print(THD *thd, TABLE_LIST *sql_table, String *str, enum_query_type query_type); /*** Construction interface to be used from the parser ***/ Table_function_json_table(Item *json): m_json(json), m_context_setup_done(false) { cur_parent= &m_nested_path; last_sibling_hook= &m_nested_path.m_nested; } void start_nested_path(Json_table_nested_path *np); void end_nested_path(); Json_table_nested_path *get_cur_nested_path() { return cur_parent; } void set_name_resolution_context(Name_resolution_context *arg) { m_context= arg; } /* SQL Parser: current column in JSON_TABLE (...) syntax */ Json_table_column *m_cur_json_table_column; private: /* Context to be used for resolving the first argument. */ Name_resolution_context *m_context; bool m_context_setup_done; /* Current NESTED PATH level being parsed */ Json_table_nested_path *cur_parent; /* Pointer to the list tail where we add the next NESTED PATH. It points to the cur_parnt->m_nested for the first nested and prev_nested->m_next_nested for the coesequent ones. */ Json_table_nested_path **last_sibling_hook; }; bool push_table_function_arg_context(LEX *lex, MEM_ROOT *alloc); TABLE *create_table_for_function(THD *thd, TABLE_LIST *sql_table); table_map add_table_function_dependencies(List *join_list, table_map nest_tables); #endif /* JSON_TABLE_INCLUDED */ server/private/my_minidump.h000064400000001520151031265040012217 0ustar00/* Copyright (c) 2021, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include #ifdef __cplusplus extern "C" { #endif BOOL my_create_minidump(DWORD pid, BOOL verbose); #ifdef __cplusplus } #endif server/private/item.h000064400001041326151031265040010637 0ustar00#ifndef SQL_ITEM_INCLUDED #define SQL_ITEM_INCLUDED /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. Copyright (c) 2009, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_priv.h" /* STRING_BUFFER_USUAL_SIZE */ #include "unireg.h" #include "sql_const.h" /* RAND_TABLE_BIT, MAX_FIELD_NAME */ #include "field.h" /* Derivation */ #include "sql_type.h" #include "sql_time.h" #include "sql_schema.h" #include "mem_root_array.h" #include #include "cset_narrowing.h" C_MODE_START #include /* A prototype for a C-compatible structure to store a value of any data type. Currently it has to stay in /sql, as it depends on String and my_decimal. We'll do the following changes: 1. add pure C "struct st_string" and "struct st_my_decimal" 2. change type of m_string to struct st_string and move inside the union 3. change type of m_decmal to struct st_my_decimal and move inside the union 4. move the definition to some file in /include */ class st_value { public: st_value() {} st_value(char *buffer, size_t buffer_size) : m_string(buffer, buffer_size, &my_charset_bin) {} enum enum_dynamic_column_type m_type; union { longlong m_longlong; double m_double; MYSQL_TIME m_time; } value; String m_string; my_decimal m_decimal; }; C_MODE_END class Value: public st_value { public: Value(char *buffer, size_t buffer_size) : st_value(buffer, buffer_size) {} Value() {} bool is_null() const { return m_type == DYN_COL_NULL; } bool is_longlong() const { return m_type == DYN_COL_UINT || m_type == DYN_COL_INT; } bool is_double() const { return m_type == DYN_COL_DOUBLE; } bool is_temporal() const { return m_type == DYN_COL_DATETIME; } bool is_string() const { return m_type == DYN_COL_STRING; } bool is_decimal() const { return m_type == DYN_COL_DECIMAL; } }; template class ValueBuffer: public Value { char buffer[buffer_size]; public: ValueBuffer(): Value(buffer, buffer_size) {} void reset_buffer() { m_string.set_buffer_if_not_allocated(buffer, buffer_size, &my_charset_bin); } }; #ifdef DBUG_OFF static inline const char *dbug_print_item(Item *item) { return NULL; } #else const char *dbug_print_item(Item *item); #endif class Virtual_tmp_table; class sp_head; class Protocol; struct TABLE_LIST; void item_init(void); /* Init item functions */ class Item_basic_value; class Item_result_field; class Item_field; class Item_ref; class Item_param; class user_var_entry; class JOIN; struct KEY_FIELD; struct SARGABLE_PARAM; class RANGE_OPT_PARAM; class SEL_TREE; enum precedence { LOWEST_PRECEDENCE, ASSIGN_PRECEDENCE, // := OR_PRECEDENCE, // OR, || (unless PIPES_AS_CONCAT) XOR_PRECEDENCE, // XOR AND_PRECEDENCE, // AND, && NOT_PRECEDENCE, // NOT (unless HIGH_NOT_PRECEDENCE) CMP_PRECEDENCE, // =, <=>, >=, >, <=, <, <>, !=, IS BETWEEN_PRECEDENCE, // BETWEEN IN_PRECEDENCE, // IN, LIKE, REGEXP BITOR_PRECEDENCE, // | BITAND_PRECEDENCE, // & SHIFT_PRECEDENCE, // <<, >> INTERVAL_PRECEDENCE, // first argument in +INTERVAL ADD_PRECEDENCE, // +, - MUL_PRECEDENCE, // *, /, DIV, %, MOD BITXOR_PRECEDENCE, // ^ PIPES_PRECEDENCE, // || (if PIPES_AS_CONCAT) NEG_PRECEDENCE, // unary -, ~, !, NOT (if HIGH_NOT_PRECEDENCE) COLLATE_PRECEDENCE, // BINARY, COLLATE DEFAULT_PRECEDENCE, HIGHEST_PRECEDENCE }; bool mark_unsupported_function(const char *where, void *store, uint result); /* convenience helper for mark_unsupported_function() above */ bool mark_unsupported_function(const char *w1, const char *w2, void *store, uint result); /* Bits for the split_sum_func() function */ #define SPLIT_SUM_SKIP_REGISTERED 1 /* Skip registered funcs */ #define SPLIT_SUM_SELECT 2 /* SELECT item; Split all parts */ /* Values for item->marker for cond items in the WHERE clause as used by the optimizer. Note that for Item_fields, the marker contains 'select->cur_pos_in_select_list */ /* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */ #define MARKER_UNDEF_POS -1 #define MARKER_UNUSED 0 #define MARKER_CHANGE_COND 1 #define MARKER_PROCESSED 2 #define MARKER_CHECK_ON_READ 3 #define MARKER_NULL_KEY 4 #define MARKER_FOUND_IN_ORDER 6 /* Used as bits in marker by Item::check_pushable_cond() */ #define MARKER_NO_EXTRACTION (1 << 6) #define MARKER_FULL_EXTRACTION (1 << 7) #define MARKER_DELETION (1 << 8) #define MARKER_IMMUTABLE (1 << 9) #define MARKER_SUBSTITUTION (1 << 10) /* Used as bits in marker by window functions */ #define MARKER_SORTORDER_CHANGE (1 << 11) #define MARKER_PARTITION_CHANGE (1 << 12) #define MARKER_FRAME_CHANGE (1 << 13) #define MARKER_EXTRACTION_MASK \ (MARKER_NO_EXTRACTION | MARKER_FULL_EXTRACTION | MARKER_DELETION | \ MARKER_IMMUTABLE) extern const char *item_empty_name; void dummy_error_processor(THD *thd, void *data); void view_error_processor(THD *thd, void *data); typedef List* ignored_tables_list_t; bool ignored_list_includes_table(ignored_tables_list_t list, TABLE_LIST *tbl); /* Instances of Name_resolution_context store the information necessary for name resolution of Items and other context analysis of a query made in fix_fields(). This structure is a part of SELECT_LEX, a pointer to this structure is assigned when an item is created (which happens mostly during parsing (sql_yacc.yy)), but the structure itself will be initialized after parsing is complete TODO: move subquery of INSERT ... SELECT and CREATE ... SELECT to separate SELECT_LEX which allow to remove tricks of changing this structure before and after INSERT/CREATE and its SELECT to make correct field name resolution. */ struct Name_resolution_context: Sql_alloc { /* The name resolution context to search in when an Item cannot be resolved in this context (the context of an outer select) */ Name_resolution_context *outer_context= nullptr; /* List of tables used to resolve the items of this context. Usually these are tables from the FROM clause of SELECT statement. The exceptions are INSERT ... SELECT and CREATE ... SELECT statements, where SELECT subquery is not moved to a separate SELECT_LEX. For these types of statements we have to change this member dynamically to ensure correct name resolution of different parts of the statement. */ TABLE_LIST *table_list= nullptr; /* In most cases the two table references below replace 'table_list' above for the purpose of name resolution. The first and last name resolution table references allow us to search only in a sub-tree of the nested join tree in a FROM clause. This is needed for NATURAL JOIN, JOIN ... USING and JOIN ... ON. */ TABLE_LIST *first_name_resolution_table= nullptr; /* Last table to search in the list of leaf table references that begins with first_name_resolution_table. */ TABLE_LIST *last_name_resolution_table= nullptr; /* Cache first_name_resolution_table in setup_natural_join_row_types */ TABLE_LIST *natural_join_first_table= nullptr; /* SELECT_LEX item belong to, in case of merged VIEW it can differ from SELECT_LEX where item was created, so we can't use table_list/field_list from there */ st_select_lex *select_lex= nullptr; /* Processor of errors caused during Item name resolving, now used only to hide underlying tables in errors about views (i.e. it substitute some errors for views) */ void (*error_processor)(THD *, void *)= &dummy_error_processor; void *error_processor_data= nullptr; /* When TRUE items are resolved in this context both against the SELECT list and this->table_list. If FALSE, items are resolved only against this->table_list. */ bool resolve_in_select_list= false; /* Bitmap of tables that should be ignored when doing name resolution. Normally it is {0}. Non-zero values are used by table functions. */ ignored_tables_list_t ignored_tables= nullptr; /* Security context of this name resolution context. It's used for views and is non-zero only if the view is defined with SQL SECURITY DEFINER. */ Security_context *security_ctx= nullptr; Name_resolution_context() = default; /** Name resolution context with resolution in only one table */ Name_resolution_context(TABLE_LIST *table) : first_name_resolution_table(table), last_name_resolution_table(table) {} void init() { resolve_in_select_list= FALSE; error_processor= &dummy_error_processor; ignored_tables= nullptr; first_name_resolution_table= nullptr; last_name_resolution_table= nullptr; } void resolve_in_table_list_only(TABLE_LIST *tables) { table_list= first_name_resolution_table= tables; resolve_in_select_list= FALSE; } void process_error(THD *thd) { (*error_processor)(thd, error_processor_data); } st_select_lex *outer_select() { return (outer_context ? outer_context->select_lex : NULL); } }; /* Store and restore the current state of a name resolution context. */ class Name_resolution_context_state { private: TABLE_LIST *save_table_list; TABLE_LIST *save_first_name_resolution_table; TABLE_LIST *save_next_name_resolution_table; bool save_resolve_in_select_list; TABLE_LIST *save_next_local; public: Name_resolution_context_state() = default; /* Remove gcc warning */ public: /* Save the state of a name resolution context. */ void save_state(Name_resolution_context *context, TABLE_LIST *table_list) { save_table_list= context->table_list; save_first_name_resolution_table= context->first_name_resolution_table; save_resolve_in_select_list= context->resolve_in_select_list; save_next_local= table_list->next_local; save_next_name_resolution_table= table_list->next_name_resolution_table; } /* Restore a name resolution context from saved state. */ void restore_state(Name_resolution_context *context, TABLE_LIST *table_list) { table_list->next_local= save_next_local; table_list->next_name_resolution_table= save_next_name_resolution_table; context->table_list= save_table_list; context->first_name_resolution_table= save_first_name_resolution_table; context->resolve_in_select_list= save_resolve_in_select_list; } TABLE_LIST *get_first_name_resolution_table() { return save_first_name_resolution_table; } }; class Name_resolution_context_backup { Name_resolution_context &ctx; TABLE_LIST &table_list; table_map save_map; Name_resolution_context_state ctx_state; public: Name_resolution_context_backup(Name_resolution_context &_ctx, TABLE_LIST &_table_list) : ctx(_ctx), table_list(_table_list), save_map(_table_list.map) { ctx_state.save_state(&ctx, &table_list); ctx.table_list= &table_list; ctx.first_name_resolution_table= &table_list; } ~Name_resolution_context_backup() { ctx_state.restore_state(&ctx, &table_list); table_list.map= save_map; } }; /* This enum is used to report information about monotonicity of function represented by Item* tree. Monotonicity is defined only for Item* trees that represent table partitioning expressions (i.e. have no subselects/user vars/PS parameters etc etc). An Item* tree is assumed to have the same monotonicity properties as its corresponding function F: [signed] longlong F(field1, field2, ...) { put values of field_i into table record buffer; return item->val_int(); } NOTE At the moment function monotonicity is not well defined (and so may be incorrect) for Item trees with parameters/return types that are different from INT_RESULT, may be NULL, or are unsigned. It will be possible to address this issue once the related partitioning bugs (BUG#16002, BUG#15447, BUG#13436) are fixed. The NOT_NULL enums are used in TO_DAYS, since TO_DAYS('2001-00-00') returns NULL which puts those rows into the NULL partition, but '2000-12-31' < '2001-00-00' < '2001-01-01'. So special handling is needed for this (see Bug#20577). */ typedef enum monotonicity_info { NON_MONOTONIC, /* none of the below holds */ MONOTONIC_INCREASING, /* F() is unary and (x < y) => (F(x) <= F(y)) */ MONOTONIC_INCREASING_NOT_NULL, /* But only for valid/real x and y */ MONOTONIC_STRICT_INCREASING,/* F() is unary and (x < y) => (F(x) < F(y)) */ MONOTONIC_STRICT_INCREASING_NOT_NULL /* But only for valid/real x and y */ } enum_monotonicity_info; /*************************************************************************/ class sp_rcontext; /** A helper class to collect different behavior of various kinds of SP variables: - local SP variables and SP parameters - PACKAGE BODY routine variables - (there will be more kinds in the future) */ class Sp_rcontext_handler { public: virtual ~Sp_rcontext_handler() = default; /** A prefix used for SP variable names in queries: - EXPLAIN EXTENDED - SHOW PROCEDURE CODE Local variables and SP parameters have empty prefixes. Package body variables are marked with a special prefix. This improves readability of the output of these queries, especially when a local variable or a parameter has the same name with a package body variable. */ virtual const LEX_CSTRING *get_name_prefix() const= 0; /** At execution time THD->spcont points to the run-time context (sp_rcontext) of the currently executed routine. Local variables store their data in the sp_rcontext pointed by thd->spcont. Package body variables store data in separate sp_rcontext that belongs to the package. This method provides access to the proper sp_rcontext structure, depending on the SP variable kind. */ virtual sp_rcontext *get_rcontext(sp_rcontext *ctx) const= 0; }; class Sp_rcontext_handler_local: public Sp_rcontext_handler { public: const LEX_CSTRING *get_name_prefix() const override; sp_rcontext *get_rcontext(sp_rcontext *ctx) const override; }; class Sp_rcontext_handler_package_body: public Sp_rcontext_handler { public: const LEX_CSTRING *get_name_prefix() const override; sp_rcontext *get_rcontext(sp_rcontext *ctx) const override; }; extern MYSQL_PLUGIN_IMPORT Sp_rcontext_handler_local sp_rcontext_handler_local; extern MYSQL_PLUGIN_IMPORT Sp_rcontext_handler_package_body sp_rcontext_handler_package_body; class Item_equal; struct st_join_table* const NO_PARTICULAR_TAB= (struct st_join_table*)0x1; typedef struct replace_equal_field_arg { Item_equal *item_equal; struct st_join_table *context_tab; } REPLACE_EQUAL_FIELD_ARG; class Settable_routine_parameter { public: /* Set required privileges for accessing the parameter. SYNOPSIS set_required_privilege() rw if 'rw' is true then we are going to read and set the parameter, so SELECT and UPDATE privileges might be required, otherwise we only reading it and SELECT privilege might be required. */ Settable_routine_parameter() = default; virtual ~Settable_routine_parameter() = default; virtual void set_required_privilege(bool rw) {}; /* Set parameter value. SYNOPSIS set_value() thd thread handle ctx context to which parameter belongs (if it is local variable). it item which represents new value RETURN FALSE if parameter value has been set, TRUE if error has occurred. */ virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it)= 0; virtual void set_out_param_info(Send_field *info) {} virtual const Send_field *get_out_param_info() const { return NULL; } virtual Item_param *get_item_param() { return 0; } }; /* A helper class to calculate offset and length of a query fragment - outside of SP - inside an SP - inside a compound block */ class Query_fragment { uint m_pos; uint m_length; void set(size_t pos, size_t length) { DBUG_ASSERT(pos < UINT_MAX32); DBUG_ASSERT(length < UINT_MAX32); m_pos= (uint) pos; m_length= (uint) length; } public: Query_fragment(THD *thd, sp_head *sphead, const char *start, const char *end); uint pos() const { return m_pos; } uint length() const { return m_length; } }; /** This is used for items in the query that needs to be rewritten before binlogging At the moment this applies to Item_param and Item_splocal */ class Rewritable_query_parameter { public: /* Offset inside the query text. Value of 0 means that this object doesn't have to be replaced (for example SP variables in control statements) */ my_ptrdiff_t pos_in_query; /* Byte length of parameter name in the statement. This is not Item::name.length because name.length contains byte length of UTF8-encoded name, but the query string is in the client charset. */ uint len_in_query; bool limit_clause_param; Rewritable_query_parameter(uint pos_in_q= 0, uint len_in_q= 0) : pos_in_query(pos_in_q), len_in_query(len_in_q), limit_clause_param(false) { } virtual ~Rewritable_query_parameter() = default; virtual bool append_for_log(THD *thd, String *str) = 0; }; class Copy_query_with_rewrite { THD *thd; const char *src; size_t src_len, from; String *dst; bool copy_up_to(size_t bytes) { DBUG_ASSERT(bytes >= from); return dst->append(src + from, uint32(bytes - from)); } public: Copy_query_with_rewrite(THD *t, const char *s, size_t l, String *d) :thd(t), src(s), src_len(l), from(0), dst(d) { } bool append(Rewritable_query_parameter *p) { if (copy_up_to(p->pos_in_query) || p->append_for_log(thd, dst)) return true; from= p->pos_in_query + p->len_in_query; return false; } bool finalize() { return copy_up_to(src_len); } }; struct st_dyncall_create_def { Item *key, *value; CHARSET_INFO *cs; uint len, frac; DYNAMIC_COLUMN_TYPE type; }; typedef struct st_dyncall_create_def DYNCALL_CREATE_DEF; typedef bool (Item::*Item_processor) (void *arg); /* Analyzer function SYNOPSIS argp in/out IN: Analysis parameter OUT: Parameter to be passed to the transformer RETURN TRUE Invoke the transformer FALSE Don't do it */ typedef bool (Item::*Item_analyzer) (uchar **argp); typedef Item* (Item::*Item_transformer) (THD *thd, uchar *arg); typedef void (*Cond_traverser) (const Item *item, void *arg); typedef bool (Item::*Pushdown_checker) (uchar *arg); struct st_cond_statistic; struct find_selective_predicates_list_processor_data { TABLE *table; List list; }; class MY_LOCALE; class Item_equal; class COND_EQUAL; class st_select_lex_unit; class Item_func_not; class Item_splocal; /** String_copier that sends Item specific warnings. */ class String_copier_for_item: public String_copier { THD *m_thd; public: bool copy_with_warn(CHARSET_INFO *dstcs, String *dst, CHARSET_INFO *srccs, const char *src, uint32 src_length, uint32 nchars); String_copier_for_item(THD *thd): m_thd(thd) { } }; /** A helper class describing what kind of Item created a temporary field. - If m_field is set, then the temporary field was created from Field (e.g. when the Item was Item_field, or Item_ref pointing to Item_field) - If m_default_field is set, then there is a usable DEFAULT value. (e.g. when the Item is Item_field) - If m_item_result_field is set, then the temporary field was created from certain sub-types of Item_result_field (e.g. Item_func) See create_tmp_field() in sql_select.cc for details. */ class Tmp_field_src { Field *m_field; Field *m_default_field; Item_result_field *m_item_result_field; public: Tmp_field_src() :m_field(0), m_default_field(0), m_item_result_field(0) { } Field *field() const { return m_field; } Field *default_field() const { return m_default_field; } Item_result_field *item_result_field() const { return m_item_result_field; } void set_field(Field *field) { m_field= field; } void set_default_field(Field *field) { m_default_field= field; } void set_item_result_field(Item_result_field *item) { m_item_result_field= item; } }; /** Parameters for create_tmp_field_ex(). See create_tmp_field() in sql_select.cc for details. */ class Tmp_field_param { bool m_group; bool m_modify_item; bool m_table_cant_handle_bit_fields; bool m_make_copy_field; public: Tmp_field_param(bool group, bool modify_item, bool table_cant_handle_bit_fields, bool make_copy_field) :m_group(group), m_modify_item(modify_item), m_table_cant_handle_bit_fields(table_cant_handle_bit_fields), m_make_copy_field(make_copy_field) { } bool group() const { return m_group; } bool modify_item() const { return m_modify_item; } bool table_cant_handle_bit_fields() const { return m_table_cant_handle_bit_fields; } bool make_copy_field() const { return m_make_copy_field; } void set_modify_item(bool to) { m_modify_item= to; } }; class Item_const { public: virtual ~Item_const() = default; virtual const Type_all_attributes *get_type_all_attributes_from_const() const= 0; virtual bool const_is_null() const { return false; } virtual const longlong *const_ptr_longlong() const { return NULL; } virtual const double *const_ptr_double() const { return NULL; } virtual const my_decimal *const_ptr_my_decimal() const { return NULL; } virtual const MYSQL_TIME *const_ptr_mysql_time() const { return NULL; } virtual const String *const_ptr_string() const { return NULL; } }; struct subselect_table_finder_param { THD *thd; /* We're searching for different TABLE_LIST objects referring to the same table as this one */ const TABLE_LIST *find; /* NUL - not found, ERROR_TABLE - search error, or the found table reference */ TABLE_LIST *dup; }; /****************************************************************************/ #define STOP_PTR ((void *) 1) /* Base flags (including IN) for an item */ typedef uint8 item_flags_t; enum class item_base_t : item_flags_t { NONE= 0, #define ITEM_FLAGS_MAYBE_NULL_SHIFT 0 // Must match MAYBE_NULL MAYBE_NULL= (1<<0), // May be NULL. IN_ROLLUP= (1<<1), // Appears in GROUP BY list // of a query with ROLLUP. FIXED= (1<<2), // Was fixed with fix_fields(). IS_EXPLICIT_NAME= (1<<3), // The name of this Item was set by the user // (or was auto generated otherwise) IS_IN_WITH_CYCLE= (1<<4), // This item is in CYCLE clause // of WITH. IS_COND= (1<<5) // The item is used as . // Must be evaluated using val_bool(). // Note, not all items used as a search // condition set this flag yet. }; /* Flags that tells us what kind of items the item contains */ enum class item_with_t : item_flags_t { NONE= 0, SP_VAR= (1<<0), // If Item contains a stored procedure variable WINDOW_FUNC= (1<<1), // If item contains a window func FIELD= (1<<2), // If any item except Item_sum contains a field. SUM_FUNC= (1<<3), // If item contains a sum func SUBQUERY= (1<<4), // If item containts a sub query ROWNUM_FUNC= (1<<5), // If ROWNUM function was used PARAM= (1<<6) // If user parameter was used }; /* Make operations in item_base_t and item_with_t work like 'int' */ static inline item_base_t operator&(const item_base_t a, const item_base_t b) { return (item_base_t) (((item_flags_t) a) & ((item_flags_t) b)); } static inline item_base_t & operator&=(item_base_t &a, item_base_t b) { a= (item_base_t) (((item_flags_t) a) & (item_flags_t) b); return a; } static inline item_base_t operator|(const item_base_t a, const item_base_t b) { return (item_base_t) (((item_flags_t) a) | ((item_flags_t) b)); } static inline item_base_t & operator|=(item_base_t &a, item_base_t b) { a= (item_base_t) (((item_flags_t) a) | (item_flags_t) b); return a; } static inline item_base_t operator~(const item_base_t a) { return (item_base_t) ~(item_flags_t) a; } static inline item_with_t operator&(const item_with_t a, const item_with_t b) { return (item_with_t) (((item_flags_t) a) & ((item_flags_t) b)); } static inline item_with_t & operator&=(item_with_t &a, item_with_t b) { a= (item_with_t) (((item_flags_t) a) & (item_flags_t) b); return a; } static inline item_with_t operator|(const item_with_t a, const item_with_t b) { return (item_with_t) (((item_flags_t) a) | ((item_flags_t) b)); } static inline item_with_t & operator|=(item_with_t &a, item_with_t b) { a= (item_with_t) (((item_flags_t) a) | (item_flags_t) b); return a; } static inline item_with_t operator~(const item_with_t a) { return (item_with_t) ~(item_flags_t) a; } class Item :public Value_source, public Type_all_attributes { static void *operator new(size_t size); public: static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return alloc_root(mem_root, size); } static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, WINDOW_FUNC_ITEM, /* NOT NULL literal-alike constants, which do not change their value during an SQL statement execution, but can optionally change their value between statements: - Item_literal - real NOT NULL constants - Item_param - can change between statements - Item_splocal - can change between statements - Item_user_var_as_out_param - hack Note, Item_user_var_as_out_param actually abuses the type code. It should be moved out of the Item tree eventually. */ CONST_ITEM, NULL_ITEM, // Item_null or Item_param bound to NULL COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM, CONTEXTUALLY_TYPED_VALUE_ITEM, PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, PARAM_ITEM, TRIGGER_FIELD_ITEM, EXPR_CACHE_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; enum traverse_order { POSTFIX, PREFIX }; protected: SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param); /** Create a field based on the exact data type handler. */ Field *create_table_field_from_handler(MEM_ROOT *root, TABLE *table) { const Type_handler *h= type_handler(); return h->make_and_init_table_field(root, &name, Record_addr(maybe_null()), *this, table); } /** Create a field based on field_type of argument. This is used to create a field for - IFNULL(x,something) - time functions - prepared statement placeholders - SP variables with data type references: DECLARE a TYPE OF t1.a; @retval NULL error @retval !NULL on success */ Field *tmp_table_field_from_field_type(MEM_ROOT *root, TABLE *table) { DBUG_ASSERT(fixed()); const Type_handler *h= type_handler()->type_handler_for_tmp_table(this); return h->make_and_init_table_field(root, &name, Record_addr(maybe_null()), *this, table); } /** Create a temporary field for a simple Item, which does not need any special action after the field creation: - is not an Item_field descendant (and not a reference to Item_field) - is not an Item_result_field descendant - does not need to copy any DEFAULT value to the result Field - does not need to set Field::is_created_from_null_item for the result See create_tmp_field_ex() for details on parameters and return values. */ Field *create_tmp_field_ex_simple(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) { DBUG_ASSERT(!param->make_copy_field()); DBUG_ASSERT(!is_result_field()); DBUG_ASSERT(type() != NULL_ITEM); return tmp_table_field_from_field_type(root, table); } Field *create_tmp_field_int(MEM_ROOT *root, TABLE *table, uint convert_int_length); Field *tmp_table_field_from_field_type_maybe_null(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param, bool is_explicit_null); virtual void raise_error_not_evaluable(); void push_note_converted_to_negative_complement(THD *thd); void push_note_converted_to_positive_complement(THD *thd); /* Helper methods, to get an Item value from another Item */ double val_real_from_item(Item *item) { DBUG_ASSERT(fixed()); double value= item->val_real(); null_value= item->null_value; return value; } longlong val_int_from_item(Item *item) { DBUG_ASSERT(fixed()); longlong value= item->val_int(); null_value= item->null_value; return value; } String *val_str_from_item(Item *item, String *str) { DBUG_ASSERT(fixed()); String *res= item->val_str(str); if (res) res->set_charset(collation.collation); if ((null_value= item->null_value)) res= NULL; return res; } bool val_native_from_item(THD *thd, Item *item, Native *to) { DBUG_ASSERT(fixed()); null_value= item->val_native(thd, to); DBUG_ASSERT(null_value == item->null_value); return null_value; } bool val_native_from_field(Field *field, Native *to) { if ((null_value= field->is_null())) return true; return (null_value= field->val_native(to)); } bool val_native_with_conversion_from_item(THD *thd, Item *item, Native *to, const Type_handler *handler) { DBUG_ASSERT(fixed()); return (null_value= item->val_native_with_conversion(thd, to, handler)); } my_decimal *val_decimal_from_item(Item *item, my_decimal *decimal_value) { DBUG_ASSERT(fixed()); my_decimal *value= item->val_decimal(decimal_value); if ((null_value= item->null_value)) value= NULL; return value; } bool get_date_from_item(THD *thd, Item *item, MYSQL_TIME *ltime, date_mode_t fuzzydate) { bool rc= item->get_date(thd, ltime, fuzzydate); null_value= MY_TEST(rc || item->null_value); return rc; } public: /* Cache val_str() into the own buffer, e.g. to evaluate constant expressions with subqueries in the ORDER/GROUP clauses. */ String *val_str() { return val_str(&str_value); } String *val_str_null_to_empty(String *to) { String *res= val_str(to); if (res) return res; to->set_charset(collation.collation); to->length(0); return to; } String *val_str_null_to_empty(String *to, bool null_to_empty) { return null_to_empty ? val_str_null_to_empty(to) : val_str(to); } virtual Item_func *get_item_func() { return NULL; } const MY_LOCALE *locale_from_val_str(); /* All variables for the Item class */ /** Intrusive list pointer for free list. If not null, points to the next Item on some Query_arena's free list. For instance, stored procedures have their own Query_arena's. @see Query_arena::free_list */ Item *next; /* str_values's main purpose is to be used to cache the value in save_in_field. Calling full_name() for Item_field will also use str_value. */ String str_value; LEX_CSTRING name; /* Name of item */ /* Original item name (if it was renamed)*/ const char *orig_name; /* All common bool variables for an Item is stored here */ item_base_t base_flags; item_with_t with_flags; /* Marker is used in some functions to temporary mark an item */ int16 marker; /* Tells is the val() value of the item is/was null. This should not be part of the bit flags as it's changed a lot and also we use pointers to it */ bool null_value; /* Cache of the result of is_expensive(). */ int8 is_expensive_cache; /** The index in the JOIN::join_tab array of the JOIN_TAB this Item is attached to. Items are attached (or 'pushed') to JOIN_TABs during optimization by the make_cond_for_table procedure. During query execution, this item is evaluated when the join loop reaches the corresponding JOIN_TAB. If the value of join_tab_idx >= MAX_TABLES, this means that there is no corresponding JOIN_TAB. */ uint8 join_tab_idx; inline bool maybe_null() const { return (bool) (base_flags & item_base_t::MAYBE_NULL); } inline bool in_rollup() const { return (bool) (base_flags & item_base_t::IN_ROLLUP); } inline bool fixed() const { return (bool) (base_flags & item_base_t::FIXED); } inline bool is_explicit_name() const { return (bool) (base_flags & item_base_t::IS_EXPLICIT_NAME); } inline bool is_in_with_cycle() const { return (bool) (base_flags & item_base_t::IS_IN_WITH_CYCLE); } inline bool is_cond() const { return (bool) (base_flags & item_base_t::IS_COND); } inline bool with_sp_var() const { return (bool) (with_flags & item_with_t::SP_VAR); } inline bool with_window_func() const { return (bool) (with_flags & item_with_t::WINDOW_FUNC); } inline bool with_field() const { return (bool) (with_flags & item_with_t::FIELD); } inline bool with_sum_func() const { return (bool) (with_flags & item_with_t::SUM_FUNC); } inline bool with_subquery() const { return (bool) (with_flags & item_with_t::SUBQUERY); } inline bool with_rownum_func() const { return (bool) (with_flags & item_with_t::ROWNUM_FUNC); } inline bool with_param() const { return (bool) (with_flags & item_with_t::PARAM); } inline void copy_flags(const Item *org, item_base_t mask) { base_flags= (item_base_t) (((item_flags_t) base_flags & ~(item_flags_t) mask) | ((item_flags_t) org->base_flags & (item_flags_t) mask)); } inline void copy_flags(const Item *org, item_with_t mask) { with_flags= (item_with_t) (((item_flags_t) with_flags & ~(item_flags_t) mask) | ((item_flags_t) org->with_flags & (item_flags_t) mask)); } // alloc & destruct is done as start of select on THD::mem_root Item(THD *thd); /* Constructor used by Item_field, Item_ref & aggregate (sum) functions. Used for duplicating lists in processing queries with temporary tables Also it used for Item_cond_and/Item_cond_or for creating top AND/OR structure of WHERE clause to protect it of optimisation changes in prepared statements */ Item(THD *thd, Item *item); Item(); /* For const item */ virtual ~Item() { #ifdef EXTRA_DEBUG name.str= 0; name.length= 0; #endif } /*lint -e1509 */ void set_name(THD *thd, const char *str, size_t length, CHARSET_INFO *cs); void set_name(THD *thd, String *str) { set_name(thd, str->ptr(), str->length(), str->charset()); } void set_name(THD *thd, const LEX_CSTRING &str, CHARSET_INFO *cs= system_charset_info) { set_name(thd, str.str, str.length, cs); } void set_name_no_truncate(THD *thd, const char *str, uint length, CHARSET_INFO *cs); void init_make_send_field(Send_field *tmp_field, const Type_handler *h); void share_name_with(const Item *item) { name= item->name; copy_flags(item, item_base_t::IS_EXPLICIT_NAME); } virtual void cleanup(); virtual void make_send_field(THD *thd, Send_field *field); bool fix_fields_if_needed(THD *thd, Item **ref) { return fixed() ? false : fix_fields(thd, ref); } /* fix_fields_if_needed_for_scalar() is used where we need to filter items that can't be scalars and want to return error for it. */ bool fix_fields_if_needed_for_scalar(THD *thd, Item **ref) { return fix_fields_if_needed(thd, ref) || check_cols(1); } bool fix_fields_if_needed_for_bool(THD *thd, Item **ref) { return fix_fields_if_needed_for_scalar(thd, ref); } bool fix_fields_if_needed_for_order_by(THD *thd, Item **ref) { return fix_fields_if_needed_for_scalar(thd, ref); } /* By default we assume that an Item is fixed by the constructor */ virtual bool fix_fields(THD *, Item **) { /* This should not normally be called, because usually before fix_fields() we check fixed() to be false. But historically we allow fix_fields() to be called for Items who return basic_const_item()==true. */ DBUG_ASSERT(fixed()); DBUG_ASSERT(basic_const_item()); return false; } virtual void unfix_fields() { DBUG_ASSERT(0); } /* Fix after some tables has been pulled out. Basically re-calculate all attributes that are dependent on the tables. */ virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) {}; /* This is for items that require a fixup after the JOIN::prepare() is done. */ virtual void fix_after_optimize(THD *thd) {} /* This method should be used in case where we are sure that we do not need complete fix_fields() procedure. Usually this method is used by the optimizer when it has to create a new item out of other already fixed items. For example, if the optimizer has to create a new Item_func for an inferred equality whose left and right parts are already fixed items. In some cases the optimizer cannot use directly fixed items as the arguments of the created functional item, but rather uses intermediate type conversion items. Then the method is supposed to be applied recursively. */ virtual void quick_fix_field() { DBUG_ASSERT(0); } bool save_in_value(THD *thd, st_value *value) { return type_handler()->Item_save_in_value(thd, this, value); } /* Function returns 1 on overflow and -1 on fatal errors */ int save_in_field_no_warnings(Field *field, bool no_conversions); virtual int save_in_field(Field *field, bool no_conversions); virtual bool save_in_param(THD *thd, Item_param *param); virtual void save_org_in_field(Field *field, fast_field_copier data __attribute__ ((__unused__))) { (void) save_in_field(field, 1); } virtual fast_field_copier setup_fast_field_copier(Field *field) { return NULL; } virtual int save_safe_in_field(Field *field) { return save_in_field(field, 1); } virtual bool send(Protocol *protocol, st_value *buffer) { return type_handler()->Item_send(this, protocol, buffer); } virtual bool eq(const Item *, bool binary_cmp) const; enum_field_types field_type() const { return type_handler()->field_type(); } virtual const Type_handler *type_handler() const= 0; /** Detects if an Item has a fixed data type which is known even before fix_fields(). Currently it's important only to find Items with a fixed boolean data type. More item types can be marked in the future as having a fixed data type (e.g. all literals, all fixed type functions, etc). @retval NULL if the Item type is not known before fix_fields() @retval the pointer to the data type handler, if the data type is known before fix_fields(). */ virtual const Type_handler *fixed_type_handler() const { return NULL; } const Type_handler *type_handler_for_comparison() const { return type_handler()->type_handler_for_comparison(); } virtual const Type_handler *real_type_handler() const { return type_handler(); } const Type_handler *cast_to_int_type_handler() const { return real_type_handler()->cast_to_int_type_handler(); } /* result_type() of an item specifies how the value should be returned */ Item_result result_type() const { return type_handler()->result_type(); } /* ... while cmp_type() specifies how it should be compared */ Item_result cmp_type() const { return type_handler()->cmp_type(); } const Type_handler *string_type_handler() const { return Type_handler::string_type_handler(max_length); } /* Calculate the maximum length of an expression. This method is used in data type aggregation for UNION, e.g.: SELECT 'b' UNION SELECT COALESCE(double_10_3_field) FROM t1; The result is usually equal to max_length, except for some numeric types. In case of the INT, FLOAT, DOUBLE data types Item::max_length and Item::decimals are ignored, so the returned value depends only on the data type itself. E.g. for an expression of the DOUBLE(10,3) data type, the result is always 53 (length 10 and precision 3 do not matter). max_length is ignored for these numeric data types because the length limit means only "expected maximum length", it is not a hard limit, so it does not impose any data truncation. E.g. a column of the type INT(4) can normally store big values up to 2147483647 without truncation. When we're aggregating such column for UNION it's important to create a long enough result column, not to lose any data. For detailed behaviour of various data types see implementations of the corresponding Type_handler_xxx::max_display_length(). Note, Item_field::max_display_length() overrides this to get max_display_length() from the underlying field. */ virtual uint32 max_display_length() const { return type_handler()->max_display_length(this); } const TYPELIB *get_typelib() const override { return NULL; } /* optimized setting of maybe_null without jumps. Minimizes code size */ inline void set_maybe_null(bool maybe_null_arg) { base_flags= ((item_base_t) ((base_flags & ~item_base_t::MAYBE_NULL)) | (item_base_t) (maybe_null_arg << ITEM_FLAGS_MAYBE_NULL_SHIFT)); } /* This is used a lot, so make it simpler to use */ void set_maybe_null() { base_flags|= item_base_t::MAYBE_NULL; } /* This is used when calling Type_all_attributes::set_type_maybe_null() */ void set_type_maybe_null(bool maybe_null_arg) override { set_maybe_null(maybe_null_arg); } void set_typelib(const TYPELIB *typelib) override { // Non-field Items (e.g. hybrid functions) never have ENUM/SET types yet. DBUG_ASSERT(0); } Item_cache* get_cache(THD *thd) const { return type_handler()->Item_get_cache(thd, this); } virtual enum Type type() const =0; bool is_of_type(Type t, Item_result cmp) const { return type() == t && cmp_type() == cmp; } /* real_type() is the type of base item. This is same as type() for most items, except Item_ref() and Item_cache_wrapper() where it shows the type for the underlying item. */ virtual enum Type real_type() const { return type(); } /* Return information about function monotonicity. See comment for enum_monotonicity_info for details. This function can only be called after fix_fields() call. */ virtual enum_monotonicity_info get_monotonicity_info() const { return NON_MONOTONIC; } /* Convert "func_arg $CMP$ const" half-interval into "FUNC(func_arg) $CMP2$ const2" SYNOPSIS val_int_endpoint() left_endp FALSE <=> The interval is "x < const" or "x <= const" TRUE <=> The interval is "x > const" or "x >= const" incl_endp IN FALSE <=> the comparison is '<' or '>' TRUE <=> the comparison is '<=' or '>=' OUT The same but for the "F(x) $CMP$ F(const)" comparison DESCRIPTION This function is defined only for unary monotonic functions. The caller supplies the source half-interval x $CMP$ const The value of const is supplied implicitly as the value this item's argument, the form of $CMP$ comparison is specified through the function's arguments. The calle returns the result interval F(x) $CMP2$ F(const) passing back F(const) as the return value, and the form of $CMP2$ through the out parameter. NULL values are assumed to be comparable and be less than any non-NULL values. RETURN The output range bound, which equal to the value of val_int() - If the value of the function is NULL then the bound is the smallest possible value of LONGLONG_MIN */ virtual longlong val_int_endpoint(bool left_endp, bool *incl_endp) { DBUG_ASSERT(0); return 0; } /* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */ /* Return double precision floating point representation of item. SYNOPSIS val_real() RETURN In case of NULL value return 0.0 and set null_value flag to TRUE. If value is not null null_value flag will be reset to FALSE. */ virtual double val_real()=0; Double_null to_double_null() { // val_real() must be caleed on a separate line. See to_longlong_null() double nr= val_real(); return Double_null(nr, null_value); } /* Return integer representation of item. SYNOPSIS val_int() RETURN In case of NULL value return 0 and set null_value flag to TRUE. If value is not null null_value flag will be reset to FALSE. */ virtual longlong val_int()=0; Longlong_hybrid to_longlong_hybrid() { return Longlong_hybrid(val_int(), unsigned_flag); } Longlong_null to_longlong_null() { longlong nr= val_int(); /* C++ does not guarantee the order of parameter evaluation, so to make sure "null_value" is passed to the constructor after the val_int() call, val_int() is caled on a separate line. */ return Longlong_null(nr, null_value); } Longlong_hybrid_null to_longlong_hybrid_null() { return Longlong_hybrid_null(to_longlong_null(), unsigned_flag); } /** Get a value for CAST(x AS SIGNED). Too large positive unsigned integer values are converted to negative complements. Values of non-integer data types are adjusted to the SIGNED range. */ virtual longlong val_int_signed_typecast() { return cast_to_int_type_handler()->Item_val_int_signed_typecast(this); } longlong val_int_signed_typecast_from_str(); /** Get a value for CAST(x AS UNSIGNED). Negative signed integer values are converted to positive complements. Values of non-integer data types are adjusted to the UNSIGNED range. */ virtual longlong val_int_unsigned_typecast() { return cast_to_int_type_handler()->Item_val_int_unsigned_typecast(this); } longlong val_int_unsigned_typecast_from_int(); longlong val_int_unsigned_typecast_from_str(); longlong val_int_unsigned_typecast_from_real(); /** Get a value for CAST(x AS UNSIGNED). Huge positive unsigned values are converted to negative complements. */ longlong val_int_signed_typecast_from_int(); longlong val_int_signed_typecast_from_real(); /* This is just a shortcut to avoid the cast. You should still use unsigned_flag to check the sign of the item. */ inline ulonglong val_uint() { return (ulonglong) val_int(); } virtual bool hash_not_null(Hasher *hasher) { DBUG_ASSERT(0); return true; } /* Return string representation of this item object. SYNOPSIS val_str() str an allocated buffer this or any nested Item object can use to store return value of this method. NOTE The caller can modify the returned String, if it's not marked "const" (with the String::mark_as_const() method). That means that if the item returns its own internal buffer (e.g. tmp_value), it *must* be marked "const" [1]. So normally it's preferable to return the result value in the String, that was passed as an argument. But, for example, SUBSTR() returns a String that simply points into the buffer of SUBSTR()'s args[0]->val_str(). Such a String is always "const", so it's ok to use tmp_value for that and avoid reallocating/copying of the argument String. [1] consider SELECT CONCAT(f, ":", f) FROM (SELECT func() AS f); here the return value of f() is used twice in the top-level select, and if they share the same tmp_value buffer, modifying the first one will implicitly modify the second too. RETURN In case of NULL value return 0 (NULL pointer) and set null_value flag to TRUE. If value is not null null_value flag will be reset to FALSE. */ virtual String *val_str(String *str)=0; bool val_native_with_conversion(THD *thd, Native *to, const Type_handler *th) { return th->Item_val_native_with_conversion(thd, this, to); } bool val_native_with_conversion_result(THD *thd, Native *to, const Type_handler *th) { return th->Item_val_native_with_conversion_result(thd, this, to); } virtual bool val_native(THD *thd, Native *to) { /* The default implementation for the Items that do not need native format: - Item_basic_value (default implementation) - Item_copy - Item_exists_subselect - Item_sum_field - Item_sum_or_func (default implementation) - Item_proc - Item_type_holder (as val_xxx() are never called for it); These hybrid Item types override val_native(): - Item_field - Item_param - Item_sp_variable - Item_ref - Item_cache_wrapper - Item_direct_ref - Item_direct_view_ref - Item_ref_null_helper - Item_name_const - Item_time_literal - Item_sum_or_func Note, these hybrid type Item_sum_or_func descendants override the default implementation: * Item_sum_hybrid * Item_func_hybrid_field_type * Item_func_min_max * Item_func_sp * Item_func_last_value * Item_func_rollup_const */ DBUG_ASSERT(0); return (null_value= 1); } virtual bool val_native_result(THD *thd, Native *to) { return val_native(thd, to); } /* Returns string representation of this item in ASCII format. SYNOPSIS val_str_ascii() str - similar to val_str(); NOTE This method is introduced for performance optimization purposes. 1. val_str() result of some Items in string context depends on @@character_set_results. @@character_set_results can be set to a "real multibyte" character set like UCS2, UTF16, UTF32. (We'll use only UTF32 in the examples below for convenience.) So the default string result of such functions in these circumstances is real multi-byte character set, like UTF32. For example, all numbers in string context return result in @@character_set_results: SELECT CONCAT(20010101); -> UTF32 We do sprintf() first (to get ASCII representation) and then convert to UTF32; So these kind "data sources" can use ASCII representation internally, but return multi-byte data only because @@character_set_results wants so. Therefore, conversion from ASCII to UTF32 is applied internally. 2. Some other functions need in fact ASCII input. For example, inet_aton(), GeometryFromText(), Convert_TZ(), GET_FORMAT(). Similar, fields of certain type, like DATE, TIME, when you insert string data into them, expect in fact ASCII input. If they get non-ASCII input, for example UTF32, they convert input from UTF32 to ASCII, and then use ASCII representation to do further processing. 3. Now imagine we pass result of a data source of the first type to a data destination of the second type. What happens: a. data source converts data from ASCII to UTF32, because @@character_set_results wants so and passes the result to data destination. b. data destination gets UTF32 string. c. data destination converts UTF32 string to ASCII, because it needs ASCII representation to be able to handle data correctly. As a result we get two steps of unnecessary conversion: From ASCII to UTF32, then from UTF32 to ASCII. A better way to handle these situations is to pass ASCII representation directly from the source to the destination. This is why val_str_ascii() introduced. RETURN Similar to val_str() */ virtual String *val_str_ascii(String *str); /* Returns the result of val_str_ascii(), translating NULLs back to empty strings (if MODE_EMPTY_STRING_IS_NULL is set). */ String *val_str_ascii_revert_empty_string_is_null(THD *thd, String *str); /* Returns the val_str() value converted to the given character set. */ String *val_str(String *str, String *converter, CHARSET_INFO *to); virtual String *val_json(String *str) { return val_str(str); } /* Return decimal representation of item with fixed point. SYNOPSIS val_decimal() decimal_buffer buffer which can be used by Item for returning value (but can be not) NOTE Returned value should not be changed if it is not the same which was passed via argument. RETURN Return pointer on my_decimal (it can be other then passed via argument) if value is not NULL (null_value flag will be reset to FALSE). In case of NULL value it return 0 pointer and set null_value flag to TRUE. */ virtual my_decimal *val_decimal(my_decimal *decimal_buffer)= 0; /* Return boolean value of item. RETURN FALSE value is false or NULL TRUE value is true (not equal to 0) */ virtual bool val_bool() { return type_handler()->Item_val_bool(this); } bool eval_const_cond() { DBUG_ASSERT(const_item()); DBUG_ASSERT(!is_expensive()); return val_bool(); } bool can_eval_in_optimize() { return const_item() && !is_expensive(); } /* save_val() is method of val_* family which stores value in the given field. */ virtual void save_val(Field *to) { save_org_in_field(to, NULL); } /* save_result() is method of val*result() family which stores value in the given field. */ virtual void save_result(Field *to) { save_val(to); } /* Helper functions, see item_sum.cc */ String *val_string_from_real(String *str); String *val_string_from_int(String *str); my_decimal *val_decimal_from_real(my_decimal *decimal_value); my_decimal *val_decimal_from_int(my_decimal *decimal_value); my_decimal *val_decimal_from_string(my_decimal *decimal_value); longlong val_int_from_real() { DBUG_ASSERT(fixed()); return Converter_double_to_longlong_with_warn(val_real(), false).result(); } longlong val_int_from_str(int *error); /* Returns true if this item can be calculated during value_depends_on_sql_mode() */ bool value_depends_on_sql_mode_const_item() { /* Currently we use value_depends_on_sql_mode() only for virtual column expressions. They should not contain any expensive items. If we ever get a crash on the assert below, it means check_vcol_func_processor() is badly implemented for this item. */ DBUG_ASSERT(!is_expensive()); /* It should return const_item() actually. But for some reasons Item_field::const_item() returns true at value_depends_on_sql_mode() call time. This should be checked and fixed. */ return basic_const_item(); } virtual Sql_mode_dependency value_depends_on_sql_mode() const { return Sql_mode_dependency(); } int save_time_in_field(Field *field, bool no_conversions); int save_date_in_field(Field *field, bool no_conversions); int save_str_in_field(Field *field, bool no_conversions); int save_real_in_field(Field *field, bool no_conversions); int save_int_in_field(Field *field, bool no_conversions); int save_bool_in_field(Field *field, bool no_conversions); int save_decimal_in_field(Field *field, bool no_conversions); int save_str_value_in_field(Field *field, String *result); virtual Field *get_tmp_table_field() { return 0; } virtual Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table); inline const char *full_name() const { return full_name_cstring().str; } virtual LEX_CSTRING full_name_cstring() const { if (name.str) return name; return { STRING_WITH_LEN("???") }; } const char *field_name_or_null() { return real_item()->type() == Item::FIELD_ITEM ? name.str : NULL; } const TABLE_SHARE *field_table_or_null(); /* *result* family of methods is analog of *val* family (see above) but return value of result_field of item if it is present. If Item have not result field, it return val(). This methods set null_value flag in same way as *val* methods do it. */ virtual double val_result() { return val_real(); } virtual longlong val_int_result() { return val_int(); } virtual String *str_result(String* tmp) { return val_str(tmp); } virtual my_decimal *val_decimal_result(my_decimal *val) { return val_decimal(val); } virtual bool val_bool_result() { return val_bool(); } virtual bool is_null_result() { return is_null(); } /* Returns 1 if result type and collation for val_str() can change between calls */ virtual bool dynamic_result() { return 0; } /* Bitmap of tables used by item (note: if you need to check dependencies on individual columns, check out class Field_enumerator) */ virtual table_map used_tables() const { return (table_map) 0L; } virtual table_map all_used_tables() const { return used_tables(); } /* Return table map of tables that can't be NULL tables (tables that are used in a context where if they would contain a NULL row generated by a LEFT or RIGHT join, the item would not be true). This expression is used on WHERE item to determinate if a LEFT JOIN can be converted to a normal join. Generally this function should return used_tables() if the function would return null if any of the arguments are null As this is only used in the beginning of optimization, the value don't have to be updated in update_used_tables() */ virtual table_map not_null_tables() const { return used_tables(); } /* Returns true if this is a simple constant item like an integer, not a constant expression. Used in the optimizer to propagate basic constants. */ virtual bool basic_const_item() const { return 0; } /** Determines if the expression is allowed as a virtual column assignment source: INSERT INTO t1 (vcol) VALUES (10) -> error INSERT INTO t1 (vcol) VALUES (NULL) -> ok */ virtual bool vcol_assignment_allowed_value() const { return false; } /** Test if "this" is an ORDER position (rather than an expression). Notes: - can be called before fix_fields(). - local SP variables (even of integer types) are always expressions, not positions. (And they can't be used before fix_fields is called for them). */ virtual bool is_order_clause_position() const { return false; } /* Determines if the Item is an evaluable expression, that is it can return a value, so we can call methods val_xxx(), get_date(), etc. Most items are evaluable expressions. Examples of non-evaluable expressions: - Item_contextually_typed_value_specification (handling DEFAULT and IGNORE) - Item_type_param bound to DEFAULT and IGNORE We cannot call the mentioned methods for these Items, their method implementations typically have DBUG_ASSERT(0). */ virtual bool is_evaluable_expression() const { return true; } /** * Check whether the item is a parameter ('?') of stored routine. * Default implementation returns false. Method is overridden in the class * Item_param where it returns true. */ virtual bool is_stored_routine_parameter() const { return false; } bool check_is_evaluable_expression_or_error() { if (is_evaluable_expression()) return false; // Ok raise_error_not_evaluable(); return true; // Error } /* Create a shallow copy of the item (usually invoking copy constructor). For deep copying see build_clone(). Return value: - pointer to a copy of the Item - nullptr if the item is not copyable */ Item *get_copy(THD *thd) const { Item *copy= do_get_copy(thd); if (copy) { // Make sure the copy is of same type as this item DBUG_ASSERT(typeid(*copy) == typeid(*this)); } return copy; } /* Creates a clone of the item by deep copying. Return value: - pointer to a clone of the Item - nullptr if the item is not clonable */ Item* build_clone(THD *thd) const { Item *clone= do_build_clone(thd); if (clone) { // Make sure the clone is of same type as this item DBUG_ASSERT(typeid(*clone) == typeid(*this)); } return clone; } /* Clones the constant item (not necessary returning the same item type) Return value: - pointer to a clone of the Item - nullptr if the item is not clonable Note: the clone may have item type different from this (i.e., instance of another basic constant class may be returned). For real clones look at build_clone()/get_copy() methods */ virtual Item *clone_item(THD *thd) const { return nullptr; } virtual cond_result eq_cmp_result() const { return COND_OK; } inline uint float_length(uint decimals_par) const { return decimals < FLOATING_POINT_DECIMALS ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} /* Returns total number of decimal digits */ decimal_digits_t decimal_precision() const override { return type_handler()->Item_decimal_precision(this); } /* Returns the number of integer part digits only */ inline decimal_digits_t decimal_int_part() const { return (decimal_digits_t) my_decimal_int_part(decimal_precision(), decimals); } /* Returns the number of fractional digits only. NOT_FIXED_DEC is replaced to the maximum possible number of fractional digits, taking into account the data type. */ decimal_digits_t decimal_scale() const { return type_handler()->Item_decimal_scale(this); } /* Returns how many digits a divisor adds into a division result. This is important when the integer part of the divisor can be 0. In this example: SELECT 1 / 0.000001; -> 1000000.0000 the divisor adds 5 digits into the result precision. Currently this method only replaces NOT_FIXED_DEC to TIME_SECOND_PART_DIGITS for temporal data types. This method can be made virtual, to create more efficient (smaller) data types for division results. For example, in SELECT 1/1.000001; the divisor could provide no additional precision into the result, so could any other items that are know to return a result with non-zero integer part. */ uint divisor_precision_increment() const { return type_handler()->Item_divisor_precision_increment(this); } /** TIME or DATETIME precision of the item: 0..6 */ uint time_precision(THD *thd) { return const_item() ? type_handler()->Item_time_precision(thd, this) : MY_MIN(decimals, TIME_SECOND_PART_DIGITS); } uint datetime_precision(THD *thd) { return const_item() ? type_handler()->Item_datetime_precision(thd, this) : MY_MIN(decimals, TIME_SECOND_PART_DIGITS); } virtual longlong val_int_min() const { return LONGLONG_MIN; } /* Returns true if this is constant (during query execution, i.e. its value will not change until next fix_fields) and its value is known. */ virtual bool const_item() const { return used_tables() == 0; } /* Returns true if this is constant but its value may be not known yet. (Can be used for parameters of prep. stmts or of stored procedures.) */ virtual bool const_during_execution() const { return (used_tables() & ~PARAM_TABLE_BIT) == 0; } /** This method is used for to: - to generate a view definition query (SELECT-statement); - to generate a SQL-query for EXPLAIN EXTENDED; - to generate a SQL-query to be shown in INFORMATION_SCHEMA; - debug. For more information about view definition query, INFORMATION_SCHEMA query and why they should be generated from the Item-tree, @see mysql_register_view(). */ virtual enum precedence precedence() const { return DEFAULT_PRECEDENCE; } enum precedence higher_precedence() const { return (enum precedence)(precedence() + 1); } void print_parenthesised(String *str, enum_query_type query_type, enum precedence parent_prec); /** This helper is used to print expressions as a part of a table definition, in particular for - generated columns - check constraints - default value expressions - partitioning expressions */ void print_for_table_def(String *str) { print_parenthesised(str, (enum_query_type)(QT_ITEM_ORIGINAL_FUNC_NULLIF | QT_ITEM_IDENT_SKIP_DB_NAMES | QT_ITEM_IDENT_SKIP_TABLE_NAMES | QT_NO_DATA_EXPANSION | QT_TO_SYSTEM_CHARSET | QT_FOR_FRM), LOWEST_PRECEDENCE); } virtual void print(String *str, enum_query_type query_type); class Print: public String { public: Print(Item *item, enum_query_type type) { item->print(this, type); } }; void print_item_w_name(String *str, enum_query_type query_type); void print_value(String *str); virtual void update_used_tables() {} virtual COND *build_equal_items(THD *thd, COND_EQUAL *inheited, bool link_item_fields, COND_EQUAL **cond_equal_ref) { update_used_tables(); DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]); return this; } virtual COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value, bool top_level); virtual void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) { return; } /* Make a select tree for all keys in a condition or a condition part @param param Context @param cond_ptr[OUT] Store a replacement item here if the condition can be simplified, e.g.: WHERE part1 OR part2 OR part3 with one of the partN evaluating to SEL_TREE::ALWAYS. */ virtual SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr); /* Checks whether the item is: - a simple equality (field=field_item or field=constant_item), or - a row equality and form multiple equality predicates. */ virtual bool check_equality(THD *thd, COND_EQUAL *cond, List *eq_list) { return false; } virtual void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, uint flags) {} /* Called for items that really have to be split */ void split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, Item **ref, uint flags); virtual bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)= 0; bool get_date_from_int(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); bool get_date_from_real(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); bool get_date_from_string(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); bool get_time(THD *thd, MYSQL_TIME *ltime) { return get_date(thd, ltime, Time::Options(thd)); } // Get a DATE or DATETIME value in numeric packed format for comparison virtual longlong val_datetime_packed(THD *thd) { return Datetime(thd, this, Datetime::Options_cmp(thd)).to_packed(); } // Get a TIME value in numeric packed format for comparison virtual longlong val_time_packed(THD *thd) { return Time(thd, this, Time::Options_cmp(thd)).to_packed(); } longlong val_datetime_packed_result(THD *thd); longlong val_time_packed_result(THD *thd); virtual bool get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { return get_date(thd, ltime,fuzzydate); } /* The method allows to determine nullness of a complex expression without fully evaluating it, instead of calling val/result*() then checking null_value. Used in Item_func_isnull/Item_func_isnotnull and Item_sum_count. Any new item which can be NULL must implement this method. */ virtual bool is_null() { return 0; } /* Make sure the null_value member has a correct value. */ virtual void update_null_value () { return type_handler()->Item_update_null_value(this); } /* Inform the item that there will be no distinction between its result being FALSE or NULL. NOTE This function will be called for eg. Items that are top-level AND-parts of the WHERE clause. Items implementing this function (currently Item_cond_and and subquery-related item) enable special optimizations when they are "top level". */ virtual void top_level_item() {} /* Return TRUE if it is item of top WHERE level (AND/OR) and it is important, return FALSE if it not important (we can not use to simplify calculations) or not top level */ virtual bool is_top_level_item() const { return FALSE; /* not important */} /* return IN/ALL/ANY subquery or NULL */ virtual Item_in_subselect* get_IN_subquery() { return NULL; /* in is not IN/ALL/ANY */ } /* set field of temporary table for Item which can be switched on temporary table during query processing (grouping and so on) */ virtual bool is_result_field() { return 0; } virtual bool is_bool_literal() const { return false; } /* This is to handle printing of default values */ virtual bool need_parentheses_in_default() { return false; } virtual void save_in_result_field(bool no_conversions) {} /* Data type format implied by the CHECK CONSTRAINT, to be sent to the client in the result set metadata. */ virtual bool set_format_by_check_constraint(Send_field_extended_metadata *) const { return false; } /* set value of aggregate function in case of no rows for grouping were found */ virtual void no_rows_in_result() {} virtual void restore_to_before_no_rows_in_result() {} virtual Item *copy_or_same(THD *thd) { return this; } virtual Item *copy_andor_structure(THD *thd) { return this; } virtual Item *real_item() { return this; } const Item *real_item() const { return const_cast(this)->real_item(); } virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } virtual Item *make_odbc_literal(THD *thd, const LEX_CSTRING *typestr) { return this; } static CHARSET_INFO *default_charset(); CHARSET_INFO *charset_for_protocol(void) const { return type_handler()->charset_for_protocol(this); }; virtual bool walk(Item_processor processor, bool walk_subquery, void *arg) { return (this->*processor)(arg); } virtual Item* transform(THD *thd, Item_transformer transformer, uchar *arg); virtual Item* top_level_transform(THD *thd, Item_transformer transformer, uchar *arg) { return transform(thd, transformer, arg); } /* This function performs a generic "compilation" of the Item tree. The process of compilation is assumed to go as follows: compile() { if (this->*some_analyzer(...)) { compile children if any; this->*some_transformer(...); } } i.e. analysis is performed top-down while transformation is done bottom-up. */ virtual Item* compile(THD *thd, Item_analyzer analyzer, uchar **arg_p, Item_transformer transformer, uchar *arg_t) { if ((this->*analyzer) (arg_p)) return ((this->*transformer) (thd, arg_t)); return 0; } virtual Item* top_level_compile(THD *thd, Item_analyzer analyzer, uchar **arg_p, Item_transformer transformer, uchar *arg_t) { return compile(thd, analyzer, arg_p, transformer, arg_t); } virtual void traverse_cond(Cond_traverser traverser, void *arg, traverse_order order) { (*traverser)(this, arg); } /*========= Item processors, to be used with Item::walk() ========*/ virtual bool remove_dependence_processor(void *arg) { return 0; } virtual bool cleanup_processor(void *arg); virtual bool cleanup_excluding_fields_processor (void *arg) { return cleanup_processor(arg); } bool cleanup_excluding_immutables_processor (void *arg); virtual bool cleanup_excluding_const_fields_processor (void *arg) { return cleanup_processor(arg); } virtual bool collect_item_field_processor(void *arg) { return 0; } virtual bool unknown_splocal_processor(void *arg) { return 0; } virtual bool collect_outer_ref_processor(void *arg) {return 0; } virtual bool check_inner_refs_processor(void *arg) { return 0; } virtual bool find_item_in_field_list_processor(void *arg) { return 0; } virtual bool find_item_processor(void *arg); virtual bool change_context_processor(void *arg) { return 0; } virtual bool reset_query_id_processor(void *arg) { return 0; } virtual bool is_expensive_processor(void *arg) { return 0; } bool remove_immutable_flag_processor (void *arg); // FIXME reduce the number of "add field to bitmap" processors virtual bool add_field_to_set_processor(void *arg) { return 0; } virtual bool register_field_in_read_map(void *arg) { return 0; } virtual bool register_field_in_write_map(void *arg) { return 0; } virtual bool register_field_in_bitmap(void *arg) { return 0; } virtual bool update_table_bitmaps_processor(void *arg) { return 0; } virtual bool enumerate_field_refs_processor(void *arg) { return 0; } virtual bool mark_as_eliminated_processor(void *arg) { return 0; } virtual bool eliminate_subselect_processor(void *arg) { return 0; } virtual bool view_used_tables_processor(void *arg) { return 0; } virtual bool eval_not_null_tables(void *arg) { return 0; } virtual bool is_subquery_processor(void *arg) { return 0; } virtual bool count_sargable_conds(void *arg) { return 0; } virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; } virtual bool exists2in_processor(void *arg) { return 0; } virtual bool find_selective_predicates_list_processor(void *arg) { return 0; } virtual bool cleanup_is_expensive_cache_processor(void *arg) { is_expensive_cache= (int8)(-1); return 0; } virtual bool set_extraction_flag_processor(void *arg) { set_extraction_flag(*(int16*)arg); return 0; } virtual bool subselect_table_finder_processor(void *arg) { return 0; }; /* TRUE if the expression depends only on the table indicated by tab_map or can be converted to such an exression using equalities. Not to be used for AND/OR formulas. */ virtual bool excl_dep_on_table(table_map tab_map) { return false; } /* TRUE if the expression depends only on grouping fields of sel or can be converted to such an expression using equalities. It also checks if the expression doesn't contain stored procedures, subqueries or randomly generated elements. Not to be used for AND/OR formulas. */ virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) { return false; } /* TRUE if the expression depends only on fields from the left part of IN subquery or can be converted to such an expression using equalities. Not to be used for AND/OR formulas. */ virtual bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) { return false; } virtual bool switch_to_nullable_fields_processor(void *arg) { return 0; } virtual bool find_function_processor (void *arg) { return 0; } /* Check if a partition function is allowed SYNOPSIS check_partition_func_processor() int_arg Ignored RETURN VALUE TRUE Partition function not accepted FALSE Partition function accepted DESCRIPTION check_partition_func_processor is used to check if a partition function uses an allowed function. An allowed function will always ensure that X=Y guarantees that also part_function(X)=part_function(Y) where X is a set of partition fields and so is Y. The problems comes mainly from character sets where two equal strings can be quite unequal. E.g. the german character for double s is equal to 2 s. The default is that an item is not allowed in a partition function. Allowed functions can never depend on server version, they cannot depend on anything related to the environment. They can also only depend on a set of fields in the table itself. They cannot depend on other tables and cannot contain any queries and cannot contain udf's or similar. If a new Item class is defined and it inherits from a class that is allowed in a partition function then it is very important to consider whether this should be inherited to the new class. If not the function below should be defined in the new Item class. The general behaviour is that most integer functions are allowed. If the partition function contains any multi-byte collations then the function check_part_func_fields will report an error on the partition function independent of what functions are used. So the only character sets allowed are single character collation and even for those only a limited set of functions are allowed. The problem with multi-byte collations is that almost every string function has the ability to change things such that two strings that are equal will not be equal after manipulated by a string function. E.g. two strings one contains a double s, there is a special german character that is equal to two s. Now assume a string function removes one character at this place, then in one the double s will be removed and in the other there will still be one s remaining and the strings are no longer equal and thus the partition function will not sort equal strings into the same partitions. So the check if a partition function is valid is two steps. First check that the field types are valid, next check that the partition function is valid. The current set of partition functions valid assumes that there are no multi-byte collations amongst the partition fields. */ virtual bool check_partition_func_processor(void *arg) { return true; } virtual bool post_fix_fields_part_expr_processor(void *arg) { return 0; } virtual bool rename_fields_processor(void *arg) { return 0; } virtual bool rename_table_processor(void *arg) { return 0; } /* TRUE if the function is knowingly TRUE or FALSE. Not to be used for AND/OR formulas. */ virtual bool is_simplified_cond_processor(void *arg) { return false; } /** Processor used to check acceptability of an item in the defining expression for a virtual column @param arg always ignored @retval 0 the item is accepted in the definition of a virtual column @retval 1 otherwise */ struct vcol_func_processor_result { uint errors; /* Bits of possible errors */ const char *name; /* Not supported function */ Alter_info *alter_info; vcol_func_processor_result() : errors(0), name(NULL), alter_info(NULL) {} }; struct func_processor_rename { LEX_CSTRING db_name; LEX_CSTRING table_name; List fields; }; struct func_processor_rename_table { Lex_ident_db old_db; Lex_ident_table old_table; Lex_ident_db new_db; Lex_ident_table new_table; }; virtual bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE); } virtual bool check_handler_func_processor(void *arg) { return 0; } virtual bool check_field_expression_processor(void *arg) { return 0; } virtual bool check_func_default_processor(void *arg) { return 0; } virtual bool update_func_default_processor(void *arg) { return 0; } /* Check if an expression value has allowed arguments, like DATE/DATETIME for date functions. Also used by partitioning code to reject timezone-dependent expressions in a (sub)partitioning function. */ virtual bool check_valid_arguments_processor(void *arg) { return 0; } virtual bool update_vcol_processor(void *arg) { return 0; } virtual bool set_fields_as_dependent_processor(void *arg) { return 0; } /* Find if some of the key parts of table keys (the reference on table is passed as an argument) participate in the expression. If there is some, sets a bit for this key in the proper key map. */ virtual bool check_index_dependence(void *arg) { return 0; } virtual bool check_sequence_privileges(void *arg) { return 0; } /*============== End of Item processor list ======================*/ /* Given a condition P from the WHERE clause or from an ON expression of the processed SELECT S and a set of join tables from S marked in the parameter 'allowed'={T} a call of P->find_not_null_fields({T}) has to find the set fields {F} of the tables from 'allowed' such that: - each field from {F} is declared as nullable - each record of table t from {T} that contains NULL as the value for at at least one field from {F} can be ignored when building the result set for S It is assumed here that the condition P is conjunctive and all its column references belong to T. Examples: CREATE TABLE t1 (a int, b int); CREATE TABLE t2 (a int, b int); SELECT * FROM t1,t2 WHERE t1.a=t2.a and t1.b > 5; A call of find_not_null_fields() for the whole WHERE condition and {t1,t2} should find {t1.a,t1.b,t2.a} SELECT * FROM t1 LEFT JOIN ON (t1.a=t2.a and t2.a > t2.b); A call of find_not_null_fields() for the ON expression and {t2} should find {t2.a,t2.b} The function returns TRUE if it succeeds to prove that all records of a table from {T} can be ignored. Otherwise it always returns FALSE. Example: SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t2.a IS NULL; A call of find_not_null_fields() for the WHERE condition and {t1,t2} will return TRUE. It is assumed that the implementation of this virtual function saves the info on the found set of fields in the structures associates with tables from {T}. */ virtual bool find_not_null_fields(table_map allowed) { return false; } bool cache_const_expr_analyzer(uchar **arg); Item* cache_const_expr_transformer(THD *thd, uchar *arg); virtual Item* propagate_equal_fields(THD*, const Context &, COND_EQUAL *) { return this; }; Item* propagate_equal_fields_and_change_item_tree(THD *thd, const Context &ctx, COND_EQUAL *cond, Item **place); /* arg points to REPLACE_EQUAL_FIELD_ARG object */ virtual Item *replace_equal_field(THD *thd, uchar *arg) { return this; } struct Collect_deps_prm { List *parameters; /* unit from which we count nest_level */ st_select_lex_unit *nest_level_base; uint count; int nest_level; bool collect; }; /* For SP local variable returns pointer to Item representing its current value and pointer to current Item otherwise. */ virtual Item *this_item() { return this; } virtual const Item *this_item() const { return this; } /* For SP local variable returns address of pointer to Item representing its current value and pointer passed via parameter otherwise. */ virtual Item **this_item_addr(THD *thd, Item **addr_arg) { return addr_arg; } // Row emulation virtual uint cols() const { return 1; } virtual Item* element_index(uint i) { return this; } virtual Item** addr(uint i) { return 0; } virtual bool check_cols(uint c); bool check_type_traditional_scalar(const LEX_CSTRING &opname) const; bool check_type_scalar(const LEX_CSTRING &opname) const; bool check_type_or_binary(const LEX_CSTRING &opname, const Type_handler *handler) const; bool check_type_general_purpose_string(const LEX_CSTRING &opname) const; bool check_type_can_return_int(const LEX_CSTRING &opname) const; bool check_type_can_return_decimal(const LEX_CSTRING &opname) const; bool check_type_can_return_real(const LEX_CSTRING &opname) const; bool check_type_can_return_str(const LEX_CSTRING &opname) const; bool check_type_can_return_text(const LEX_CSTRING &opname) const; bool check_type_can_return_date(const LEX_CSTRING &opname) const; bool check_type_can_return_time(const LEX_CSTRING &opname) const; // It is not row => null inside is impossible virtual bool null_inside() { return 0; } // used in row subselects to get value of elements virtual void bring_value() {} const Type_handler *type_handler_long_or_longlong() const { return Type_handler::type_handler_long_or_longlong(max_char_length(), unsigned_flag); } /** Create field for temporary table. @param table Temporary table @param [OUT] src Who created the fields @param param Create parameters @retval NULL (on error) @retval a pointer to a newly create Field (on success) */ virtual Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param)= 0; virtual Item_field *field_for_view_update() { return 0; } virtual Item *neg_transformer(THD *thd) { return NULL; } virtual Item *update_value_transformer(THD *thd, uchar *select_arg) { return this; } virtual Item *expr_cache_insert_transformer(THD *thd, uchar *unused) { return this; } virtual Item *derived_field_transformer_for_having(THD *thd, uchar *arg) { return this; } virtual Item *derived_field_transformer_for_where(THD *thd, uchar *arg) { return this; } virtual Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) { return this; } /* Now is not used. */ virtual Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) { return this; } virtual Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) { return this; } virtual Item *in_predicate_to_in_subs_transformer(THD *thd, uchar *arg) { return this; } virtual Item *in_predicate_to_equality_transformer(THD *thd, uchar *arg) { return this; } virtual Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) { return this; } virtual Item *multiple_equality_transformer(THD *thd, uchar *arg); virtual bool expr_cache_is_needed(THD *) { return FALSE; } virtual Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs) const { /* This will return "true" if conversion happens: - between two non-binary different character sets - from "binary" to "unsafe" character set (those that can have non-well-formed string) - from "binary" to UCS2-alike character set with mbminlen>1, when prefix left-padding is needed for an incomplete character: binary 0xFF -> ucs2 0x00FF) */ if (!String::needs_conversion_on_storage(length, collation.collation, tocs)) return false; /* No needs to add converter if an "arg" is NUMERIC or DATETIME value (which is pure ASCII) and at the same time target DTCollation is ASCII-compatible. For example, no needs to rewrite: SELECT * FROM t1 WHERE datetime_field = '2010-01-01'; to SELECT * FROM t1 WHERE CONVERT(datetime_field USING cs) = '2010-01-01'; TODO: avoid conversion of any values with repertoire ASCII and 7bit-ASCII-compatible, not only numeric/datetime origin. */ if (collation.derivation == DERIVATION_NUMERIC && collation.repertoire == MY_REPERTOIRE_ASCII && !(collation.collation->state & MY_CS_NONASCII) && !(tocs->state & MY_CS_NONASCII)) return false; return true; } bool needs_charset_converter(CHARSET_INFO *tocs) { // Pass 1 as length to force conversion if tocs->mbminlen>1. return needs_charset_converter(1, tocs); } Item *const_charset_converter(THD *thd, CHARSET_INFO *tocs, bool lossless, const char *func_name); Item *const_charset_converter(THD *thd, CHARSET_INFO *tocs, bool lossless) { return const_charset_converter(thd, tocs, lossless, NULL); } void delete_self() { cleanup(); delete this; } virtual const Item_const *get_item_const() const { return NULL; } virtual Item_splocal *get_item_splocal() { return 0; } virtual Rewritable_query_parameter *get_rewritable_query_parameter() { return 0; } /* Return Settable_routine_parameter interface of the Item. Return 0 if this Item is not Settable_routine_parameter. */ virtual Settable_routine_parameter *get_settable_routine_parameter() { return 0; } virtual Load_data_outvar *get_load_data_outvar() { return 0; } Load_data_outvar *get_load_data_outvar_or_error() { Load_data_outvar *dst= get_load_data_outvar(); if (dst) return dst; my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), name.str); return NULL; } /** Test whether an expression is expensive to compute. Used during optimization to avoid computing expensive expressions during this phase. Also used to force temp tables when sorting on expensive functions. @todo Normally we should have a method: cost Item::execution_cost(), where 'cost' is either 'double' or some structure of various cost parameters. @note This function is now used to prevent evaluation of expensive subquery predicates during the optimization phase. It also prevents evaluation of predicates that are not computable at this moment. */ virtual bool is_expensive() { if (is_expensive_cache < 0) is_expensive_cache= walk(&Item::is_expensive_processor, 0, NULL); return MY_TEST(is_expensive_cache); } String *check_well_formed_result(String *str, bool send_error= 0); bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs); bool too_big_for_varchar() const { return max_char_length() > CONVERT_IF_BIGGER_TO_BLOB; } void fix_length_and_charset(uint32 max_char_length_arg, CHARSET_INFO *cs) { max_length= char_to_byte_length_safe(max_char_length_arg, cs->mbmaxlen); collation.collation= cs; } void fix_char_length(size_t max_char_length_arg) { max_length= char_to_byte_length_safe(max_char_length_arg, collation.collation->mbmaxlen); } /* Return TRUE if the item points to a column of an outer-joined table. */ virtual bool is_outer_field() const { DBUG_ASSERT(fixed()); return FALSE; } Item* set_expr_cache(THD *thd); virtual Item_equal *get_item_equal() { return NULL; } virtual void set_item_equal(Item_equal *item_eq) {}; virtual Item_equal *find_item_equal(COND_EQUAL *cond_equal) { return NULL; } /** Set the join tab index to the minimal (left-most) JOIN_TAB to which this Item is attached. The number is an index is depth_first_tab() traversal order. */ virtual void set_join_tab_idx(uint8 join_tab_idx_arg) { if (join_tab_idx_arg < join_tab_idx) join_tab_idx= join_tab_idx_arg; } uint get_join_tab_idx() const { return join_tab_idx; } table_map view_used_tables(TABLE_LIST *view) { view->view_used_tables= 0; walk(&Item::view_used_tables_processor, 0, view); return view->view_used_tables; } /** Collect and add to the list cache parameters for this Item. @note Now implemented only for subqueries and in_optimizer, if we need it for general function then this method should be defined for Item_func. */ virtual void get_cache_parameters(List ¶meters) { }; virtual void mark_as_condition_AND_part(TABLE_LIST *embedding) {}; /* how much position should be reserved for Exists2In transformation */ virtual uint exists2in_reserved_items() { return 0; }; virtual Item *neg(THD *thd); /** Inform the item that it is located under a NOT, which is a top-level item. */ virtual void under_not(Item_func_not * upper __attribute__((unused))) {}; void register_in(THD *thd); bool depends_only_on(table_map view_map) { return marker & MARKER_FULL_EXTRACTION; } int get_extraction_flag() { return marker & MARKER_EXTRACTION_MASK; } void set_extraction_flag(int16 flags) { marker &= ~MARKER_EXTRACTION_MASK; marker|= flags; } void clear_extraction_flag() { marker &= ~MARKER_EXTRACTION_MASK; } void check_pushable_cond(Pushdown_checker excl_dep_func, uchar *arg); bool pushable_cond_checker_for_derived(uchar *arg) { return excl_dep_on_table(*((table_map *)arg)); } bool pushable_cond_checker_for_subquery(uchar *arg) { DBUG_ASSERT(((Item*) arg)->get_IN_subquery()); return excl_dep_on_in_subq_left_part(((Item*)arg)->get_IN_subquery()); } Item *build_pushable_cond(THD *thd, Pushdown_checker checker, uchar *arg); /* Checks if this item depends only on the arg table */ bool pushable_equality_checker_for_derived(uchar *arg) { return (used_tables() == *((table_map *)arg)); } /* Checks if this item consists in the left part of arg IN subquery predicate */ bool pushable_equality_checker_for_subquery(uchar *arg); /** This method is to set relationship between a positional parameter represented by the '?' and an actual argument value passed to the call of PS/SP by the USING clause. The method is overridden in classes Item_param and Item_default_value. */ virtual bool associate_with_target_field(THD *, Item_field *) { DBUG_ASSERT(fixed()); return false; } protected: /* Service function for public method get_copy(). See comments for get_copy() above. Override this method in derived classes to create shallow copies of the item */ virtual Item *do_get_copy(THD *thd) const = 0; /* Service function for public method build_clone(). See comments for build_clone() above. Override this method in derived classes to create deep copies (clones) of the item where possible */ virtual Item* do_build_clone(THD *thd) const = 0; }; MEM_ROOT *get_thd_memroot(THD *thd); template inline Item* get_item_copy (THD *thd, const T* item) { Item *copy= new (get_thd_memroot(thd)) T(*item); if (likely(copy)) copy->register_in(thd); return copy; } #ifndef DBUG_OFF /** A helper class to print the data type and the value for an Item in debug builds. */ class DbugStringItemTypeValue: public StringBuffer<128> { public: DbugStringItemTypeValue(THD *thd, const Item *item) { append('('); Name Item_name= item->type_handler()->name(); append(Item_name.ptr(), Item_name.length()); append(')'); const_cast(item)->print(this, QT_EXPLAIN); /* Append end \0 to allow usage of c_ptr() */ append('\0'); str_length--; } }; #endif /* DBUG_OFF */ /** Compare two Items for List::add_unique() */ bool cmp_items(Item *a, Item *b); /** Array of items, e.g. function or aggerate function arguments. */ class Item_args { protected: Item **args, *tmp_arg[2]; uint arg_count; void set_arguments(THD *thd, List &list); bool walk_args(Item_processor processor, bool walk_subquery, void *arg) { for (uint i= 0; i < arg_count; i++) { if (args[i]->walk(processor, walk_subquery, arg)) return true; } return false; } bool transform_args(THD *thd, Item_transformer transformer, uchar *arg); void propagate_equal_fields(THD *, const Item::Context &, COND_EQUAL *); bool excl_dep_on_table(table_map tab_map) { for (uint i= 0; i < arg_count; i++) { if (args[i]->const_item()) continue; if (!args[i]->excl_dep_on_table(tab_map)) return false; } return true; } bool excl_dep_on_grouping_fields(st_select_lex *sel); bool eq(const Item_args *other, bool binary_cmp) const { for (uint i= 0; i < arg_count ; i++) { if (!args[i]->eq(other->args[i], binary_cmp)) return false; } return true; } bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) { for (uint i= 0; i < arg_count; i++) { if (args[i]->const_item()) continue; if (!args[i]->excl_dep_on_in_subq_left_part(subq_pred)) return false; } return true; } public: Item_args(void) :args(NULL), arg_count(0) { } Item_args(Item *a) :args(tmp_arg), arg_count(1) { args[0]= a; } Item_args(Item *a, Item *b) :args(tmp_arg), arg_count(2) { args[0]= a; args[1]= b; } Item_args(THD *thd, Item *a, Item *b, Item *c) { arg_count= 0; if (likely((args= (Item**) thd_alloc(thd, sizeof(Item*) * 3)))) { arg_count= 3; args[0]= a; args[1]= b; args[2]= c; } } Item_args(THD *thd, Item *a, Item *b, Item *c, Item *d) { arg_count= 0; if (likely((args= (Item**) thd_alloc(thd, sizeof(Item*) * 4)))) { arg_count= 4; args[0]= a; args[1]= b; args[2]= c; args[3]= d; } } Item_args(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e) { arg_count= 5; if (likely((args= (Item**) thd_alloc(thd, sizeof(Item*) * 5)))) { arg_count= 5; args[0]= a; args[1]= b; args[2]= c; args[3]= d; args[4]= e; } } Item_args(THD *thd, List &list) { set_arguments(thd, list); } Item_args(THD *thd, const Item_args *other); bool alloc_arguments(THD *thd, uint count); void add_argument(Item *item) { args[arg_count++]= item; } /** Extract row elements from the given position. For example, for this input: (1,2),(3,4),(5,6) pos=0 will extract (1,3,5) pos=1 will extract (2,4,6) @param thd - current thread, to allocate memory on its mem_root @param rows - an array of compatible ROW-type items @param pos - the element position to extract */ bool alloc_and_extract_row_elements(THD *thd, const Item_args *rows, uint pos) { DBUG_ASSERT(rows->argument_count() > 0); DBUG_ASSERT(rows->arguments()[0]->cols() > pos); if (alloc_arguments(thd, rows->argument_count())) return true; for (uint i= 0; i < rows->argument_count(); i++) { DBUG_ASSERT(rows->arguments()[0]->cols() == rows->arguments()[i]->cols()); Item *arg= rows->arguments()[i]->element_index(pos); add_argument(arg); } DBUG_ASSERT(argument_count() == rows->argument_count()); return false; } inline Item **arguments() const { return args; } inline uint argument_count() const { return arg_count; } inline void remove_arguments() { arg_count=0; } Sql_mode_dependency value_depends_on_sql_mode_bit_or() const; }; /* Class to be used to enumerate all field references in an item tree. This includes references to outside but not fields of the tables within a subquery. Suggested usage: class My_enumerator : public Field_enumerator { virtual void visit_field() { ... your actions ...} } My_enumerator enumerator; item->walk(Item::enumerate_field_refs_processor, ...,&enumerator); This is similar to Visitor pattern. */ class Field_enumerator { public: virtual void visit_field(Item_field *field)= 0; virtual ~Field_enumerator() = default;; /* purecov: inspected */ Field_enumerator() = default; /* Remove gcc warning */ }; class Item_string; class Item_fixed_hybrid: public Item { public: Item_fixed_hybrid(THD *thd): Item(thd) { base_flags&= ~item_base_t::FIXED; } Item_fixed_hybrid(THD *thd, Item_fixed_hybrid *item) :Item(thd, item) { base_flags|= (item->base_flags & item_base_t::FIXED); } bool fix_fields(THD *thd, Item **ref) override { DBUG_ASSERT(!fixed()); base_flags|= item_base_t::FIXED; return false; } void cleanup() override { Item::cleanup(); base_flags&= ~item_base_t::FIXED; } void quick_fix_field() override { base_flags|= item_base_t::FIXED; } void unfix_fields() override { base_flags&= ~item_base_t::FIXED; } }; /** A common class for Item_basic_constant and Item_param */ class Item_basic_value :public Item, public Item_const { protected: // Value metadata, e.g. to make string processing easier class Metadata: private MY_STRING_METADATA { public: Metadata(const String *str) { my_string_metadata_get(this, str->charset(), str->ptr(), str->length()); } Metadata(const String *str, my_repertoire_t repertoire_arg) { MY_STRING_METADATA::repertoire= repertoire_arg; MY_STRING_METADATA::char_length= str->numchars(); } my_repertoire_t repertoire() const { return MY_STRING_METADATA::repertoire; } size_t char_length() const { return MY_STRING_METADATA::char_length; } }; void fix_charset_and_length(CHARSET_INFO *cs, Derivation dv, Metadata metadata) { /* We have to have a different max_length than 'length' here to ensure that we get the right length if we do use the item to create a new table. In this case max_length must be the maximum number of chars for a string of this type because we in Create_field:: divide the max_length with mbmaxlen). */ collation.set(cs, dv, metadata.repertoire()); fix_char_length(metadata.char_length()); decimals= NOT_FIXED_DEC; } void fix_charset_and_length_from_str_value(const String &str, Derivation dv) { fix_charset_and_length(str.charset(), dv, Metadata(&str)); } Item_basic_value(THD *thd): Item(thd) {} Item_basic_value(): Item() {} public: Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { /* create_tmp_field_ex() for this type of Items is called for: - CREATE TABLE ... SELECT - In ORDER BY: SELECT max(a) FROM t1 GROUP BY a ORDER BY 'const'; - In CURSORS: DECLARE c CURSOR FOR SELECT 'test'; OPEN c; */ return tmp_table_field_from_field_type_maybe_null(root, table, src, param, type() == Item::NULL_ITEM); } bool eq(const Item *item, bool binary_cmp) const override; const Type_all_attributes *get_type_all_attributes_from_const() const override { return this; } }; class Item_basic_constant :public Item_basic_value { public: Item_basic_constant(THD *thd): Item_basic_value(thd) {}; Item_basic_constant(): Item_basic_value() {}; bool check_vcol_func_processor(void *) override { return false; } const Item_const *get_item_const() const override { return this; } virtual Item_basic_constant *make_string_literal_concat(THD *thd, const LEX_CSTRING *) { DBUG_ASSERT(0); return this; } bool val_bool() override = 0; }; /***************************************************************************** The class is a base class for representation of stored routine variables in the Item-hierarchy. There are the following kinds of SP-vars: - local variables (Item_splocal); - CASE expression (Item_case_expr); *****************************************************************************/ class Item_sp_variable :public Item_fixed_hybrid { protected: /* THD, which is stored in fix_fields() and is used in this_item() to avoid current_thd use. */ THD *m_thd; bool fix_fields_from_item(THD *thd, Item **, const Item *); public: LEX_CSTRING m_name; public: #ifdef DBUG_ASSERT_EXISTS /* Routine to which this Item_splocal belongs. Used for checking if correct runtime context is used for variable handling. */ const sp_head *m_sp; #endif public: Item_sp_variable(THD *thd, const LEX_CSTRING *sp_var_name); public: bool fix_fields(THD *thd, Item **) override= 0; double val_real() override; longlong val_int() override; String *val_str(String *sp) override; my_decimal *val_decimal(my_decimal *decimal_value) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool val_native(THD *thd, Native *to) override; bool is_null() override; public: void make_send_field(THD *thd, Send_field *field) override; bool const_item() const override { return true; } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { return create_tmp_field_ex_simple(root, table, src, param); } inline int save_in_field(Field *field, bool no_conversions) override; inline bool send(Protocol *protocol, st_value *buffer) override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(m_name.str, arg, VCOL_IMPOSSIBLE); } }; /***************************************************************************** Item_sp_variable inline implementation. *****************************************************************************/ inline int Item_sp_variable::save_in_field(Field *field, bool no_conversions) { return this_item()->save_in_field(field, no_conversions); } inline bool Item_sp_variable::send(Protocol *protocol, st_value *buffer) { return this_item()->send(protocol, buffer); } /***************************************************************************** A reference to local SP variable (incl. reference to SP parameter), used in runtime. *****************************************************************************/ class Item_splocal :public Item_sp_variable, private Settable_routine_parameter, public Rewritable_query_parameter, public Type_handler_hybrid_field_type { protected: const Sp_rcontext_handler *m_rcontext_handler; uint m_var_idx; Type m_type; bool append_value_for_log(THD *thd, String *str); sp_rcontext *get_rcontext(sp_rcontext *local_ctx) const; Item_field *get_variable(sp_rcontext *ctx) const; public: Item_splocal(THD *thd, const Sp_rcontext_handler *rh, const LEX_CSTRING *sp_var_name, uint sp_var_idx, const Type_handler *handler, uint pos_in_q= 0, uint len_in_q= 0); bool fix_fields(THD *, Item **) override; Item *this_item() override; const Item *this_item() const override; Item **this_item_addr(THD *thd, Item **) override; void print(String *str, enum_query_type query_type) override; public: inline const LEX_CSTRING *my_name() const; inline uint get_var_idx() const; Type type() const override { return m_type; } const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } uint cols() const override { return this_item()->cols(); } Item* element_index(uint i) override { return this_item()->element_index(i); } Item** addr(uint i) override { return this_item()->addr(i); } bool check_cols(uint c) override; private: bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; public: Item_splocal *get_item_splocal() override { return this; } Rewritable_query_parameter *get_rewritable_query_parameter() override { return this; } Settable_routine_parameter *get_settable_routine_parameter() override { return this; } bool append_for_log(THD *thd, String *str) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } /* Override the inherited create_field_for_create_select(), because we want to preserve the exact data type for: DECLARE a1 INT; DECLARE a2 TYPE OF t1.a2; CREATE TABLE t1 AS SELECT a1, a2; The inherited implementation would create a column based on result_type(), which is less exact. */ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) override { return create_table_field_from_handler(root, table); } bool is_valid_limit_clause_variable_with_error() const { /* In case if the variable has an anchored data type, e.g.: DECLARE a TYPE OF t1.a; type_handler() is set to &type_handler_null and this function detects such variable as not valid in LIMIT. */ if (type_handler()->is_limit_clause_valid_type()) return true; my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); return false; } }; /** An Item_splocal variant whose data type becomes known only at sp_rcontext creation time, e.g. "DECLARE var1 t1.col1%TYPE". */ class Item_splocal_with_delayed_data_type: public Item_splocal { public: Item_splocal_with_delayed_data_type(THD *thd, const Sp_rcontext_handler *rh, const LEX_CSTRING *sp_var_name, uint sp_var_idx, uint pos_in_q, uint len_in_q) :Item_splocal(thd, rh, sp_var_name, sp_var_idx, &type_handler_null, pos_in_q, len_in_q) { } Item *do_get_copy(THD *) const override { return nullptr; } Item *do_build_clone(THD *thd) const override { return nullptr; } }; /** SP variables that are fields of a ROW. DELCARE r ROW(a INT,b INT); SELECT r.a; -- This is handled by Item_splocal_row_field */ class Item_splocal_row_field :public Item_splocal { protected: LEX_CSTRING m_field_name; uint m_field_idx; bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; public: Item_splocal_row_field(THD *thd, const Sp_rcontext_handler *rh, const LEX_CSTRING *sp_var_name, const LEX_CSTRING *sp_field_name, uint sp_var_idx, uint sp_field_idx, const Type_handler *handler, uint pos_in_q= 0, uint len_in_q= 0) :Item_splocal(thd, rh, sp_var_name, sp_var_idx, handler, pos_in_q, len_in_q), m_field_name(*sp_field_name), m_field_idx(sp_field_idx) { } bool fix_fields(THD *thd, Item **) override; Item *this_item() override; const Item *this_item() const override; Item **this_item_addr(THD *thd, Item **) override; bool append_for_log(THD *thd, String *str) override; void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *) const override { return nullptr; } Item *do_build_clone(THD *thd) const override { return nullptr; } }; class Item_splocal_row_field_by_name :public Item_splocal_row_field { bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; public: Item_splocal_row_field_by_name(THD *thd, const Sp_rcontext_handler *rh, const LEX_CSTRING *sp_var_name, const LEX_CSTRING *sp_field_name, uint sp_var_idx, const Type_handler *handler, uint pos_in_q= 0, uint len_in_q= 0) :Item_splocal_row_field(thd, rh, sp_var_name, sp_field_name, sp_var_idx, 0 /* field index will be set later */, handler, pos_in_q, len_in_q) { } bool fix_fields(THD *thd, Item **it) override; void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *) const override { return nullptr; } Item *do_build_clone(THD *thd) const override { return nullptr; } }; /***************************************************************************** Item_splocal inline implementation. *****************************************************************************/ inline const LEX_CSTRING *Item_splocal::my_name() const { return &m_name; } inline uint Item_splocal::get_var_idx() const { return m_var_idx; } /***************************************************************************** A reference to case expression in SP, used in runtime. *****************************************************************************/ class Item_case_expr :public Item_sp_variable { public: Item_case_expr(THD *thd, uint case_expr_id); public: bool fix_fields(THD *thd, Item **) override; Item *this_item() override; const Item *this_item() const override; Item **this_item_addr(THD *thd, Item **) override; Type type() const override; const Type_handler *type_handler() const override { return this_item()->type_handler(); } public: /* NOTE: print() is intended to be used from views and for debug. Item_case_expr can not occur in views, so here it is only for debug purposes. */ void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *) const override { return nullptr; } Item *do_build_clone(THD *thd) const override { return nullptr; } private: uint m_case_expr_id; }; /***************************************************************************** Item_case_expr inline implementation. *****************************************************************************/ inline enum Item::Type Item_case_expr::type() const { return this_item()->type(); } /* NAME_CONST(given_name, const_value). This 'function' has all properties of the supplied const_value (which is assumed to be a literal constant), and the name given_name. This is used to replace references to SP variables when we write PROCEDURE statements into the binary log. TODO Together with Item_splocal and Item::this_item() we can actually extract common a base of this class and Item_splocal. Maybe it is possible to extract a common base with class Item_ref, too. */ class Item_name_const : public Item_fixed_hybrid { Item *value_item; Item *name_item; public: Item_name_const(THD *thd, Item *name_arg, Item *val); bool fix_fields(THD *, Item **) override; Type type() const override; double val_real() override; longlong val_int() override; String *val_str(String *sp) override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool val_native(THD *thd, Native *to) override; bool is_null() override; void print(String *str, enum_query_type query_type) override; const Type_handler *type_handler() const override { return value_item->type_handler(); } bool const_item() const override { return true; } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { /* We can get to here when using a CURSOR for a query with NAME_CONST(): DECLARE c CURSOR FOR SELECT NAME_CONST('x','y') FROM t1; OPEN c; */ return tmp_table_field_from_field_type_maybe_null(root, table, src, param, type() == Item::NULL_ITEM); } int save_in_field(Field *field, bool no_conversions) override { return value_item->save_in_field(field, no_conversions); } bool send(Protocol *protocol, st_value *buffer) override { return value_item->send(protocol, buffer); } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("name_const()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_literal: public Item_basic_constant { public: Item_literal(THD *thd): Item_basic_constant(thd) { } Item_literal(): Item_basic_constant() {} Type type() const override { return CONST_ITEM; } bool check_partition_func_processor(void *int_arg) override { return false;} bool const_item() const override { return true; } bool basic_const_item() const override { return true; } bool is_expensive() override { return false; } bool cleanup_is_expensive_cache_processor(void *arg) override { return 0; } }; class Item_num: public Item_literal { public: Item_num(THD *thd): Item_literal(thd) { collation= DTCollation_numeric(); } Item_num(): Item_literal() { collation= DTCollation_numeric(); } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } }; #define NO_CACHED_FIELD_INDEX ((field_index_t) ~0U) class st_select_lex; class Item_result_field :public Item_fixed_hybrid /* Item with result field */ { protected: Field *create_tmp_field_ex_from_handler(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param, const Type_handler *h); public: Field *result_field; /* Save result here */ Item_result_field(THD *thd): Item_fixed_hybrid(thd), result_field(0) {} // Constructor used for Item_sum/Item_cond_and/or (see Item comment) Item_result_field(THD *thd, Item_result_field *item): Item_fixed_hybrid(thd, item), result_field(item->result_field) {} ~Item_result_field() = default; Field *get_tmp_table_field() override { return result_field; } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { DBUG_ASSERT(fixed()); const Type_handler *h= type_handler()->type_handler_for_tmp_table(this); return create_tmp_field_ex_from_handler(root, table, src, param, h); } void get_tmp_field_src(Tmp_field_src *src, const Tmp_field_param *param); /* This implementation of used_tables() used by Item_avg_field and Item_variance_field which work when only temporary table left, so theu return table map of the temporary table. */ table_map used_tables() const override { return 1; } bool is_result_field() override { return true; } void save_in_result_field(bool no_conversions) override { save_in_field(result_field, no_conversions); } void cleanup() override; bool check_vcol_func_processor(void *) override { return false; } }; class Item_ident :public Item_result_field { protected: /* We have to store initial values of db_name, table_name and field_name to be able to restore them during cleanup() because they can be updated during fix_fields() to values from Field object and life-time of those is shorter than life-time of Item_field. */ Lex_table_name orig_db_name; Lex_table_name orig_table_name; Lex_ident orig_field_name; void undeclared_spvar_error() const; public: Name_resolution_context *context; Lex_table_name db_name; Lex_table_name table_name; Lex_ident field_name; /* Cached pointer to table which contains this field, used for the same reason by prep. stmt. too in case then we have not-fully qualified field. 0 - means no cached value. */ TABLE_LIST *cached_table; st_select_lex *depended_from; /* Cached value of index for this field in table->field array, used by prepared stmts for speeding up their re-execution. Holds NO_CACHED_FIELD_INDEX if index value is not known. */ field_index_t cached_field_index; /* Some Items resolved in another select should not be marked as dependency of the subquery where they are. During normal name resolution, we check this. Stored procedures and prepared statements first try to resolve an ident item using a cached table reference and field position from the previous query execution (cached_table/cached_field_index). If the tables were not changed, the ident matches the table/field, and we have faster resolution of the ident without looking through all tables and fields in the query. But in this case, we can not check all conditions about this ident item dependency, so we should cache the condition in this variable. */ bool can_be_depended; /* NOTE: came from TABLE::alias_name_used and this is only a hint! See comment for TABLE::alias_name_used. */ bool alias_name_used; /* true if item was resolved against alias */ Item_ident(THD *thd, Name_resolution_context *context_arg, const LEX_CSTRING &db_name_arg, const LEX_CSTRING &table_name_arg, const LEX_CSTRING &field_name_arg); Item_ident(THD *thd, Item_ident *item); Item_ident(THD *thd, TABLE_LIST *view_arg, const LEX_CSTRING &field_name_arg); LEX_CSTRING full_name_cstring() const override; void cleanup() override; st_select_lex *get_depended_from() const; bool remove_dependence_processor(void * arg) override; void print(String *str, enum_query_type query_type) override; bool change_context_processor(void *cntx) override { context= (Name_resolution_context *)cntx; return FALSE; } /** Collect outer references */ bool collect_outer_ref_processor(void *arg) override; friend bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator *it, bool any_privileges, bool returning_field); }; class Item_field :public Item_ident, public Load_data_outvar { protected: void set_field(Field *field); public: Field *field; Item_equal *item_equal; /* if any_privileges set to TRUE then here real effective privileges will be stored */ privilege_t have_privileges; /* field need any privileges (for VIEW creation) */ bool any_privileges; Item_field(THD *thd, Name_resolution_context *context_arg, const LEX_CSTRING &db_arg, const LEX_CSTRING &table_name_arg, const LEX_CSTRING &field_name_arg); Item_field(THD *thd, Name_resolution_context *context_arg, const LEX_CSTRING &field_name_arg) :Item_field(thd, context_arg, null_clex_str, null_clex_str, field_name_arg) { } Item_field(THD *thd, Name_resolution_context *context_arg) :Item_field(thd, context_arg, null_clex_str, null_clex_str, null_clex_str) { } /* Constructor needed to process subselect with temporary tables (see Item) */ Item_field(THD *thd, Item_field *item); /* Constructor used inside setup_wild(), ensures that field, table, and database names will live as long as Item_field (this is important in prepared statements). */ Item_field(THD *thd, Name_resolution_context *context_arg, Field *field); /* If this constructor is used, fix_fields() won't work, because db_name, table_name and column_name are unknown. It's necessary to call reset_field() before fix_fields() for all fields created this way. */ Item_field(THD *thd, Field *field); Type type() const override { return FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const override; double val_real() override; longlong val_int() override; my_decimal *val_decimal(my_decimal *) override; String *val_str(String*) override; void save_result(Field *to) override; double val_result() override; longlong val_int_result() override; bool val_native(THD *thd, Native *to) override; bool val_native_result(THD *thd, Native *to) override; String *str_result(String* tmp) override; my_decimal *val_decimal_result(my_decimal *) override; bool val_bool_result() override; bool is_null_result() override; bool send(Protocol *protocol, st_value *buffer) override; Load_data_outvar *get_load_data_outvar() override { return this; } bool load_data_set_null(THD *thd, const Load_data_param *param) override { return field->load_data_set_null(thd); } bool load_data_set_value(THD *thd, const char *pos, uint length, const Load_data_param *param) override { field->load_data_set_value(pos, length, param->charset()); return false; } bool load_data_set_no_data(THD *thd, const Load_data_param *param) override; void load_data_print_for_log_event(THD *thd, String *to) const override; bool load_data_add_outvar(THD *thd, Load_data_param *param) const override { return param->add_outvar_field(thd, field); } uint load_data_fixed_length() const override { return field->field_length; } void reset_field(Field *f); bool fix_fields(THD *, Item **) override; void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; void make_send_field(THD *thd, Send_field *tmp_field) override; int save_in_field(Field *field,bool no_conversions) override; void save_org_in_field(Field *field, fast_field_copier optimizer_data) override; fast_field_copier setup_fast_field_copier(Field *field) override; table_map used_tables() const override; table_map all_used_tables() const override; const Type_handler *type_handler() const override { const Type_handler *handler= field->type_handler(); return handler->type_handler_for_item_field(); } const Type_handler *real_type_handler() const override { if (field->is_created_from_null_item) return &type_handler_null; return field->type_handler(); } uint32 character_octet_length() const override { return field->character_octet_length(); } Field *create_tmp_field_from_item_field(MEM_ROOT *root, TABLE *new_table, Item_ref *orig_item, const Tmp_field_param *param); Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override; const TYPELIB *get_typelib() const override { return field->get_typelib(); } enum_monotonicity_info get_monotonicity_info() const override { return MONOTONIC_STRICT_INCREASING; } Sql_mode_dependency value_depends_on_sql_mode() const override { return Sql_mode_dependency(0, field->value_depends_on_sql_mode()); } bool hash_not_null(Hasher *hasher) override { if (field->is_null()) return true; field->hash_not_null(hasher); return false; } longlong val_int_endpoint(bool left_endp, bool *incl_endp) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool get_date_result(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate) override; longlong val_datetime_packed(THD *thd) override; longlong val_time_packed(THD *thd) override; bool is_null() override { return field->is_null(); } void update_null_value() override; void update_table_bitmaps() { if (field && field->table) { TABLE *tab= field->table; tab->covering_keys.intersect(field->part_of_key); if (tab->read_set) tab->mark_column_with_deps(field); } } void update_used_tables() override { update_table_bitmaps(); } COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) override { /* normilize_cond() replaced all conditions of type WHERE/HAVING field to: WHERE/HAVING field<>0 By the time of a build_equal_items() call, all such conditions should already be replaced. No Item_field are possible. Note, some Item_field derivants are still possible. Item_insert_value: SELECT * FROM t1 WHERE VALUES(a); Item_default_value: SELECT * FROM t1 WHERE DEFAULT(a); */ DBUG_ASSERT(type() != FIELD_ITEM); return Item_ident::build_equal_items(thd, inherited, link_item_fields, cond_equal_ref); } bool is_result_field() override { return false; } void save_in_result_field(bool no_conversions) override; Item *get_tmp_table_item(THD *thd) override; bool find_not_null_fields(table_map allowed) override; bool collect_item_field_processor(void * arg) override; bool unknown_splocal_processor(void *arg) override; bool add_field_to_set_processor(void * arg) override; bool find_item_in_field_list_processor(void *arg) override; bool register_field_in_read_map(void *arg) override; bool register_field_in_write_map(void *arg) override; bool register_field_in_bitmap(void *arg) override; bool check_partition_func_processor(void *) override {return false;} bool post_fix_fields_part_expr_processor(void *bool_arg) override; bool check_valid_arguments_processor(void *bool_arg) override; bool check_field_expression_processor(void *arg) override; bool enumerate_field_refs_processor(void *arg) override; bool update_table_bitmaps_processor(void *arg) override; bool switch_to_nullable_fields_processor(void *arg) override; bool update_vcol_processor(void *arg) override; bool rename_fields_processor(void *arg) override; bool rename_table_processor(void *arg) override; bool check_vcol_func_processor(void *arg) override; bool set_fields_as_dependent_processor(void *arg) override { if (!(used_tables() & OUTER_REF_TABLE_BIT)) { depended_from= (st_select_lex *) arg; item_equal= NULL; } return 0; } void cleanup() override; Item_equal *get_item_equal() override { return item_equal; } void set_item_equal(Item_equal *item_eq) override { item_equal= item_eq; } Item_equal *find_item_equal(COND_EQUAL *cond_equal) override; Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *) override; Item *replace_equal_field(THD *thd, uchar *arg) override; uint32 max_display_length() const override { return field->max_display_length(); } Item_field *field_for_view_update() override { return this; } int fix_outer_field(THD *thd, Field **field, Item **reference); Item *update_value_transformer(THD *thd, uchar *select_arg) override; Item *derived_field_transformer_for_having(THD *thd, uchar *arg) override; Item *derived_field_transformer_for_where(THD *thd, uchar *arg) override; Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) override; Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) override; Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) override; void print(String *str, enum_query_type query_type) override; bool excl_dep_on_table(table_map tab_map) override; bool excl_dep_on_grouping_fields(st_select_lex *sel) override; bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override; bool cleanup_excluding_fields_processor(void *arg) override { return field ? 0 : cleanup_processor(arg); } bool cleanup_excluding_const_fields_processor(void *arg) override { return field && const_item() ? 0 : cleanup_processor(arg); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item* do_build_clone(THD *thd) const override { return get_copy(thd); } bool is_outer_field() const override { DBUG_ASSERT(fixed()); return field->table->pos_in_table_list->outer_join; } bool check_index_dependence(void *arg) override; friend class Item_default_value; friend class Item_insert_value; friend class st_select_lex_unit; }; /** Item_field for the ROW data type */ class Item_field_row: public Item_field, public Item_args { public: Item_field_row(THD *thd, Field *field) :Item_field(thd, field), Item_args() { } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } const Type_handler *type_handler() const override { return &type_handler_row; } uint cols() const override { return arg_count; } Item* element_index(uint i) override { return arg_count ? args[i] : this; } Item** addr(uint i) override { return arg_count ? args + i : NULL; } bool check_cols(uint c) override { if (cols() != c) { my_error(ER_OPERAND_COLUMNS, MYF(0), c); return true; } return false; } bool row_create_items(THD *thd, List *list); }; /* @brief Item_temptable_field is the same as Item_field, except that print() continues to work even if the table has been dropped. @detail We need this item for "ANALYZE statement" feature. Query execution has these steps: 1. Run the query. 2. Cleanup starts. Temporary tables are destroyed 3. print "ANALYZE statement" output, if needed 4. Call close_thread_table() for regular tables. Step #4 is done after step #3, so "ANALYZE stmt" has no problem printing Item_field objects that refer to regular tables. However, Step #3 is done after Step #2. Attempt to print Item_field objects that refer to temporary tables will cause access to freed memory. To resolve this, we use Item_temptable_field to refer to items in temporary (work) tables. */ class Item_temptable_field :public Item_field { public: Item_temptable_field(THD *thd, Name_resolution_context *context_arg, Field *field) : Item_field(thd, context_arg, field) {} Item_temptable_field(THD *thd, Field *field) : Item_field(thd, field) {} Item_temptable_field(THD *thd, Item_field *item) : Item_field(thd, item) {}; void print(String *str, enum_query_type query_type) override; }; class Item_null :public Item_basic_constant { public: Item_null(THD *thd, const char *name_par=0, CHARSET_INFO *cs= &my_charset_bin): Item_basic_constant(thd) { set_maybe_null(); null_value= TRUE; max_length= 0; name.str= name_par ? name_par : "NULL"; name.length= strlen(name.str); collation.set(cs, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII); } Type type() const override { return NULL_ITEM; } bool vcol_assignment_allowed_value() const override { return true; } bool val_bool() override; double val_real() override; longlong val_int() override; String *val_str(String *str) override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; longlong val_datetime_packed(THD *) override; longlong val_time_packed(THD *) override; int save_in_field(Field *field, bool no_conversions) override; int save_safe_in_field(Field *field) override; bool send(Protocol *protocol, st_value *buffer) override; const Type_handler *type_handler() const override { return &type_handler_null; } bool basic_const_item() const override { return true; } Item *clone_item(THD *thd) const override; bool const_is_null() const override { return true; } bool is_null() override { return true; } void print(String *str, enum_query_type) override { str->append(NULL_clex_str); } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; bool check_partition_func_processor(void *) override { return false; } Item_basic_constant *make_string_literal_concat(THD *thd, const LEX_CSTRING *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_null_result :public Item_null { public: Field *result_field; Item_null_result(THD *thd): Item_null(thd), result_field(0) {} bool is_result_field() override { return result_field != 0; } const Type_handler *type_handler() const override { if (result_field) return result_field->type_handler(); return &type_handler_null; } Field *create_tmp_field_ex(MEM_ROOT *, TABLE *, Tmp_field_src *, const Tmp_field_param *) override { DBUG_ASSERT(0); return NULL; } void save_in_result_field(bool no_conversions) override { save_in_field(result_field, no_conversions); } bool check_partition_func_processor(void *int_arg) override { return true; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE); } }; /* Item represents one placeholder ('?') of prepared statement Notes: Item_param::field_type() is used when this item is in a temporary table. This is NOT placeholder metadata sent to client, as this value is assigned after sending metadata (in setup_one_conversion_function). For example in case of 'SELECT ?' you'll get MYSQL_TYPE_STRING both in result set and placeholders metadata, no matter what type you will supply for this placeholder in mysql_stmt_execute. Item_param has two Type_handler pointers, which can point to different handlers: 1. In the Type_handler_hybrid_field_type member It's initialized in: - Item_param::setup_conversion(), for client-server PS protocol, according to the bind type. - Item_param::set_from_item(), for EXECUTE and EXECUTE IMMEDIATE, according to the actual parameter data type. 2. In the "value" member. It's initialized in: - Item_param::set_param_func(), for client-server PS protocol. - Item_param::set_from_item(), for EXECUTE and EXECUTE IMMEDIATE. */ class Item_param :public Item_basic_value, private Settable_routine_parameter, public Rewritable_query_parameter, private Type_handler_hybrid_field_type { /* NO_VALUE is a special value meaning that the parameter has not been assigned yet. Item_param::state is assigned to NO_VALUE in constructor and is used at prepare time. 1. At prepare time Item_param::fix_fields() sets "fixed" to true, but as Item_param::state is still NO_VALUE, Item_param::basic_const_item() returns false. This prevents various optimizations to happen at prepare time fix_fields(). For example, in this query: PREPARE stmt FROM 'SELECT FORMAT(10000,2,?)'; Item_param::basic_const_item() is tested from Item_func_format::fix_length_and_dec(). 2. At execute time: When Item_param gets a value (or a pseudo-value like DEFAULT_VALUE or IGNORE_VALUE): - Item_param::state changes from NO_VALUE to something else - Item_param::fixed is changed to true All Item_param::set_xxx() make sure to do so. In the state with an assigned value: - Item_param::basic_const_item() returns true - Item::type() returns NULL_ITEM or CONST_ITEM, depending on the value assigned. So in this state Item_param behaves in many cases like a literal. When Item_param::cleanup() is called: - Item_param::state does not change - Item_param::fixed changes to false Note, this puts Item_param into an inconsistent state: - Item_param::basic_const_item() still returns "true" - Item_param::type() still pretends to be a basic constant Item Both are not expected in combination with fixed==false. However, these methods are not really called in this state, see asserts in Item_param::basic_const_item() and Item_param::type(). When Item_param::reset() is called: - Item_param::state changes to NO_VALUE - Item_param::fixed changes to false */ enum enum_item_param_state { NO_VALUE, NULL_VALUE, SHORT_DATA_VALUE, LONG_DATA_VALUE, DEFAULT_VALUE, IGNORE_VALUE } state; void fix_temporal(uint32 max_length_arg, uint decimals_arg); struct CONVERSION_INFO { /* Character sets conversion info for string values. Character sets of client and connection defined at bind time are used for all conversions, even if one of them is later changed (i.e. between subsequent calls to mysql_stmt_execute). */ CHARSET_INFO *character_set_client; CHARSET_INFO *character_set_of_placeholder; /* This points at character set of connection if conversion to it is required (i. e. if placeholder typecode is not BLOB). Otherwise it's equal to character_set_client (to simplify check in convert_str_value()). */ CHARSET_INFO *final_character_set_of_str_value; private: bool needs_conversion() const { return final_character_set_of_str_value != character_set_of_placeholder; } bool convert(THD *thd, String *str); public: void set(THD *thd, CHARSET_INFO *cs); bool convert_if_needed(THD *thd, String *str) { /* Check is so simple because all charsets were set up properly in setup_one_conversion_function, where typecode of placeholder was also taken into account: the variables are different here only if conversion is really necessary. */ if (needs_conversion()) return convert(thd, str); str->set_charset(final_character_set_of_str_value); return false; } }; bool m_empty_string_is_null; class PValue_simple { public: union { longlong integer; double real; CONVERSION_INFO cs_info; MYSQL_TIME time; }; void swap(PValue_simple &other) { swap_variables(PValue_simple, *this, other); } }; class PValue: public Type_handler_hybrid_field_type, public PValue_simple, public Value_source { public: PValue(): Type_handler_hybrid_field_type(&type_handler_null) {} my_decimal m_decimal; String m_string; /* A buffer for string and long data values. Historically all allocated values returned from val_str() were treated as eligible to modification. I. e. in some cases Item_func_concat can append it's second argument to return value of the first one. Because of that we can't return the original buffer holding string data from val_str(), and have to have one buffer for data and another just pointing to the data. This is the latter one and it's returned from val_str(). Can not be declared inside the union as it's not a POD type. */ String m_string_ptr; void swap(PValue &other) { Type_handler_hybrid_field_type::swap(other); PValue_simple::swap(other); m_decimal.swap(other.m_decimal); m_string.swap(other.m_string); m_string_ptr.swap(other.m_string_ptr); } double val_real(const Type_std_attributes *attr) const; longlong val_int(const Type_std_attributes *attr) const; my_decimal *val_decimal(my_decimal *dec, const Type_std_attributes *attr); String *val_str(String *str, const Type_std_attributes *attr); }; PValue value; const String *value_query_val_str(THD *thd, String* str) const; Item *value_clone_item(THD *thd) const; bool is_evaluable_expression() const override; bool can_return_value() const; public: /* Used for bulk protocol only. */ enum enum_indicator_type indicator; const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } bool vcol_assignment_allowed_value() const override { switch (state) { case NULL_VALUE: case DEFAULT_VALUE: case IGNORE_VALUE: return true; case NO_VALUE: case SHORT_DATA_VALUE: case LONG_DATA_VALUE: break; } return false; } Item_param(THD *thd, const LEX_CSTRING *name_arg, uint pos_in_query_arg, uint len_in_query_arg); void cleanup() override { m_default_field= NULL; Item::cleanup(); } Type type() const override { // Don't pretend to be a constant unless value for this item is set. switch (state) { case NO_VALUE: return PARAM_ITEM; case NULL_VALUE: return NULL_ITEM; case SHORT_DATA_VALUE: return CONST_ITEM; case LONG_DATA_VALUE: return CONST_ITEM; case DEFAULT_VALUE: return PARAM_ITEM; case IGNORE_VALUE: return PARAM_ITEM; } DBUG_ASSERT(0); return PARAM_ITEM; } bool is_order_clause_position() const override { return state == SHORT_DATA_VALUE && type_handler()->is_order_clause_position_type(); } const Item_const *get_item_const() const override { switch (state) { case SHORT_DATA_VALUE: case LONG_DATA_VALUE: case NULL_VALUE: return this; case IGNORE_VALUE: case DEFAULT_VALUE: case NO_VALUE: break; } return NULL; } bool const_is_null() const override { return state == NULL_VALUE; } bool can_return_const_value(Item_result type) const { return can_return_value() && value.type_handler()->cmp_type() == type && type_handler()->cmp_type() == type; } const longlong *const_ptr_longlong() const override { return can_return_const_value(INT_RESULT) ? &value.integer : NULL; } const double *const_ptr_double() const override { return can_return_const_value(REAL_RESULT) ? &value.real : NULL; } const my_decimal *const_ptr_my_decimal() const override { return can_return_const_value(DECIMAL_RESULT) ? &value.m_decimal : NULL; } const MYSQL_TIME *const_ptr_mysql_time() const override { return can_return_const_value(TIME_RESULT) ? &value.time : NULL; } const String *const_ptr_string() const override { return can_return_const_value(STRING_RESULT) ? &value.m_string : NULL; } double val_real() override { return can_return_value() ? value.val_real(this) : 0e0; } longlong val_int() override { return can_return_value() ? value.val_int(this) : 0; } my_decimal *val_decimal(my_decimal *dec) override { return can_return_value() ? value.val_decimal(dec, this) : NULL; } String *val_str(String *str) override { return can_return_value() ? value.val_str(str, this) : NULL; } bool get_date(THD *thd, MYSQL_TIME *tm, date_mode_t fuzzydate) override; bool val_native(THD *thd, Native *to) override { return Item_param::type_handler()->Item_param_val_native(thd, this, to); } int save_in_field(Field *field, bool no_conversions) override; void set_default(bool set_type_handler_null); void set_ignore(bool set_type_handler_null); void set_null(); void set_int(longlong i, uint32 max_length_arg); void set_double(double i); void set_decimal(const char *str, ulong length); void set_decimal(const my_decimal *dv, bool unsigned_arg); bool set_str(const char *str, ulong length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); bool set_longdata(const char *str, ulong length); void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg); void set_time(const MYSQL_TIME *tm, uint32 max_length_arg, uint decimals_arg); bool set_from_item(THD *thd, Item *item); void reset(); void set_param_tiny(uchar **pos, ulong len); void set_param_short(uchar **pos, ulong len); void set_param_int32(uchar **pos, ulong len); void set_param_int64(uchar **pos, ulong len); void set_param_float(uchar **pos, ulong len); void set_param_double(uchar **pos, ulong len); void set_param_decimal(uchar **pos, ulong len); void set_param_time(uchar **pos, ulong len); void set_param_datetime(uchar **pos, ulong len); void set_param_date(uchar **pos, ulong len); void set_param_str(uchar **pos, ulong len); void setup_conversion(THD *thd, uchar param_type); void setup_conversion_blob(THD *thd); void setup_conversion_string(THD *thd, CHARSET_INFO *fromcs); /* Assign placeholder value from bind data. Note, that 'len' has different semantics in embedded library (as we don't need to check that packet is not broken there). See sql_prepare.cc for details. */ void set_param_func(uchar **pos, ulong len) { /* To avoid Item_param::set_xxx() asserting on data type mismatch, we set the value type handler here: - It can not be initialized yet after Item_param::setup_conversion(). - Also, for LIMIT clause parameters, the value type handler might have changed from the real type handler to type_handler_longlong. So here we'll restore it. */ const Type_handler *h= Item_param::type_handler(); value.set_handler(h); h->Item_param_set_param_func(this, pos, len); } bool set_value(THD *thd, const Type_all_attributes *attr, const st_value *val, const Type_handler *h) { value.set_handler(h); // See comments in set_param_func() return h->Item_param_set_from_value(thd, this, attr, val); } bool set_limit_clause_param(longlong nr) { value.set_handler(&type_handler_slonglong); set_int(nr, MY_INT64_NUM_DECIMAL_DIGITS); return !unsigned_flag && value.integer < 0; } const String *query_val_str(THD *thd, String *str) const; bool convert_str_value(THD *thd); /* If value for parameter was not set we treat it as non-const so no one will use parameters value in fix_fields still parameter is constant during execution. */ bool const_item() const override { return state != NO_VALUE; } table_map used_tables() const override { return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; } void print(String *str, enum_query_type query_type) override; bool is_null() override { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; } bool basic_const_item() const override; bool has_no_value() const { return state == NO_VALUE; } bool has_long_data_value() const { return state == LONG_DATA_VALUE; } bool has_int_value() const { return state == SHORT_DATA_VALUE && value.type_handler()->cmp_type() == INT_RESULT; } bool is_stored_routine_parameter() const override { return true; } /* This method is used to make a copy of a basic constant item when propagating constants in the optimizer. The reason to create a new item and not use the existing one is not precisely known (2005/04/16). Probably we are trying to preserve tree structure of items, in other words, avoid pointing at one item from two different nodes of the tree. Return a new basic constant item if parameter value is a basic constant, assert otherwise. This method is called only if basic_const_item returned TRUE. */ Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; Item *clone_item(THD *thd) const override; void set_param_type_and_swap_value(Item_param *from); Rewritable_query_parameter *get_rewritable_query_parameter() override { return this; } Settable_routine_parameter *get_settable_routine_parameter() override { return m_is_settable_routine_parameter ? this : nullptr; } bool append_for_log(THD *thd, String *str) override; bool check_vcol_func_processor(void *) override { return false; } Item *do_get_copy(THD *thd) const override { return nullptr; } Item *do_build_clone(THD *thd) const override { return nullptr; } bool add_as_clone(THD *thd); void sync_clones(); bool register_clone(Item_param *i) { return m_clones.push_back(i); } void raise_error_not_evaluable() override { invalid_default_param(); } private: void invalid_default_param() const; bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; void set_out_param_info(Send_field *info) override; public: const Send_field *get_out_param_info() const override; Item_param *get_item_param() override { return this; } void make_send_field(THD *thd, Send_field *field) override; /** See comments on @see Item::associate_with_target_field for method description */ bool associate_with_target_field(THD *, Item_field *field) override { m_associated_field= field; return false; } bool assign_default(Field *field); private: Send_field *m_out_param_info; bool m_is_settable_routine_parameter; /* Array of all references of this parameter marker used in a CTE to its clones created for copies of this marker used the CTE's copies. It's used to synchronize the actual value of the parameter with the values of the clones. */ Mem_root_array m_clones; Item_field *m_associated_field; Field *m_default_field; }; class Item_int :public Item_num { public: longlong value; Item_int(THD *thd, int32 i,size_t length= MY_INT32_NUM_DECIMAL_DIGITS): Item_num(thd), value((longlong) i) { max_length=(uint32)length; } Item_int(THD *thd, longlong i,size_t length= MY_INT64_NUM_DECIMAL_DIGITS): Item_num(thd), value(i) { max_length=(uint32)length; } Item_int(THD *thd, ulonglong i, size_t length= MY_INT64_NUM_DECIMAL_DIGITS): Item_num(thd), value((longlong)i) { max_length=(uint32)length; unsigned_flag= 1; } Item_int(THD *thd, const char *str_arg,longlong i,size_t length): Item_num(thd), value(i) { max_length=(uint32)length; name.str= str_arg; name.length= safe_strlen(name.str); } Item_int(THD *thd, const char *str_arg,longlong i,size_t length, bool flag): Item_num(thd), value(i) { max_length=(uint32)length; name.str= str_arg; name.length= safe_strlen(name.str); unsigned_flag= flag; } Item_int(const char *str_arg,longlong i,size_t length): Item_num(), value(i) { max_length=(uint32)length; name.str= str_arg; name.length= safe_strlen(name.str); unsigned_flag= 1; } Item_int(THD *thd, const char *str_arg, size_t length=64); const Type_handler *type_handler() const override { return type_handler_long_or_longlong(); } Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) override { return tmp_table_field_from_field_type(root, table); } const longlong *const_ptr_longlong() const override { return &value; } bool val_bool() override { return value != 0; } longlong val_int() override { DBUG_ASSERT(!is_cond()); return value; } longlong val_int_min() const override { return value; } double val_real() override { return (double) value; } my_decimal *val_decimal(my_decimal *) override; String *val_str(String*) override; int save_in_field(Field *field, bool no_conversions) override; bool is_order_clause_position() const override { return true; } Item *clone_item(THD *thd) const override; void print(String *str, enum_query_type query_type) override; Item *neg(THD *thd) override; decimal_digits_t decimal_precision() const override { return (decimal_digits_t) (max_length - MY_TEST(value < 0)); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /* We sometimes need to distinguish a number from a boolean: a[1] and a[true] are different things in XPath. Also in JSON boolean values should be treated differently. */ class Item_bool :public Item_int { public: Item_bool(THD *thd, const char *str_arg, longlong i): Item_int(thd, str_arg, i, 1) {} Item_bool(THD *thd, bool i) :Item_int(thd, (longlong) i, 1) { } Item_bool(const char *str_arg, longlong i): Item_int(str_arg, i, 1) {} bool is_bool_literal() const override { return true; } Item *neg_transformer(THD *thd) override; const Type_handler *type_handler() const override { return &type_handler_bool; } const Type_handler *fixed_type_handler() const override { return &type_handler_bool; } void quick_fix_field() override { /* We can get here when Item_bool is created instead of a constant predicate at various condition optimization stages in sql_select. */ } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_bool_static :public Item_bool { public: Item_bool_static(const char *str_arg, longlong i): Item_bool(str_arg, i) {}; void set_join_tab_idx(uint8 join_tab_idx_arg) override { DBUG_ASSERT(0); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; extern const Item_bool_static Item_false, Item_true; class Item_uint :public Item_int { public: Item_uint(THD *thd, const char *str_arg, size_t length); Item_uint(THD *thd, ulonglong i): Item_int(thd, i, 10) {} Item_uint(THD *thd, const char *str_arg, longlong i, uint length); double val_real() override { return ulonglong2double((ulonglong)value); } Item *clone_item(THD *thd) const override; Item *neg(THD *thd) override; decimal_digits_t decimal_precision() const override { return decimal_digits_t(max_length); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_datetime :public Item_int { protected: MYSQL_TIME ltime; public: Item_datetime(THD *thd): Item_int(thd, 0) { unsigned_flag=0; } int save_in_field(Field *field, bool no_conversions) override; longlong val_int() override; double val_real() override { return (double)val_int(); } void set(longlong packed, enum_mysql_timestamp_type ts_type); bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) override { *to= ltime; return false; } }; /* decimal (fixed point) constant */ class Item_decimal :public Item_num { protected: my_decimal decimal_value; public: Item_decimal(THD *thd, const char *str_arg, size_t length, CHARSET_INFO *charset); Item_decimal(THD *thd, const char *str, const my_decimal *val_arg, uint decimal_par, uint length); Item_decimal(THD *thd, const my_decimal *value_par); Item_decimal(THD *thd, longlong val, bool unsig); Item_decimal(THD *thd, double val, int precision, int scale); Item_decimal(THD *thd, const uchar *bin, int precision, int scale); const Type_handler *type_handler() const override { return &type_handler_newdecimal; } bool val_bool() override { return decimal_value.to_bool(); } longlong val_int() override { DBUG_ASSERT(!is_cond()); return decimal_value.to_longlong(unsigned_flag); } double val_real() override { return decimal_value.to_double(); } String *val_str(String *to) override { return decimal_value.to_string(to); } my_decimal *val_decimal(my_decimal *val) override { return &decimal_value; } const my_decimal *const_ptr_my_decimal() const override { return &decimal_value; } int save_in_field(Field *field, bool no_conversions) override; Item *clone_item(THD *thd) const override; void print(String *str, enum_query_type query_type) override { decimal_value.to_string(&str_value); str->append(str_value); } Item *neg(THD *thd) override; decimal_digits_t decimal_precision() const override { return decimal_value.precision(); } void set_decimal_value(my_decimal *value_par); Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_float :public Item_num { const char *presentation; public: double value; Item_float(THD *thd, const char *str_arg, size_t length); Item_float(THD *thd, const char *str, double val_arg, uint decimal_par, uint length): Item_num(thd), value(val_arg) { presentation= name.str= str; name.length= safe_strlen(str); decimals=(uint8) decimal_par; max_length= length; } Item_float(THD *thd, double value_par, uint decimal_par): Item_num(thd), presentation(0), value(value_par) { decimals= (uint8) decimal_par; } int save_in_field(Field *field, bool no_conversions) override; const Type_handler *type_handler() const override { return &type_handler_double; } const double *const_ptr_double() const override { return &value; } bool val_bool() override { return value != 0.0; } double val_real() override { return value; } longlong val_int() override { DBUG_ASSERT(!is_cond()); if (value <= (double) LONGLONG_MIN) { return LONGLONG_MIN; } else if (value >= (double) (ulonglong) LONGLONG_MAX) { return LONGLONG_MAX; } return (longlong) rint(value); } String *val_str(String*) override; my_decimal *val_decimal(my_decimal *) override; Item *clone_item(THD *thd) const override; Item *neg(THD *thd) override; void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_static_float_func :public Item_float { const char *func_name; public: Item_static_float_func(THD *thd, const char *str, double val_arg, uint decimal_par, uint length): Item_float(thd, NullS, val_arg, decimal_par, length), func_name(str) {} void print(String *str, enum_query_type) override { str->append(func_name, strlen(func_name)); } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override { return const_charset_converter(thd, tocs, true, func_name); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_string :public Item_literal { protected: void fix_from_value(Derivation dv, const Metadata metadata) { fix_charset_and_length(str_value.charset(), dv, metadata); } void fix_and_set_name_from_value(THD *thd, Derivation dv, const Metadata metadata) { fix_from_value(dv, metadata); set_name(thd, &str_value); } protected: /* Just create an item and do not fill string representation */ Item_string(THD *thd, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE): Item_literal(thd) { collation.set(cs, dv); max_length= 0; set_name(thd, NULL, 0, system_charset_info); decimals= NOT_FIXED_DEC; } public: Item_string(THD *thd, CHARSET_INFO *csi, const char *str_arg, uint length_arg) :Item_literal(thd) { collation.set(csi, DERIVATION_COERCIBLE); set_name(thd, NULL, 0, system_charset_info); decimals= NOT_FIXED_DEC; str_value.copy(str_arg, length_arg, csi); max_length= str_value.numchars() * csi->mbmaxlen; } // Constructors with the item name set from its value Item_string(THD *thd, const char *str, uint length, CHARSET_INFO *cs, Derivation dv, my_repertoire_t repertoire) :Item_literal(thd) { str_value.set_or_copy_aligned(str, length, cs); fix_and_set_name_from_value(thd, dv, Metadata(&str_value, repertoire)); } Item_string(THD *thd, const char *str, size_t length, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) :Item_literal(thd) { str_value.set_or_copy_aligned(str, length, cs); fix_and_set_name_from_value(thd, dv, Metadata(&str_value)); } Item_string(THD *thd, const String *str, CHARSET_INFO *tocs, uint *conv_errors, Derivation dv, my_repertoire_t repertoire) :Item_literal(thd) { if (str_value.copy(str, tocs, conv_errors)) str_value.set("", 0, tocs); // EOM ? str_value.mark_as_const(); fix_and_set_name_from_value(thd, dv, Metadata(&str_value, repertoire)); } // Constructors with an externally provided item name Item_string(THD *thd, const LEX_CSTRING &name_par, const LEX_CSTRING &str, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) :Item_literal(thd) { str_value.set_or_copy_aligned(str.str, str.length, cs); fix_from_value(dv, Metadata(&str_value)); set_name(thd, name_par); } Item_string(THD *thd, const LEX_CSTRING &name_par, const LEX_CSTRING &str, CHARSET_INFO *cs, Derivation dv, my_repertoire_t repertoire) :Item_literal(thd) { str_value.set_or_copy_aligned(str.str, str.length, cs); fix_from_value(dv, Metadata(&str_value, repertoire)); set_name(thd, name_par); } void print_value(String *to) const { str_value.print(to); } bool val_bool() override { return val_real() != 0.0; } double val_real() override; longlong val_int() override; const String *const_ptr_string() const override { return &str_value; } String *val_str(String*) override { return (String*) &str_value; } my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_string(thd, ltime, fuzzydate); } int save_in_field(Field *field, bool no_conversions) override; const Type_handler *type_handler() const override { return &type_handler_varchar; } Item *clone_item(THD *thd) const override; Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override { return const_charset_converter(thd, tocs, true); } inline void append(const char *str, uint length) { str_value.append(str, length); max_length= str_value.numchars() * collation.collation->mbmaxlen; } void print(String *str, enum_query_type query_type) override; /** Return TRUE if character-set-introducer was explicitly specified in the original query for this item (text literal). This operation is to be called from Item_string::print(). The idea is that when a query is generated (re-constructed) from the Item-tree, character-set-introducers should appear only for those literals, where they were explicitly specified by the user. Otherwise, that may lead to loss collation information (character set introducers implies default collation for the literal). Basically, that makes sense only for views and hopefully will be gone one day when we start using original query as a view definition. @return This operation returns the value of m_cs_specified attribute. @retval TRUE if character set introducer was explicitly specified in the original query. @retval FALSE otherwise. */ virtual bool is_cs_specified() const { return false; } String *check_well_formed_result(bool send_error) { return Item::check_well_formed_result(&str_value, send_error); } Item_basic_constant *make_string_literal_concat(THD *thd, const LEX_CSTRING *) override; Item *make_odbc_literal(THD *thd, const LEX_CSTRING *typestr) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_string_with_introducer :public Item_string { public: Item_string_with_introducer(THD *thd, const LEX_CSTRING &str, CHARSET_INFO *cs): Item_string(thd, str.str, str.length, cs) { } Item_string_with_introducer(THD *thd, const LEX_CSTRING &name_arg, const LEX_CSTRING &str, CHARSET_INFO *tocs): Item_string(thd, name_arg, str, tocs) { } bool is_cs_specified() const override { return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_string_sys :public Item_string { public: Item_string_sys(THD *thd, const char *str, uint length): Item_string(thd, str, length, system_charset_info) { } Item_string_sys(THD *thd, const char *str): Item_string(thd, str, (uint) strlen(str), system_charset_info) { } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_string_ascii :public Item_string { public: Item_string_ascii(THD *thd, const char *str, uint length): Item_string(thd, str, length, &my_charset_latin1, DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII) { } Item_string_ascii(THD *thd, const char *str): Item_string(thd, str, (uint) strlen(str), &my_charset_latin1, DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII) { } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_static_string_func :public Item_string { const LEX_CSTRING func_name; public: Item_static_string_func(THD *thd, const LEX_CSTRING &name_par, const LEX_CSTRING &str, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE): Item_string(thd, LEX_CSTRING({NullS,0}), str, cs, dv), func_name(name_par) {} Item_static_string_func(THD *thd, const LEX_CSTRING &name_par, const String *str, CHARSET_INFO *tocs, uint *conv_errors, Derivation dv, my_repertoire_t repertoire): Item_string(thd, str, tocs, conv_errors, dv, repertoire), func_name(name_par) {} Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override { return const_charset_converter(thd, tocs, true, func_name.str); } void print(String *str, enum_query_type) override { str->append(func_name); } bool check_partition_func_processor(void *) override { return true; } bool check_vcol_func_processor(void *arg) override { // VCOL_TIME_FUNC because the value is not constant, but does not // require fix_fields() to be re-run for every statement. return mark_unsupported_function(func_name.str, arg, VCOL_TIME_FUNC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* for show tables */ class Item_partition_func_safe_string: public Item_string { public: Item_partition_func_safe_string(THD *thd, const LEX_CSTRING &name_arg, uint length, CHARSET_INFO *cs): Item_string(thd, name_arg, LEX_CSTRING({0,0}), cs) { max_length= length; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("safe_string", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /** Item_empty_string -- is a utility class to put an item into List which is then used in protocol.send_result_set_metadata() when sending SHOW output to the client. */ class Item_empty_string :public Item_partition_func_safe_string { public: Item_empty_string(THD *thd, const LEX_CSTRING &header, uint length, CHARSET_INFO *cs= &my_charset_utf8mb3_general_ci) :Item_partition_func_safe_string(thd, header, length * cs->mbmaxlen, cs) { } Item_empty_string(THD *thd, const char *header, uint length, CHARSET_INFO *cs= &my_charset_utf8mb3_general_ci) :Item_partition_func_safe_string(thd, LEX_CSTRING({header, strlen(header)}), length * cs->mbmaxlen, cs) { } void make_send_field(THD *thd, Send_field *field) override; }; class Item_return_int :public Item_int { enum_field_types int_field_type; public: Item_return_int(THD *thd, const char *name_arg, uint length, enum_field_types field_type_arg, longlong value_arg= 0): Item_int(thd, name_arg, value_arg, length), int_field_type(field_type_arg) { unsigned_flag=1; } const Type_handler *type_handler() const override { const Type_handler *h= Type_handler::get_handler_by_field_type(int_field_type); return unsigned_flag ? h->type_handler_unsigned() : h; } }; /** Item_hex_constant -- a common class for hex literals: X'HHHH' and 0xHHHH */ class Item_hex_constant: public Item_literal { private: void hex_string_init(THD *thd, const char *str, size_t str_length); public: Item_hex_constant(THD *thd): Item_literal(thd) { hex_string_init(thd, "", 0); } Item_hex_constant(THD *thd, const char *str, size_t str_length): Item_literal(thd) { hex_string_init(thd, str, str_length); } const Type_handler *type_handler() const override { return &type_handler_varchar; } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override { return const_charset_converter(thd, tocs, true); } const String *const_ptr_string() const override { return &str_value; } String *val_str(String*) override { return &str_value; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } }; /** Item_hex_hybrid -- is a class implementing 0xHHHH literals, e.g.: SELECT 0x3132; They can behave as numbers and as strings depending on context. */ class Item_hex_hybrid: public Item_hex_constant { public: Item_hex_hybrid(THD *thd): Item_hex_constant(thd) {} Item_hex_hybrid(THD *thd, const char *str, size_t str_length): Item_hex_constant(thd, str, str_length) {} const Type_handler *type_handler() const override { return &type_handler_hex_hybrid; } decimal_digits_t decimal_precision() const override; bool val_bool() override { return longlong_from_hex_hybrid(str_value.ptr(), str_value.length()) != 0; } double val_real() override { return (double) (ulonglong) Item_hex_hybrid::val_int(); } longlong val_int() override { DBUG_ASSERT(!is_cond()); return longlong_from_hex_hybrid(str_value.ptr(), str_value.length()); } my_decimal *val_decimal(my_decimal *decimal_value) override { longlong value= Item_hex_hybrid::val_int(); int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value); return decimal_value; } int save_in_field(Field *field, bool) override { field->set_notnull(); return field->store_hex_hybrid(str_value.ptr(), str_value.length()); } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /** Item_hex_string -- is a class implementing X'HHHH' literals, e.g.: SELECT X'3132'; Unlike Item_hex_hybrid, X'HHHH' literals behave as strings in all contexts. X'HHHH' are also used in replication of string constants in case of "dangerous" charsets (sjis, cp932, big5, gbk) who can have backslash (0x5C) as the second byte of a multi-byte character, so using '\' escaping for these charsets is not desirable. */ class Item_hex_string: public Item_hex_constant { public: Item_hex_string(THD *thd): Item_hex_constant(thd) {} Item_hex_string(THD *thd, const char *str, size_t str_length): Item_hex_constant(thd, str, str_length) {} bool val_bool() override { return double_from_string_with_check(&str_value) != 0.0; } longlong val_int() override { DBUG_ASSERT(!is_cond()); return longlong_from_string_with_check(&str_value); } double val_real() override { return double_from_string_with_check(&str_value); } my_decimal *val_decimal(my_decimal *decimal_value) override { return val_decimal_from_string(decimal_value); } int save_in_field(Field *field, bool) override { field->set_notnull(); return field->store(str_value.ptr(), str_value.length(), collation.collation); } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_bin_string: public Item_hex_hybrid { public: Item_bin_string(THD *thd, const char *str, size_t str_length); void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_timestamp_literal: public Item_literal { Timestamp_or_zero_datetime m_value; public: Item_timestamp_literal(THD *thd) :Item_literal(thd) { } const Type_handler *type_handler() const override { return &type_handler_timestamp2; } int save_in_field(Field *field, bool) override { Timestamp_or_zero_datetime_native native(m_value, decimals); return native.save_in_field(field, decimals); } bool val_bool() override { return m_value.to_bool(); } longlong val_int() override { DBUG_ASSERT(!is_cond()); return m_value.to_datetime(current_thd).to_longlong(); } double val_real() override { return m_value.to_datetime(current_thd).to_double(); } String *val_str(String *to) override { return m_value.to_datetime(current_thd).to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) override { return m_value.to_datetime(current_thd).to_decimal(to); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { bool res= m_value.to_TIME(thd, ltime, fuzzydate); DBUG_ASSERT(!res); return res; } bool val_native(THD *thd, Native *to) override { return m_value.to_native(to, decimals); } void set_value(const Timestamp_or_zero_datetime &value) { m_value= value; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_temporal_literal :public Item_literal { public: Item_temporal_literal(THD *thd) :Item_literal(thd) { collation= DTCollation_numeric(); decimals= 0; } Item_temporal_literal(THD *thd, decimal_digits_t dec_arg): Item_literal(thd) { collation= DTCollation_numeric(); decimals= dec_arg; } int save_in_field(Field *field, bool no_conversions) override { return save_date_in_field(field, no_conversions); } }; /** DATE'2010-01-01' */ class Item_date_literal: public Item_temporal_literal { protected: Date cached_time; bool update_null() { return (maybe_null() && (null_value= cached_time.check_date_with_warn(current_thd))); } public: Item_date_literal(THD *thd, const Date *ltime) :Item_temporal_literal(thd), cached_time(*ltime) { DBUG_ASSERT(cached_time.is_valid_date()); max_length= MAX_DATE_WIDTH; /* If date has zero month or day, it can return NULL in case of NO_ZERO_DATE or NO_ZERO_IN_DATE. If date is `February 30`, it can return NULL in case if no ALLOW_INVALID_DATES is set. We can't set null_value using the current sql_mode here in constructor, because sql_mode can change in case of prepared statements between PREPARE and EXECUTE. Here we only set maybe_null to true if the value has such anomalies. Later (during execution time), if maybe_null is true, then the value will be checked per row, according to the execution time sql_mode. The check_date() below call should cover all cases mentioned. */ set_maybe_null(cached_time.check_date(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)); } const Type_handler *type_handler() const override { return &type_handler_newdate; } void print(String *str, enum_query_type query_type) override; const MYSQL_TIME *const_ptr_mysql_time() const override { return cached_time.get_mysql_time(); } Item *clone_item(THD *thd) const override; bool val_bool() override { return update_null() ? false : cached_time.to_bool(); } longlong val_int() override { DBUG_ASSERT(!is_cond()); return update_null() ? 0 : cached_time.to_longlong(); } double val_real() override { return update_null() ? 0 : cached_time.to_double(); } String *val_str(String *to) override { return update_null() ? 0 : cached_time.to_string(to); } my_decimal *val_decimal(my_decimal *to) override { return update_null() ? 0 : cached_time.to_decimal(to); } longlong val_datetime_packed(THD *thd) override { return update_null() ? 0 : cached_time.valid_date_to_packed(); } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /** TIME'10:10:10' */ class Item_time_literal final: public Item_temporal_literal { protected: Time cached_time; public: Item_time_literal(THD *thd, const Time *ltime, decimal_digits_t dec_arg): Item_temporal_literal(thd, dec_arg), cached_time(*ltime) { DBUG_ASSERT(cached_time.is_valid_time()); max_length= MIN_TIME_WIDTH + (decimals ? decimals + 1 : 0); } const Type_handler *type_handler() const override { return &type_handler_time2; } void print(String *str, enum_query_type query_type) override; const MYSQL_TIME *const_ptr_mysql_time() const override { return cached_time.get_mysql_time(); } Item *clone_item(THD *thd) const override; bool val_bool() override { return cached_time.to_bool(); } longlong val_int() override { DBUG_ASSERT(!is_cond()); return cached_time.to_longlong(); } double val_real() override { return cached_time.to_double(); } String *val_str(String *to) override { return cached_time.to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) override { return cached_time.to_decimal(to); } longlong val_time_packed(THD *thd) override { return cached_time.valid_time_to_packed(); } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; bool val_native(THD *thd, Native *to) override { return Time(thd, this).to_native(to, decimals); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /** TIMESTAMP'2001-01-01 10:20:30' */ class Item_datetime_literal: public Item_temporal_literal { protected: Datetime cached_time; bool update_null() { return (maybe_null() && (null_value= cached_time.check_date_with_warn(current_thd))); } public: Item_datetime_literal(THD *thd, const Datetime *ltime, decimal_digits_t dec_arg): Item_temporal_literal(thd, dec_arg), cached_time(*ltime) { DBUG_ASSERT(cached_time.is_valid_datetime()); max_length= MAX_DATETIME_WIDTH + (decimals ? decimals + 1 : 0); // See the comment on maybe_null in Item_date_literal set_maybe_null(cached_time.check_date(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)); } const Type_handler *type_handler() const override { return &type_handler_datetime2; } void print(String *str, enum_query_type query_type) override; const MYSQL_TIME *const_ptr_mysql_time() const override { return cached_time.get_mysql_time(); } Item *clone_item(THD *thd) const override; bool val_bool() override { return update_null() ? false : cached_time.to_bool(); } longlong val_int() override { DBUG_ASSERT(!is_cond()); return update_null() ? 0 : cached_time.to_longlong(); } double val_real() override { return update_null() ? 0 : cached_time.to_double(); } String *val_str(String *to) override { return update_null() ? NULL : cached_time.to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) override { return update_null() ? NULL : cached_time.to_decimal(to); } longlong val_datetime_packed(THD *thd) override { return update_null() ? 0 : cached_time.valid_datetime_to_packed(); } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /** An error-safe counterpart for Item_date_literal */ class Item_date_literal_for_invalid_dates: public Item_date_literal { /** During equal field propagation we can replace non-temporal constants found in equalities to their native temporal equivalents: WHERE date_column='2001-01-01' ... -> WHERE date_column=DATE'2001-01-01' ... This is done to make the equal field propagation code handle mixtures of different temporal types in the same expressions easier (MDEV-8706), e.g. WHERE LENGTH(date_column)=10 AND date_column=TIME'00:00:00' Item_date_literal_for_invalid_dates::get_date() (unlike the regular Item_date_literal::get_date()) does not check the result for NO_ZERO_IN_DATE and NO_ZERO_DATE, always returns success (false), and does not produce error/warning messages. We need these _for_invalid_dates classes to be able to rewrite: SELECT * FROM t1 WHERE date_column='0000-00-00' ... to: SELECT * FROM t1 WHERE date_column=DATE'0000-00-00' ... to avoid returning NULL value instead of '0000-00-00' even in sql_mode=TRADITIONAL. */ public: Item_date_literal_for_invalid_dates(THD *thd, const Date *ltime) :Item_date_literal(thd, ltime) { base_flags&= ~item_base_t::MAYBE_NULL; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { cached_time.copy_to_mysql_time(ltime); return (null_value= false); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /** An error-safe counterpart for Item_datetime_literal (see Item_date_literal_for_invalid_dates for comments) */ class Item_datetime_literal_for_invalid_dates final: public Item_datetime_literal { public: Item_datetime_literal_for_invalid_dates(THD *thd, const Datetime *ltime, decimal_digits_t dec_arg) :Item_datetime_literal(thd, ltime, dec_arg) { base_flags&= ~item_base_t::MAYBE_NULL; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { cached_time.copy_to_mysql_time(ltime); return (null_value= false); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Used_tables_and_const_cache { public: /* In some cases used_tables_cache is not what used_tables() return so the method should be used where one need used tables bit map (even internally in Item_func_* code). */ table_map used_tables_cache; bool const_item_cache; Used_tables_and_const_cache() :used_tables_cache(0), const_item_cache(true) { } Used_tables_and_const_cache(const Used_tables_and_const_cache *other) :used_tables_cache(other->used_tables_cache), const_item_cache(other->const_item_cache) { } inline void used_tables_and_const_cache_init() { used_tables_cache= 0; const_item_cache= true; } inline void used_tables_and_const_cache_join(const Item *item) { used_tables_cache|= item->used_tables(); const_item_cache&= item->const_item(); } inline void used_tables_and_const_cache_update_and_join(Item *item) { item->update_used_tables(); used_tables_and_const_cache_join(item); } /* Call update_used_tables() for all "argc" items in the array "argv" and join with the current cache. "this" must be initialized with a constructor or re-initialized with used_tables_and_const_cache_init(). */ void used_tables_and_const_cache_update_and_join(uint argc, Item **argv) { for (uint i=0 ; i < argc ; i++) used_tables_and_const_cache_update_and_join(argv[i]); } /* Call update_used_tables() for all items in the list and join with the current cache. "this" must be initialized with a constructor or re-initialized with used_tables_and_const_cache_init(). */ void used_tables_and_const_cache_update_and_join(List &list) { List_iterator_fast li(list); Item *item; while ((item=li++)) used_tables_and_const_cache_update_and_join(item); } }; /** An abstract class representing common features of regular functions and aggregate functions. */ class Item_func_or_sum: public Item_result_field, public Item_args, public Used_tables_and_const_cache { protected: bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems, uint flags, int item_sep) { return Type_std_attributes::agg_arg_charsets(c, func_name_cstring(), items, nitems, flags, item_sep); } bool agg_arg_charsets_for_string_result(DTCollation &c, Item **items, uint nitems, int item_sep= 1) { return Type_std_attributes:: agg_arg_charsets_for_string_result(c, func_name_cstring(), items, nitems, item_sep); } bool agg_arg_charsets_for_string_result_with_comparison(DTCollation &c, Item **items, uint nitems, int item_sep= 1) { return Type_std_attributes:: agg_arg_charsets_for_string_result_with_comparison(c, func_name_cstring(), items, nitems, item_sep); } /* Aggregate arguments for comparison, e.g: a=b, a LIKE b, a RLIKE b - don't convert to @@character_set_connection if all arguments are numbers - don't allow DERIVATION_NONE */ bool agg_arg_charsets_for_comparison(DTCollation &c, Item **items, uint nitems, int item_sep= 1) { return Type_std_attributes:: agg_arg_charsets_for_comparison(c, func_name_cstring(), items, nitems, item_sep); } public: // This method is used by Arg_comparator bool agg_arg_charsets_for_comparison(CHARSET_INFO **cs, Item **a, Item **b, bool allow_narrowing) { THD *thd= current_thd; DTCollation tmp; if (tmp.set((*a)->collation, (*b)->collation, MY_COLL_CMP_CONV) || tmp.derivation == DERIVATION_NONE) { my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0), (*a)->collation.collation->coll_name.str, (*a)->collation.derivation_name(), (*b)->collation.collation->coll_name.str, (*b)->collation.derivation_name(), func_name()); return true; } if (allow_narrowing && (*a)->collation.derivation == (*b)->collation.derivation) { // allow_narrowing==true only for = and <=> comparisons. if (Utf8_narrow::should_do_narrowing(thd, (*a)->collation.collation, (*b)->collation.collation)) { // a is a subset, b is a superset (e.g. utf8mb3 vs utf8mb4) *cs= (*b)->collation.collation; // Compare using the wider cset return false; } else if (Utf8_narrow::should_do_narrowing(thd, (*b)->collation.collation, (*a)->collation.collation)) { // a is a superset, b is a subset (e.g. utf8mb4 vs utf8mb3) *cs= (*a)->collation.collation; // Compare using the wider cset return false; } } /* If necessary, convert both *a and *b to the collation in tmp: */ Single_coll_err error_for_a= {(*b)->collation, true}; Single_coll_err error_for_b= {(*a)->collation, false}; if (agg_item_set_converter(tmp, func_name_cstring(), a, 1, MY_COLL_CMP_CONV, 1, /*just for error message*/ &error_for_a) || agg_item_set_converter(tmp, func_name_cstring(), b, 1, MY_COLL_CMP_CONV, 1, /*just for error message*/ &error_for_b)) return true; *cs= tmp.collation; return false; } public: Item_func_or_sum(THD *thd): Item_result_field(thd), Item_args() {} Item_func_or_sum(THD *thd, Item *a): Item_result_field(thd), Item_args(a) { } Item_func_or_sum(THD *thd, Item *a, Item *b): Item_result_field(thd), Item_args(a, b) { } Item_func_or_sum(THD *thd, Item *a, Item *b, Item *c): Item_result_field(thd), Item_args(thd, a, b, c) { } Item_func_or_sum(THD *thd, Item *a, Item *b, Item *c, Item *d): Item_result_field(thd), Item_args(thd, a, b, c, d) { } Item_func_or_sum(THD *thd, Item *a, Item *b, Item *c, Item *d, Item *e): Item_result_field(thd), Item_args(thd, a, b, c, d, e) { } Item_func_or_sum(THD *thd, Item_func_or_sum *item): Item_result_field(thd, item), Item_args(thd, item), Used_tables_and_const_cache(item) { } Item_func_or_sum(THD *thd, List &list): Item_result_field(thd), Item_args(thd, list) { } bool walk(Item_processor processor, bool walk_subquery, void *arg) override { if (walk_args(processor, walk_subquery, arg)) return true; return (this->*processor)(arg); } /* Built-in schema, e.g. mariadb_schema, oracle_schema, maxdb_schema */ virtual const Schema *schema() const { // A function does not belong to a built-in schema by default return NULL; } /* This method is used for debug purposes to print the name of an item to the debug log. The second use of this method is as a helper function of print() and error messages, where it is applicable. To suit both goals it should return a meaningful, distinguishable and sintactically correct string. This method should not be used for runtime type identification, use enum {Sum}Functype and Item_func::functype()/Item_sum::sum_func() instead. Added here, to the parent class of both Item_func and Item_sum. NOTE: for Items inherited from Item_sum, func_name() and func_name_cstring() returns part of function name till first argument (including '(') to make difference in names for functions with 'distinct' clause and without 'distinct' and also to make printing of items inherited from Item_sum uniform. */ inline const char *func_name() const { return (char*) func_name_cstring().str; } virtual LEX_CSTRING func_name_cstring() const= 0; virtual bool fix_length_and_dec()= 0; bool const_item() const override { return const_item_cache; } table_map used_tables() const override { return used_tables_cache; } Item* do_build_clone(THD *thd) const override; Sql_mode_dependency value_depends_on_sql_mode() const override { return Item_args::value_depends_on_sql_mode_bit_or().soft_to_hard(); } }; class sp_head; class sp_name; struct st_sp_security_context; class Item_sp { protected: // Can be NULL in some non-SELECT queries Name_resolution_context *context; public: sp_name *m_name; sp_head *m_sp; TABLE *dummy_table; uchar result_buf[64]; sp_rcontext *func_ctx; MEM_ROOT sp_mem_root; Query_arena *sp_query_arena; /* The result field of the stored function. */ Field *sp_result_field; Item_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name_arg); Item_sp(THD *thd, Item_sp *item); LEX_CSTRING func_name_cstring(THD *thd, bool is_package_function) const; void cleanup(); bool sp_check_access(THD *thd); bool execute(THD *thd, bool *null_value, Item **args, uint arg_count); bool execute_impl(THD *thd, Item **args, uint arg_count); bool init_result_field(THD *thd, uint max_length, uint maybe_null, bool *null_value, LEX_CSTRING *name); void process_error(THD *thd) { if (context) context->process_error(thd); } }; class Item_ref :public Item_ident { protected: void set_properties(); bool set_properties_only; // the item doesn't need full fix_fields public: enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF, AGGREGATE_REF }; Item **ref; bool reference_trough_name; Item_ref(THD *thd, Name_resolution_context *context_arg, const LEX_CSTRING &db_arg, const LEX_CSTRING &table_name_arg, const LEX_CSTRING &field_name_arg): Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg), set_properties_only(0), ref(0), reference_trough_name(1) {} Item_ref(THD *thd, Name_resolution_context *context_arg, const LEX_CSTRING &field_name_arg) :Item_ref(thd, context_arg, null_clex_str, null_clex_str, field_name_arg) { } /* This constructor is used in two scenarios: A) *item = NULL No initialization is performed, fix_fields() call will be necessary. B) *item points to an Item this Item_ref will refer to. This is used for GROUP BY. fix_fields() will not be called in this case, so we call set_properties to make this item "fixed". set_properties performs a subset of action Item_ref::fix_fields does, and this subset is enough for Item_ref's used in GROUP BY. TODO we probably fix a superset of problems like in BUG#6658. Check this with Bar, and if we have a more broader set of problems like this. */ Item_ref(THD *thd, Name_resolution_context *context_arg, Item **item, const LEX_CSTRING &table_name_arg, const LEX_CSTRING &field_name_arg, bool alias_name_used_arg= FALSE); Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item, const LEX_CSTRING &field_name_arg, bool alias_name_used_arg= FALSE); /* Constructor need to process subselect with temporary tables (see Item) */ Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), set_properties_only(0), ref(item->ref) {} enum Type type() const override { return REF_ITEM; } enum Type real_type() const override { return ref ? (*ref)->type() : REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const override { const Item *it= item->real_item(); return ref && (*ref)->eq(it, binary_cmp); } void save_val(Field *to) override; void save_result(Field *to) override; double val_real() override; longlong val_int() override; my_decimal *val_decimal(my_decimal *) override; bool val_bool() override; String *val_str(String* tmp) override; bool val_native(THD *thd, Native *to) override; bool is_null() override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; longlong val_datetime_packed(THD *) override; longlong val_time_packed(THD *) override; double val_result() override; longlong val_int_result() override; String *str_result(String* tmp) override; bool val_native_result(THD *thd, Native *to) override; my_decimal *val_decimal_result(my_decimal *) override; bool val_bool_result() override; bool is_null_result() override; bool send(Protocol *prot, st_value *buffer) override; void make_send_field(THD *thd, Send_field *field) override; bool fix_fields(THD *, Item **) override; void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; int save_in_field(Field *field, bool no_conversions) override; void save_org_in_field(Field *field, fast_field_copier optimizer_data) override; fast_field_copier setup_fast_field_copier(Field *field) override { return (*ref)->setup_fast_field_copier(field); } const Type_handler *type_handler() const override { return (*ref)->type_handler(); } const Type_handler *real_type_handler() const override { return (*ref)->real_type_handler(); } uint32 character_octet_length() const override { return Item_ref::real_item()->character_octet_length(); } Field *get_tmp_table_field() override { return result_field ? result_field : (*ref)->get_tmp_table_field(); } Item *get_tmp_table_item(THD *thd) override; Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override; Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *) override; table_map used_tables() const override; void update_used_tables() override; COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) override { /* normilize_cond() replaced all conditions of type WHERE/HAVING field to: WHERE/HAVING field<>0 By the time of a build_equal_items() call, all such conditions should already be replaced. No Item_ref referencing to Item_field are possible. */ DBUG_ASSERT(real_type() != FIELD_ITEM); return Item_ident::build_equal_items(thd, inherited, link_item_fields, cond_equal_ref); } bool const_item() const override { return (*ref)->const_item(); } table_map not_null_tables() const override { return depended_from ? 0 : (*ref)->not_null_tables(); } bool find_not_null_fields(table_map allowed) override { return depended_from ? false : (*ref)->find_not_null_fields(allowed); } void save_in_result_field(bool no_conversions) override { (*ref)->save_in_field(result_field, no_conversions); } Item *real_item() override { return ref ? (*ref)->real_item() : this; } const Item *real_item() const { return const_cast(this)->Item_ref::real_item(); } const TYPELIB *get_typelib() const override { return ref ? (*ref)->get_typelib() : NULL; } bool walk(Item_processor processor, bool walk_subquery, void *arg) override { if (ref && *ref) return (*ref)->walk(processor, walk_subquery, arg) || (this->*processor)(arg); else return FALSE; } Item* transform(THD *thd, Item_transformer, uchar *arg) override; Item* compile(THD *thd, Item_analyzer analyzer, uchar **arg_p, Item_transformer transformer, uchar *arg_t) override; bool enumerate_field_refs_processor(void *arg) override { return (*ref)->enumerate_field_refs_processor(arg); } void no_rows_in_result() override { (*ref)->no_rows_in_result(); } void restore_to_before_no_rows_in_result() override { (*ref)->restore_to_before_no_rows_in_result(); } void print(String *str, enum_query_type query_type) override; enum precedence precedence() const override { return ref ? (*ref)->precedence() : DEFAULT_PRECEDENCE; } void cleanup() override; Item_field *field_for_view_update() override { return (*ref)->field_for_view_update(); } Load_data_outvar *get_load_data_outvar() override { return (*ref)->get_load_data_outvar(); } virtual Ref_Type ref_type() { return REF; } // Row emulation: forwarding of ROW-related calls to ref uint cols() const override { return ref && result_type() == ROW_RESULT ? (*ref)->cols() : 1; } Item* element_index(uint i) override { return ref && result_type() == ROW_RESULT ? (*ref)->element_index(i) : this; } Item** addr(uint i) override { return ref && result_type() == ROW_RESULT ? (*ref)->addr(i) : 0; } bool check_cols(uint c) override { return ref && result_type() == ROW_RESULT ? (*ref)->check_cols(c) : Item::check_cols(c); } bool null_inside() override { return ref && result_type() == ROW_RESULT ? (*ref)->null_inside() : 0; } void bring_value() override { if (ref && result_type() == ROW_RESULT) (*ref)->bring_value(); } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("ref", arg, VCOL_IMPOSSIBLE); } bool basic_const_item() const override { return ref && (*ref)->basic_const_item(); } bool is_outer_field() const override { DBUG_ASSERT(fixed()); DBUG_ASSERT(ref); return (*ref)->is_outer_field(); } Item *do_build_clone(THD *thd) const override; /** Checks if the item tree that ref points to contains a subquery. */ Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } bool excl_dep_on_table(table_map tab_map) override { table_map used= used_tables(); if (used & OUTER_REF_TABLE_BIT) return false; return (used == tab_map) || (*ref)->excl_dep_on_table(tab_map); } bool excl_dep_on_grouping_fields(st_select_lex *sel) override { return (*ref)->excl_dep_on_grouping_fields(sel); } bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override { return (*ref)->excl_dep_on_in_subq_left_part(subq_pred); } bool cleanup_excluding_fields_processor(void *arg) override { Item *item= real_item(); if (item && item->type() == FIELD_ITEM && ((Item_field *)item)->field) return 0; return cleanup_processor(arg); } bool cleanup_excluding_const_fields_processor(void *arg) override { Item *item= real_item(); if (item && item->type() == FIELD_ITEM && ((Item_field *) item)->field && item->const_item()) return 0; return cleanup_processor(arg); } Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) override { return (*ref)->field_transformer_for_having_pushdown(thd, arg); } }; /* The same as Item_ref, but get value from val_* family of method to get value of item on which it referred instead of result* family. */ class Item_direct_ref :public Item_ref { public: Item_direct_ref(THD *thd, Name_resolution_context *context_arg, Item **item, const LEX_CSTRING &table_name_arg, const LEX_CSTRING &field_name_arg, bool alias_name_used_arg= FALSE): Item_ref(thd, context_arg, item, table_name_arg, field_name_arg, alias_name_used_arg) {} /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {} Item_direct_ref(THD *thd, TABLE_LIST *view_arg, Item **item, const LEX_CSTRING &field_name_arg, bool alias_name_used_arg= FALSE): Item_ref(thd, view_arg, item, field_name_arg, alias_name_used_arg) {} bool fix_fields(THD *thd, Item **it) override { if ((*ref)->fix_fields_if_needed_for_scalar(thd, ref)) return TRUE; return Item_ref::fix_fields(thd, it); } void save_val(Field *to) override; /* Below we should have all val() methods as in Item_ref */ double val_real() override; longlong val_int() override; my_decimal *val_decimal(my_decimal *) override; bool val_bool() override; String *val_str(String* tmp) override; bool val_native(THD *thd, Native *to) override; bool is_null() override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; longlong val_datetime_packed(THD *) override; longlong val_time_packed(THD *) override; Ref_Type ref_type() override { return DIRECT_REF; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } /* Should be called if ref is changed */ inline void ref_changed() { set_properties(); } }; /** This class is the same as Item_direct_ref but created to wrap Item_ident before fix_fields() call */ class Item_direct_ref_to_ident :public Item_direct_ref { Item_ident *ident; public: Item_direct_ref_to_ident(THD *thd, Item_ident *item): Item_direct_ref(thd, item->context, (Item**)&item, item->table_name, item->field_name, FALSE) { ident= item; ref= (Item**)&ident; } bool fix_fields(THD *thd, Item **it) override { DBUG_ASSERT(ident->type() == FIELD_ITEM || ident->type() == REF_ITEM); if (ident->fix_fields_if_needed_for_scalar(thd, ref)) return TRUE; set_properties(); return FALSE; } void print(String *str, enum_query_type query_type) override { ident->print(str, query_type); } }; class Item_cache; class Expression_cache; class Expression_cache_tracker; /** The objects of this class can store its values in an expression cache. */ class Item_cache_wrapper :public Item_result_field { private: /* Pointer on the cached expression */ Item *orig_item; Expression_cache *expr_cache; /* In order to put the expression into the expression cache and return value of val_*() method, we will need to get the expression value twice (probably in different types). In order to avoid making two (potentially costly) orig_item->val_*() calls, we store expression value in this Item_cache object. */ Item_cache *expr_value; List parameters; Item *check_cache(); void cache(); void init_on_demand(); public: Item_cache_wrapper(THD *thd, Item *item_arg); ~Item_cache_wrapper(); Type type() const override { return EXPR_CACHE_ITEM; } Type real_type() const override { return orig_item->type(); } bool set_cache(THD *thd); Expression_cache_tracker* init_tracker(MEM_ROOT *mem_root); bool fix_fields(THD *thd, Item **it) override; void cleanup() override; Item *get_orig_item() const { return orig_item; } /* Methods of getting value which should be cached in the cache */ void save_val(Field *to) override; double val_real() override; longlong val_int() override; String *val_str(String* tmp) override; bool val_native(THD *thd, Native *to) override; my_decimal *val_decimal(my_decimal *) override; bool val_bool() override; bool is_null() override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool send(Protocol *protocol, st_value *buffer) override; void save_org_in_field(Field *field, fast_field_copier) override { save_val(field); } void save_in_result_field(bool) override { save_val(result_field); } Item* get_tmp_table_item(THD *thd_arg) override; /* Following methods make this item transparent as much as possible */ void print(String *str, enum_query_type query_type) override; LEX_CSTRING full_name_cstring() const override { return orig_item->full_name_cstring(); } void make_send_field(THD *thd, Send_field *field) override { orig_item->make_send_field(thd, field); } bool eq(const Item *item, bool binary_cmp) const override { const Item *it= item->real_item(); return orig_item->eq(it, binary_cmp); } void fix_after_pullout(st_select_lex *new_parent, Item **refptr, bool merge) override { orig_item->fix_after_pullout(new_parent, &orig_item, merge); } int save_in_field(Field *to, bool no_conversions) override; const Type_handler *type_handler() const override { return orig_item->type_handler(); } table_map used_tables() const override { return orig_item->used_tables(); } void update_used_tables() override { orig_item->update_used_tables(); } bool const_item() const override { return orig_item->const_item(); } table_map not_null_tables() const override { return orig_item->not_null_tables(); } bool walk(Item_processor processor, bool walk_subquery, void *arg) override { return orig_item->walk(processor, walk_subquery, arg) || (this->*processor)(arg); } bool enumerate_field_refs_processor(void *arg) override { return orig_item->enumerate_field_refs_processor(arg); } Item_field *field_for_view_update() override { return orig_item->field_for_view_update(); } /* Row emulation: forwarding of ROW-related calls to orig_item */ uint cols() const override { return result_type() == ROW_RESULT ? orig_item->cols() : 1; } Item* element_index(uint i) override { return result_type() == ROW_RESULT ? orig_item->element_index(i) : this; } Item** addr(uint i) override { return result_type() == ROW_RESULT ? orig_item->addr(i) : 0; } bool check_cols(uint c) override { return (result_type() == ROW_RESULT ? orig_item->check_cols(c) : Item::check_cols(c)); } bool null_inside() override { return result_type() == ROW_RESULT ? orig_item->null_inside() : 0; } void bring_value() override { if (result_type() == ROW_RESULT) orig_item->bring_value(); } bool is_expensive() override { return orig_item->is_expensive(); } bool is_expensive_processor(void *arg) override { return orig_item->is_expensive_processor(arg); } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("cache", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *) const override { return nullptr; } }; /* Class for view fields, the same as Item_direct_ref, but call fix_fields of reference if it is not called yet */ class Item_direct_view_ref :public Item_direct_ref { Item_equal *item_equal; TABLE_LIST *view; TABLE *null_ref_table; #define NO_NULL_TABLE (reinterpret_cast(0x1)) void set_null_ref_table() { if (!view->is_inner_table_of_outer_join() || !(null_ref_table= view->get_real_join_table())) null_ref_table= NO_NULL_TABLE; if (null_ref_table && null_ref_table != NO_NULL_TABLE) set_maybe_null(); } bool check_null_ref() { DBUG_ASSERT(null_ref_table); if (null_ref_table != NO_NULL_TABLE && null_ref_table->null_row) { null_value= 1; return TRUE; } return FALSE; } public: Item_direct_view_ref(THD *thd, Name_resolution_context *context_arg, Item **item, LEX_CSTRING &table_name_arg, LEX_CSTRING &field_name_arg, TABLE_LIST *view_arg): Item_direct_ref(thd, context_arg, item, table_name_arg, field_name_arg), item_equal(0), view(view_arg), null_ref_table(NULL) { if (fixed()) set_null_ref_table(); } bool fix_fields(THD *, Item **) override; bool eq(const Item *item, bool binary_cmp) const override; Item *get_tmp_table_item(THD *thd) override { if (const_item()) return copy_or_same(thd); Item *item= Item_ref::get_tmp_table_item(thd); item->name= name; return item; } Ref_Type ref_type() override { return VIEW_REF; } Item_equal *get_item_equal() override { return item_equal; } void set_item_equal(Item_equal *item_eq) override { item_equal= item_eq; } Item_equal *find_item_equal(COND_EQUAL *cond_equal) override; Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *) override; Item *replace_equal_field(THD *thd, uchar *arg) override; table_map used_tables() const override; void update_used_tables() override; table_map not_null_tables() const override; bool const_item() const override { return (*ref)->const_item() && (null_ref_table == NO_NULL_TABLE); } TABLE *get_null_ref_table() const { return null_ref_table; } bool walk(Item_processor processor, bool walk_subquery, void *arg) override { return (*ref)->walk(processor, walk_subquery, arg) || (this->*processor)(arg); } bool view_used_tables_processor(void *arg) override { TABLE_LIST *view_arg= (TABLE_LIST *) arg; if (view_arg == view) view_arg->view_used_tables|= (*ref)->used_tables(); return 0; } bool excl_dep_on_table(table_map tab_map) override; bool excl_dep_on_grouping_fields(st_select_lex *sel) override; bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override; Item *derived_field_transformer_for_having(THD *thd, uchar *arg) override; Item *derived_field_transformer_for_where(THD *thd, uchar *arg) override; Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) override; Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) override; Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) override; void save_val(Field *to) override { if (check_null_ref()) to->set_null(); else Item_direct_ref::save_val(to); } double val_real() override { if (check_null_ref()) return 0; else return Item_direct_ref::val_real(); } longlong val_int() override { if (check_null_ref()) return 0; else return Item_direct_ref::val_int(); } String *val_str(String* tmp) override { if (check_null_ref()) return NULL; else return Item_direct_ref::val_str(tmp); } bool val_native(THD *thd, Native *to) override { if (check_null_ref()) return true; return Item_direct_ref::val_native(thd, to); } my_decimal *val_decimal(my_decimal *tmp) override { if (check_null_ref()) return NULL; else return Item_direct_ref::val_decimal(tmp); } bool val_bool() override { if (check_null_ref()) return 0; else return Item_direct_ref::val_bool(); } bool is_null() override { if (check_null_ref()) return 1; else return Item_direct_ref::is_null(); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { if (check_null_ref()) { bzero((char*) ltime,sizeof(*ltime)); return 1; } return Item_direct_ref::get_date(thd, ltime, fuzzydate); } longlong val_time_packed(THD *thd) override { if (check_null_ref()) return 0; else return Item_direct_ref::val_time_packed(thd); } longlong val_datetime_packed(THD *thd) override { if (check_null_ref()) return 0; else return Item_direct_ref::val_datetime_packed(thd); } bool send(Protocol *protocol, st_value *buffer) override; void save_org_in_field(Field *field, fast_field_copier) override { if (check_null_ref()) field->set_null(); else Item_direct_ref::save_val(field); } void save_in_result_field(bool no_conversions) override { if (check_null_ref()) result_field->set_null(); else Item_direct_ref::save_in_result_field(no_conversions); } int save_in_field(Field *field, bool no_conversions) override { if (check_null_ref()) return set_field_to_null_with_conversions(field, no_conversions); return Item_direct_ref::save_in_field(field, no_conversions); } void cleanup() override { null_ref_table= NULL; item_equal= NULL; Item_direct_ref::cleanup(); } /* TODO move these val_*_result function to Item_direct_ref (maybe) */ double val_result() override; longlong val_int_result() override; String *str_result(String* tmp) override; my_decimal *val_decimal_result(my_decimal *val) override; bool val_bool_result() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *field_transformer_for_having_pushdown(THD *, uchar *) override { return this; } }; /* Class for outer fields. An object of this class is created when the select where the outer field was resolved is a grouping one. After it has been fixed the ref field will point to either an Item_ref or an Item_direct_ref object which will be used to access the field. See also comments for the fix_inner_refs() and the Item_field::fix_outer_field() functions. */ class Item_sum; class Item_outer_ref :public Item_direct_ref { public: Item *outer_ref; /* The aggregate function under which this outer ref is used, if any. */ Item_sum *in_sum_func; /* TRUE <=> that the outer_ref is already present in the select list of the outer select. */ bool found_in_select_list; bool found_in_group_by; Item_outer_ref(THD *thd, Name_resolution_context *context_arg, Item_field *outer_field_arg): Item_direct_ref(thd, context_arg, 0, outer_field_arg->table_name, outer_field_arg->field_name), outer_ref(outer_field_arg), in_sum_func(0), found_in_select_list(0), found_in_group_by(0) { ref= &outer_ref; set_properties(); /* reset flag set in set_properties() */ base_flags&= ~item_base_t::FIXED; } Item_outer_ref(THD *thd, Name_resolution_context *context_arg, Item **item, const LEX_CSTRING &table_name_arg, LEX_CSTRING &field_name_arg, bool alias_name_used_arg): Item_direct_ref(thd, context_arg, item, table_name_arg, field_name_arg, alias_name_used_arg), outer_ref(0), in_sum_func(0), found_in_select_list(1), found_in_group_by(0) {} void save_in_result_field(bool no_conversions) override { outer_ref->save_org_in_field(result_field, NULL); } bool fix_fields(THD *, Item **) override; void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; table_map used_tables() const override { return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT; } table_map not_null_tables() const override { return 0; } Ref_Type ref_type() override { return OUTER_REF; } bool check_inner_refs_processor(void * arg) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_in_subselect; /* An object of this class: - Converts val_XXX() calls to ref->val_XXX_result() calls, like Item_ref. - Sets owner->was_null=TRUE if it has returned a NULL value from any val_XXX() function. This allows to inject an Item_ref_null_helper object into subquery and then check if the subquery has produced a row with NULL value. */ class Item_ref_null_helper: public Item_ref { protected: Item_in_subselect* owner; public: Item_ref_null_helper(THD *thd, Name_resolution_context *context_arg, Item_in_subselect* master, Item **item, const LEX_CSTRING &table_name_arg, const LEX_CSTRING &field_name_arg): Item_ref(thd, context_arg, item, table_name_arg, field_name_arg), owner(master) {} void save_val(Field *to) override; double val_real() override; longlong val_int() override; String* val_str(String* s) override; my_decimal *val_decimal(my_decimal *) override; bool val_bool() override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool val_native(THD *thd, Native *to) override; void print(String *str, enum_query_type query_type) override; table_map used_tables() const override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* The following class is used to optimize comparing of date and bigint columns We need to save the original item ('ref') to be able to call ref->save_in_field(). This is used to create index search keys. An instance of Item_int_with_ref may have signed or unsigned integer value. */ class Item_int_with_ref :public Item_int { Item *ref; public: Item_int_with_ref(THD *thd, longlong i, Item *ref_arg, bool unsigned_arg): Item_int(thd, i), ref(ref_arg) { unsigned_flag= unsigned_arg; } int save_in_field(Field *field, bool no_conversions) override { return ref->save_in_field(field, no_conversions); } Item *clone_item(THD *thd) const override; Item *real_item() override { return ref; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; #ifdef MYSQL_SERVER #include "item_sum.h" #include "item_func.h" #include "item_row.h" #include "item_cmpfunc.h" #include "item_strfunc.h" #include "item_timefunc.h" #include "item_subselect.h" #include "item_xmlfunc.h" #include "item_jsonfunc.h" #include "item_create.h" #include "item_vers.h" #endif /** Base class to implement typed value caching Item classes Item_copy_ classes are very similar to the corresponding Item_ classes (e.g. Item_copy_string is similar to Item_string) but they add the following additional functionality to Item_ : 1. Nullability 2. Possibility to store the value not only on instantiation time, but also later. Item_copy_ classes are a functionality subset of Item_cache_ classes, as e.g. they don't support comparisons with the original Item as Item_cache_ classes do. Item_copy_ classes are used in GROUP BY calculation. TODO: Item_copy should be made an abstract interface and Item_copy_ classes should inherit both the respective Item_ class and the interface. Ideally we should drop Item_copy_ classes altogether and merge their functionality to Item_cache_ (and these should be made to inherit from Item_). */ class Item_copy :public Item, public Type_handler_hybrid_field_type { protected: /** Type_handler_hybrid_field_type is used to store the type of the resulting field that would be used to store the data in the cache. This is to avoid calls to the original item. */ /** The original item that is copied */ Item *item; /** Constructor of the Item_copy class stores metadata information about the original class as well as a pointer to it. */ Item_copy(THD *thd, Item *org): Item(thd) { DBUG_ASSERT(org->fixed()); item= org; null_value= item->maybe_null(); copy_flags(item, item_base_t::MAYBE_NULL); Type_std_attributes::set(item); name= item->name; set_handler(item->type_handler()); #ifndef DBUG_OFF copied_in= 0; #endif } #ifndef DBUG_OFF bool copied_in; #endif public: /** Update the cache with the value of the original item This is the method that updates the cached value. It must be explicitly called by the user of this class to store the value of the original item in the cache. */ virtual void copy() = 0; Item *get_item() { return item; } /** All of the subclasses should have the same type tag */ Type type() const override { return COPY_STR_ITEM; } const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { DBUG_ASSERT(0); return NULL; } void make_send_field(THD *thd, Send_field *field) override { item->make_send_field(thd, field); } table_map used_tables() const override { return (table_map) 1L; } bool const_item() const override { return false; } bool is_null() override { return null_value; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("copy", arg, VCOL_IMPOSSIBLE); } /* Override the methods below as pure virtual to make sure all the sub-classes implement them. */ String *val_str(String*) override = 0; my_decimal *val_decimal(my_decimal *) override = 0; double val_real() override = 0; longlong val_int() override = 0; int save_in_field(Field *field, bool no_conversions) override = 0; bool walk(Item_processor processor, bool walk_subquery, void *args) override { return (item->walk(processor, walk_subquery, args)) || (this->*processor)(args); } }; /** Implementation of a string cache. Uses Item::str_value for storage */ class Item_copy_string : public Item_copy { public: Item_copy_string(THD *thd, Item *item_arg): Item_copy(thd, item_arg) {} String *val_str(String*) override; my_decimal *val_decimal(my_decimal *) override; double val_real() override; longlong val_int() override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { DBUG_ASSERT(copied_in); return get_date_from_string(thd, ltime, fuzzydate); } void copy() override; int save_in_field(Field *field, bool no_conversions) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /** We need a separate class Item_copy_timestamp because TIMESTAMP->string->TIMESTAMP conversion is not round trip safe near the DST change, e.g. '2010-10-31 02:25:26' can mean: - my_time_t(1288477526) - summer time in Moscow - my_time_t(1288481126) - winter time in Moscow, one hour later */ class Item_copy_timestamp: public Item_copy { Timestamp_or_zero_datetime m_value; bool sane() const { return !null_value || m_value.is_zero_datetime(); } public: Item_copy_timestamp(THD *thd, Item *arg): Item_copy(thd, arg) { } const Type_handler *type_handler() const override { return &type_handler_timestamp2; } void copy() override { Timestamp_or_zero_datetime_native_null tmp(current_thd, item, false); null_value= tmp.is_null(); m_value= tmp.is_null() ? Timestamp_or_zero_datetime() : Timestamp_or_zero_datetime(tmp); #ifndef DBUG_OFF copied_in=1; #endif } int save_in_field(Field *field, bool) override { DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); if (null_value) return set_field_to_null(field); Timestamp_or_zero_datetime_native native(m_value, decimals); return native.save_in_field(field, decimals); } longlong val_int() override { DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); return null_value ? 0 : m_value.to_datetime(current_thd).to_longlong(); } double val_real() override { DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); return null_value ? 0e0 : m_value.to_datetime(current_thd).to_double(); } String *val_str(String *to) override { DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); return null_value ? NULL : m_value.to_datetime(current_thd).to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) override { DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); return null_value ? NULL : m_value.to_datetime(current_thd).to_decimal(to); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); bool res= m_value.to_TIME(thd, ltime, fuzzydate); DBUG_ASSERT(!res); return null_value || res; } bool val_native(THD *thd, Native *to) override { DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); return null_value || m_value.to_native(to, decimals); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /* Cached_item_XXX objects are not exactly caches. They do the following: Each Cached_item_XXX object has - its source item - saved value of the source item - cmp() method that compares the saved value with the current value of the source item, and if they were not equal saves item's value into the saved value. TODO: add here: - a way to save the new value w/o comparison - a way to do less/equal/greater comparison */ class Cached_item :public Sql_alloc { public: bool null_value; Cached_item() :null_value(0) {} /* Compare the cached value with the source value. If not equal, copy the source value to the cache. @return true - Not equal false - Equal */ virtual bool cmp(void)=0; /* Compare the cached value with the source value, without copying */ virtual int cmp_read_only()=0; virtual ~Cached_item(); /*line -e1509 */ }; class Cached_item_item : public Cached_item { protected: Item *item; Cached_item_item(Item *arg) : item(arg) {} public: void fetch_value_from(Item *new_item) { Item *save= item; item= new_item; cmp(); item= save; } }; class Cached_item_str :public Cached_item_item { uint32 value_max_length; String value,tmp_value; public: Cached_item_str(THD *thd, Item *arg); bool cmp() override; int cmp_read_only() override; ~Cached_item_str(); // Deallocate String:s }; class Cached_item_real :public Cached_item_item { double value; public: Cached_item_real(Item *item_par) :Cached_item_item(item_par),value(0.0) {} bool cmp() override; int cmp_read_only() override; }; class Cached_item_int :public Cached_item_item { longlong value; public: Cached_item_int(Item *item_par) :Cached_item_item(item_par),value(0) {} bool cmp() override; int cmp_read_only() override; }; class Cached_item_decimal :public Cached_item_item { my_decimal value; public: Cached_item_decimal(Item *item_par); bool cmp() override; int cmp_read_only() override; }; class Cached_item_field :public Cached_item { uchar *buff; Field *field; uint length; public: Cached_item_field(THD *thd, Field *arg_field): field(arg_field) { field= arg_field; /* TODO: take the memory allocation below out of the constructor. */ buff= (uchar*) thd_calloc(thd, length= field->pack_length()); } bool cmp() override; int cmp_read_only() override; }; class Item_default_value : public Item_field { bool vcol_assignment_ok:1; bool m_associated:1; bool m_share_field:1; void calculate(); public: Item *arg= nullptr; Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a, bool vcol_assignment_arg) : Item_field(thd, context_arg), vcol_assignment_ok(vcol_assignment_arg), arg(a) { m_associated= false; m_share_field= false; } Type type() const override { return DEFAULT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const override; bool fix_fields(THD *, Item **) override; void cleanup() override; void print(String *str, enum_query_type query_type) override; String *val_str(String *str) override; double val_real() override; longlong val_int() override; my_decimal *val_decimal(my_decimal *decimal_value) override; bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate) override; bool val_native(THD *thd, Native *to) override; bool val_native_result(THD *thd, Native *to) override; longlong val_datetime_packed(THD *thd) override { return Item::val_datetime_packed(thd); } longlong val_time_packed(THD *thd) override { return Item::val_time_packed(thd); } /* Result variants */ double val_result() override; longlong val_int_result() override; String *str_result(String* tmp) override; my_decimal *val_decimal_result(my_decimal *val) override; bool val_bool_result() override; bool is_null_result() override; bool get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool send(Protocol *protocol, st_value *buffer) override; int save_in_field(Field *field_arg, bool no_conversions) override; void save_in_result_field(bool no_conversions) override; bool save_in_param(THD *, Item_param *param) override { // It should not be possible to have "EXECUTE .. USING DEFAULT(a)" DBUG_ASSERT(0); param->set_default(true); return false; } table_map used_tables() const override; void update_used_tables() override { if (field && field->default_value) field->default_value->expr->update_used_tables(); } bool vcol_assignment_allowed_value() const override { return vcol_assignment_ok; } Item *get_tmp_table_item(THD *) override { return this; } Item_field *field_for_view_update() override { return nullptr; } bool update_vcol_processor(void *) override { return false; } bool check_field_expression_processor(void *arg) override; bool check_func_default_processor(void *) override { return true; } bool update_func_default_processor(void *arg) override; bool register_field_in_read_map(void *arg) override; bool walk(Item_processor processor, bool walk_subquery, void *args) override { return (arg && arg->walk(processor, walk_subquery, args)) || (this->*processor)(args); } Item *transform(THD *thd, Item_transformer transformer, uchar *args) override; Item *derived_field_transformer_for_having(THD *thd, uchar *arg) override { return NULL; } Item *derived_field_transformer_for_where(THD *thd, uchar *arg) override { return NULL; } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override; /** See comments on @see Item::associate_with_target_field for method description */ bool associate_with_target_field(THD *thd, Item_field *field) override; Item *do_get_copy(THD *thd) const override { Item_default_value *new_item= (Item_default_value *) get_item_copy(thd, this); // This is a copy so do not manage the field and should not delete it new_item->m_share_field= 1; return new_item; } Item* do_build_clone(THD *thd) const override { return get_copy(thd); } private: bool tie_field(THD *thd); }; class Item_contextually_typed_value_specification: public Item { public: Item_contextually_typed_value_specification(THD *thd) :Item(thd) { } Type type() const override { return CONTEXTUALLY_TYPED_VALUE_ITEM; } bool vcol_assignment_allowed_value() const override { return true; } bool eq(const Item *item, bool binary_cmp) const override { return false; } bool is_evaluable_expression() const override { return false; } Field *create_tmp_field_ex(MEM_ROOT *, TABLE *, Tmp_field_src *, const Tmp_field_param *) override { DBUG_ASSERT(0); return NULL; } String *val_str(String *str) override { DBUG_ASSERT(0); // never should be called null_value= true; return 0; } double val_real() override { DBUG_ASSERT(0); // never should be called null_value= true; return 0.0; } longlong val_int() override { DBUG_ASSERT(0); // never should be called null_value= true; return 0; } my_decimal *val_decimal(my_decimal *) override { DBUG_ASSERT(0); // never should be called null_value= true; return 0; } bool get_date(THD *, MYSQL_TIME *, date_mode_t) override { DBUG_ASSERT(0); // never should be called return (null_value= true); } bool send(Protocol *, st_value *) override { DBUG_ASSERT(0); return true; } const Type_handler *type_handler() const override { DBUG_ASSERT(0); return &type_handler_null; } }; /* ::= DEFAULT */ class Item_default_specification: public Item_contextually_typed_value_specification { public: Item_default_specification(THD *thd) :Item_contextually_typed_value_specification(thd) { } void print(String *str, enum_query_type) override { str->append(STRING_WITH_LEN("default")); } int save_in_field(Field *field_arg, bool) override { return field_arg->save_in_field_default_value(false); } bool save_in_param(THD *, Item_param *param) override { param->set_default(true); return false; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /** This class is used as bulk parameter INGNORE representation. It just do nothing when assigned to a field This is a non-standard MariaDB extension. */ class Item_ignore_specification: public Item_contextually_typed_value_specification { public: Item_ignore_specification(THD *thd) :Item_contextually_typed_value_specification(thd) { } void print(String *str, enum_query_type) override { str->append(STRING_WITH_LEN("ignore")); } int save_in_field(Field *field_arg, bool) override { return field_arg->save_in_field_ignore_value(false); } bool save_in_param(THD *, Item_param *param) override { param->set_ignore(true); return false; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /* Item_insert_value -- an implementation of VALUES() function. You can use the VALUES(col_name) function in the UPDATE clause to refer to column values from the INSERT portion of the INSERT ... UPDATE statement. In other words, VALUES(col_name) in the UPDATE clause refers to the value of col_name that would be inserted, had no duplicate-key conflict occurred. In all other places this function returns NULL. */ class Item_insert_value : public Item_field { public: Item *arg; Item_insert_value(THD *thd, Name_resolution_context *context_arg, Item *a) :Item_field(thd, context_arg), arg(a) {} bool eq(const Item *item, bool binary_cmp) const override; bool fix_fields(THD *, Item **) override; void print(String *str, enum_query_type query_type) override; int save_in_field(Field *field_arg, bool no_conversions) override { return Item_field::save_in_field(field_arg, no_conversions); } Type type() const override { return INSERT_VALUE_ITEM; } /* We use RAND_TABLE_BIT to prevent Item_insert_value from being treated as a constant and precalculated before execution */ table_map used_tables() const override { return RAND_TABLE_BIT; } Item_field *field_for_view_update() override { return nullptr; } bool walk(Item_processor processor, bool walk_subquery, void *args) override { return arg->walk(processor, walk_subquery, args) || (this->*processor)(args); } bool check_partition_func_processor(void *) override { return true; } bool update_vcol_processor(void *) override { return false; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("value()", arg, VCOL_IMPOSSIBLE); } }; class Table_triggers_list; /* Represents NEW/OLD version of field of row which is changed/read in trigger. Note: For this item main part of actual binding to Field object happens not during fix_fields() call (like for Item_field) but right after parsing of trigger definition, when table is opened, with special setup_field() call. On fix_fields() stage we simply choose one of two Field instances representing either OLD or NEW version of this field. */ class Item_trigger_field : public Item_field, private Settable_routine_parameter { private: GRANT_INFO *table_grants; public: /* Next in list of all Item_trigger_field's in trigger */ Item_trigger_field *next_trg_field; /* Pointer to Table_trigger_list object for table of this trigger */ Table_triggers_list *triggers; /* Is this item represents row from NEW or OLD row ? */ enum __attribute__((packed)) row_version_type {OLD_ROW, NEW_ROW}; row_version_type row_version; /* Index of the field in the TABLE::field array */ field_index_t field_idx; private: /* Trigger field is read-only unless it belongs to the NEW row in a BEFORE INSERT of BEFORE UPDATE trigger. */ bool read_only; /* 'want_privilege' holds privileges required to perform operation on this trigger field (SELECT_ACL if we are going to read it and UPDATE_ACL if we are going to update it). It is initialized at parse time but can be updated later if this trigger field is used as OUT or INOUT parameter of stored routine (in this case set_required_privilege() is called to appropriately update want_privilege and cleanup() is responsible for restoring of original want_privilege once parameter's value is updated). */ privilege_t original_privilege; privilege_t want_privilege; public: Item_trigger_field(THD *thd, Name_resolution_context *context_arg, row_version_type row_ver_arg, const LEX_CSTRING &field_name_arg, privilege_t priv, const bool ro) :Item_field(thd, context_arg, field_name_arg), table_grants(NULL), next_trg_field(NULL), triggers(NULL), row_version(row_ver_arg), field_idx(NO_CACHED_FIELD_INDEX), read_only (ro), original_privilege(priv), want_privilege(priv) { } void setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info); Type type() const override { return TRIGGER_FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const override; bool fix_fields(THD *, Item **) override; void print(String *str, enum_query_type query_type) override; table_map used_tables() const override { return (table_map)0L; } Field *get_tmp_table_field() override { return nullptr; } Item *copy_or_same(THD *) override { return this; } Item *get_tmp_table_item(THD *thd) override { return copy_or_same(thd); } void cleanup() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } private: void set_required_privilege(bool rw) override; bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; public: Settable_routine_parameter *get_settable_routine_parameter() override { return read_only ? nullptr : this; } bool set_value(THD *thd, Item **it) { return set_value(thd, NULL, it); } public: bool unknown_splocal_processor(void *) override { return false; } bool check_vcol_func_processor(void *arg) override; }; /** @todo Implement the is_null() method for this class. Currently calling is_null() on any Item_cache object resolves to Item::is_null(), which returns FALSE for any value. */ class Item_cache: public Item_fixed_hybrid, public Type_handler_hybrid_field_type { protected: Item *example; /** Field that this object will get value from. This is used by index-based subquery engines to detect and remove the equality injected by IN->EXISTS transformation. */ Field *cached_field; /* TRUE <=> cache holds value of the last stored item (i.e actual value). store() stores item to be cached and sets this flag to FALSE. On the first call of val_xxx function if this flag is set to FALSE the cache_value() will be called to actually cache value of saved item. cache_value() will set this flag to TRUE. */ bool value_cached; table_map used_table_map; public: /* This is set if at least one of the values of a sub query is NULL Item_cache_row returns this with null_inside(). For not row items, it's set to the value of null_value It is set after cache_value() is called. */ bool null_value_inside; Item_cache(THD *thd): Item_fixed_hybrid(thd), Type_handler_hybrid_field_type(&type_handler_string), example(0), cached_field(0), value_cached(0), used_table_map(0) { set_maybe_null(); null_value= 1; null_value_inside= true; quick_fix_field(); } protected: Item_cache(THD *thd, const Type_handler *handler): Item_fixed_hybrid(thd), Type_handler_hybrid_field_type(handler), example(0), cached_field(0), value_cached(0), used_table_map(0) { set_maybe_null(); null_value= 1; null_value_inside= true; quick_fix_field(); } public: virtual bool allocate(THD *thd, uint i) { return 0; } virtual bool setup(THD *thd, Item *item) { example= item; Type_std_attributes::set(item); base_flags|= item->base_flags & item_base_t::IS_COND; if (item->type() == FIELD_ITEM) cached_field= ((Item_field *)item)->field; return 0; }; void set_used_tables(table_map map) { used_table_map= map; } table_map used_tables() const override { return used_table_map; } Type type() const override { return CACHE_ITEM; } const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { return create_tmp_field_ex_simple(root, table, src, param); } virtual void keep_array() {} #ifndef DBUG_OFF bool is_array_kept() { return TRUE; } #endif void print(String *str, enum_query_type query_type) override; bool eq_def(const Field *field) { return cached_field ? cached_field->eq_def (field) : FALSE; } bool eq(const Item *item, bool binary_cmp) const override { return this == item; } bool check_vcol_func_processor(void *arg) override { if (example) { Item::vcol_func_processor_result *res= (Item::vcol_func_processor_result*) arg; example->check_vcol_func_processor(arg); /* Item_cache of a non-deterministic function requires re-fixing even if the function itself doesn't (e.g. CURRENT_TIMESTAMP) */ if (res->errors & VCOL_NOT_STRICTLY_DETERMINISTIC) res->errors|= VCOL_SESSION_FUNC; return false; } return mark_unsupported_function("cache", arg, VCOL_IMPOSSIBLE); } bool fix_fields(THD *thd, Item **ref) override { quick_fix_field(); if (example && !example->fixed()) return example->fix_fields(thd, ref); return 0; } void cleanup() override { clear(); Item_fixed_hybrid::cleanup(); } /** Check if saved item has a non-NULL value. Will cache value of saved item if not already done. @return TRUE if cached value is non-NULL. */ bool has_value() { return (value_cached || cache_value()) && !null_value; } virtual void store(Item *item); virtual Item *get_item() { return example; } virtual bool cache_value()= 0; bool basic_const_item() const override { return example && example->basic_const_item(); } virtual void clear() { null_value= TRUE; value_cached= FALSE; } bool is_null() override { return !has_value(); } bool is_expensive() override { if (value_cached) return false; return example->is_expensive(); } bool is_expensive_processor(void *arg) override { DBUG_ASSERT(example); if (value_cached) return false; return example->is_expensive_processor(arg); } virtual void set_null(); bool walk(Item_processor processor, bool walk_subquery, void *arg) override { if (arg == STOP_PTR) return FALSE; if (example && example->walk(processor, walk_subquery, arg)) return TRUE; return (this->*processor)(arg); } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; void split_sum_func2_example(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, uint flags) { example->split_sum_func2(thd, ref_pointer_array, fields, &example, flags); } Item *get_example() const { return example; } virtual Item *convert_to_basic_const_item(THD *thd) { return 0; }; Item *derived_field_transformer_for_having(THD *thd, uchar *) override { return convert_to_basic_const_item(thd); } Item *derived_field_transformer_for_where(THD *thd, uchar *) override { return convert_to_basic_const_item(thd); } Item *grouping_field_transformer_for_where(THD *thd, uchar *) override { return convert_to_basic_const_item(thd); } Item *in_subq_field_transformer_for_where(THD *thd, uchar *) override { return convert_to_basic_const_item(thd); } Item *in_subq_field_transformer_for_having(THD *thd, uchar *) override { return convert_to_basic_const_item(thd); } }; class Item_cache_int: public Item_cache { protected: longlong value; public: Item_cache_int(THD *thd, const Type_handler *handler): Item_cache(thd, handler), value(0) {} double val_real() override; longlong val_int() override; String* val_str(String *str) override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_int(thd, ltime, fuzzydate); } bool cache_value() override; int save_in_field(Field *field, bool no_conversions) override; Item *convert_to_basic_const_item(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_cache_bool: public Item_cache_int { public: Item_cache_bool(THD *thd) :Item_cache_int(thd, &type_handler_bool) { } bool cache_value() override; bool val_bool() override { return !has_value() ? false : (bool) value; } longlong val_int() override { DBUG_ASSERT(!is_cond()); return Item_cache_bool::val_bool(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_cache_year: public Item_cache_int { public: Item_cache_year(THD *thd, const Type_handler *handler) :Item_cache_int(thd, handler) { } bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode) override { return type_handler_year.Item_get_date_with_warn(thd, this, to, mode); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_cache_temporal: public Item_cache_int { protected: Item_cache_temporal(THD *thd, const Type_handler *handler); public: bool cache_value() override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; int save_in_field(Field *field, bool no_conversions) override; bool setup(THD *thd, Item *item) override { if (Item_cache_int::setup(thd, item)) return true; set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); return false; } void store_packed(longlong val_arg, Item *example); /* Having a clone_item method tells optimizer that this object is a constant and need not be optimized further. Important when storing packed datetime values. */ Item *clone_item(THD *thd) const override; Item *convert_to_basic_const_item(THD *thd) override; virtual Item *make_literal(THD *) =0; }; class Item_cache_time: public Item_cache_temporal { public: Item_cache_time(THD *thd) :Item_cache_temporal(thd, &type_handler_time2) { } bool cache_value() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *make_literal(THD *) override; longlong val_datetime_packed(THD *thd) override { Datetime::Options_cmp opt(thd); return has_value() ? Datetime(thd, this, opt).to_packed() : 0; } longlong val_time_packed(THD *) override { return has_value() ? value : 0; } longlong val_int() override { return has_value() ? Time(this).to_longlong() : 0; } double val_real() override { return has_value() ? Time(this).to_double() : 0; } String *val_str(String *to) override { return has_value() ? Time(this).to_string(to, decimals) : NULL; } my_decimal *val_decimal(my_decimal *to) override { return has_value() ? Time(this).to_decimal(to) : NULL; } bool val_native(THD *thd, Native *to) override { return has_value() ? Time(thd, this).to_native(to, decimals) : true; } }; class Item_cache_datetime: public Item_cache_temporal { public: Item_cache_datetime(THD *thd) :Item_cache_temporal(thd, &type_handler_datetime2) { } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *make_literal(THD *) override; longlong val_datetime_packed(THD *) override { return has_value() ? value : 0; } longlong val_time_packed(THD *thd) override { return Time(thd, this, Time::Options_cmp(thd)).to_packed(); } longlong val_int() override { return has_value() ? Datetime(this).to_longlong() : 0; } double val_real() override { return has_value() ? Datetime(this).to_double() : 0; } String *val_str(String *to) override { return has_value() ? Datetime(this).to_string(to, decimals) : NULL; } my_decimal *val_decimal(my_decimal *to) override { return has_value() ? Datetime(this).to_decimal(to) : NULL; } }; class Item_cache_date: public Item_cache_temporal { public: Item_cache_date(THD *thd) :Item_cache_temporal(thd, &type_handler_newdate) { } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *make_literal(THD *) override; longlong val_datetime_packed(THD *) override { return has_value() ? value : 0; } longlong val_time_packed(THD *thd) override { return Time(thd, this, Time::Options_cmp(thd)).to_packed(); } longlong val_int() override { return has_value() ? Date(this).to_longlong() : 0; } double val_real() override { return has_value() ? Date(this).to_double() : 0; } String *val_str(String *to) override { return has_value() ? Date(this).to_string(to) : NULL; } my_decimal *val_decimal(my_decimal *to) override { return has_value() ? Date(this).to_decimal(to) : NULL; } }; class Item_cache_timestamp: public Item_cache { Timestamp_or_zero_datetime_native m_native; Datetime to_datetime(THD *thd); public: Item_cache_timestamp(THD *thd) :Item_cache(thd, &type_handler_timestamp2) { } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } bool cache_value() override; String* val_str(String *to) override { return to_datetime(current_thd).to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) override { return to_datetime(current_thd).to_decimal(to); } longlong val_int() override { return to_datetime(current_thd).to_longlong(); } double val_real() override { return to_datetime(current_thd).to_double(); } longlong val_datetime_packed(THD *thd) override { return to_datetime(thd).to_packed(); } longlong val_time_packed(THD *) override { DBUG_ASSERT(0); return 0; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; int save_in_field(Field *field, bool no_conversions) override; bool val_native(THD *thd, Native *to) override; }; class Item_cache_real: public Item_cache { protected: double value; public: Item_cache_real(THD *thd, const Type_handler *h) :Item_cache(thd, h), value(0) {} double val_real() override; longlong val_int() override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_real(thd, ltime, fuzzydate); } bool cache_value() override; Item *convert_to_basic_const_item(THD *thd) override; }; class Item_cache_double: public Item_cache_real { public: Item_cache_double(THD *thd) :Item_cache_real(thd, &type_handler_double) { } String *val_str(String *str) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_cache_float: public Item_cache_real { public: Item_cache_float(THD *thd) :Item_cache_real(thd, &type_handler_float) { } String *val_str(String *str) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_cache_decimal: public Item_cache { protected: my_decimal decimal_value; public: Item_cache_decimal(THD *thd): Item_cache(thd, &type_handler_newdecimal) {} double val_real() override; longlong val_int() override; String* val_str(String *str) override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode) override { return decimal_to_datetime_with_warn(thd, VDec(this).ptr(), to, mode, NULL, NULL); } bool cache_value() override; Item *convert_to_basic_const_item(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_cache_str: public Item_cache { char buffer[STRING_BUFFER_USUAL_SIZE]; String *value, value_buff; bool is_varbinary; public: Item_cache_str(THD *thd, const Item *item): Item_cache(thd, item->type_handler()), value(0), is_varbinary(item->type() == FIELD_ITEM && Item_cache_str::field_type() == MYSQL_TYPE_VARCHAR && !((const Item_field *) item)->field->has_charset()) { collation.set(const_cast(item->collation)); } double val_real() override; longlong val_int() override; String* val_str(String *) override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_string(thd, ltime, fuzzydate); } CHARSET_INFO *charset() const { return value->charset(); }; int save_in_field(Field *field, bool no_conversions) override; bool cache_value() override; Item *convert_to_basic_const_item(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_cache_str_for_nullif: public Item_cache_str { public: Item_cache_str_for_nullif(THD *thd, const Item *item) :Item_cache_str(thd, item) { } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override { /** Item_cache_str::safe_charset_converter() returns a new Item_cache with Item_func_conv_charset installed on "example". The original Item_cache is not referenced (neither directly nor recursively) from the result of Item_cache_str::safe_charset_converter(). For NULLIF() purposes we need a different behavior: we need a new instance of Item_func_conv_charset, with the original Item_cache referenced in args[0]. See MDEV-9181. */ return Item::safe_charset_converter(thd, tocs); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; class Item_cache_row: public Item_cache { Item_cache **values; uint item_count; bool save_array; public: Item_cache_row(THD *thd): Item_cache(thd, &type_handler_row), values(0), item_count(2), save_array(0) {} /* 'allocate' used only in row transformer, to preallocate space for row cache. */ bool allocate(THD *thd, uint num) override; /* 'setup' is needed only by row => it not called by simple row subselect (only by IN subselect (in subselect optimizer)) */ bool setup(THD *thd, Item *item) override; void store(Item *item) override; void illegal_method_call(const char *); void make_send_field(THD *, Send_field *) override { illegal_method_call("make_send_field"); }; double val_real() override { illegal_method_call("val"); return 0; }; longlong val_int() override { illegal_method_call("val_int"); return 0; }; String *val_str(String *) override { illegal_method_call("val_str"); return nullptr; }; my_decimal *val_decimal(my_decimal *) override { illegal_method_call("val_decimal"); return nullptr; }; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { illegal_method_call("val_decimal"); return true; } uint cols() const override { return item_count; } Item *element_index(uint i) override { return values[i]; } Item **addr(uint i) override { return (Item **) (values + i); } bool check_cols(uint c) override; bool null_inside() override; void bring_value() override; void keep_array() override { save_array= 1; } #ifndef DBUG_OFF bool is_array_kept() { return save_array; } #endif void cleanup() override { DBUG_ENTER("Item_cache_row::cleanup"); Item_cache::cleanup(); if (!save_array) values= 0; DBUG_VOID_RETURN; } bool cache_value() override; void set_null() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; /* Item_type_holder used to store type. name, length of Item for UNIONS & derived tables. Item_type_holder do not need cleanup() because its time of live limited by single SP/PS execution. */ class Item_type_holder: public Item, public Type_handler_hybrid_field_type { protected: const TYPELIB *enum_set_typelib; public: Item_type_holder(THD *thd, Item *item, const Type_handler *handler, const Type_all_attributes *attr, bool maybe_null_arg) :Item(thd), Type_handler_hybrid_field_type(handler), enum_set_typelib(attr->get_typelib()) { name= item->name; Type_std_attributes::set(*attr); set_maybe_null(maybe_null_arg); copy_flags(item, item_base_t::IS_EXPLICIT_NAME | item_base_t::IS_IN_WITH_CYCLE); } const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler()-> type_handler_for_item_field(); } const Type_handler *real_type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } Type type() const override { return TYPE_HOLDER; } const TYPELIB *get_typelib() const override { return enum_set_typelib; } /* When handling a query like this: VALUES ('') UNION VALUES( _utf16 0x0020 COLLATE utf16_bin); Item_type_holder can be passed to Type_handler_xxx::Item_hybrid_func_fix_attributes() We don't want the latter to perform character set conversion of a Item_type_holder by calling its val_str(), which calls DBUG_ASSERT(0). Let's override const_item() and is_expensive() to avoid this. Note, Item_hybrid_func_fix_attributes() could probably have a new argument to distinguish what we need: - (a) aggregate data type attributes only - (b) install converters after attribute aggregation So st_select_lex_unit::join_union_type_attributes() could ask it to do (a) only, without (b). */ bool const_item() const override { return false; } bool is_expensive() override { return true; } double val_real() override; longlong val_int() override; my_decimal *val_decimal(my_decimal *) override; String *val_str(String*) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, const Tmp_field_param *param) override { return Item_type_holder::real_type_handler()-> make_and_init_table_field(root, &name, Record_addr(maybe_null()), *this, table); } Item *do_get_copy(THD *) const override { return nullptr; } Item *do_build_clone(THD *) const override { return nullptr; } }; class st_select_lex; void mark_select_range_as_dependent(THD *thd, st_select_lex *last_select, st_select_lex *current_sel, Field *found_field, Item *found_item, Item_ident *resolved_item, bool suppress_warning_output); extern Cached_item *new_Cached_item(THD *thd, Item *item, bool pass_through_ref); extern Item_result item_cmp_type(Item_result a,Item_result b); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); extern int stored_field_cmp_to_item(THD *thd, Field *field, Item *item); extern const String my_null_string; /** Interface for Item iterator */ class Item_iterator { public: /** Shall set this iterator to the position before the first item @note This method also may perform some other initialization actions like allocation of certain resources. */ virtual void open()= 0; /** Shall return the next Item (or NULL if there is no next item) and move pointer to position after it. */ virtual Item *next()= 0; /** Shall force iterator to free resources (if it holds them) @note One should not use the iterator without open() call after close() */ virtual void close()= 0; virtual ~Item_iterator() = default; }; /** Item iterator over List_iterator_fast for Item references */ class Item_iterator_ref_list: public Item_iterator { List_iterator list; public: Item_iterator_ref_list(List_iterator &arg_list): list(arg_list) {} void open() override { list.rewind(); } Item *next() override { return *(list++); } void close() override {} }; /** Item iterator over List_iterator_fast for Items */ class Item_iterator_list: public Item_iterator { List_iterator list; public: Item_iterator_list(List_iterator &arg_list): list(arg_list) {} void open() override { list.rewind(); } Item *next() override { return (list++); } void close() override {} }; /** Item iterator over Item interface for rows */ class Item_iterator_row: public Item_iterator { Item *base_item; uint current; public: Item_iterator_row(Item *base) : base_item(base), current(0) {} void open() override { current= 0; } Item *next() override { if (current >= base_item->cols()) return NULL; return base_item->element_index(current++); } void close() override {} }; /* fix_escape_item() sets the out "escape" parameter to: - native code in case of an 8bit character set - Unicode code point in case of a multi-byte character set The value meaning a not-initialized ESCAPE character must not be equal to any valid value, so must be outside of these ranges: - -128..+127, not to conflict with a valid 8bit charcter - 0..0x10FFFF, not to conflict with a valid Unicode code point The exact value does not matter. */ #define ESCAPE_NOT_INITIALIZED -1000 /* It's used in ::fix_fields() methods of LIKE and JSON_SEARCH functions to handle the ESCAPE parameter. This parameter is quite non-standard so the specific function. */ bool fix_escape_item(THD *thd, Item *escape_item, String *tmp_str, bool escape_used_in_parsing, CHARSET_INFO *cmp_cs, int *escape); inline bool Virtual_column_info::is_equal(const Virtual_column_info* vcol) const { return type_handler() == vcol->type_handler() && stored_in_db == vcol->is_stored() && expr->eq(vcol->expr, true); } inline void Virtual_column_info::print(String* str) { expr->print_for_table_def(str); } class Item_direct_ref_to_item : public Item_direct_ref { Item *m_item; public: Item_direct_ref_to_item(THD *thd, Item *item); void change_item(THD *thd, Item *); bool fix_fields(THD *thd, Item **it) override; void print(String *str, enum_query_type query_type) override; Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; Item *get_tmp_table_item(THD *thd) override { return m_item->get_tmp_table_item(thd); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) override { return m_item->build_equal_items(thd, inherited, link_item_fields, cond_equal_ref); } LEX_CSTRING full_name_cstring() const override { return m_item->full_name_cstring(); } void make_send_field(THD *thd, Send_field *field) override { m_item->make_send_field(thd, field); } bool eq(const Item *item, bool binary_cmp) const override { const Item *it= item->real_item(); return m_item->eq(it, binary_cmp); } void fix_after_pullout(st_select_lex *new_parent, Item **refptr, bool merge) override { m_item->fix_after_pullout(new_parent, &m_item, merge); } void save_val(Field *to) override { return m_item->save_val(to); } void save_result(Field *to) override { return m_item->save_result(to); } int save_in_field(Field *to, bool no_conversions) override { return m_item->save_in_field(to, no_conversions); } const Type_handler *type_handler() const override { return m_item->type_handler(); } table_map used_tables() const override { return m_item->used_tables(); } void update_used_tables() override { m_item->update_used_tables(); } bool const_item() const override { return m_item->const_item(); } table_map not_null_tables() const override { return m_item->not_null_tables(); } bool walk(Item_processor processor, bool walk_subquery, void *arg) override { return m_item->walk(processor, walk_subquery, arg) || (this->*processor)(arg); } bool enumerate_field_refs_processor(void *arg) override { return m_item->enumerate_field_refs_processor(arg); } Item_field *field_for_view_update() override { return m_item->field_for_view_update(); } /* Row emulation: forwarding of ROW-related calls to orig_item */ uint cols() const override { return m_item->cols(); } Item* element_index(uint i) override { return this; } Item** addr(uint i) override { return &m_item; } bool check_cols(uint c) override { return Item::check_cols(c); } bool null_inside() override { return m_item->null_inside(); } void bring_value() override {} Item_equal *get_item_equal() override { return m_item->get_item_equal(); } void set_item_equal(Item_equal *item_eq) override { m_item->set_item_equal(item_eq); } Item_equal *find_item_equal(COND_EQUAL *cond_equal) override { return m_item->find_item_equal(cond_equal); } Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { return m_item->propagate_equal_fields(thd, ctx, cond); } Item *replace_equal_field(THD *thd, uchar *arg) override { return m_item->replace_equal_field(thd, arg); } bool excl_dep_on_table(table_map tab_map) override { return m_item->excl_dep_on_table(tab_map); } bool excl_dep_on_grouping_fields(st_select_lex *sel) override { return m_item->excl_dep_on_grouping_fields(sel); } bool is_expensive() override { return m_item->is_expensive(); } void set_item(Item *item) { m_item= item; } Item *do_build_clone(THD *thd) const override { Item *clone_item= m_item->build_clone(thd); if (clone_item) { Item_direct_ref_to_item *copy= (Item_direct_ref_to_item *) get_copy(thd); if (!copy) return 0; copy->set_item(clone_item); return copy; } return 0; } void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, uint flags) override { m_item->split_sum_func(thd, ref_pointer_array, fields, flags); } /* This processor states that this is safe for virtual columns (because this Item transparency) */ bool check_vcol_func_processor(void *arg) override { return FALSE;} }; inline bool TABLE::mark_column_with_deps(Field *field) { bool res; if (!(res= bitmap_fast_test_and_set(read_set, field->field_index))) { if (field->vcol_info) mark_virtual_column_deps(field); } return res; } inline bool TABLE::mark_virtual_column_with_deps(Field *field) { bool res; DBUG_ASSERT(field->vcol_info); if (!(res= bitmap_fast_test_and_set(read_set, field->field_index))) mark_virtual_column_deps(field); return res; } inline void TABLE::mark_virtual_column_deps(Field *field) { DBUG_ASSERT(field->vcol_info); DBUG_ASSERT(field->vcol_info->expr); field->vcol_info->expr->walk(&Item::register_field_in_read_map, 1, 0); } inline void TABLE::use_all_stored_columns() { bitmap_set_all(read_set); if (Field **vf= vfield) for (; *vf; vf++) bitmap_clear_bit(read_set, (*vf)->field_index); } #endif /* SQL_ITEM_INCLUDED */ server/private/lex_symbol.h000064400000002453151031265040012053 0ustar00/* Copyright (c) 2000, 2001, 2004, 2006, 2007 MySQL AB Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* This struct includes all reserved words and functions */ #ifndef _lex_symbol_h #define _lex_symbol_h struct st_sym_group; typedef struct st_symbol { const char *name; uint tok; uint length; struct st_sym_group *group; } SYMBOL; typedef struct st_lex_symbol { SYMBOL *symbol; char *str; uint length; } LEX_SYMBOL; typedef struct st_sym_group { const char *name; const char *needed_define; } SYM_GROUP; extern SYM_GROUP sym_group_common; extern SYM_GROUP sym_group_geom; extern SYM_GROUP sym_group_rtree; #endif /* _lex_symbol_h */ server/private/wsrep.h000064400000006354151031265040011042 0ustar00/* Copyright 2014 Codership Oy & SkySQL Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef WSREP_INCLUDED #define WSREP_INCLUDED #include #include "log.h" #ifdef WITH_WSREP #define IF_WSREP(A,B) A #define DBUG_ASSERT_IF_WSREP(A) DBUG_ASSERT(A) extern ulong wsrep_debug; // wsrep_mysqld.cc extern void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...); #define WSREP_DEBUG(...) \ if (wsrep_debug) WSREP_LOG(sql_print_information, ##__VA_ARGS__) #define WSREP_INFO(...) WSREP_LOG(sql_print_information, ##__VA_ARGS__) #define WSREP_WARN(...) WSREP_LOG(sql_print_warning, ##__VA_ARGS__) #define WSREP_ERROR(...) WSREP_LOG(sql_print_error, ##__VA_ARGS__) #define WSREP_UNKNOWN(fmt, ...) WSREP_ERROR("UNKNOWN: " fmt, ##__VA_ARGS__) #define WSREP_LOG_CONFLICT_THD(thd, role) \ WSREP_INFO("%s: \n " \ " THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n " \ " SQL: %s", \ role, \ thd_get_thread_id(thd), \ wsrep_thd_client_mode_str(thd), \ wsrep_thd_client_state_str(thd), \ wsrep_thd_transaction_state_str(thd), \ wsrep_thd_trx_seqno(thd), \ wsrep_thd_query(thd) \ ); #define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort) \ if (wsrep_debug || wsrep_log_conflicts) \ { \ WSREP_INFO("cluster conflict due to %s for threads:", \ (bf_abort) ? "high priority abort" : "certification failure" \ ); \ if (bf_thd) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \ if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread"); \ WSREP_INFO("context: %s:%d", __FILE__, __LINE__); \ } #else /* !WITH_WSREP */ /* These macros are needed to compile MariaDB without WSREP support * (e.g. embedded) */ #define IF_WSREP(A,B) B //#define DBUG_ASSERT_IF_WSREP(A) #define WSREP_DEBUG(...) //#define WSREP_INFO(...) //#define WSREP_WARN(...) #define WSREP_ERROR(...) #endif /* WITH_WSREP */ #endif /* WSREP_INCLUDED */ server/private/sql_basic_types.h000064400000022470151031265040013063 0ustar00/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2009, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* File that includes common types used globally in MariaDB */ #ifndef SQL_TYPES_INCLUDED #define SQL_TYPES_INCLUDED typedef ulonglong sql_mode_t; typedef int64 query_id_t; enum enum_nullability { NOT_NULL, NULLABLE }; /* "fuzzydate" with strict data type control. Represents a mixture of *only* data type conversion flags, without rounding. Please keep "explicit" in constructors and conversion methods. */ class date_conv_mode_t { public: enum value_t { CONV_NONE= 0U, /* FUZZY_DATES is used for the result will only be used for comparison purposes. Conversion is as relaxed as possible. */ FUZZY_DATES= 1U, TIME_ONLY= 4U, INTERVAL_hhmmssff= 8U, INTERVAL_DAY= 16U, RANGE0_LAST= INTERVAL_DAY, NO_ZERO_IN_DATE= (1UL << 23), // MODE_NO_ZERO_IN_DATE NO_ZERO_DATE= (1UL << 24), // MODE_NO_ZERO_DATE INVALID_DATES= (1UL << 25) // MODE_INVALID_DATES }; /* BIT-OR for all known values. Let's have a separate enum for it. - We don't put this value "value_t", to avoid handling it in switch(). - We don't put this value as a static const inside the class, because "gdb" would display it every time when we do "print" for a time_round_mode_t value. - We can't put into into a function returning this value, because it's not allowed to use functions in static_assert. */ enum known_values_t { KNOWN_MODES= FUZZY_DATES | TIME_ONLY | INTERVAL_hhmmssff | INTERVAL_DAY | NO_ZERO_IN_DATE | NO_ZERO_DATE | INVALID_DATES }; private: value_t m_mode; public: // Constructors explicit date_conv_mode_t(ulonglong fuzzydate) :m_mode((value_t) fuzzydate) { } // Conversion operators explicit operator ulonglong() const { return m_mode; } explicit operator bool() const { return m_mode != 0; } // Unary operators ulonglong operator~() const { return ~m_mode; } // Dyadic bitwise operators date_conv_mode_t operator&(const date_conv_mode_t &other) const { return date_conv_mode_t(m_mode & other.m_mode); } date_conv_mode_t operator&(const ulonglong other) const { return date_conv_mode_t(m_mode & other); } date_conv_mode_t operator|(const date_conv_mode_t &other) const { return date_conv_mode_t(m_mode | other.m_mode); } // Dyadic bitwise assignment operators date_conv_mode_t &operator&=(const date_conv_mode_t &other) { m_mode= value_t(m_mode & other.m_mode); return *this; } date_conv_mode_t &operator|=(const date_conv_mode_t &other) { m_mode= value_t(m_mode | other.m_mode); return *this; } }; /* Fractional rounding mode for temporal data types. */ class time_round_mode_t { public: enum value_t { /* Use FRAC_NONE when the value needs no rounding nor truncation, because it is already known not to haveany fractional digits outside of the requested precision. */ FRAC_NONE= 0, FRAC_TRUNCATE= date_conv_mode_t::RANGE0_LAST << 1, // 32 FRAC_ROUND= date_conv_mode_t::RANGE0_LAST << 2 // 64 }; // BIT-OR for all known values. See comments in time_conv_mode_t. enum known_values_t { KNOWN_MODES= FRAC_TRUNCATE | FRAC_ROUND }; private: value_t m_mode; public: // Constructors explicit time_round_mode_t(ulonglong mode) :m_mode((value_t) mode) { #ifdef MYSQL_SERVER DBUG_ASSERT(mode == FRAC_NONE || mode == FRAC_TRUNCATE || mode == FRAC_ROUND); #endif } // Conversion operators explicit operator ulonglong() const { return m_mode; } value_t mode() const { return m_mode; } // Comparison operators bool operator==(const time_round_mode_t &other) { return m_mode == other.m_mode; } }; /* "fuzzydate" with strict data type control. Used as a parameter to get_date() and represents a mixture of: - data type conversion flags - fractional second rounding flags Please keep "explicit" in constructors and conversion methods. */ class date_mode_t { public: enum value_t { CONV_NONE= date_conv_mode_t::CONV_NONE, // 0 FUZZY_DATES= date_conv_mode_t::FUZZY_DATES, // 1 TIME_ONLY= date_conv_mode_t::TIME_ONLY, // 4 INTERVAL_hhmmssff= date_conv_mode_t::INTERVAL_hhmmssff, // 8 INTERVAL_DAY= date_conv_mode_t::INTERVAL_DAY, // 16 FRAC_TRUNCATE= time_round_mode_t::FRAC_TRUNCATE, // 32 FRAC_ROUND= time_round_mode_t::FRAC_ROUND, // 64 NO_ZERO_IN_DATE= date_conv_mode_t::NO_ZERO_IN_DATE, // (1UL << 23) NO_ZERO_DATE= date_conv_mode_t::NO_ZERO_DATE, // (1UL << 24) INVALID_DATES= date_conv_mode_t::INVALID_DATES, // (1UL << 25) }; protected: value_t m_mode; public: // Constructors explicit date_mode_t(ulonglong fuzzydate) :m_mode((value_t) fuzzydate) { } // Conversion operators explicit operator ulonglong() const { return m_mode; } explicit operator bool() const { return m_mode != 0; } explicit operator date_conv_mode_t() const { return date_conv_mode_t(ulonglong(m_mode) & date_conv_mode_t::KNOWN_MODES); } explicit operator time_round_mode_t() const { return time_round_mode_t(ulonglong(m_mode) & time_round_mode_t::KNOWN_MODES); } // Unary operators ulonglong operator~() const { return ~m_mode; } bool operator!() const { return !m_mode; } // Dyadic bitwise operators date_mode_t operator&(const date_mode_t &other) const { return date_mode_t(m_mode & other.m_mode); } date_mode_t operator&(ulonglong other) const { return date_mode_t(m_mode & other); } date_mode_t operator|(const date_mode_t &other) const { return date_mode_t(m_mode | other.m_mode); } // Dyadic bitwise assignment operators date_mode_t &operator&=(const date_mode_t &other) { m_mode= value_t(m_mode & other.m_mode); return *this; } date_mode_t &operator|=(const date_mode_t &other) { m_mode= value_t(m_mode | other.m_mode); return *this; } date_mode_t &operator|=(const date_conv_mode_t &other) { m_mode= value_t(m_mode | ulonglong(other)); return *this; } }; // Bitwise OR out-of-class operators for data type mixtures static inline date_mode_t operator|(const date_mode_t &a, const date_conv_mode_t &b) { return date_mode_t(ulonglong(a) | ulonglong(b)); } static inline date_mode_t operator|(const date_conv_mode_t &a, const time_round_mode_t &b) { return date_mode_t(ulonglong(a) | ulonglong(b)); } static inline date_mode_t operator|(const date_conv_mode_t &a, const date_mode_t &b) { return date_mode_t(ulonglong(a) | ulonglong(b)); } // Bitwise AND out-of-class operators for data type mixtures static inline date_conv_mode_t operator&(const date_mode_t &a, const date_conv_mode_t &b) { return date_conv_mode_t(ulonglong(a) & ulonglong(b)); } static inline date_conv_mode_t operator&(const date_conv_mode_t &a, const date_mode_t &b) { return date_conv_mode_t(ulonglong(a) & ulonglong(b)); } static inline date_conv_mode_t operator&(sql_mode_t &a, const date_conv_mode_t &b) { return date_conv_mode_t(a & ulonglong(b)); } static const date_conv_mode_t TIME_CONV_NONE (date_conv_mode_t::CONV_NONE), TIME_FUZZY_DATES (date_conv_mode_t::FUZZY_DATES), TIME_TIME_ONLY (date_conv_mode_t::TIME_ONLY), TIME_INTERVAL_hhmmssff (date_conv_mode_t::INTERVAL_hhmmssff), TIME_INTERVAL_DAY (date_conv_mode_t::INTERVAL_DAY), TIME_NO_ZERO_IN_DATE (date_conv_mode_t::NO_ZERO_IN_DATE), TIME_NO_ZERO_DATE (date_conv_mode_t::NO_ZERO_DATE), TIME_INVALID_DATES (date_conv_mode_t::INVALID_DATES); // An often used combination static const date_conv_mode_t TIME_NO_ZEROS (date_conv_mode_t::NO_ZERO_DATE| date_conv_mode_t::NO_ZERO_IN_DATE); // Flags understood by str_to_xxx, number_to_xxx, check_date static const date_conv_mode_t TIME_MODE_FOR_XXX_TO_DATE (date_mode_t::NO_ZERO_IN_DATE | date_mode_t::NO_ZERO_DATE | date_mode_t::INVALID_DATES); static const time_round_mode_t TIME_FRAC_NONE (time_round_mode_t::FRAC_NONE), TIME_FRAC_TRUNCATE (time_round_mode_t::FRAC_TRUNCATE), TIME_FRAC_ROUND (time_round_mode_t::FRAC_ROUND); #endif server/private/wsrep_xid.h000064400000003015151031265040011675 0ustar00/* Copyright (C) 2015-2025 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA. */ #ifndef WSREP_XID_H #define WSREP_XID_H #include #ifdef WITH_WSREP #include "wsrep_mysqld.h" #include "wsrep/gtid.hpp" #include "handler.h" // XID typedef void wsrep_xid_init(xid_t*, const wsrep::gtid&, const wsrep_server_gtid_t&); const wsrep::id& wsrep_xid_uuid(const XID&); wsrep::seqno wsrep_xid_seqno(const XID&); template T wsrep_get_SE_checkpoint(); bool wsrep_set_SE_checkpoint(const wsrep::gtid& gtid, const wsrep_server_gtid_t&); //void wsrep_get_SE_checkpoint(XID&); /* uncomment if needed */ //void wsrep_set_SE_checkpoint(XID&); /* uncomment if needed */ void wsrep_sort_xid_array(XID *array, int len); std::string wsrep_xid_print(const XID *xid); bool wsrep_is_xid_gtid_undefined(const XID *xid); #endif /* WITH_WSREP */ #endif /* WSREP_UTILS_H */ server/private/embedded_priv.h000064400000003305151031265040012464 0ustar00/* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Prototypes for the embedded version of MySQL */ #include C_MODE_START void lib_connection_phase(NET *net, int phase); void init_embedded_mysql(MYSQL *mysql, ulong client_flag); void *create_embedded_thd(ulong client_flag); int check_embedded_connection(MYSQL *mysql, const char *db); void free_old_query(MYSQL *mysql); THD *embedded_get_current_thd(); void embedded_set_current_thd(THD *thd); extern MYSQL_METHODS embedded_methods; /* This one is used by embedded library to gather returning data */ typedef struct embedded_query_result { MYSQL_ROWS **prev_ptr; unsigned int warning_count, server_status; struct st_mysql_data *next; my_ulonglong affected_rows, insert_id; char info[MYSQL_ERRMSG_SIZE]; MYSQL_FIELD *fields_list; unsigned int last_errno; char sqlstate[SQLSTATE_LENGTH+1]; } EQR; typedef struct st_mariadb_field_extension { MARIADB_CONST_STRING metadata[MARIADB_FIELD_ATTR_LAST+1]; /* 10.5 */ } MARIADB_FIELD_EXTENSION; C_MODE_END server/private/scope.h000064400000010451151031265040011004 0ustar00/* Copyright (c) 2020, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #pragma once #include #include namespace detail { template class scope_exit { public: template explicit scope_exit(F &&f) : function_(std::forward(f)) { } template scope_exit(F &&f, bool engaged) : function_(std::forward(f)), engaged_(engaged) { } scope_exit(scope_exit &&rhs) : function_(std::move(rhs.function_)), engaged_(rhs.engaged_) { rhs.release(); } scope_exit(const scope_exit &)= delete; scope_exit &operator=(scope_exit &&)= delete; scope_exit &operator=(const scope_exit &)= delete; void release() { engaged_= false; } void engage() { DBUG_ASSERT(!engaged_); engaged_= true; } ~scope_exit() { if (engaged_) function_(); } private: Callable function_; bool engaged_= true; }; } // end namespace detail template inline ::detail::scope_exit::type> make_scope_exit(Callable &&f, bool engaged= true) { return ::detail::scope_exit::type>( std::forward(f), engaged); } #define CONCAT_IMPL(x, y) x##y #define CONCAT(x, y) CONCAT_IMPL(x, y) #define ANONYMOUS_VARIABLE CONCAT(_anonymous_variable, __LINE__) #define SCOPE_EXIT auto ANONYMOUS_VARIABLE= make_scope_exit #define IF_CLASS(C) typename std::enable_if::value>::type #define IF_NOT_CLASS(C) typename std::enable_if::value>::type namespace detail { template class Scope_value { public: // Use SFINAE for passing structs by reference and plain types by value. // This ctor is defined only if T is a class or struct: template Scope_value(T &variable, const T &scope_value) : variable_(&variable), saved_value_(variable) { variable= scope_value; } // This ctor is defined only if T is NOT a class or struct: template Scope_value(T &variable, const T scope_value) : variable_(&variable), saved_value_(variable) { variable= scope_value; } Scope_value(Scope_value &&rhs) : variable_(rhs.variable_), saved_value_(rhs.saved_value_) { rhs.variable_= NULL; } Scope_value(const Scope_value &)= delete; Scope_value &operator=(const Scope_value &)= delete; Scope_value &operator=(Scope_value &&)= delete; ~Scope_value() { if (variable_) *variable_= saved_value_; } private: T *variable_; T saved_value_; }; } // namespace detail // Use like this: // auto _= make_scope_value(var, tmp_value); template inline ::detail::Scope_value make_scope_value(T &variable, const T &scope_value) { return ::detail::Scope_value(variable, scope_value); } template inline ::detail::Scope_value make_scope_value(T &variable, T scope_value) { return ::detail::Scope_value(variable, scope_value); } /* Note: perfect forwarding version can not pass const: template inline detail::Scope_value make_scope_value(T &variable, U &&scope_value) { return detail::Scope_value(variable, std::forward(scope_value)); } as `const U &&` fails with error `expects an rvalue for 2nd argument`. That happens because const U && is treated as rvalue only (this is the exact syntax for declaring rvalues). */ #define SCOPE_VALUE auto ANONYMOUS_VARIABLE= make_scope_value #define SCOPE_SET(VAR, MASK) auto ANONYMOUS_VARIABLE= make_scope_value(VAR, VAR | MASK) #define SCOPE_CLEAR(VAR, MASK) auto ANONYMOUS_VARIABLE= make_scope_value(VAR, VAR & ~MASK) server/private/queues.h000064400000006625151031265040011212 0ustar00/* Copyright (C) 2010 Monty Program Ab All Rights reserved Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Code for general handling of priority Queues. Implementation of queues from "Algorithms in C" by Robert Sedgewick. */ #ifndef _queues_h #define _queues_h #include #ifdef __cplusplus extern "C" { #endif typedef struct st_queue { uchar **root; void *first_cmp_arg; uint elements; uint max_elements; uint offset_to_key; /* compare is done on element+offset */ uint offset_to_queue_pos; /* If we want to store position in element */ uint auto_extent; int max_at_top; /* Normally 1, set to -1 if queue_top gives max */ qsort_cmp2 compare; } QUEUE; #define queue_first_element(queue) 1 #define queue_last_element(queue) (queue)->elements #define queue_empty(queue) ((queue)->elements == 0) #define queue_top(queue) ((queue)->root[1]) #define queue_element(queue,index) ((queue)->root[index]) #define queue_end(queue) ((queue)->root[(queue)->elements]) #define queue_replace_top(queue) _downheap(queue, 1) #define queue_set_cmp_arg(queue, set_arg) (queue)->first_cmp_arg= set_arg #define queue_set_max_at_top(queue, set_arg) \ (queue)->max_at_top= set_arg ? -1 : 1 #define queue_remove_top(queue_arg) queue_remove((queue_arg), queue_first_element(queue_arg)) int init_queue(QUEUE *queue,uint max_elements,uint offset_to_key, my_bool max_at_top, qsort_cmp2 compare, void *first_cmp_arg, uint offset_to_queue_pos, uint auto_extent); int reinit_queue(QUEUE *queue,uint max_elements,uint offset_to_key, my_bool max_at_top, qsort_cmp2 compare, void *first_cmp_arg, uint offset_to_queue_pos, uint auto_extent); int resize_queue(QUEUE *queue, uint max_elements); void delete_queue(QUEUE *queue); void queue_insert(QUEUE *queue, uchar *element); int queue_insert_safe(QUEUE *queue, uchar *element); uchar *queue_remove(QUEUE *queue,uint idx); void queue_replace(QUEUE *queue,uint idx); #define queue_remove_all(queue) { (queue)->elements= 0; } #define queue_is_full(queue) (queue->elements == queue->max_elements) void _downheap(QUEUE *queue, uint idx); void queue_fix(QUEUE *queue); #define is_queue_inited(queue) ((queue)->root != 0) #ifdef __cplusplus } #endif #endif server/private/sys_vars_shared.h000064400000005251151031265040013074 0ustar00#ifndef SYS_VARS_SHARED_INCLUDED #define SYS_VARS_SHARED_INCLUDED /* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file "protected" interface to sys_var - server configuration variables. This header is included by files implementing support and utility functions of sys_var's (set_var.cc) and files implementing classes in the sys_var hierarchy (sql_plugin.cc) */ #include #include "set_var.h" extern bool throw_bounds_warning(THD *thd, const char *name,const char *v); extern bool throw_bounds_warning(THD *thd, const char *name, bool fixed, bool is_unsigned, longlong v); extern bool throw_bounds_warning(THD *thd, const char *name, bool fixed, double v); extern sys_var *intern_find_sys_var(const char *str, size_t length); extern sys_var_chain all_sys_vars; /** wrapper to hide a mutex and an rwlock under a common interface */ class PolyLock { public: virtual void rdlock()= 0; virtual void wrlock()= 0; virtual void unlock()= 0; virtual ~PolyLock() = default; }; class PolyLock_mutex: public PolyLock { mysql_mutex_t *mutex; public: PolyLock_mutex(mysql_mutex_t *arg): mutex(arg) {} void rdlock() override { mysql_mutex_lock(mutex); } void wrlock() override { mysql_mutex_lock(mutex); } void unlock() override { mysql_mutex_unlock(mutex); } }; class PolyLock_rwlock: public PolyLock { mysql_rwlock_t *rwlock; public: PolyLock_rwlock(mysql_rwlock_t *arg): rwlock(arg) {} void rdlock() override { mysql_rwlock_rdlock(rwlock); } void wrlock() override { mysql_rwlock_wrlock(rwlock); } void unlock() override { mysql_rwlock_unlock(rwlock); } }; class AutoWLock { PolyLock *lock; public: AutoWLock(PolyLock *l) : lock(l) { if (lock) lock->wrlock(); } ~AutoWLock() { if (lock) lock->unlock(); } }; class AutoRLock { PolyLock *lock; public: AutoRLock(PolyLock *l) : lock(l) { if (lock) lock->rdlock(); } ~AutoRLock() { if (lock) lock->unlock(); } }; #endif /* SYS_VARS_SHARED_INCLUDED */ server/private/threadpool.h000064400000011312151031265040012031 0ustar00/* Copyright (C) 2012, 2020, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #pragma once #ifdef HAVE_POOL_OF_THREADS #define MAX_THREAD_GROUPS 100000 /* Threadpool parameters */ extern uint threadpool_min_threads; /* Minimum threads in pool */ extern uint threadpool_idle_timeout; /* Shutdown idle worker threads after this timeout */ extern uint threadpool_size; /* Number of parallel executing threads */ extern uint threadpool_max_size; extern uint threadpool_stall_limit; /* time interval in milliseconds for stall checks*/ extern uint threadpool_max_threads; /* Maximum threads in pool */ extern uint threadpool_oversubscribe; /* Maximum active threads in group */ extern uint threadpool_prio_kickup_timer; /* Time before low prio item gets prio boost */ extern my_bool threadpool_exact_stats; /* Better queueing time stats for information_schema, at small performance cost */ extern my_bool threadpool_dedicated_listener; /* Listener thread does not pick up work items. */ #ifdef _WIN32 extern uint threadpool_mode; /* Thread pool implementation , windows or generic */ #define TP_MODE_WINDOWS 0 #define TP_MODE_GENERIC 1 #endif #define DEFAULT_THREADPOOL_STALL_LIMIT 500U struct TP_connection; struct st_vio; extern void tp_callback(TP_connection *c); extern void tp_timeout_handler(TP_connection *c); /* Threadpool statistics */ struct TP_STATISTICS { /* Current number of worker thread. */ Atomic_counter num_worker_threads; }; extern TP_STATISTICS tp_stats; /* Functions to set threadpool parameters */ extern void tp_set_min_threads(uint val); extern void tp_set_max_threads(uint val); extern void tp_set_threadpool_size(uint val); extern void tp_set_threadpool_stall_limit(uint val); extern int tp_get_idle_thread_count(); extern int tp_get_thread_count(); enum TP_PRIORITY { TP_PRIORITY_HIGH, TP_PRIORITY_LOW, TP_PRIORITY_AUTO }; enum TP_STATE { TP_STATE_IDLE, TP_STATE_RUNNING, TP_STATE_PENDING }; /* Connection structure, encapsulates THD + structures for asynchronous IO and pool. Platform specific parts are specified in subclasses called connection_t, inside threadpool_win.cc and threadpool_unix.cc */ class CONNECT; struct TP_connection { THD* thd; CONNECT* connect; TP_STATE state; TP_PRIORITY priority; TP_connection(CONNECT *c) : thd(0), connect(c), state(TP_STATE_IDLE), priority(TP_PRIORITY_HIGH) {} virtual ~TP_connection() = default; /* Initialize io structures windows threadpool, epoll etc */ virtual int init() = 0; virtual void set_io_timeout(int sec) = 0; /* Read for the next client command (async) with specified timeout */ virtual int start_io() = 0; virtual void wait_begin(int type)= 0; virtual void wait_end() = 0; IF_WIN(virtual,) void init_vio(st_vio *){}; }; struct TP_pool { virtual ~TP_pool() = default; virtual int init()= 0; virtual TP_connection *new_connection(CONNECT *)= 0; virtual void add(TP_connection *c)= 0; virtual int set_max_threads(uint){ return 0; } virtual int set_min_threads(uint){ return 0; } virtual int set_pool_size(uint){ return 0; } virtual int set_idle_timeout(uint){ return 0; } virtual int set_oversubscribe(uint){ return 0; } virtual int set_stall_limit(uint){ return 0; } virtual int get_thread_count() { return tp_stats.num_worker_threads; } virtual int get_idle_thread_count(){ return 0; } virtual void resume(TP_connection* c)=0; }; #ifdef _WIN32 struct TP_pool_win:TP_pool { TP_pool_win(); int init() override; ~TP_pool_win() override; TP_connection *new_connection(CONNECT *c) override; void add(TP_connection *) override; int set_max_threads(uint) override; int set_min_threads(uint) override; void resume(TP_connection *c) override; }; #endif struct TP_pool_generic :TP_pool { TP_pool_generic(); ~TP_pool_generic(); int init() override; TP_connection *new_connection(CONNECT *c) override; void add(TP_connection *) override; int set_pool_size(uint) override; int set_stall_limit(uint) override; int get_idle_thread_count() override; void resume(TP_connection* c) override; }; #endif /* HAVE_POOL_OF_THREADS */ server/private/session_tracker.h000064400000033703151031265040013076 0ustar00#ifndef SESSION_TRACKER_INCLUDED #define SESSION_TRACKER_INCLUDED /* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2016, 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "m_string.h" #include "thr_lock.h" #include "sql_hset.h" #ifndef EMBEDDED_LIBRARY /* forward declarations */ class THD; class set_var; class String; class user_var_entry; enum enum_session_tracker { SESSION_SYSVARS_TRACKER, /* Session system variables */ CURRENT_SCHEMA_TRACKER, /* Current schema */ SESSION_STATE_CHANGE_TRACKER, TRANSACTION_INFO_TRACKER, /* Transaction state */ #ifdef USER_VAR_TRACKING USER_VARIABLES_TRACKER, #endif // USER_VAR_TRACKING SESSION_TRACKER_END /* must be the last */ }; /** State_tracker An abstract class that defines the interface for any of the server's 'session state change tracker'. A tracker, however, is a sub- class of this class which takes care of tracking the change in value of a part- icular session state type and thus defines various methods listed in this interface. The change information is later serialized and transmitted to the client through protocol's OK packet. Tracker system variables :- A tracker is normally mapped to a system variable. So in order to enable, disable or modify the sub-entities of a tracker, the user needs to modify the respective system variable either through SET command or via command line option. As required in system variable handling, this interface also includes two functions to help in the verification of the supplied value (ON_UPDATE) of the tracker system variable, namely - update(). */ class State_tracker { protected: /** Is tracking enabled for a particular session state type ? @note: it is a cache of the corresponding thd->variables.session_track_xxx variable */ bool m_enabled; void set_changed(THD *thd); private: /** Has the session state type changed ? */ bool m_changed; public: virtual ~State_tracker() = default; /** Getters */ bool is_enabled() const { return m_enabled; } bool is_changed() const { return m_changed; } void reset_changed() { m_changed= false; } /** Called by THD::init() when new connection is being created We may inherit m_changed from previous connection served by this THD if connection was broken or client didn't have session tracking capability. Thus we have to reset it here. */ virtual bool enable(THD *thd) { reset_changed(); return update(thd, 0); } /** To be invoked when the tracker's system variable is updated (ON_UPDATE).*/ virtual bool update(THD *thd, set_var *var)= 0; /** Store changed data into the given buffer. */ virtual bool store(THD *thd, String *buf)= 0; /** Mark the entity as changed. */ void mark_as_changed(THD *thd) { if (is_enabled()) set_changed(thd); } }; /** Session_sysvars_tracker This is a tracker class that enables & manages the tracking of session system variables. It internally maintains a hash of user supplied variable references and a boolean field to store if the variable was changed by the last statement. */ class Session_sysvars_tracker: public State_tracker { struct sysvar_node_st { sys_var *m_svar; bool *test_load; bool m_changed; }; class vars_list { /** Registered system variables. (@@session_track_system_variables) A hash to store the name of all the system variables specified by the user. */ HASH m_registered_sysvars; /** If TRUE then we want to check all session variable. */ bool track_all; void init() { my_hash_init(PSI_INSTRUMENT_ME, &m_registered_sysvars, &my_charset_bin, 0, 0, 0, sysvars_get_key, my_free, HASH_UNIQUE | (mysqld_server_initialized ? HASH_THREAD_SPECIFIC : 0)); } void free_hash() { DBUG_ASSERT(my_hash_inited(&m_registered_sysvars)); my_hash_free(&m_registered_sysvars); } sysvar_node_st *search(const sys_var *svar) { return reinterpret_cast( my_hash_search(&m_registered_sysvars, reinterpret_cast(&svar), sizeof(sys_var*))); } sysvar_node_st *at(ulong i) { DBUG_ASSERT(i < m_registered_sysvars.records); return reinterpret_cast( my_hash_element(&m_registered_sysvars, i)); } public: vars_list(): track_all(false) { init(); } ~vars_list() { if (my_hash_inited(&m_registered_sysvars)) free_hash(); } void deinit() { free_hash(); } sysvar_node_st *insert_or_search(const sys_var *svar) { sysvar_node_st *res= search(svar); if (!res) { if (track_all) { insert(svar); return search(svar); } } return res; } bool insert(const sys_var *svar); void reinit(); void reset(); inline bool is_enabled() { return track_all || m_registered_sysvars.records; } void copy(vars_list* from, THD *thd); bool parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error, CHARSET_INFO *char_set); bool construct_var_list(char *buf, size_t buf_len); bool store(THD *thd, String *buf); }; /** Two objects of vars_list type are maintained to manage various operations. */ vars_list orig_list; bool m_parsed; public: void init(THD *thd); void deinit(THD *thd); bool enable(THD *thd) override; bool update(THD *thd, set_var *var) override; bool store(THD *thd, String *buf) override; void mark_as_changed(THD *thd, const sys_var *var); void deinit() { orig_list.deinit(); } /* callback */ static const uchar *sysvars_get_key(const void *entry, size_t *length, my_bool); friend bool sysvartrack_global_update(THD *thd, char *str, size_t len); }; bool sysvartrack_validate_value(THD *thd, const char *str, size_t len); bool sysvartrack_global_update(THD *thd, char *str, size_t len); /** Current_schema_tracker, This is a tracker class that enables & manages the tracking of current schema for a particular connection. */ class Current_schema_tracker: public State_tracker { public: bool update(THD *thd, set_var *var) override; bool store(THD *thd, String *buf) override; }; /* Session_state_change_tracker This is a boolean tracker class that will monitor any change that contributes to a session state change. Attributes that contribute to session state change include: - Successful change to System variables - User defined variables assignments - temporary tables created, altered or deleted - prepared statements added or removed - change in current database - change of current role */ class Session_state_change_tracker: public State_tracker { public: bool update(THD *thd, set_var *var) override; bool store(THD *thd, String *buf) override; }; /* Transaction_state_tracker */ /** Transaction state (no transaction, transaction active, work attached, etc.) */ enum enum_tx_state { TX_EMPTY = 0, ///< "none of the below" TX_EXPLICIT = 1, ///< an explicit transaction is active TX_IMPLICIT = 2, ///< an implicit transaction is active TX_READ_TRX = 4, ///< transactional reads were done TX_READ_UNSAFE = 8, ///< non-transaction reads were done TX_WRITE_TRX = 16, ///< transactional writes were done TX_WRITE_UNSAFE = 32, ///< non-transactional writes were done TX_STMT_UNSAFE = 64, ///< "unsafe" (non-deterministic like UUID()) stmts TX_RESULT_SET = 128, ///< result set was sent TX_WITH_SNAPSHOT= 256, ///< WITH CONSISTENT SNAPSHOT was used TX_LOCKED_TABLES= 512 ///< LOCK TABLES is active }; /** Transaction access mode */ enum enum_tx_read_flags { TX_READ_INHERIT = 0, ///< not explicitly set, inherit session.tx_read_only TX_READ_ONLY = 1, ///< START TRANSACTION READ ONLY, or tx_read_only=1 TX_READ_WRITE = 2, ///< START TRANSACTION READ WRITE, or tx_read_only=0 }; /** Transaction isolation level */ enum enum_tx_isol_level { TX_ISOL_INHERIT = 0, ///< not explicitly set, inherit session.tx_isolation TX_ISOL_UNCOMMITTED = 1, TX_ISOL_COMMITTED = 2, TX_ISOL_REPEATABLE = 3, TX_ISOL_SERIALIZABLE= 4 }; /** Transaction tracking level */ enum enum_session_track_transaction_info { TX_TRACK_NONE = 0, ///< do not send tracker items on transaction info TX_TRACK_STATE = 1, ///< track transaction status TX_TRACK_CHISTICS = 2 ///< track status and characteristics }; /** This is a tracker class that enables & manages the tracking of current transaction info for a particular connection. */ class Transaction_state_tracker : public State_tracker { /** Helper function: turn table info into table access flag */ enum_tx_state calc_trx_state(THD *thd, thr_lock_type l, bool has_trx); public: bool enable(THD *thd) override { m_enabled= false; tx_changed= TX_CHG_NONE; tx_curr_state= TX_EMPTY; tx_reported_state= TX_EMPTY; tx_read_flags= TX_READ_INHERIT; tx_isol_level= TX_ISOL_INHERIT; return State_tracker::enable(thd); } bool update(THD *thd, set_var *var) override; bool store(THD *thd, String *buf) override; /** Change transaction characteristics */ void set_read_flags(THD *thd, enum enum_tx_read_flags flags); void set_isol_level(THD *thd, enum enum_tx_isol_level level); /** Change transaction state */ void clear_trx_state(THD *thd, uint clear); void add_trx_state(THD *thd, uint add); void inline add_trx_state(THD *thd, thr_lock_type l, bool has_trx) { add_trx_state(thd, calc_trx_state(thd, l, has_trx)); } void add_trx_state_from_thd(THD *thd); void end_trx(THD *thd); private: enum enum_tx_changed { TX_CHG_NONE = 0, ///< no changes from previous stmt TX_CHG_STATE = 1, ///< state has changed from previous stmt TX_CHG_CHISTICS = 2 ///< characteristics have changed from previous stmt }; /** any trackable changes caused by this statement? */ uint tx_changed; /** transaction state */ uint tx_curr_state, tx_reported_state; /** r/w or r/o set? session default? */ enum enum_tx_read_flags tx_read_flags; /** isolation level */ enum enum_tx_isol_level tx_isol_level; inline void update_change_flags(THD *thd) { tx_changed &= uint(~TX_CHG_STATE); tx_changed |= (tx_curr_state != tx_reported_state) ? TX_CHG_STATE : 0; if (tx_changed != TX_CHG_NONE) set_changed(thd); } }; #define TRANSACT_TRACKER(X) \ do { if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) \ thd->session_tracker.transaction_info.X; } while(0) /** User_variables_tracker This is a tracker class that enables & manages the tracking of user variables. */ #ifdef USER_VAR_TRACKING class User_variables_tracker: public State_tracker { Hash_set m_changed_user_variables; public: User_variables_tracker(): m_changed_user_variables(PSI_INSTRUMENT_ME, &my_charset_bin, 0, 0, sizeof(const user_var_entry*), 0, 0, HASH_UNIQUE | mysqld_server_initialized ? HASH_THREAD_SPECIFIC : 0) {} bool update(THD *thd, set_var *var); bool store(THD *thd, String *buf); void mark_as_changed(THD *thd, const user_var_entry *var) { if (is_enabled()) { m_changed_user_variables.insert(var); set_changed(thd); } } void deinit() { m_changed_user_variables.~Hash_set(); } }; #endif // USER_VAR_TRACKING /** Session_tracker This class holds an object each for all tracker classes and provides methods necessary for systematic detection and generation of session state change information. */ class Session_tracker { State_tracker *m_trackers[SESSION_TRACKER_END]; /* The following two functions are private to disable copying. */ Session_tracker(Session_tracker const &other) { DBUG_ASSERT(FALSE); } Session_tracker& operator= (Session_tracker const &rhs) { DBUG_ASSERT(FALSE); return *this; } public: Current_schema_tracker current_schema; Session_state_change_tracker state_change; Transaction_state_tracker transaction_info; Session_sysvars_tracker sysvars; #ifdef USER_VAR_TRACKING User_variables_tracker user_variables; #endif // USER_VAR_TRACKING Session_tracker() { m_trackers[SESSION_SYSVARS_TRACKER]= &sysvars; m_trackers[CURRENT_SCHEMA_TRACKER]= ¤t_schema; m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change; m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info; #ifdef USER_VAR_TRACKING m_trackers[USER_VARIABLES_TRACKER]= &user_variables; #endif // USER_VAR_TRACKING } void enable(THD *thd) { for (int i= 0; i < SESSION_TRACKER_END; i++) m_trackers[i]->enable(thd); } void store(THD *thd, String *main_buf); }; int session_tracker_init(); #else #define TRANSACT_TRACKER(X) do{}while(0) class Session_tracker { class Dummy_tracker { public: void mark_as_changed(THD *thd) {} void mark_as_changed(THD *thd, const sys_var *var) {} }; public: Dummy_tracker current_schema; Dummy_tracker state_change; Dummy_tracker sysvars; }; #endif //EMBEDDED_LIBRARY #endif /* SESSION_TRACKER_INCLUDED */ server/private/sql_plugin.h000064400000016575151031265040012065 0ustar00/* Copyright (c) 2005, 2012, Oracle and/or its affiliates. Copyright (c) 2009, 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _sql_plugin_h #define _sql_plugin_h /* the following #define adds server-only members to enum_mysql_show_type, that is defined in plugin.h */ #define SHOW_always_last SHOW_KEY_CACHE_LONG, \ SHOW_HAVE, SHOW_MY_BOOL, SHOW_HA_ROWS, SHOW_SYS, \ SHOW_LONG_NOFLUSH, SHOW_LEX_STRING, SHOW_ATOMIC_COUNTER_UINT32_T, \ /* SHOW_*_STATUS must be at the end, SHOW_LONG_STATUS being first */ \ SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, SHOW_LONGLONG_STATUS, \ SHOW_UINT32_STATUS #include "mariadb.h" #undef SHOW_always_last #include "m_string.h" /* LEX_STRING */ #include "my_alloc.h" /* MEM_ROOT */ class sys_var; enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED}; enum enum_plugin_load_option { PLUGIN_OFF, PLUGIN_ON, PLUGIN_FORCE, PLUGIN_FORCE_PLUS_PERMANENT }; extern const char *global_plugin_typelib_names[]; extern volatile int global_plugin_version; extern ulong dlopen_count; #include #include "sql_list.h" #ifdef DBUG_OFF #define plugin_ref_to_int(A) A #define plugin_int_to_ref(A) A #else #define plugin_ref_to_int(A) (A ? A[0] : NULL) #define plugin_int_to_ref(A) &(A) #endif /* the following flags are valid for plugin_init() */ #define PLUGIN_INIT_SKIP_PLUGIN_TABLE 1U #define PLUGIN_INIT_SKIP_INITIALIZATION 2U #define INITIAL_LEX_PLUGIN_LIST_SIZE 16 typedef enum enum_mysql_show_type SHOW_TYPE; typedef struct st_mysql_show_var SHOW_VAR; #define MYSQL_ANY_PLUGIN -1 /* different values of st_plugin_int::state though they look like a bitmap, plugin may only be in one of those eigenstates, not in a superposition of them :) It's a bitmap, because it makes it easier to test "whether the state is one of those..." */ #define PLUGIN_IS_FREED 1U #define PLUGIN_IS_DELETED 2U #define PLUGIN_IS_UNINITIALIZED 4U #define PLUGIN_IS_READY 8U #define PLUGIN_IS_DYING 16U #define PLUGIN_IS_DISABLED 32U struct st_ptr_backup { void **ptr; void *value; void save(void **p) { ptr= p; value= *p; } void save(const char **p) { save((void**)p); } void restore() { *ptr= value; } }; /* A handle for the dynamic library containing a plugin or plugins. */ struct st_plugin_dl { LEX_CSTRING dl; void *handle; struct st_maria_plugin *plugins; st_ptr_backup *ptr_backup; uint nbackups; uint ref_count; /* number of plugins loaded from the library */ int mysqlversion; int mariaversion; bool allocated; }; /* A handle of a plugin */ struct st_plugin_int { LEX_CSTRING name; struct st_maria_plugin *plugin; struct st_plugin_dl *plugin_dl; st_ptr_backup *ptr_backup; uint nbackups; uint state; uint ref_count; /* number of threads using the plugin */ uint locks_total; /* how many times the plugin was locked */ void *data; /* plugin type specific, e.g. handlerton */ MEM_ROOT mem_root; /* memory for dynamic plugin structures */ sys_var *system_vars; /* server variables for this plugin */ enum enum_plugin_load_option load_option; /* OFF, ON, FORCE, F+PERMANENT */ }; extern mysql_mutex_t LOCK_plugin; /* See intern_plugin_lock() for the explanation for the conditionally defined plugin_ref type */ #ifdef DBUG_OFF typedef struct st_plugin_int *plugin_ref; #define plugin_ref_to_int(A) A #define plugin_int_to_ref(A) A #define plugin_decl(pi) ((pi)->plugin) #define plugin_dlib(pi) ((pi)->plugin_dl) #define plugin_data(pi,cast) ((cast)((pi)->data)) #define plugin_name(pi) (&((pi)->name)) #define plugin_state(pi) ((pi)->state) #define plugin_load_option(pi) ((pi)->load_option) #define plugin_equals(p1,p2) ((p1) == (p2)) #else typedef struct st_plugin_int **plugin_ref; #define plugin_ref_to_int(A) (A ? A[0] : NULL) #define plugin_int_to_ref(A) &(A) #define plugin_decl(pi) ((pi)[0]->plugin) #define plugin_dlib(pi) ((pi)[0]->plugin_dl) #define plugin_data(pi,cast) ((cast)((pi)[0]->data)) #define plugin_name(pi) (&((pi)[0]->name)) #define plugin_state(pi) ((pi)[0]->state) #define plugin_load_option(pi) ((pi)[0]->load_option) #define plugin_equals(p1,p2) ((p1) && (p2) && (p1)[0] == (p2)[0]) #endif typedef int (*plugin_type_init)(void *); extern I_List *opt_plugin_load_list_ptr; extern char *opt_plugin_dir_ptr; extern MYSQL_PLUGIN_IMPORT char opt_plugin_dir[FN_REFLEN]; extern const LEX_CSTRING plugin_type_names[]; extern ulong plugin_maturity; extern TYPELIB plugin_maturity_values; extern const char *plugin_maturity_names[]; extern int plugin_init(int *argc, char **argv, int init_flags); extern void plugin_shutdown(void); void add_plugin_options(DYNAMIC_ARRAY *options, MEM_ROOT *mem_root); extern bool plugin_is_ready(const LEX_CSTRING *name, int type); #define my_plugin_lock_by_name(A,B,C) plugin_lock_by_name(A,B,C) #define my_plugin_lock(A,B) plugin_lock(A,B) extern plugin_ref plugin_lock(THD *thd, plugin_ref ptr); extern plugin_ref plugin_lock_by_name(THD *thd, const LEX_CSTRING *name, int type); extern void plugin_unlock(THD *thd, plugin_ref plugin); extern void plugin_unlock_list(THD *thd, plugin_ref *list, uint count); extern bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name, const LEX_CSTRING *dl); extern bool mysql_uninstall_plugin(THD *thd, const LEX_CSTRING *name, const LEX_CSTRING *dl); extern bool plugin_register_builtin(struct st_mysql_plugin *plugin); extern void plugin_thdvar_init(THD *thd); extern void plugin_thdvar_cleanup(THD *thd); sys_var *find_plugin_sysvar(st_plugin_int *plugin, st_mysql_sys_var *var); void plugin_opt_set_limits(struct my_option *, const struct st_mysql_sys_var *); extern SHOW_COMP_OPTION plugin_status(const char *name, size_t len, int type); extern bool check_valid_path(const char *path, size_t length); extern void plugin_mutex_init(); typedef my_bool (plugin_foreach_func)(THD *thd, plugin_ref plugin, void *arg); #define plugin_foreach(A,B,C,D) plugin_foreach_with_mask(A,B,C,PLUGIN_IS_READY,D) extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func, int type, uint state_mask, void *arg); extern void sync_dynamic_session_variables(THD* thd, bool global_lock); extern bool plugin_dl_foreach(THD *thd, const LEX_CSTRING *dl, plugin_foreach_func *func, void *arg); extern void sync_dynamic_session_variables(THD* thd, bool global_lock); #endif #ifdef WITH_WSREP extern void wsrep_plugins_pre_init(); extern void wsrep_plugins_post_init(); #endif /* WITH_WSREP */ server/private/wsrep_client_state.h000064400000003036151031265040013572 0ustar00/* Copyright 2018 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef WSREP_CLIENT_STATE_H #define WSREP_CLIENT_STATE_H /* wsrep-lib */ #include "wsrep/client_state.hpp" #include "my_global.h" class THD; class Wsrep_client_state : public wsrep::client_state { public: Wsrep_client_state(THD* thd, wsrep::mutex& mutex, wsrep::condition_variable& cond, wsrep::server_state& server_state, wsrep::client_service& client_service, const wsrep::client_id& id) : wsrep::client_state(mutex, cond, server_state, client_service, id, wsrep::client_state::m_local) , m_thd(thd) { } THD* thd() { return m_thd; } private: THD* m_thd; }; #endif /* WSREP_CLIENT_STATE_H */ server/private/rpl_parallel.h000064400000042065151031265040012352 0ustar00#ifndef RPL_PARALLEL_H #define RPL_PARALLEL_H #include "log_event.h" struct rpl_parallel; struct rpl_parallel_entry; struct rpl_parallel_thread_pool; extern struct rpl_parallel_thread_pool pool_bkp_for_pfs; class Relay_log_info; struct inuse_relaylog; /* Structure used to keep track of the parallel replication of a batch of event-groups that group-committed together on the master. It is used to ensure that every event group in one batch has reached the commit stage before the next batch starts executing. Note the lifetime of this structure: - It is allocated when the first event in a new batch of group commits is queued, from the free list rpl_parallel_entry::gco_free_list. - The gco for the batch currently being queued is owned by rpl_parallel_entry::current_gco. The gco for a previous batch that has been fully queued is owned by the gco->prev_gco pointer of the gco for the following batch. - The worker thread waits on gco->COND_group_commit_orderer for rpl_parallel_entry::count_committing_event_groups to reach wait_count before starting; the first waiter links the gco into the next_gco pointer of the gco of the previous batch for signalling. - When an event group reaches the commit stage, it signals the COND_group_commit_orderer if its gco->next_gco pointer is non-NULL and rpl_parallel_entry::count_committing_event_groups has reached gco->next_gco->wait_count. - The gco lives until all its event groups have completed their commit. This is detected by rpl_parallel_entry::last_committed_sub_id being greater than or equal gco->last_sub_id. Once this happens, the gco is freed. Note that since update of last_committed_sub_id can happen out-of-order, the thread that frees a given gco can be for any later event group, not necessarily an event group from the gco being freed. */ struct group_commit_orderer { /* Wakeup condition, used with rpl_parallel_entry::LOCK_parallel_entry. */ mysql_cond_t COND_group_commit_orderer; uint64 wait_count; group_commit_orderer *prev_gco; group_commit_orderer *next_gco; /* The sub_id of last event group in the previous GCO. Only valid if prev_gco != NULL. */ uint64 prior_sub_id; /* The sub_id of the last event group in this GCO. Only valid when next_gco is non-NULL. */ uint64 last_sub_id; /* This flag is set when this GCO has been installed into the next_gco pointer of the previous GCO. */ bool installed; enum force_switch_bits { /* This flag is set for a GCO in which we have event groups with multiple different commit_id values from the master. This happens when we optimistically try to execute in parallel transactions not known to be conflict-free. When this flag is set, in case of DDL we need to start a new GCO regardless of current commit_id, as DDL is not safe to speculatively apply in parallel with prior event groups. */ MULTI_BATCH= 1, /* This flag is set for a GCO that contains DDL. If set, it forces a switch to a new GCO upon seeing a new commit_id, as DDL is not safe to speculatively replicate in parallel with subsequent transactions. */ FORCE_SWITCH= 2 }; uint8 flags; #ifndef DBUG_OFF /* Flag set when the GCO has been freed and entered the free list, to catch (in debug) errors in the complex lifetime of this object. */ bool gc_done; #endif }; struct rpl_parallel_thread { bool delay_start; bool running; bool stop; bool pause_for_ftwrl; mysql_mutex_t LOCK_rpl_thread; mysql_cond_t COND_rpl_thread; mysql_cond_t COND_rpl_thread_queue; mysql_cond_t COND_rpl_thread_stop; struct rpl_parallel_thread *next; /* For free list. */ struct rpl_parallel_thread_pool *pool; THD *thd; /* Who owns the thread, if any (it's a pointer into the rpl_parallel_entry::rpl_threads array. */ struct rpl_parallel_thread **current_owner; /* The rpl_parallel_entry of the owner. */ rpl_parallel_entry *current_entry; struct queued_event { queued_event *next; /* queued_event can hold either an event to be executed, or just a binlog position to be updated without any associated event. */ enum queued_event_t { QUEUED_EVENT, QUEUED_POS_UPDATE, QUEUED_MASTER_RESTART } typ; union { Log_event *ev; /* QUEUED_EVENT */ rpl_parallel_entry *entry_for_queued; /* QUEUED_POS_UPDATE and QUEUED_MASTER_RESTART */ }; rpl_group_info *rgi; inuse_relaylog *ir; ulonglong future_event_relay_log_pos; char event_relay_log_name[FN_REFLEN]; char future_event_master_log_name[FN_REFLEN]; ulonglong event_relay_log_pos; my_off_t future_event_master_log_pos; size_t event_size; } *event_queue, *last_in_queue; uint64 queued_size; /* These free lists are protected by LOCK_rpl_thread. */ queued_event *qev_free_list; rpl_group_info *rgi_free_list; group_commit_orderer *gco_free_list; /* These free lists are local to the thread, so need not be protected by any lock. They are moved to the global free lists in batches in the function batch_free(), to reduce LOCK_rpl_thread contention. The lists are not NULL-terminated (as we do not need to traverse them). Instead, if they are non-NULL, the loc_XXX_last_ptr_ptr points to the `next' pointer of the last element, which is used to link into the front of the global freelists. */ queued_event *loc_qev_list, **loc_qev_last_ptr_ptr; size_t loc_qev_size; uint64 qev_free_pending; rpl_group_info *loc_rgi_list, **loc_rgi_last_ptr_ptr; group_commit_orderer *loc_gco_list, **loc_gco_last_ptr_ptr; /* These keep track of batch update of inuse_relaylog refcounts. */ inuse_relaylog *accumulated_ir_last; uint64 accumulated_ir_count; char channel_name[MAX_CONNECTION_NAME]; uint channel_name_length; rpl_gtid last_seen_gtid; int last_error_number; char last_error_message[MAX_SLAVE_ERRMSG]; ulonglong last_error_timestamp; ulonglong worker_idle_time; ulong last_trans_retry_count; ulonglong start_time; void start_time_tracker() { start_time= microsecond_interval_timer(); } ulonglong compute_time_lapsed() { return (ulonglong)((microsecond_interval_timer() - start_time) / 1000000.0); } void add_to_worker_idle_time_and_reset() { worker_idle_time+= compute_time_lapsed(); start_time=0; } ulonglong get_worker_idle_time() { if (start_time) return (worker_idle_time + compute_time_lapsed()); else return worker_idle_time; } void enqueue(queued_event *qev) { if (last_in_queue) last_in_queue->next= qev; else event_queue= qev; last_in_queue= qev; queued_size+= qev->event_size; } void dequeue1(queued_event *list) { DBUG_ASSERT(list == event_queue); event_queue= last_in_queue= NULL; } void dequeue2(size_t dequeue_size) { queued_size-= dequeue_size; } queued_event *get_qev_common(Log_event *ev, ulonglong event_size); queued_event *get_qev(Log_event *ev, ulonglong event_size, Relay_log_info *rli); queued_event *retry_get_qev(Log_event *ev, queued_event *orig_qev, const char *relay_log_name, ulonglong event_pos, ulonglong event_size); /* Put a qev on the local free list, to be later released to the global free list by batch_free(). */ void loc_free_qev(queued_event *qev); /* Release an rgi immediately to the global free list. Requires holding the LOCK_rpl_thread mutex. */ void free_qev(queued_event *qev); rpl_group_info *get_rgi(Relay_log_info *rli, Gtid_log_event *gtid_ev, rpl_parallel_entry *e, ulonglong event_size); /* Put an gco on the local free list, to be later released to the global free list by batch_free(). */ void loc_free_rgi(rpl_group_info *rgi); /* Release an rgi immediately to the global free list. Requires holding the LOCK_rpl_thread mutex. */ void free_rgi(rpl_group_info *rgi); group_commit_orderer *get_gco(uint64 wait_count, group_commit_orderer *prev, uint64 first_sub_id); /* Put a gco on the local free list, to be later released to the global free list by batch_free(). */ void loc_free_gco(group_commit_orderer *gco); /* Move all local free lists to the global ones. Requires holding LOCK_rpl_thread. */ void batch_free(); /* Update inuse_relaylog refcounts with what we have accumulated so far. */ void inuse_relaylog_refcount_update(); rpl_parallel_thread(); }; struct pool_bkp_for_pfs{ uint32 count; bool inited, is_valid; struct rpl_parallel_thread **rpl_thread_arr; void init(uint32 thd_count) { DBUG_ASSERT(thd_count); rpl_thread_arr= (rpl_parallel_thread **) my_malloc(PSI_INSTRUMENT_ME, thd_count * sizeof(rpl_parallel_thread*), MYF(MY_WME | MY_ZEROFILL)); for (uint i=0; i *thread_sched_fifo; uint32 rpl_thread_max; /* Keep track of all XA XIDs that may still be active in a worker thread. The elements are of type xid_active_generation. */ DYNAMIC_ARRAY maybe_active_xid; /* Keeping track of the current scheduling generation. A new generation means that every worker thread in the rpl_threads array have been scheduled at least one event group. When we have scheduled to slot current_generation_idx= 0, 1, ..., N-1 in this order, we know that (at least) one generation has passed. */ uint64 current_generation; uint32 current_generation_idx; /* The sub_id of the last transaction to commit within this domain_id. Must be accessed under LOCK_parallel_entry protection. Event groups commit in order, so the rpl_group_info for an event group will be alive (at least) as long as rpl_group_info::gtid_sub_id > last_committed_sub_id. This can be used to safely refer back to previous event groups if they are still executing, and ignore them if they completed, without requiring explicit synchronisation between the threads. */ uint64 last_committed_sub_id; /* The sub_id of the last event group in this replication domain that was queued for execution by a worker thread. */ uint64 current_sub_id; /* The largest sub_id that has started its transaction. Protected by LOCK_parallel_entry. (Transactions can start out-of-order, so this value signifies that no transactions with larger sub_id have started, but not necessarily that all transactions with smaller sub_id have started). */ uint64 largest_started_sub_id; rpl_group_info *current_group_info; /* If we get an error in some event group, we set the sub_id of that event group here. Then later event groups (with higher sub_id) can know not to try to start (event groups that already started will be rolled back when wait_for_prior_commit() returns error). The value is ULONGLONG_MAX when no error occurred. */ uint64 stop_on_error_sub_id; /* During FLUSH TABLES WITH READ LOCK, transactions with sub_id larger than this value must not start, but wait until the global read lock is released. The value is set to ULONGLONG_MAX when no FTWRL is pending. */ uint64 pause_sub_id; /* Total count of event groups queued so far. */ uint64 count_queued_event_groups; /* Count of event groups that have started (but not necessarily completed) the commit phase. We use this to know when every event group in a previous batch of master group commits have started committing on the slave, so that it is safe to start executing the events in the following batch. */ uint64 count_committing_event_groups; /* The group_commit_orderer object for the events currently being queued. */ group_commit_orderer *current_gco; void check_scheduling_generation(sched_bucket *cur); sched_bucket *check_xa_xid_dependency(xid_t *xid); rpl_parallel_thread * choose_thread(rpl_group_info *rgi, bool *did_enter_cond, PSI_stage_info *old_stage, Gtid_log_event *gtid_ev); int queue_master_restart(rpl_group_info *rgi, Format_description_log_event *fdev); /* the initial size of maybe_ array corresponds to the case of each worker receives perhaps unlikely XA-PREPARE and XA-COMMIT within the same generation. */ inline uint active_xid_init_alloc() { return 3 * 2 * rpl_thread_max; } }; struct rpl_parallel { HASH domain_hash; rpl_parallel_entry *current; bool sql_thread_stopping; rpl_parallel(); ~rpl_parallel(); void reset(); rpl_parallel_entry *find(uint32 domain_id); void wait_for_done(THD *thd, Relay_log_info *rli); void stop_during_until(); int wait_for_workers_idle(THD *thd); int do_event(rpl_group_info *serial_rgi, Log_event *ev, ulonglong event_size); static bool workers_idle(Relay_log_info *rli); }; extern struct rpl_parallel_thread_pool global_rpl_thread_pool; extern void wait_for_pending_deadlock_kill(THD *thd, rpl_group_info *rgi); extern int rpl_parallel_resize_pool_if_no_slaves(void); extern int rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool); extern int rpl_parallel_inactivate_pool(rpl_parallel_thread_pool *pool); extern bool process_gtid_for_restart_pos(Relay_log_info *rli, rpl_gtid *gtid); extern int rpl_pause_for_ftwrl(THD *thd); extern void rpl_unpause_after_ftwrl(THD *thd); #endif /* RPL_PARALLEL_H */ server/private/bounded_queue.h000064400000013715151031265040012525 0ustar00/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef BOUNDED_QUEUE_INCLUDED #define BOUNDED_QUEUE_INCLUDED #include "my_base.h" #include #include "queues.h" #include class Sort_param; /** A priority queue with a fixed, limited size. This is a wrapper on top of QUEUE and the queue_xxx() functions. It keeps the top-N elements which are inserted. Elements of type Element_type are pushed into the queue. For each element, we call a user-supplied keymaker_function, to generate a key of type Key_type for the element. Instances of Key_type are compared with the user-supplied compare_function. The underlying QUEUE implementation needs one extra element for replacing the lowest/highest element when pushing into a full queue. */ template class Bounded_queue { public: Bounded_queue() { memset(&m_queue, 0, sizeof(m_queue)); } ~Bounded_queue() { delete_queue(&m_queue); } /** Function for making sort-key from input data. @param param Sort parameters. @param to Where to put the key. @param from The input data. */ typedef uint (*keymaker_function)(Sort_param *param, Key_type *to, Element_type *from, bool packing_keys); /** Initialize the queue. @param max_elements The size of the queue. @param max_at_top Set to true if you want biggest element on top. false: We keep the n largest elements. pop() will return the smallest key in the result set. true: We keep the n smallest elements. pop() will return the largest key in the result set. @param compare_length Length of the data (i.e. the keys) used for sorting. @param keymaker Function which generates keys for elements. @param sort_param Sort parameters. @param sort_keys Array of pointers to keys to sort. @retval 0 OK, 1 Could not allocate memory. We do *not* take ownership of any of the input pointer arguments. */ int init(ha_rows max_elements, bool max_at_top, size_t compare_length, keymaker_function keymaker, Sort_param *sort_param, Key_type **sort_keys); /** Pushes an element on the queue. If the queue is already full, we discard one element. Calls keymaker_function to generate a key for the element. @param element The element to be pushed. */ void push(Element_type *element); /** Removes the top element from the queue. @retval Pointer to the (key of the) removed element. @note This function is for unit testing, where we push elements into to the queue, and test that the appropriate keys are retained. Interleaving of push() and pop() operations has not been tested. */ Key_type **pop() { // Don't return the extra element to the client code. if (queue_is_full((&m_queue))) queue_remove(&m_queue, 0); DBUG_ASSERT(m_queue.elements > 0); if (m_queue.elements == 0) return NULL; return reinterpret_cast(queue_remove(&m_queue, 0)); } /** The number of elements in the queue. */ uint num_elements() const { return m_queue.elements; } /** Is the queue initialized? */ bool is_initialized() const { return m_queue.max_elements > 0; } private: Key_type **m_sort_keys; size_t m_compare_length; keymaker_function m_keymaker; Sort_param *m_sort_param; st_queue m_queue; }; template int Bounded_queue::init(ha_rows max_elements, bool max_at_top, size_t compare_length, keymaker_function keymaker, Sort_param *sort_param, Key_type **sort_keys) { DBUG_ASSERT(sort_keys != NULL); m_sort_keys= sort_keys; m_compare_length= compare_length; m_keymaker= keymaker; m_sort_param= sort_param; // init_queue() takes an uint, and also does (max_elements + 1) if (max_elements >= (UINT_MAX - 1)) return 1; // We allocate space for one extra element, for replace when queue is full. return init_queue(&m_queue, (uint) max_elements + 1, 0, max_at_top, get_ptr_compare(compare_length), &m_compare_length, 0, 0); } template void Bounded_queue::push(Element_type *element) { DBUG_ASSERT(is_initialized()); if (queue_is_full((&m_queue))) { // Replace top element with new key, and re-order the queue. Key_type **pq_top= reinterpret_cast(queue_top(&m_queue)); (void)(*m_keymaker)(m_sort_param, *pq_top, element, false); queue_replace_top(&m_queue); } else { // Insert new key into the queue. (*m_keymaker)(m_sort_param, m_sort_keys[m_queue.elements], element, false); queue_insert(&m_queue, reinterpret_cast(&m_sort_keys[m_queue.elements])); } } #endif // BOUNDED_QUEUE_INCLUDED server/private/sql_hset.h000064400000006511151031265040011517 0ustar00#ifndef SQL_HSET_INCLUDED #define SQL_HSET_INCLUDED /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_global.h" #include "hash.h" /** A type-safe wrapper around mysys HASH. */ template class Hash_set { public: enum { START_SIZE= 8 }; /** Constructs an empty unique hash. */ Hash_set(PSI_memory_key psi_key, const uchar *(*K)(const void *, size_t *, my_bool), CHARSET_INFO *cs= &my_charset_bin) { my_hash_init(psi_key, &m_hash, cs, START_SIZE, 0, 0, K, 0, HASH_UNIQUE); } Hash_set(PSI_memory_key psi_key, CHARSET_INFO *charset, ulong default_array_elements, size_t key_offset, size_t key_length, my_hash_get_key get_key, void (*free_element)(void*), uint flags) { my_hash_init(psi_key, &m_hash, charset, default_array_elements, key_offset, key_length, get_key, free_element, flags); } /** Destroy the hash by freeing the buckets table. Does not call destructors for the elements. */ ~Hash_set() { my_hash_free(&m_hash); } /** Insert a single value into a hash. Does not tell whether the value was inserted -- if an identical value existed, it is not replaced. @retval TRUE Out of memory. @retval FALSE OK. The value either was inserted or existed in the hash. */ bool insert(T *value) { return my_hash_insert(&m_hash, reinterpret_cast(value)); } bool remove(T *value) { return my_hash_delete(&m_hash, reinterpret_cast(value)); } T *find(const void *key, size_t klen) const { return (T*)my_hash_search(&m_hash, reinterpret_cast(key), klen); } /** Is this hash set empty? */ bool is_empty() const { return m_hash.records == 0; } /** Returns the number of unique elements. */ size_t size() const { return static_cast(m_hash.records); } /** Erases all elements from the container */ void clear() { my_hash_reset(&m_hash); } const T* at(size_t i) const { return reinterpret_cast(my_hash_element(const_cast(&m_hash), i)); } /** An iterator over hash elements. Is not insert-stable. */ class Iterator { public: Iterator(Hash_set &hash_set) : m_hash(&hash_set.m_hash), m_idx(0) {} /** Return the current element and reposition the iterator to the next element. */ inline T *operator++(int) { if (m_idx < m_hash->records) return reinterpret_cast(my_hash_element(m_hash, m_idx++)); return NULL; } void rewind() { m_idx= 0; } private: HASH *m_hash; uint m_idx; }; private: HASH m_hash; }; #endif // SQL_HSET_INCLUDED server/private/item_xmlfunc.h000064400000010777151031265040012400 0ustar00#ifndef ITEM_XMLFUNC_INCLUDED #define ITEM_XMLFUNC_INCLUDED /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2009, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file defines all XML functions */ typedef struct my_xml_node_st MY_XML_NODE; /* Structure to store nodeset elements */ class MY_XPATH_FLT { public: uint num; // Absolute position in MY_XML_NODE array uint pos; // Relative position in context uint size; // Context size public: MY_XPATH_FLT(uint32 num_arg, uint32 pos_arg) :num(num_arg), pos(pos_arg), size(0) { } MY_XPATH_FLT(uint32 num_arg, uint32 pos_arg, uint32 size_arg) :num(num_arg), pos(pos_arg), size(size_arg) { } bool append_to(Native *to) const { return to->append((const char*) this, (uint32) sizeof(*this)); } }; class NativeNodesetBuffer: public NativeBuffer<16*sizeof(MY_XPATH_FLT)> { public: const MY_XPATH_FLT &element(uint i) const { const MY_XPATH_FLT *p= (MY_XPATH_FLT*) (ptr() + i * sizeof(MY_XPATH_FLT)); return *p; } uint32 elements() const { return length() / sizeof(MY_XPATH_FLT); } }; class Item_xml_str_func: public Item_str_func { protected: /* A helper class to store raw and parsed XML. */ class XML { bool m_cached; String *m_raw_ptr; // Pointer to text representation String m_raw_buf; // Cached text representation String m_parsed_buf; // Array of MY_XML_NODEs, pointing to raw_buffer bool parse(); void reset() { m_cached= false; m_raw_ptr= (String *) 0; } public: XML() { reset(); } void set_charset(CHARSET_INFO *cs) { m_parsed_buf.set_charset(cs); } String *raw() { return m_raw_ptr; } String *parsed() { return &m_parsed_buf; } const MY_XML_NODE *node(uint idx); bool cached() { return m_cached; } bool parse(String *raw, bool cache); bool parse(Item *item, bool cache) { String *res; if (!(res= item->val_str(&m_raw_buf))) { m_raw_ptr= (String *) 0; m_cached= cache; return true; } return parse(res, cache); } }; String m_xpath_query; // XPath query text Item *nodeset_func; XML xml; bool get_xml(XML *xml_arg, bool cache= false) { if (!cache && xml_arg->cached()) return xml_arg->raw() == 0; return xml_arg->parse(args[0], cache); } public: Item_xml_str_func(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) { set_maybe_null(); } Item_xml_str_func(THD *thd, Item *a, Item *b, Item *c): Item_str_func(thd, a, b, c) { set_maybe_null(); } bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override; bool const_item() const override { return const_item_cache && (!nodeset_func || nodeset_func->const_item()); } }; class Item_func_xml_extractvalue: public Item_xml_str_func { public: Item_func_xml_extractvalue(THD *thd, Item *a, Item *b): Item_xml_str_func(thd, a, b) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("extractvalue") }; return name; } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_xml_update: public Item_xml_str_func { NativeNodesetBuffer tmp_native_value2; String tmp_value3; bool collect_result(String *str, const MY_XML_NODE *cut, const String *replace); public: Item_func_xml_update(THD *thd, Item *a, Item *b, Item *c): Item_xml_str_func(thd, a, b, c) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("updatexml") }; return name; } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #endif /* ITEM_XMLFUNC_INCLUDED */ server/private/partition_element.h000064400000012131151031265040013412 0ustar00#ifndef PARTITION_ELEMENT_INCLUDED #define PARTITION_ELEMENT_INCLUDED /* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_base.h" /* ha_rows */ #include "handler.h" /* UNDEF_NODEGROUP */ /** * An enum and a struct to handle partitioning and subpartitioning. */ enum partition_type { NOT_A_PARTITION= 0, RANGE_PARTITION, HASH_PARTITION, LIST_PARTITION, VERSIONING_PARTITION }; enum partition_state { PART_NORMAL= 0, PART_IS_DROPPED= 1, PART_TO_BE_DROPPED= 2, PART_TO_BE_ADDED= 3, PART_TO_BE_REORGED= 4, PART_REORGED_DROPPED= 5, PART_CHANGED= 6, PART_IS_CHANGED= 7, PART_IS_ADDED= 8, PART_ADMIN= 9 }; /* This struct is used to keep track of column expressions as part of the COLUMNS concept in conjunction with RANGE and LIST partitioning. The value can be either of MINVALUE, MAXVALUE and an expression that must be constant and evaluate to the same type as the column it represents. The data in this fixed in two steps. The parser will only fill in whether it is a max_value or provide an expression. Filling in column_value, part_info, partition_id, null_value is done by the function fix_column_value_function. However the item tree needs fixed also before writing it into the frm file (in add_column_list_values). To distinguish between those two variants, fixed= 1 after the fixing in add_column_list_values and fixed= 2 otherwise. This is since the fixing in add_column_list_values isn't a complete fixing. */ typedef struct p_column_list_val { void* column_value; Item* item_expression; partition_info *part_info; uint partition_id; bool max_value; // MAXVALUE for RANGE type or DEFAULT value for LIST type bool null_value; char fixed; } part_column_list_val; /* This struct is used to contain the value of an element in the VALUES IN struct. It needs to keep knowledge of whether it is a signed/unsigned value and whether it is NULL or not. */ typedef struct p_elem_val { longlong value; uint added_items; bool null_value; bool unsigned_flag; part_column_list_val *col_val_array; } part_elem_value; struct st_ddl_log_memory_entry; enum stat_trx_field { STAT_TRX_END= 0 }; class partition_element :public Sql_alloc { public: enum elem_type_enum { CONVENTIONAL= 0, CURRENT, HISTORY }; List subpartitions; List list_val_list; ha_rows part_max_rows; ha_rows part_min_rows; longlong range_value; const char *partition_name; const char *tablespace_name; struct st_ddl_log_memory_entry *log_entry; const char* part_comment; const char* data_file_name; const char* index_file_name; handlerton *engine_type; LEX_CSTRING connect_string; enum partition_state part_state; uint16 nodegroup_id; bool has_null_value; bool signed_flag; // Range value signed bool max_value; // MAXVALUE range uint32 id; bool empty; elem_type_enum type; partition_element() : part_max_rows(0), part_min_rows(0), range_value(0), partition_name(NULL), tablespace_name(NULL), log_entry(NULL), part_comment(NULL), data_file_name(NULL), index_file_name(NULL), engine_type(NULL), connect_string(null_clex_str), part_state(PART_NORMAL), nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE), signed_flag(FALSE), max_value(FALSE), id(UINT_MAX32), empty(true), type(CONVENTIONAL) {} partition_element(partition_element *part_elem) : part_max_rows(part_elem->part_max_rows), part_min_rows(part_elem->part_min_rows), range_value(0), partition_name(NULL), tablespace_name(part_elem->tablespace_name), log_entry(NULL), part_comment(part_elem->part_comment), data_file_name(part_elem->data_file_name), index_file_name(part_elem->index_file_name), engine_type(part_elem->engine_type), connect_string(null_clex_str), part_state(part_elem->part_state), nodegroup_id(part_elem->nodegroup_id), has_null_value(FALSE), signed_flag(part_elem->signed_flag), max_value(part_elem->max_value), id(part_elem->id), empty(part_elem->empty), type(CONVENTIONAL) {} ~partition_element() = default; part_column_list_val& get_col_val(uint idx) { part_elem_value *ev= list_val_list.head(); DBUG_ASSERT(ev); DBUG_ASSERT(ev->col_val_array); return ev->col_val_array[idx]; } }; #endif /* PARTITION_ELEMENT_INCLUDED */ server/private/wsrep_trans_observer.h000064400000043307151031265040014157 0ustar00/* Copyright 2016-2025 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef WSREP_TRANS_OBSERVER_H #define WSREP_TRANS_OBSERVER_H #include "my_global.h" #include "mysql/service_wsrep.h" #include "wsrep_applier.h" /* wsrep_apply_error */ #include "wsrep_xid.h" #include "wsrep_thd.h" #include "wsrep_binlog.h" /* register/deregister group commit */ #include "my_dbug.h" class THD; void wsrep_commit_empty(THD* thd, bool all); /* Return true if THD has active wsrep transaction. */ static inline bool wsrep_is_active(THD* thd) { return (thd->wsrep_cs().state() != wsrep::client_state::s_none && thd->wsrep_cs().transaction().active() && !thd->internal_transaction()); } /* Return true if transaction is ordered. */ static inline bool wsrep_is_ordered(THD* thd) { return thd->wsrep_trx().ordered(); } /* Return true if transaction has been BF aborted but has not been rolled back yet. It is required that the caller holds thd->LOCK_thd_data. */ static inline bool wsrep_must_abort(THD* thd) { mysql_mutex_assert_owner(&thd->LOCK_thd_data); return (thd->wsrep_trx().state() == wsrep::transaction::s_must_abort); } /* Return true if the transaction must be replayed. */ static inline bool wsrep_must_replay(THD* thd) { return (thd->wsrep_trx().state() == wsrep::transaction::s_must_replay); } /* Return true if transaction has not been committed. Note that we don't require thd->LOCK_thd_data here. Calling this method makes sense only from codepaths which are past ordered_commit state and the wsrep transaction is immune to BF aborts at that point. */ static inline bool wsrep_not_committed(THD* thd) { return (thd->wsrep_trx().state() != wsrep::transaction::s_committed); } /* Return true if THD is either committing a transaction or statement is autocommit. */ static inline bool wsrep_is_real(THD* thd, bool all) { return (all || thd->transaction->all.ha_list == 0); } /* Check if a transaction has generated changes. */ static inline bool wsrep_has_changes(THD* thd) { // Transaction has changes to replicate if it // has appended one or more certification keys, // and has actual changes to replicate in binlog // cache. Except for streaming replication, // where commit message may have no payload. return !thd->wsrep_trx().is_empty() && (!wsrep_is_binlog_cache_empty(thd) || thd->wsrep_trx().is_streaming()); } /* Check if an active transaction has been BF aborted. */ static inline bool wsrep_is_bf_aborted(THD* thd) { return (thd->wsrep_trx().active() && thd->wsrep_trx().bf_aborted()); } static inline int wsrep_check_pk(THD* thd) { if (!wsrep_certify_nonPK) { for (TABLE* table= thd->open_tables; table != NULL; table= table->next) { if (table->key_info == NULL || table->s->primary_key == MAX_KEY) { WSREP_DEBUG("No primary key found for table %s.%s", table->s->db.str, table->s->table_name.str); wsrep_override_error(thd, ER_LOCK_DEADLOCK); return 1; } } } return 0; } static inline bool wsrep_streaming_enabled(THD* thd) { return (thd->wsrep_sr().fragment_size() > 0); } /* Return number of fragments successfully certified for the current statement. */ static inline size_t wsrep_fragments_certified_for_stmt(THD* thd) { return thd->wsrep_trx().fragments_certified_for_statement(); } static inline int wsrep_start_transaction(THD* thd, wsrep_trx_id_t trx_id) { if (thd->wsrep_cs().state() != wsrep::client_state::s_none) { if (wsrep_is_active(thd) == false) return thd->wsrep_cs().start_transaction(wsrep::transaction_id(trx_id)); } return 0; } /**/ static inline int wsrep_start_trx_if_not_started(THD* thd) { int ret= 0; DBUG_ASSERT(thd->wsrep_next_trx_id() != WSREP_UNDEFINED_TRX_ID); DBUG_ASSERT(thd->wsrep_cs().mode() == Wsrep_client_state::m_local); if (thd->wsrep_trx().active() == false) { ret= wsrep_start_transaction(thd, thd->wsrep_next_trx_id()); } return ret; } /* Called after each row operation. Return zero on succes, non-zero on failure. */ static inline int wsrep_after_row_internal(THD* thd) { if (thd->wsrep_cs().state() != wsrep::client_state::s_none && wsrep_thd_is_local(thd)) { if (wsrep_check_pk(thd)) { return 1; } else if (wsrep_streaming_enabled(thd)) { return thd->wsrep_cs().after_row(); } } return 0; } /* Helper method to determine whether commit time hooks should be run for the transaction. Commit hooks must be run in the following cases: - The transaction is local and has generated write set and is committing. - The transaction has been BF aborted - Is running in high priority mode and is ordered. This can be replayer, applier or storage access. */ static inline bool wsrep_run_commit_hook(THD* thd, bool all) { DBUG_ENTER("wsrep_run_commit_hook"); DBUG_PRINT("wsrep", ("Is_active: %d is_real %d has_changes %d is_applying %d " "is_ordered: %d", wsrep_is_active(thd), wsrep_is_real(thd, all), wsrep_has_changes(thd), wsrep_thd_is_applying(thd), wsrep_is_ordered(thd))); /* skipping non-wsrep threads */ if (!WSREP(thd)) DBUG_RETURN(false); /* Is MST commit or autocommit? */ bool ret= wsrep_is_active(thd) && wsrep_is_real(thd, all); /* Do not commit if we are aborting */ ret= ret && (thd->wsrep_trx().state() != wsrep::transaction::s_aborting); if (ret && !(wsrep_has_changes(thd) || /* Has generated write set */ /* Is high priority (replay, applier, storage) and the transaction is scheduled for commit ordering */ (wsrep_thd_is_applying(thd) && wsrep_is_ordered(thd)))) { mysql_mutex_lock(&thd->LOCK_thd_data); DBUG_PRINT("wsrep", ("state: %s", wsrep::to_c_string(thd->wsrep_trx().state()))); /* Transaction is local but has no changes, the commit hooks will be skipped and the wsrep transaction is terminated in wsrep_commit_empty() */ if (thd->wsrep_trx().state() == wsrep::transaction::s_executing) { ret= false; } mysql_mutex_unlock(&thd->LOCK_thd_data); } mysql_mutex_lock(&thd->LOCK_thd_data); /* Transaction creating sequence is TOI or RSU, CREATE SEQUENCE = CREATE + INSERT (initial value) and replicated using statement based replication, thus the commit hooks will be skipped. For TEMPORARY SEQUENCES commit hooks will be done as CREATE + INSERT is not replicated and needs to be committed locally. */ if (ret && (thd->wsrep_cs().mode() == wsrep::client_state::m_toi || thd->wsrep_cs().mode() == wsrep::client_state::m_rsu) && thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE && !thd->lex->tmp_table()) ret= false; mysql_mutex_unlock(&thd->LOCK_thd_data); DBUG_PRINT("wsrep", ("return: %d", ret)); DBUG_RETURN(ret); } /* Called before the transaction is prepared. Return zero on succes, non-zero on failure. */ static inline int wsrep_before_prepare(THD* thd, bool all) { DBUG_ENTER("wsrep_before_prepare"); WSREP_DEBUG("wsrep_before_prepare: %d", wsrep_is_real(thd, all)); int ret= 0; DBUG_ASSERT(wsrep_run_commit_hook(thd, all)); if ((ret= thd->wsrep_parallel_slave_wait_for_prior_commit())) { DBUG_RETURN(ret); } if ((ret= thd->wsrep_cs().before_prepare()) == 0) { DBUG_ASSERT(!thd->wsrep_trx().ws_meta().gtid().is_undefined()); /* Here we init xid with UUID and wsrep seqno. GTID is set to undefined because commit order is decided later in wsrep_before_commit(). wsrep_before_prepare() is executed out of order. */ wsrep_xid_init(&thd->wsrep_xid, thd->wsrep_trx().ws_meta().gtid(), wsrep_gtid_server.undefined()); } mysql_mutex_lock(&thd->LOCK_thd_kill); if (thd->killed) wsrep_backup_kill_for_commit(thd); mysql_mutex_unlock(&thd->LOCK_thd_kill); DBUG_RETURN(ret); } /* Called after the transaction has been prepared. Return zero on succes, non-zero on failure. */ static inline int wsrep_after_prepare(THD* thd, bool all) { DBUG_ENTER("wsrep_after_prepare"); WSREP_DEBUG("wsrep_after_prepare: %d", wsrep_is_real(thd, all)); DBUG_ASSERT(wsrep_run_commit_hook(thd, all)); int ret= thd->wsrep_cs().after_prepare(); DBUG_ASSERT(ret == 0 || thd->wsrep_cs().current_error() || thd->wsrep_cs().transaction().state() == wsrep::transaction::s_must_replay); DBUG_RETURN(ret); } /* Called before the transaction is committed. This function must be called from both client and applier contexts before commit. Return zero on succes, non-zero on failure. */ static inline int wsrep_before_commit(THD* thd, bool all) { DBUG_ENTER("wsrep_before_commit"); WSREP_DEBUG("wsrep_before_commit: %d, %lld", wsrep_is_real(thd, all), (long long)wsrep_thd_trx_seqno(thd)); int ret= 0; DBUG_ASSERT(wsrep_run_commit_hook(thd, all)); if ((ret= thd->wsrep_cs().before_commit()) == 0) { DBUG_ASSERT(!thd->wsrep_trx().ws_meta().gtid().is_undefined()); if (!thd->variables.gtid_seq_no && (thd->wsrep_trx().ws_meta().flags() & wsrep::provider::flag::commit)) { uint64 seqno= 0; if (thd->variables.wsrep_gtid_seq_no && thd->variables.wsrep_gtid_seq_no > wsrep_gtid_server.seqno()) { seqno= thd->variables.wsrep_gtid_seq_no; wsrep_gtid_server.seqno(thd->variables.wsrep_gtid_seq_no); } else { seqno= wsrep_gtid_server.seqno_inc(); } thd->variables.wsrep_gtid_seq_no= 0; thd->wsrep_current_gtid_seqno= seqno; if (mysql_bin_log.is_open() && wsrep_gtid_mode) { thd->variables.gtid_seq_no= seqno; thd->variables.gtid_domain_id= wsrep_gtid_server.domain_id; thd->variables.server_id= wsrep_gtid_server.server_id; } } wsrep_xid_init(&thd->wsrep_xid, thd->wsrep_trx().ws_meta().gtid(), wsrep_gtid_server.gtid()); wsrep_register_for_group_commit(thd); } mysql_mutex_lock(&thd->LOCK_thd_kill); if (thd->killed) wsrep_backup_kill_for_commit(thd); mysql_mutex_unlock(&thd->LOCK_thd_kill); DBUG_RETURN(ret); } /* Called after the transaction has been ordered for commit. This function must be called from both client and applier contexts after the commit has been ordered. @param thd Pointer to THD @param all @param err Error buffer in case of applying error Return zero on succes, non-zero on failure. */ static inline int wsrep_ordered_commit(THD* thd, bool all) { DBUG_ENTER("wsrep_ordered_commit"); WSREP_DEBUG("wsrep_ordered_commit: %d %lld", wsrep_is_real(thd, all), (long long) wsrep_thd_trx_seqno(thd)); DBUG_ASSERT(wsrep_run_commit_hook(thd, all)); DBUG_RETURN(thd->wsrep_cs().ordered_commit()); } /* Called after the transaction has been committed. Return zero on succes, non-zero on failure. */ static inline int wsrep_after_commit(THD* thd, bool all) { DBUG_ENTER("wsrep_after_commit"); WSREP_DEBUG("wsrep_after_commit: %d, %d, %lld, %d", wsrep_is_real(thd, all), wsrep_is_active(thd), (long long)wsrep_thd_trx_seqno(thd), wsrep_has_changes(thd)); DBUG_ASSERT(wsrep_run_commit_hook(thd, all)); if (thd->internal_transaction()) DBUG_RETURN(0); int ret= 0; if (thd->wsrep_trx().state() == wsrep::transaction::s_committing) { ret= thd->wsrep_cs().ordered_commit(); } wsrep_unregister_from_group_commit(thd); thd->wsrep_xid.null(); DBUG_RETURN(ret || thd->wsrep_cs().after_commit()); } /* Called before the transaction is rolled back. Return zero on succes, non-zero on failure. */ static inline int wsrep_before_rollback(THD* thd, bool all) { DBUG_ENTER("wsrep_before_rollback"); int ret= 0; if (wsrep_is_active(thd)) { if (!all && thd->in_active_multi_stmt_transaction()) { if (wsrep_emulate_bin_log) { wsrep_thd_binlog_stmt_rollback(thd); } if (thd->wsrep_trx().is_streaming() && (wsrep_fragments_certified_for_stmt(thd) > 0)) { /* Non-safe statement rollback during SR multi statement transaction. A statement rollback is considered unsafe, if the same statement has already replicated one or more fragments. Self abort the transaction, the actual rollback and error handling will be done in after statement phase. */ WSREP_DEBUG("statement rollback is not safe for streaming replication"); wsrep_thd_self_abort(thd); ret= 0; } } else if (wsrep_is_real(thd, all) && thd->wsrep_trx().state() != wsrep::transaction::s_aborted) { /* Real transaction rolling back and wsrep abort not completed yet */ /* Reset XID so that it does not trigger writing serialization history in InnoDB. This needs to be avoided because rollback may happen out of order and replay may follow. */ thd->wsrep_xid.null(); ret= thd->wsrep_cs().before_rollback(); } } DBUG_RETURN(ret); } /* Called after the transaction has been rolled back. Return zero on succes, non-zero on failure. */ static inline int wsrep_after_rollback(THD* thd, bool all) { DBUG_ENTER("wsrep_after_rollback"); DBUG_RETURN((wsrep_is_real(thd, all) && wsrep_is_active(thd) && thd->wsrep_cs().transaction().state() != wsrep::transaction::s_aborted) ? thd->wsrep_cs().after_rollback() : 0); } static inline int wsrep_before_statement(THD* thd) { return (thd->wsrep_cs().state() != wsrep::client_state::s_none && !thd->internal_transaction() ? thd->wsrep_cs().before_statement() : 0); } static inline int wsrep_after_statement(THD* thd) { DBUG_ENTER("wsrep_after_statement"); int ret= ((thd->wsrep_cs().state() != wsrep::client_state::s_none && thd->wsrep_cs().mode() == Wsrep_client_state::m_local) && !thd->internal_transaction() ? thd->wsrep_cs().after_statement() : 0); if (wsrep_is_active(thd)) { mysql_mutex_lock(&thd->LOCK_thd_kill); wsrep_restore_kill_after_commit(thd); mysql_mutex_unlock(&thd->LOCK_thd_kill); } DBUG_RETURN(ret); } static inline void wsrep_after_apply(THD* thd) { DBUG_ASSERT(wsrep_thd_is_applying(thd)); WSREP_DEBUG("wsrep_after_apply %lld", thd->thread_id); if (!thd->internal_transaction()) thd->wsrep_cs().after_applying(); } static inline void wsrep_open(THD* thd) { DBUG_ENTER("wsrep_open"); if (WSREP_ON_) { /* WSREP_PROVIDER_EXISTS_ cannot be set if WSREP_ON_ is not set */ DBUG_ASSERT(WSREP_PROVIDER_EXISTS_); thd->wsrep_cs().open(wsrep::client_id(thd->thread_id)); thd->wsrep_cs().debug_log_level(wsrep_debug); if (!thd->wsrep_applier && thd->variables.wsrep_trx_fragment_size) { thd->wsrep_cs().enable_streaming( wsrep_fragment_unit(thd->variables.wsrep_trx_fragment_unit), size_t(thd->variables.wsrep_trx_fragment_size)); } } DBUG_VOID_RETURN; } static inline void wsrep_close(THD* thd) { DBUG_ENTER("wsrep_close"); if (thd->wsrep_cs().state() != wsrep::client_state::s_none && !thd->internal_transaction()) { thd->wsrep_cs().close(); } DBUG_VOID_RETURN; } static inline void wsrep_cleanup(THD* thd) { DBUG_ENTER("wsrep_cleanup"); if (thd->wsrep_cs().state() != wsrep::client_state::s_none) { thd->wsrep_cs().cleanup(); } DBUG_VOID_RETURN; } static inline void wsrep_wait_rollback_complete_and_acquire_ownership(THD *thd) { DBUG_ENTER("wsrep_wait_rollback_complete_and_acquire_ownership"); if (thd->wsrep_cs().state() != wsrep::client_state::s_none && !thd->internal_transaction()) { thd->wsrep_cs().wait_rollback_complete_and_acquire_ownership(); } DBUG_VOID_RETURN; } static inline int wsrep_before_command(THD* thd, bool keep_command_error) { return (thd->wsrep_cs().state() != wsrep::client_state::s_none && !thd->internal_transaction() ? thd->wsrep_cs().before_command(keep_command_error) : 0); } static inline int wsrep_before_command(THD* thd) { return wsrep_before_command(thd, false); } /* Called after each command. Return zero on success, non-zero on failure. */ static inline void wsrep_after_command_before_result(THD* thd) { if (thd->wsrep_cs().state() != wsrep::client_state::s_none && !thd->internal_transaction()) { thd->wsrep_cs().after_command_before_result(); } } static inline void wsrep_after_command_after_result(THD* thd) { if (thd->wsrep_cs().state() != wsrep::client_state::s_none && !thd->internal_transaction()) { thd->wsrep_cs().after_command_after_result(); } } static inline void wsrep_after_command_ignore_result(THD* thd) { wsrep_after_command_before_result(thd); DBUG_ASSERT(!thd->wsrep_cs().current_error()); wsrep_after_command_after_result(thd); } static inline enum wsrep::client_error wsrep_current_error(THD* thd) { return thd->wsrep_cs().current_error(); } static inline enum wsrep::provider::status wsrep_current_error_status(THD* thd) { return thd->wsrep_cs().current_error_status(); } #endif /* WSREP_TRANS_OBSERVER */ server/private/rpl_filter.h000064400000010667151031265040012046 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef RPL_FILTER_H #define RPL_FILTER_H #include "mysql.h" #include "mysqld.h" #include "sql_list.h" /* I_List */ #include "hash.h" /* HASH */ class String; struct TABLE_LIST; typedef struct st_dynamic_array DYNAMIC_ARRAY; typedef struct st_table_rule_ent { char* db; char* tbl_name; uint key_len; } TABLE_RULE_ENT; /* Rpl_filter Inclusion and exclusion rules of tables and databases. Also handles rewrites of db. Used for replication and binlogging. */ class Rpl_filter { public: Rpl_filter(); ~Rpl_filter(); Rpl_filter(Rpl_filter const&); Rpl_filter& operator=(Rpl_filter const&); /* Checks - returns true if ok to replicate/log */ #ifndef MYSQL_CLIENT bool tables_ok(const char* db, TABLE_LIST *tables); #endif bool db_ok(const char* db); bool db_ok_with_wild_table(const char *db); bool is_on(); bool is_db_empty(); /* Setters - add filtering rules */ int add_do_table(const char* table_spec); int add_ignore_table(const char* table_spec); int set_do_table(const char* table_spec); int set_ignore_table(const char* table_spec); int add_wild_do_table(const char* table_spec); int add_wild_ignore_table(const char* table_spec); int set_wild_do_table(const char* table_spec); int set_wild_ignore_table(const char* table_spec); int add_do_db(const char* db_spec); int add_ignore_db(const char* db_spec); int set_do_db(const char* db_spec); int set_ignore_db(const char* db_spec); void set_parallel_mode(enum_slave_parallel_mode mode) { parallel_mode= mode; } /* Return given parallel mode or if one is not given, the default mode */ enum_slave_parallel_mode get_parallel_mode() { return parallel_mode; } void add_db_rewrite(const char* from_db, const char* to_db); /* Getters - to get information about current rules */ void get_do_table(String* str); void get_ignore_table(String* str); void get_wild_do_table(String* str); void get_wild_ignore_table(String* str); bool rewrite_db_is_empty(); const char* get_rewrite_db(const char* db, size_t *new_len); void copy_rewrite_db(Rpl_filter *from); I_List* get_do_db(); I_List* get_ignore_db(); void get_do_db(String* str); void get_ignore_db(String* str); private: void init_table_rule_hash(HASH* h, bool* h_inited); void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited); int add_table_rule(HASH* h, const char* table_spec); int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec); typedef int (Rpl_filter::*Add_filter)(char const*); int parse_filter_rule(const char* spec, Add_filter func); void free_string_array(DYNAMIC_ARRAY *a); void free_string_list(I_List *l); void table_rule_ent_hash_to_str(String* s, HASH* h, bool inited); void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a, bool inited); void db_rule_ent_list_to_str(String* s, I_List* l); TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len); int add_string_list(I_List *list, const char* spec); /* Those 4 structures below are uninitialized memory unless the corresponding *_inited variables are "true". */ HASH do_table; HASH ignore_table; DYNAMIC_ARRAY wild_do_table; DYNAMIC_ARRAY wild_ignore_table; enum_slave_parallel_mode parallel_mode; bool table_rules_on; bool do_table_inited; bool ignore_table_inited; bool wild_do_table_inited; bool wild_ignore_table_inited; I_List do_db; I_List ignore_db; I_List rewrite_db; }; extern Rpl_filter *global_rpl_filter; extern Rpl_filter *binlog_filter; #endif // RPL_FILTER_H server/private/mysys_err.h000064400000005716151031265040011737 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _mysys_err_h #define _mysys_err_h #ifdef __cplusplus extern "C" { #endif #define GLOBERRS (EE_ERROR_LAST - EE_ERROR_FIRST + 1) /* Nr of global errors */ #define EE(X) (globerrs[(X) - EE_ERROR_FIRST]) extern const char *globerrs[]; /* my_error_messages is here */ /* Error message numbers in global map */ /* Do not add error numbers before EE_ERROR_FIRST. If necessary to add lower numbers, change EE_ERROR_FIRST accordingly. We start with error 1 to not confuse peoples with 'error 0' */ #define EE_ERROR_FIRST 1 /*Copy first error nr.*/ #define EE_CANTCREATEFILE 1 #define EE_READ 2 #define EE_WRITE 3 #define EE_BADCLOSE 4 #define EE_OUTOFMEMORY 5 #define EE_DELETE 6 #define EE_LINK 7 #define EE_EOFERR 9 #define EE_CANTLOCK 10 #define EE_CANTUNLOCK 11 #define EE_DIR 12 #define EE_STAT 13 #define EE_CANT_CHSIZE 14 #define EE_CANT_OPEN_STREAM 15 #define EE_GETWD 16 #define EE_SETWD 17 #define EE_LINK_WARNING 18 #define EE_OPEN_WARNING 19 #define EE_DISK_FULL 20 #define EE_CANT_MKDIR 21 #define EE_UNKNOWN_CHARSET 22 #define EE_OUT_OF_FILERESOURCES 23 #define EE_CANT_READLINK 24 #define EE_CANT_SYMLINK 25 #define EE_REALPATH 26 #define EE_SYNC 27 #define EE_UNKNOWN_COLLATION 28 #define EE_FILENOTFOUND 29 #define EE_FILE_NOT_CLOSED 30 #define EE_CHANGE_OWNERSHIP 31 #define EE_CHANGE_PERMISSIONS 32 #define EE_CANT_SEEK 33 #define EE_CANT_CHMOD 34 #define EE_CANT_COPY_OWNERSHIP 35 #define EE_BADMEMORYRELEASE 36 #define EE_PERM_LOCK_MEMORY 37 #define EE_MEMCNTL 38 #define EE_DUPLICATE_CHARSET 39 #define EE_ERROR_LAST 39 /* Copy last error nr */ /* Add error numbers before EE_ERROR_LAST and change it accordingly. */ /* exit codes for all MySQL programs */ #define EXIT_UNSPECIFIED_ERROR 1 #define EXIT_UNKNOWN_OPTION 2 #define EXIT_AMBIGUOUS_OPTION 3 #define EXIT_NO_ARGUMENT_ALLOWED 4 #define EXIT_ARGUMENT_REQUIRED 5 #define EXIT_VAR_PREFIX_NOT_UNIQUE 6 #define EXIT_UNKNOWN_VARIABLE 7 #define EXIT_OUT_OF_MEMORY 8 #define EXIT_UNKNOWN_SUFFIX 9 #define EXIT_NO_PTR_TO_VARIABLE 10 #define EXIT_CANNOT_CONNECT_TO_SERVICE 11 #define EXIT_OPTION_DISABLED 12 #define EXIT_ARGUMENT_INVALID 13 #ifdef __cplusplus } #endif #endif server/private/thr_timer.h000064400000003033151031265040011666 0ustar00/* Copyright (c) 2014 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 or later of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Prototypes when using thr_timer functions */ #ifndef THR_TIMER_INCLUDED #define THR_TIMER_INCLUDED #ifdef __cplusplus extern "C" { #endif typedef struct st_timer { struct timespec expire_time; ulonglong period; my_bool expired; uint index_in_queue; void (*func)(void*); void *func_arg; } thr_timer_t; /* Main functions for library */ my_bool init_thr_timer(uint init_size_for_timer_queue); void end_thr_timer(); /* Functions for handling one timer */ void thr_timer_init(thr_timer_t *timer_data, void(*function)(void*), void *arg); void thr_timer_set_period(thr_timer_t* timer_data, ulonglong microseconds); my_bool thr_timer_settime(thr_timer_t *timer_data, ulonglong microseconds); void thr_timer_end(thr_timer_t *timer_data); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* THR_TIMER_INCLUDED */ server/private/sql_type_json.h000064400000014013151031265040012562 0ustar00#ifndef SQL_TYPE_JSON_INCLUDED #define SQL_TYPE_JSON_INCLUDED /* Copyright (c) 2019, 2021 MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mariadb.h" #include "sql_type.h" class Type_handler_json_common { public: static Virtual_column_info *make_json_valid_expr(THD *thd, const LEX_CSTRING *field_name); static bool make_json_valid_expr_if_needed(THD *thd, Column_definition *c); static bool set_format_name(Send_field_extended_metadata *to) { static const Lex_cstring fmt(STRING_WITH_LEN("json")); return to->set_format_name(fmt); } static const Type_handler *json_type_handler(uint max_octet_length); static const Type_handler *json_blob_type_handler_by_length_bytes(uint len); static const Type_handler *json_type_handler_sum(const Item_sum *sum); static const Type_handler *json_type_handler_from_generic(const Type_handler *th); static bool has_json_valid_constraint(const Field *field); static const Type_collection *type_collection(); static bool is_json_type_handler(const Type_handler *handler) { return handler->type_collection() == type_collection(); } }; template &thbase> class Type_handler_general_purpose_string_to_json: public BASE, public Type_handler_json_common { public: const Type_handler *type_handler_base() const override { return &thbase; } const Type_collection *type_collection() const override { return Type_handler_json_common::type_collection(); } bool Column_definition_validate_check_constraint(THD *thd, Column_definition *c) const override { return make_json_valid_expr_if_needed(thd, c) || BASE::Column_definition_validate_check_constraint(thd, c); } bool Column_definition_data_type_info_image(Binary_string *to, const Column_definition &def) const override { /* Override the inherited method to avoid JSON type handlers writing any extended metadata to FRM. JSON type handlers are currently detected only by CHECK(JSON_VALID()) constraint. This may change in the future to do write extended metadata to FRM, for more reliable detection. */ return false; } bool Item_append_extended_type_info(Send_field_extended_metadata *to, const Item *item) const override { return set_format_name(to); // Send "format=json" in the protocol } bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *hybrid, Type_all_attributes *attr, Item **items, uint nitems) const override { if (BASE::Item_hybrid_func_fix_attributes(thd, name, hybrid, attr, items, nitems)) return true; /* The above call can change the type handler on "hybrid", e.g. choose a proper BLOB type handler according to the calculated max_length. Convert general purpose string type handler to its JSON counterpart. This makes hybrid functions preserve JSON data types, e.g.: COALESCE(json_expr1, json_expr2) -> JSON */ hybrid->set_handler(json_type_handler_from_generic(hybrid->type_handler())); return false; } }; class Type_handler_string_json: public Type_handler_general_purpose_string_to_json { }; class Type_handler_varchar_json: public Type_handler_general_purpose_string_to_json { }; class Type_handler_tiny_blob_json: public Type_handler_general_purpose_string_to_json { }; class Type_handler_blob_json: public Type_handler_general_purpose_string_to_json { }; class Type_handler_medium_blob_json: public Type_handler_general_purpose_string_to_json { }; class Type_handler_long_blob_json: public Type_handler_general_purpose_string_to_json { }; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_string_json; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_varchar_json; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_tiny_blob_json; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_blob_json; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_medium_blob_json; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_long_blob_json; #endif // SQL_TYPE_JSON_INCLUDED server/private/sql_repl.h000064400000005745151031265040011526 0ustar00/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_REPL_INCLUDED #define SQL_REPL_INCLUDED #include "rpl_filter.h" #ifdef HAVE_REPLICATION #include "slave.h" struct slave_connection_state; extern my_bool opt_show_slave_auth_info; extern char *master_host, *master_info_file; extern int max_binlog_dump_events; extern my_bool opt_sporadic_binlog_dump_fail; int start_slave(THD* thd, Master_info* mi, bool net_report); int stop_slave(THD* thd, Master_info* mi, bool net_report); bool change_master(THD* thd, Master_info* mi, bool *master_info_added); bool mysql_show_binlog_events(THD* thd); int reset_slave(THD *thd, Master_info* mi); int reset_master(THD* thd, rpl_gtid *init_state, uint32 init_state_len, ulong next_log_number); bool purge_master_logs(THD* thd, const char* to_log); bool purge_master_logs_before_date(THD* thd, time_t purge_time); bool log_in_use(const char* log_name); void adjust_linfo_offsets(my_off_t purge_offset); void show_binlogs_get_fields(THD *thd, List *field_list); bool show_binlogs(THD* thd); extern int init_master_info(Master_info* mi); bool kill_zombie_dump_threads(THD *thd, uint32 slave_server_id); int check_binlog_magic(IO_CACHE* log, const char** errmsg); int compare_log_name(const char *log_1, const char *log_2); struct LOAD_FILE_IO_CACHE : public IO_CACHE { THD* thd; my_off_t last_pos_in_file; bool wrote_create_file, log_delayed; int (*real_read_function)(struct st_io_cache *,uchar *,size_t); }; int log_loaded_block(IO_CACHE* file, uchar *Buffer, size_t Count); int init_replication_sys_vars(); void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags); #ifdef HAVE_PSI_INTERFACE extern PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state; #endif void rpl_init_gtid_slave_state(); void rpl_deinit_gtid_slave_state(); void rpl_init_gtid_waiting(); void rpl_deinit_gtid_waiting(); int gtid_state_from_binlog_pos(const char *name, uint32 pos, String *out_str); int rpl_append_gtid_state(String *dest, bool use_binlog); int rpl_load_gtid_state(slave_connection_state *state, bool use_binlog); bool rpl_gtid_pos_check(THD *thd, char *str, size_t len); bool rpl_gtid_pos_update(THD *thd, char *str, size_t len); #else struct LOAD_FILE_IO_CACHE : public IO_CACHE { }; #endif /* HAVE_REPLICATION */ #endif /* SQL_REPL_INCLUDED */ server/private/ssl_compat.h000064400000006113151031265040012037 0ustar00/* Copyright (c) 2016, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include /* OpenSSL version specific definitions */ #if defined(OPENSSL_VERSION_NUMBER) #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ !(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x30500000L) #define HAVE_OPENSSL11 1 #define SSL_LIBRARY OpenSSL_version(OPENSSL_VERSION) #define ERR_remove_state(X) ERR_clear_error() #define EVP_CIPHER_CTX_SIZE 200 #define EVP_MD_CTX_SIZE 80 #undef EVP_MD_CTX_init #define EVP_MD_CTX_init(X) do { memset((X), 0, EVP_MD_CTX_SIZE); EVP_MD_CTX_reset(X); } while(0) #undef EVP_CIPHER_CTX_init #define EVP_CIPHER_CTX_init(X) do { memset((X), 0, EVP_CIPHER_CTX_SIZE); EVP_CIPHER_CTX_reset(X); } while(0) /* Macros below are deprecated. OpenSSL 1.1 may define them or not, depending on how it was built. */ #undef ERR_free_strings #define ERR_free_strings() #undef EVP_cleanup #define EVP_cleanup() #undef CRYPTO_cleanup_all_ex_data #define CRYPTO_cleanup_all_ex_data() #undef SSL_load_error_strings #define SSL_load_error_strings() #else #define HAVE_OPENSSL10 1 #ifdef HAVE_WOLFSSL #define SSL_LIBRARY "WolfSSL " WOLFSSL_VERSION #else #define SSL_LIBRARY SSLeay_version(SSLEAY_VERSION) #endif #ifdef HAVE_WOLFSSL #undef ERR_remove_state #define ERR_remove_state(x) do {} while(0) #elif defined (HAVE_ERR_remove_thread_state) #define ERR_remove_state(X) ERR_remove_thread_state(NULL) #endif /* HAVE_ERR_remove_thread_state */ #endif /* HAVE_OPENSSL11 */ #endif #ifdef HAVE_WOLFSSL #define EVP_MD_CTX_SIZE sizeof(wc_Md5) #endif #ifndef HAVE_OPENSSL11 #ifndef ASN1_STRING_get0_data #define ASN1_STRING_get0_data(X) ASN1_STRING_data(X) #endif #ifndef EVP_MD_CTX_SIZE #define EVP_MD_CTX_SIZE sizeof(EVP_MD_CTX) #endif #ifndef DH_set0_pqg #define DH_set0_pqg(D,P,Q,G) ((D)->p= (P), (D)->g= (G)) #endif #define EVP_CIPHER_CTX_encrypting(ctx) ((ctx)->encrypt) #define EVP_CIPHER_CTX_SIZE sizeof(EVP_CIPHER_CTX) #ifndef HAVE_WOLFSSL #define OPENSSL_init_ssl(X,Y) SSL_library_init() #define EVP_MD_CTX_reset(X) EVP_MD_CTX_cleanup(X) #define EVP_CIPHER_CTX_reset(X) EVP_CIPHER_CTX_cleanup(X) #define X509_get0_notBefore(X) X509_get_notBefore(X) #define X509_get0_notAfter(X) X509_get_notAfter(X) #endif #endif #ifndef TLS1_3_VERSION #define SSL_CTX_set_ciphersuites(X,Y) 0 #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ int check_openssl_compatibility(); #ifdef __cplusplus } #endif server/private/hash_filo.h000064400000013070151031265040011627 0ustar00/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* ** A class for static sized hash tables where old entries are deleted in ** first-in-last-out to usage. */ #ifndef HASH_FILO_H #define HASH_FILO_H #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class interface */ #endif #include "hash.h" /* my_hash_get_key, my_hash_free_key, HASH */ #include "m_string.h" /* bzero */ #include "mysqld.h" /* key_hash_filo_lock */ class hash_filo_element { private: hash_filo_element *next_used,*prev_used; public: hash_filo_element() = default; hash_filo_element *next() { return next_used; } hash_filo_element *prev() { return prev_used; } friend class hash_filo; }; class hash_filo { private: PSI_memory_key m_psi_key; const uint key_offset, key_length; const my_hash_get_key get_key; /** Size of this hash table. */ uint m_size; my_hash_free_key free_element; bool init; CHARSET_INFO *hash_charset; hash_filo_element *first_link,*last_link; public: mysql_mutex_t lock; HASH cache; hash_filo(PSI_memory_key psi_key, uint size_arg, uint key_offset_arg, uint key_length_arg, my_hash_get_key get_key_arg, my_hash_free_key free_element_arg, CHARSET_INFO *hash_charset_arg) : m_psi_key(psi_key), key_offset(key_offset_arg), key_length(key_length_arg), get_key(get_key_arg), m_size(size_arg), free_element(free_element_arg),init(0), hash_charset(hash_charset_arg), first_link(NULL), last_link(NULL) { bzero((char*) &cache,sizeof(cache)); } ~hash_filo() { if (init) { if (cache.array.buffer) /* Avoid problems with thread library */ (void) my_hash_free(&cache); mysql_mutex_destroy(&lock); } } void clear(bool locked=0) { if (!init) { init=1; mysql_mutex_init(key_hash_filo_lock, &lock, MY_MUTEX_INIT_FAST); } if (!locked) mysql_mutex_lock(&lock); first_link= NULL; last_link= NULL; (void) my_hash_free(&cache); (void) my_hash_init(m_psi_key, &cache,hash_charset,m_size,key_offset, key_length, get_key, free_element, 0); if (!locked) mysql_mutex_unlock(&lock); } hash_filo_element *first() { mysql_mutex_assert_owner(&lock); return first_link; } hash_filo_element *last() { mysql_mutex_assert_owner(&lock); return last_link; } hash_filo_element *search(uchar* key, size_t length) { mysql_mutex_assert_owner(&lock); hash_filo_element *entry=(hash_filo_element*) my_hash_search(&cache,(uchar*) key,length); if (entry) { // Found; link it first DBUG_ASSERT(first_link != NULL); DBUG_ASSERT(last_link != NULL); if (entry != first_link) { // Relink used-chain if (entry == last_link) { last_link= last_link->prev_used; /* The list must have at least 2 elements, otherwise entry would be equal to first_link. */ DBUG_ASSERT(last_link != NULL); last_link->next_used= NULL; } else { DBUG_ASSERT(entry->next_used != NULL); DBUG_ASSERT(entry->prev_used != NULL); entry->next_used->prev_used = entry->prev_used; entry->prev_used->next_used = entry->next_used; } entry->prev_used= NULL; entry->next_used= first_link; first_link->prev_used= entry; first_link=entry; } } return entry; } bool add(hash_filo_element *entry) { if (!m_size) return 1; if (cache.records == m_size) { hash_filo_element *tmp=last_link; last_link= last_link->prev_used; if (last_link != NULL) { last_link->next_used= NULL; } else { /* Pathological case, m_size == 1 */ first_link= NULL; } my_hash_delete(&cache,(uchar*) tmp); } if (my_hash_insert(&cache,(uchar*) entry)) { if (free_element) (*free_element)(entry); // This should never happen return 1; } entry->prev_used= NULL; entry->next_used= first_link; if (first_link != NULL) first_link->prev_used= entry; else last_link= entry; first_link= entry; return 0; } uint size() { return m_size; } void resize(uint new_size) { mysql_mutex_lock(&lock); m_size= new_size; clear(true); mysql_mutex_unlock(&lock); } }; template class Hash_filo: public hash_filo { public: Hash_filo(PSI_memory_key psi_key, uint size_arg, uint key_offset_arg, uint key_length_arg, my_hash_get_key get_key_arg, my_hash_free_key free_element_arg, CHARSET_INFO *hash_charset_arg) : hash_filo(psi_key, size_arg, key_offset_arg, key_length_arg, get_key_arg, free_element_arg, hash_charset_arg) {} T* first() { return (T*)hash_filo::first(); } T* last() { return (T*)hash_filo::last(); } T* search(uchar* key, size_t len) { return (T*)hash_filo::search(key, len); } }; #endif server/private/init.h000064400000001524151031265040010637 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef INIT_INCLUDED #define INIT_INCLUDED void unireg_init(ulong options); #endif /* INIT_INCLUDED */ server/private/pfs_statement_provider.h000064400000010373151031265040014464 0ustar00/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #ifndef PFS_STATEMENT_PROVIDER_H #define PFS_STATEMENT_PROVIDER_H /** @file include/pfs_statement_provider.h Performance schema instrumentation (declarations). */ #ifdef HAVE_PSI_STATEMENT_INTERFACE #ifdef MYSQL_SERVER #ifndef EMBEDDED_LIBRARY #ifndef MYSQL_DYNAMIC_PLUGIN #include "mysql/psi/psi.h" #define PSI_STATEMENT_CALL(M) pfs_ ## M ## _v1 #define PSI_DIGEST_CALL(M) pfs_ ## M ## _v1 C_MODE_START void pfs_register_statement_v1(const char *category, PSI_statement_info_v1 *info, int count); PSI_statement_locker* pfs_get_thread_statement_locker_v1(PSI_statement_locker_state *state, PSI_statement_key key, const void *charset, PSI_sp_share *sp_share); PSI_statement_locker* pfs_refine_statement_v1(PSI_statement_locker *locker, PSI_statement_key key); void pfs_start_statement_v1(PSI_statement_locker *locker, const char *db, uint db_len, const char *src_file, uint src_line); void pfs_set_statement_text_v1(PSI_statement_locker *locker, const char *text, uint text_len); void pfs_set_statement_lock_time_v1(PSI_statement_locker *locker, ulonglong count); void pfs_set_statement_rows_sent_v1(PSI_statement_locker *locker, ulonglong count); void pfs_set_statement_rows_examined_v1(PSI_statement_locker *locker, ulonglong count); void pfs_inc_statement_created_tmp_disk_tables_v1(PSI_statement_locker *locker, ulong count); void pfs_inc_statement_created_tmp_tables_v1(PSI_statement_locker *locker, ulong count); void pfs_inc_statement_select_full_join_v1(PSI_statement_locker *locker, ulong count); void pfs_inc_statement_select_full_range_join_v1(PSI_statement_locker *locker, ulong count); void pfs_inc_statement_select_range_v1(PSI_statement_locker *locker, ulong count); void pfs_inc_statement_select_range_check_v1(PSI_statement_locker *locker, ulong count); void pfs_inc_statement_select_scan_v1(PSI_statement_locker *locker, ulong count); void pfs_inc_statement_sort_merge_passes_v1(PSI_statement_locker *locker, ulong count); void pfs_inc_statement_sort_range_v1(PSI_statement_locker *locker, ulong count); void pfs_inc_statement_sort_rows_v1(PSI_statement_locker *locker, ulong count); void pfs_inc_statement_sort_scan_v1(PSI_statement_locker *locker, ulong count); void pfs_set_statement_no_index_used_v1(PSI_statement_locker *locker); void pfs_set_statement_no_good_index_used_v1(PSI_statement_locker *locker); void pfs_end_statement_v1(PSI_statement_locker *locker, void *stmt_da); PSI_digest_locker *pfs_digest_start_v1(PSI_statement_locker *locker); void pfs_digest_end_v1(PSI_digest_locker *locker, const sql_digest_storage *digest); C_MODE_END #endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_SERVER */ #endif /* HAVE_PSI_STATEMENT_INTERFACE */ #endif server/private/scheduler.h000064400000006177151031265040011663 0ustar00#ifndef SCHEDULER_INCLUDED #define SCHEDULER_INCLUDED /* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Classes for the thread scheduler */ #ifdef USE_PRAGMA_INTERFACE #pragma interface #endif class THD; /* Functions used when manipulating threads */ struct scheduler_functions { uint max_threads; Atomic_counter *connection_count; ulong *max_connections; bool (*init)(void); void (*add_connection)(CONNECT *connect); void (*thd_wait_begin)(THD *thd, int wait_type); void (*thd_wait_end)(THD *thd); void (*post_kill_notification)(THD *thd); void (*end)(void); /** resume previous unfinished command (threadpool only)*/ void (*thd_resume)(THD* thd); }; /** Scheduler types enumeration. The default of --thread-handling is the first one in the thread_handling_names array, this array has to be consistent with the order in this array, so to change default one has to change the first entry in this enum and the first entry in the thread_handling_names array. @note The last entry of the enumeration is also used to mark the thread handling as dynamic. In this case the name of the thread handling is fetched from the name of the plugin that implements it. */ enum scheduler_types { /* The default of --thread-handling is the first one in the thread_handling_names array, this array has to be consistent with the order in this array, so to change default one has to change the first entry in this enum and the first entry in the thread_handling_names array. */ SCHEDULER_ONE_THREAD_PER_CONNECTION=0, SCHEDULER_NO_THREADS, SCHEDULER_TYPES_COUNT }; void one_thread_per_connection_scheduler(scheduler_functions *func, ulong *arg_max_connections, Atomic_counter *arg_connection_count); void one_thread_scheduler(scheduler_functions *func, Atomic_counter *arg_connection_count); extern void scheduler_init(); extern void post_kill_notification(THD *); /* To be used for pool-of-threads (implemeneted differently on various OSs) */ struct thd_scheduler { public: void *data; /* scheduler-specific data structure */ }; #ifdef HAVE_POOL_OF_THREADS void pool_of_threads_scheduler(scheduler_functions* func, ulong *arg_max_connections, Atomic_counter *arg_connection_count); #else #define pool_of_threads_scheduler(A,B,C) \ one_thread_per_connection_scheduler(A, B, C) #endif /*HAVE_POOL_OF_THREADS*/ #endif /* SCHEDULER_INCLUDED */ server/private/ha_sequence.h000064400000014145151031265040012157 0ustar00#ifndef HA_SEQUENCE_INCLUDED #define HA_SEQUENCE_INCLUDED /* Copyright (c) 2017 Aliyun and/or its affiliates. Copyright (c) 2017 MariaDB corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "sql_sequence.h" #include "table.h" #include "handler.h" extern handlerton *sql_sequence_hton; /* Sequence engine handler. The sequence engine is a logic engine. It doesn't store any data. All the sequence data stored into the base table which must support non rollback writes (HA_CAN_TABLES_WITHOUT_ROLLBACK) The sequence data (SEQUENCE class) is stored in TABLE_SHARE->sequence TABLE RULES: 1. When table is created, one row is automaticlly inserted into the table. The table will always have one and only one row. 2. Any inserts or updates to the table will be validated. 3. Inserts will overwrite the original row. 4. DELETE and TRUNCATE will not affect the table. Instead a warning will be given. 5. Cache will be reset for any updates. CACHE RULES: SEQUENCE class is used to cache values that sequence defined. 1. If hit cache, we can query back the sequence nextval directly instead of reading the underlying table. 2. When run out of values, the sequence engine will reserve new values in update the base table. 3. The cache is invalidated if any update on based table. */ class ha_sequence :public handler { private: handler *file; SEQUENCE *sequence; /* From table_share->sequence */ public: /* Set when handler is write locked */ bool write_locked; ha_sequence(handlerton *hton, TABLE_SHARE *share); ~ha_sequence(); virtual handlerton *storage_ht() const override { return file->ht; } /* virtual function that are re-implemented for sequence */ int open(const char *name, int mode, uint test_if_locked) override; int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info) override; handler *clone(const char *name, MEM_ROOT *mem_root) override; int write_row(const uchar *buf) override; Table_flags table_flags() const override; /* One can't update or delete from sequence engine */ int update_row(const uchar *old_data, const uchar *new_data) override { return HA_ERR_WRONG_COMMAND; } int delete_row(const uchar *buf) override { return HA_ERR_WRONG_COMMAND; } /* One can't delete from sequence engine */ int truncate() override { return HA_ERR_WRONG_COMMAND; } /* Can't use query cache */ uint8 table_cache_type() override { return HA_CACHE_TBL_NOCACHE; } void print_error(int error, myf errflag) override; int info(uint) override; LEX_CSTRING *engine_name() override { return hton_name(file->ht); } int external_lock(THD *thd, int lock_type) override; int extra(enum ha_extra_function operation) override; /* For ALTER ONLINE TABLE */ bool check_if_incompatible_data(HA_CREATE_INFO *create_info, uint table_changes) override; enum_alter_inplace_result check_if_supported_inplace_alter(TABLE *altered_table, Alter_inplace_info *ai) override; void write_lock() { write_locked= 1;} void unlock() { write_locked= 0; } bool is_locked() { return write_locked; } /* Functions that are directly mapped to the underlying handler */ int rnd_init(bool scan) override { return file->rnd_init(scan); } /* We need to have a lock here to protect engines like MyISAM from simultaneous read and write. For sequence's this is not critical as this function is used extremely seldom. */ int rnd_next(uchar *buf) override { int error; table->s->sequence->read_lock(table); error= file->rnd_next(buf); table->s->sequence->read_unlock(table); return error; } int rnd_end() override { return file->rnd_end(); } int rnd_pos(uchar *buf, uchar *pos) override { int error; table->s->sequence->read_lock(table); error= file->rnd_pos(buf, pos); table->s->sequence->read_unlock(table); return error; } void position(const uchar *record) override { return file->position(record); } const char *table_type() const override { return file->table_type(); } ulong index_flags(uint inx, uint part, bool all_parts) const override { return file->index_flags(inx, part, all_parts); } THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) override { return file->store_lock(thd, to, lock_type); } int close(void) override { return file->close(); } const char **bas_ext() const { return file->bas_ext(); } int delete_table(const char*name) override { return file->delete_table(name); } int rename_table(const char *from, const char *to) override { return file->rename_table(from, to); } void unbind_psi() override { file->unbind_psi(); } void rebind_psi() override { file->rebind_psi(); } int discard_or_import_tablespace(my_bool discard) override; bool auto_repair(int error) const override { return file->auto_repair(error); } int repair(THD* thd, HA_CHECK_OPT* check_opt) override { return file->repair(thd, check_opt); } bool check_and_repair(THD *thd) override { return file->check_and_repair(thd); } bool is_crashed() const override { return file->is_crashed(); } void column_bitmaps_signal() override { return file->column_bitmaps_signal(); } /* New methods */ void register_original_handler(handler *file_arg) { file= file_arg; init(); /* Update cached_table_flags */ } }; #endif server/private/probes_mysql_nodtrace.h000064400000011615151031265040014274 0ustar00/* * Generated by dheadgen(1). */ #ifndef _PROBES_MYSQL_D #define _PROBES_MYSQL_D #ifdef __cplusplus extern "C" { #endif #define MYSQL_CONNECTION_START(arg0, arg1, arg2) #define MYSQL_CONNECTION_START_ENABLED() (0) #define MYSQL_CONNECTION_DONE(arg0, arg1) #define MYSQL_CONNECTION_DONE_ENABLED() (0) #define MYSQL_COMMAND_START(arg0, arg1, arg2, arg3) #define MYSQL_COMMAND_START_ENABLED() (0) #define MYSQL_COMMAND_DONE(arg0) #define MYSQL_COMMAND_DONE_ENABLED() (0) #define MYSQL_QUERY_START(arg0, arg1, arg2, arg3, arg4) #define MYSQL_QUERY_START_ENABLED() (0) #define MYSQL_QUERY_DONE(arg0) #define MYSQL_QUERY_DONE_ENABLED() (0) #define MYSQL_QUERY_PARSE_START(arg0) #define MYSQL_QUERY_PARSE_START_ENABLED() (0) #define MYSQL_QUERY_PARSE_DONE(arg0) #define MYSQL_QUERY_PARSE_DONE_ENABLED() (0) #define MYSQL_QUERY_CACHE_HIT(arg0, arg1) #define MYSQL_QUERY_CACHE_HIT_ENABLED() (0) #define MYSQL_QUERY_CACHE_MISS(arg0) #define MYSQL_QUERY_CACHE_MISS_ENABLED() (0) #define MYSQL_QUERY_EXEC_START(arg0, arg1, arg2, arg3, arg4, arg5) #define MYSQL_QUERY_EXEC_START_ENABLED() (0) #define MYSQL_QUERY_EXEC_DONE(arg0) #define MYSQL_QUERY_EXEC_DONE_ENABLED() (0) #define MYSQL_INSERT_ROW_START(arg0, arg1) #define MYSQL_INSERT_ROW_START_ENABLED() (0) #define MYSQL_INSERT_ROW_DONE(arg0) #define MYSQL_INSERT_ROW_DONE_ENABLED() (0) #define MYSQL_UPDATE_ROW_START(arg0, arg1) #define MYSQL_UPDATE_ROW_START_ENABLED() (0) #define MYSQL_UPDATE_ROW_DONE(arg0) #define MYSQL_UPDATE_ROW_DONE_ENABLED() (0) #define MYSQL_DELETE_ROW_START(arg0, arg1) #define MYSQL_DELETE_ROW_START_ENABLED() (0) #define MYSQL_DELETE_ROW_DONE(arg0) #define MYSQL_DELETE_ROW_DONE_ENABLED() (0) #define MYSQL_READ_ROW_START(arg0, arg1, arg2) #define MYSQL_READ_ROW_START_ENABLED() (0) #define MYSQL_READ_ROW_DONE(arg0) #define MYSQL_READ_ROW_DONE_ENABLED() (0) #define MYSQL_INDEX_READ_ROW_START(arg0, arg1) #define MYSQL_INDEX_READ_ROW_START_ENABLED() (0) #define MYSQL_INDEX_READ_ROW_DONE(arg0) #define MYSQL_INDEX_READ_ROW_DONE_ENABLED() (0) #define MYSQL_HANDLER_RDLOCK_START(arg0, arg1) #define MYSQL_HANDLER_RDLOCK_START_ENABLED() (0) #define MYSQL_HANDLER_WRLOCK_START(arg0, arg1) #define MYSQL_HANDLER_WRLOCK_START_ENABLED() (0) #define MYSQL_HANDLER_UNLOCK_START(arg0, arg1) #define MYSQL_HANDLER_UNLOCK_START_ENABLED() (0) #define MYSQL_HANDLER_RDLOCK_DONE(arg0) #define MYSQL_HANDLER_RDLOCK_DONE_ENABLED() (0) #define MYSQL_HANDLER_WRLOCK_DONE(arg0) #define MYSQL_HANDLER_WRLOCK_DONE_ENABLED() (0) #define MYSQL_HANDLER_UNLOCK_DONE(arg0) #define MYSQL_HANDLER_UNLOCK_DONE_ENABLED() (0) #define MYSQL_FILESORT_START(arg0, arg1) #define MYSQL_FILESORT_START_ENABLED() (0) #define MYSQL_FILESORT_DONE(arg0, arg1) #define MYSQL_FILESORT_DONE_ENABLED() (0) #define MYSQL_SELECT_START(arg0) #define MYSQL_SELECT_START_ENABLED() (0) #define MYSQL_SELECT_DONE(arg0, arg1) #define MYSQL_SELECT_DONE_ENABLED() (0) #define MYSQL_INSERT_START(arg0) #define MYSQL_INSERT_START_ENABLED() (0) #define MYSQL_INSERT_DONE(arg0, arg1) #define MYSQL_INSERT_DONE_ENABLED() (0) #define MYSQL_INSERT_SELECT_START(arg0) #define MYSQL_INSERT_SELECT_START_ENABLED() (0) #define MYSQL_INSERT_SELECT_DONE(arg0, arg1) #define MYSQL_INSERT_SELECT_DONE_ENABLED() (0) #define MYSQL_UPDATE_START(arg0) #define MYSQL_UPDATE_START_ENABLED() (0) #define MYSQL_UPDATE_DONE(arg0, arg1, arg2) #define MYSQL_UPDATE_DONE_ENABLED() (0) #define MYSQL_MULTI_UPDATE_START(arg0) #define MYSQL_MULTI_UPDATE_START_ENABLED() (0) #define MYSQL_MULTI_UPDATE_DONE(arg0, arg1, arg2) #define MYSQL_MULTI_UPDATE_DONE_ENABLED() (0) #define MYSQL_DELETE_START(arg0) #define MYSQL_DELETE_START_ENABLED() (0) #define MYSQL_DELETE_DONE(arg0, arg1) #define MYSQL_DELETE_DONE_ENABLED() (0) #define MYSQL_MULTI_DELETE_START(arg0) #define MYSQL_MULTI_DELETE_START_ENABLED() (0) #define MYSQL_MULTI_DELETE_DONE(arg0, arg1) #define MYSQL_MULTI_DELETE_DONE_ENABLED() (0) #define MYSQL_NET_READ_START() #define MYSQL_NET_READ_START_ENABLED() (0) #define MYSQL_NET_READ_DONE(arg0, arg1) #define MYSQL_NET_READ_DONE_ENABLED() (0) #define MYSQL_NET_WRITE_START(arg0) #define MYSQL_NET_WRITE_START_ENABLED() (0) #define MYSQL_NET_WRITE_DONE(arg0) #define MYSQL_NET_WRITE_DONE_ENABLED() (0) #define MYSQL_KEYCACHE_READ_START(arg0, arg1, arg2, arg3) #define MYSQL_KEYCACHE_READ_START_ENABLED() (0) #define MYSQL_KEYCACHE_READ_BLOCK(arg0) #define MYSQL_KEYCACHE_READ_BLOCK_ENABLED() (0) #define MYSQL_KEYCACHE_READ_HIT() #define MYSQL_KEYCACHE_READ_HIT_ENABLED() (0) #define MYSQL_KEYCACHE_READ_MISS() #define MYSQL_KEYCACHE_READ_MISS_ENABLED() (0) #define MYSQL_KEYCACHE_READ_DONE(arg0, arg1) #define MYSQL_KEYCACHE_READ_DONE_ENABLED() (0) #define MYSQL_KEYCACHE_WRITE_START(arg0, arg1, arg2, arg3) #define MYSQL_KEYCACHE_WRITE_START_ENABLED() (0) #define MYSQL_KEYCACHE_WRITE_BLOCK(arg0) #define MYSQL_KEYCACHE_WRITE_BLOCK_ENABLED() (0) #define MYSQL_KEYCACHE_WRITE_DONE(arg0, arg1) #define MYSQL_KEYCACHE_WRITE_DONE_ENABLED() (0) #ifdef __cplusplus } #endif #endif /* _PROBES_MYSQL_D */ server/private/rpl_mi.h000064400000035217151031265040011164 0ustar00/* Copyright (c) 2006, 2012, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef RPL_MI_H #define RPL_MI_H #ifdef HAVE_REPLICATION #include "rpl_rli.h" #include "rpl_reporting.h" #include #include "rpl_filter.h" #include "keycaches.h" typedef struct st_mysql MYSQL; /** Domain id based filter to handle DO_DOMAIN_IDS and IGNORE_DOMAIN_IDS used to set filtering on replication slave based on event's GTID domain_id. */ class Domain_id_filter { private: /* Flag to tell whether the events in the current GTID group get written to the relay log. It is set according to the domain_id based filtering rule on every GTID_EVENT and reset at the end of current GTID event group. */ bool m_filter; public: /* domain id list types */ enum enum_list_type { DO_DOMAIN_IDS= 0, IGNORE_DOMAIN_IDS }; /* DO_DOMAIN_IDS (0): Ignore all the events which do not belong to any of the domain ids in the list. IGNORE_DOMAIN_IDS (1): Ignore the events which belong to one of the domain ids in the list. */ DYNAMIC_ARRAY m_domain_ids[2]; Domain_id_filter(); ~Domain_id_filter(); /* Returns whether the current group needs to be filtered. */ bool is_group_filtered() { return m_filter; } /* Checks whether the group with the specified domain_id needs to be filtered and updates m_filter flag accordingly. */ void do_filter(ulong domain_id); /* Reset m_filter. It should be called when IO thread receives COMMIT_EVENT or XID_EVENT. */ void reset_filter(); /* Clear do_ids and ignore_ids to disable domain id filtering */ void clear_ids(); /* Update the do/ignore domain id filter lists. @param do_ids [IN] domain ids to be kept @param ignore_ids [IN] domain ids to be filtered out @param using_gtid [IN] use GTID? @retval false Success true Error */ bool update_ids(DYNAMIC_ARRAY *do_ids, DYNAMIC_ARRAY *ignore_ids, bool using_gtid); /* Serialize and store the ids from domain id lists into the thd's protocol buffer. @param thd [IN] thread handler @retval void */ void store_ids(THD *thd); /* Initialize the given domain id list (DYNAMIC_ARRAY) with the space-separated list of numbers from the specified IO_CACHE where the first number is the total number of entries to follows. @param f [IN] IO_CACHE file @param type [IN] domain id list type @retval false Success true Error */ bool init_ids(IO_CACHE *f, enum_list_type type); /* Return the elements of the give domain id list type as string. @param type [IN] domain id list type @retval a string buffer storing the total number of elements followed by the individual elements (space-separated) in the specified list. Note: Its caller's responsibility to free the returned string buffer. */ char *as_string(enum_list_type type); }; extern TYPELIB slave_parallel_mode_typelib; typedef struct st_rows_event_tracker { char binlog_file_name[FN_REFLEN]; my_off_t first_seen; my_off_t last_seen; bool stmt_end_seen; void update(const char *file_name, my_off_t pos, const uchar *buf, const Format_description_log_event *fdle); void reset(); bool check_and_report(const char* file_name, my_off_t pos); } Rows_event_tracker; /***************************************************************************** Replication IO Thread Master_info contains: - information about how to connect to a master - current master log name - current master log offset - misc control variables Master_info is initialized once from the master.info file if such exists. Otherwise, data members corresponding to master.info fields are initialized with defaults specified by master-* options. The initialization is done through init_master_info() call. The format of master.info file: log_name log_pos master_host master_user master_pass master_port master_connect_retry To write out the contents of master.info file to disk ( needed every time we read and queue data from the master ), a call to flush_master_info() is required. To clean up, call end_master_info() *****************************************************************************/ class Master_info : public Slave_reporting_capability { public: enum enum_using_gtid { USE_GTID_NO= 0, USE_GTID_CURRENT_POS= 1, USE_GTID_SLAVE_POS= 2 }; Master_info(LEX_CSTRING *connection_name, bool is_slave_recovery); ~Master_info(); bool shall_ignore_server_id(ulong s_id); void clear_in_memory_info(bool all); bool error() { /* If malloc() in initialization failed */ return connection_name.str == 0; } static const char *using_gtid_astext(enum enum_using_gtid arg); bool using_parallel() { return opt_slave_parallel_threads > 0 && parallel_mode > SLAVE_PARALLEL_NONE; } void release(); void wait_until_free(); void lock_slave_threads(); void unlock_slave_threads(); ulonglong get_slave_skip_counter() { return rli.slave_skip_counter; } ulonglong get_max_relay_log_size() { return rli.max_relay_log_size; } /* the variables below are needed because we can change masters on the fly */ char master_log_name[FN_REFLEN+6]; /* Room for multi-*/ char host[HOSTNAME_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1]; char user[USERNAME_LENGTH+1]; char password[MAX_PASSWORD_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1]; LEX_CSTRING connection_name; /* User supplied connection name */ LEX_CSTRING cmp_connection_name; /* Connection name in lower case */ bool ssl; // enables use of SSL connection if true char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN]; char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN]; char ssl_crl[FN_REFLEN], ssl_crlpath[FN_REFLEN]; bool ssl_verify_server_cert; my_off_t master_log_pos; File fd; // we keep the file open, so we need to remember the file pointer IO_CACHE file; mysql_mutex_t data_lock, run_lock, sleep_lock, start_stop_lock; mysql_cond_t data_cond, start_cond, stop_cond, sleep_cond; THD *io_thd; MYSQL* mysql; uint32 file_id; /* for 3.23 load data infile */ Relay_log_info rli; uint port; Rpl_filter* rpl_filter; /* Each replication can set its filter rule*/ /* to hold checksum alg in use until IO thread has received FD. Initialized to novalue, then set to the queried from master @@global.binlog_checksum and deactivated once FD has been received. */ enum enum_binlog_checksum_alg checksum_alg_before_fd; uint connect_retry; #ifndef DBUG_OFF int events_till_disconnect; /* The following are auxiliary DBUG variables used to kill IO thread in the middle of a group/transaction (see "kill_slave_io_after_2_events"). */ bool dbug_do_disconnect; int dbug_event_counter; #endif bool inited; volatile bool abort_slave; volatile uint slave_running; volatile ulong slave_run_id; /* The difference in seconds between the clock of the master and the clock of the slave (second - first). It must be signed as it may be <0 or >0. clock_diff_with_master is computed when the I/O thread starts; for this the I/O thread does a SELECT UNIX_TIMESTAMP() on the master. "how late the slave is compared to the master" is computed like this: clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master */ long clock_diff_with_master; /* Keeps track of the number of events before fsyncing. The option --sync-master-info determines how many events should happen before fsyncing. */ uint sync_counter; float heartbeat_period; // interface with CHANGE MASTER or master.info ulonglong received_heartbeats; // counter of received heartbeat events DYNAMIC_ARRAY ignore_server_ids; ulong master_id; /* At reconnect and until the first rotate event is seen, prev_master_id is the value of master_id during the previous connection, used to detect silent change of master server during reconnects. */ ulong prev_master_id; /* Which kind of GTID position (if any) is used when connecting to master. Note that you can not change the numeric values of these, they are used in master.info. */ enum enum_using_gtid using_gtid; /* This GTID position records how far we have fetched into the relay logs. This is used to continue fetching when the IO thread reconnects to the master. (Full slave stop/start does not use it, as it resets the relay logs). */ slave_connection_state gtid_current_pos; /* If events_queued_since_last_gtid is non-zero, it is the number of events queued so far in the relaylog of a GTID-prefixed event group. It is zero when no partial event group has been queued at the moment. */ uint64 events_queued_since_last_gtid; /* The GTID of the partially-queued event group, when events_queued_since_last_gtid is non-zero. */ rpl_gtid last_queued_gtid; /* Whether last_queued_gtid had the FL_STANDALONE flag set. */ bool last_queued_gtid_standalone; /* When slave IO thread needs to reconnect, gtid_reconnect_event_skip_count counts number of events to skip from the first GTID-prefixed event group, to avoid duplicating events in the relay log. */ uint64 gtid_reconnect_event_skip_count; /* gtid_event_seen is false until we receive first GTID event from master. */ bool gtid_event_seen; /** The struct holds some history of Rows- log-event reading/queuing by the receiver thread. Its fields are updated per each such event at time of queue_event(), and they are checked to detect the Rows- event group integrity violation at time of first non-Rows- event gets handled. */ Rows_event_tracker rows_event_tracker; bool in_start_all_slaves, in_stop_all_slaves; bool in_flush_all_relay_logs; uint users; /* Active user for object */ uint killed; /* No of DDL event group */ Atomic_counter total_ddl_groups; /* No of non-transactional event group*/ Atomic_counter total_non_trans_groups; /* No of transactional event group*/ Atomic_counter total_trans_groups; /* domain-id based filter */ Domain_id_filter domain_id_filter; /* The parallel replication mode. */ enum_slave_parallel_mode parallel_mode; /* semi_ack is used to identify if the current binlog event needs an ACK from slave, or if delay_master is enabled. */ int semi_ack; /* The flag has replicate_same_server_id semantics and is raised to accept a same-server-id event group by the gtid strict mode semisync slave. Own server-id events can normally appear as result of EITHER A. this server semisync (failover to) slave crash-recovery: the transaction was created on this server then being master, got replicated elsewhere right before the crash before commit, and finally at recovery the transaction gets evicted from the server's binlog and its gtid (slave) state; OR B. in a general circular configuration and then when a recieved (returned to slave) gtid exists in the server's binlog. Then, in gtid strict mode, it must be ignored similarly to the replicate-same-server-id rule. */ bool do_accept_own_server_id; /* Set to 1 when semi_sync is enabled. Set to 0 if there is any transmit problems to the slave, in which case any furter semi-sync reply is ignored */ bool semi_sync_reply_enabled; }; int init_master_info(Master_info* mi, const char* master_info_fname, const char* slave_info_fname, bool abort_if_no_master_info_file, int thread_mask); void end_master_info(Master_info* mi); int flush_master_info(Master_info* mi, bool flush_relay_log_cache, bool need_lock_relay_log); void copy_filter_setting(Rpl_filter* dst_filter, Rpl_filter* src_filter); void update_change_master_ids(DYNAMIC_ARRAY *new_ids, DYNAMIC_ARRAY *old_ids); void prot_store_ids(THD *thd, DYNAMIC_ARRAY *ids); /* Multi master are handled trough this struct. Changes to this needs to be protected by LOCK_active_mi; */ class Master_info_index { private: IO_CACHE index_file; char index_file_name[FN_REFLEN]; public: Master_info_index(); ~Master_info_index(); HASH master_info_hash; bool init_all_master_info(); bool write_master_name_to_index_file(LEX_CSTRING *connection_name, bool do_sync); bool check_duplicate_master_info(LEX_CSTRING *connection_name, const char *host, uint port); bool add_master_info(Master_info *mi, bool write_to_file); bool remove_master_info(Master_info *mi); Master_info *get_master_info(const LEX_CSTRING *connection_name, Sql_condition::enum_warning_level warning); bool start_all_slaves(THD *thd); bool stop_all_slaves(THD *thd); void free_connections(); bool flush_all_relay_logs(); }; /* The class rpl_io_thread_info is the THD::system_thread_info for the IO thread. */ class rpl_io_thread_info { public: }; Master_info *get_master_info(const LEX_CSTRING *connection_name, Sql_condition::enum_warning_level warning); bool check_master_connection_name(LEX_CSTRING *name); void create_logfile_name_with_suffix(char *res_file_name, size_t length, const char *info_file, bool append, LEX_CSTRING *suffix); uchar *get_key_master_info(Master_info *mi, size_t *length, my_bool not_used __attribute__((unused))); void free_key_master_info(Master_info *mi); uint any_slave_sql_running(bool already_locked); bool give_error_if_slave_running(bool already_lock); #endif /* HAVE_REPLICATION */ #endif /* RPL_MI_H */ server/private/waiting_threads.h000064400000010664151031265040013055 0ustar00/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _waiting_threads_h #define _waiting_threads_h #include #include C_MODE_START typedef struct st_wt_resource_id WT_RESOURCE_ID; typedef struct st_wt_resource WT_RESOURCE; typedef struct st_wt_resource_type { my_bool (*compare)(const void *a, const void *b); const void *(*make_key)(const WT_RESOURCE_ID *id, uint *len); /* not used */ } WT_RESOURCE_TYPE; struct st_wt_resource_id { ulonglong value; const WT_RESOURCE_TYPE *type; }; /* the below differs from sizeof(WT_RESOURCE_ID) by the amount of padding */ #define sizeof_WT_RESOURCE_ID (sizeof(ulonglong)+sizeof(void*)) #define WT_WAIT_STATS 24 #define WT_CYCLE_STATS 32 extern ulonglong wt_wait_table[WT_WAIT_STATS]; extern uint32 wt_wait_stats[WT_WAIT_STATS+1]; extern uint32 wt_cycle_stats[2][WT_CYCLE_STATS+1]; extern uint32 wt_success_stats; typedef struct st_wt_thd { /* XXX there's no protection (mutex) against concurrent access of the dynarray below. it is assumed that a caller will have it anyway (not to protect this array but to protect its own - caller's - data structures), and we'll get it for free. A caller needs to ensure that a blocker won't release a resource before a blocked thread starts waiting, which is usually done with a mutex. If the above assumption is wrong, we'll need to add a mutex here. */ DYNAMIC_ARRAY my_resources; /* 'waiting_for' is modified under waiting_for->lock, and only by thd itself 'waiting_for' is read lock-free (using pinning protocol), but a thd object can read its own 'waiting_for' without any locks or tricks. */ WT_RESOURCE *waiting_for; LF_PINS *pins; /* pointers to values */ const ulong *timeout_short; const ulong *deadlock_search_depth_short; const ulong *timeout_long; const ulong *deadlock_search_depth_long; /* weight relates to the desirability of a transaction being killed if it's part of a deadlock. In a deadlock situation transactions with lower weights are killed first. Examples of using the weight to implement different selection strategies: 1. Latest Keep all weights equal. 2. Random Assign weights at random. (variant: modify a weight randomly before every lock request) 3. Youngest Set weight to -NOW() 4. Minimum locks count locks granted in your lock manager, store the value as a weight 5. Minimum work depends on the definition of "work". For example, store the number of rows modifies in this transaction (or a length of REDO log for a transaction) as a weight. It is only statistically relevant and is not protected by any locks. */ ulong volatile weight; /* 'killed' is indirectly protected by waiting_for->lock because a killed thread needs to clear its 'waiting_for' and thus needs a lock. That is a thread needs an exclusive lock to read 'killed' reliably. But other threads may change 'killed' from 0 to 1, a shared lock is enough for that. */ my_bool killed; #ifndef DBUG_OFF const char *name; #endif } WT_THD; #define WT_TIMEOUT ETIMEDOUT #define WT_OK 0 #define WT_DEADLOCK -1 #define WT_DEPTH_EXCEEDED -2 #define WT_FREE_TO_GO -3 void wt_init(void); void wt_end(void); void wt_thd_lazy_init(WT_THD *, const ulong *, const ulong *, const ulong *, const ulong *); void wt_thd_destroy(WT_THD *); int wt_thd_will_wait_for(WT_THD *, WT_THD *, const WT_RESOURCE_ID *); int wt_thd_cond_timedwait(WT_THD *, mysql_mutex_t *); void wt_thd_release(WT_THD *, const WT_RESOURCE_ID *); #define wt_thd_release_all(THD) wt_thd_release((THD), 0) my_bool wt_resource_id_memcmp(const void *, const void *); C_MODE_END #endif server/private/mysqld_default_groups.h000064400000000314151031265040014304 0ustar00const char *load_default_groups[]= { "mysqld", "server", MYSQL_BASE_VERSION, "mariadb", MARIADB_BASE_VERSION, "mariadbd", MARIADBD_BASE_VERSION, "client-server", #ifdef WITH_WSREP "galera", #endif 0, 0}; server/private/item_cmpfunc.h000064400000407563151031265040012362 0ustar00#ifndef ITEM_CMPFUNC_INCLUDED #define ITEM_CMPFUNC_INCLUDED /* Copyright (c) 2000, 2015, Oracle and/or its affiliates. Copyright (c) 2009, 2022, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* compare and test functions */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "item_func.h" /* Item_int_func, Item_bool_func */ #include "item.h" extern Item_result item_cmp_type(Item_result a,Item_result b); inline Item_result item_cmp_type(const Item *a, const Item *b) { return item_cmp_type(a->cmp_type(), b->cmp_type()); } inline Item_result item_cmp_type(Item_result a, const Item *b) { return item_cmp_type(a, b->cmp_type()); } class Item_bool_func2; class Arg_comparator; typedef int (Arg_comparator::*arg_cmp_func)(); typedef int (*Item_field_cmpfunc)(Item *f1, Item *f2, void *arg); class Arg_comparator: public Sql_alloc { Item **a, **b; const Type_handler *m_compare_handler; CHARSET_INFO *m_compare_collation; arg_cmp_func func; Item_func_or_sum *owner; bool set_null; // TRUE <=> set owner->null_value Arg_comparator *comparators; // used only for compare_row() double precision; /* Fields used in DATE/DATETIME comparison. */ Item *a_cache, *b_cache; // Cached values of a and b items // when one of arguments is NULL. int set_cmp_func(THD *thd, Item_func_or_sum *owner_arg, const Type_handler *compare_handler, Item **a1, Item **a2); int compare_not_null_values(longlong val1, longlong val2) { if (set_null) owner->null_value= false; if (val1 < val2) return -1; if (val1 == val2) return 0; return 1; } NativeBuffer m_native1, m_native2; public: /* Allow owner function to use string buffers. */ String value1, value2; Arg_comparator(): m_compare_handler(&type_handler_null), m_compare_collation(&my_charset_bin), set_null(TRUE), comparators(0), a_cache(0), b_cache(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), m_compare_handler(&type_handler_null), m_compare_collation(&my_charset_bin), set_null(TRUE), comparators(0), a_cache(0), b_cache(0) {}; public: bool set_cmp_func_for_row_arguments(THD *thd); bool set_cmp_func_row(THD *thd); bool set_cmp_func_string(THD *thd); bool set_cmp_func_time(THD *thd); bool set_cmp_func_datetime(THD *thd); bool set_cmp_func_native(THD *thd); bool set_cmp_func_int(THD *thd); bool set_cmp_func_real(THD *thd); bool set_cmp_func_decimal(THD *thd); inline int set_cmp_func(THD *thd, Item_func_or_sum *owner_arg, const Type_handler *compare_handler, Item **a1, Item **a2, bool set_null_arg) { set_null= set_null_arg; return set_cmp_func(thd, owner_arg, compare_handler, a1, a2); } int set_cmp_func(THD *thd, Item_func_or_sum *owner_arg, Item **a1, Item **a2, bool set_null_arg) { Item *tmp_args[2]= { *a1, *a2 }; Type_handler_hybrid_field_type tmp; if (tmp.aggregate_for_comparison(owner_arg->func_name_cstring(), tmp_args, 2, false)) return 1; return set_cmp_func(thd, owner_arg, tmp.type_handler(), a1, a2, set_null_arg); } inline int compare() { return (this->*func)(); } int compare_string(); // compare args[0] & args[1] int compare_real(); // compare args[0] & args[1] int compare_decimal(); // compare args[0] & args[1] int compare_int_signed(); // compare args[0] & args[1] int compare_int_signed_unsigned(); int compare_int_unsigned_signed(); int compare_int_unsigned(); int compare_row(); // compare args[0] & args[1] int compare_e_string(); // compare args[0] & args[1] int compare_e_real(); // compare args[0] & args[1] int compare_e_decimal(); // compare args[0] & args[1] int compare_e_int(); // compare args[0] & args[1] int compare_e_int_diff_signedness(); int compare_e_row(); // compare args[0] & args[1] int compare_real_fixed(); int compare_e_real_fixed(); int compare_datetime(); int compare_e_datetime(); int compare_time(); int compare_e_time(); int compare_native(); int compare_e_native(); int compare_json_str_basic(Item *j, Item *s); int compare_json_str(); int compare_str_json(); int compare_e_json_str_basic(Item *j, Item *s); int compare_e_json_str(); int compare_e_str_json(); void min_max_update_field_native(THD *thd, Field *field, Item *item, int cmp_sign); Item** cache_converted_constant(THD *thd, Item **value, Item **cache, const Type_handler *type); inline bool is_owner_equal_func() { return (owner->type() == Item::FUNC_ITEM && ((Item_func*)owner)->functype() == Item_func::EQUAL_FUNC); } const Type_handler *compare_type_handler() const { return m_compare_handler; } Item_result compare_type() const { return m_compare_handler->cmp_type(); } CHARSET_INFO *compare_collation() const { return m_compare_collation; } Arg_comparator *subcomparators() const { return comparators; } void cleanup() { delete [] comparators; comparators= 0; } friend class Item_func; friend class Item_bool_rowready_func2; }; class SEL_ARG; struct KEY_PART; class Item_bool_func :public Item_int_func, public Type_cmp_attributes { protected: /* Build a SEL_TREE for a simple predicate @param param PARAM from SQL_SELECT::test_quick_select @param field field in the predicate @param value constant in the predicate @return Pointer to the tree built tree */ virtual SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value) { DBUG_ENTER("Item_bool_func::get_func_mm_tree"); DBUG_ASSERT(0); DBUG_RETURN(0); } /* Return the full select tree for "field_item" and "value": - a single SEL_TREE if the field is not in a multiple equality, or - a conjunction of all SEL_TREEs for all fields from the same multiple equality with "field_item". */ SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param, Item_field *field_item, Item *value); /** Test if "item" and "value" are suitable for the range optimization and get their full select tree. "Suitable" means: - "item" is a field or a field reference - "value" is NULL (e.g. WHERE field IS NULL), or "value" is an unexpensive item (e.g. WHERE field OP value) @param item - the argument that is checked to be a field @param value - the other argument @returns - NULL if the arguments are not suitable for the range optimizer. @returns - the full select tree if the arguments are suitable. */ SEL_TREE *get_full_func_mm_tree_for_args(RANGE_OPT_PARAM *param, Item *item, Item *value) { DBUG_ENTER("Item_bool_func::get_full_func_mm_tree_for_args"); Item *field= item->real_item(); if (field->type() == Item::FIELD_ITEM && !field->const_item() && (!value || !value->is_expensive())) DBUG_RETURN(get_full_func_mm_tree(param, (Item_field *) field, value)); DBUG_RETURN(NULL); } SEL_TREE *get_mm_parts(RANGE_OPT_PARAM *param, Field *field, Item_func::Functype type, Item *value); SEL_TREE *get_ne_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *lt_value, Item *gt_value); virtual SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, Field *field, KEY_PART *key_part, Item_func::Functype type, Item *value); void raise_note_if_key_become_unused(THD *thd, const Item_args &old_args); public: Item_bool_func(THD *thd): Item_int_func(thd) {} Item_bool_func(THD *thd, Item *a): Item_int_func(thd, a) {} Item_bool_func(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} Item_bool_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} Item_bool_func(THD *thd, List &list): Item_int_func(thd, list) { } Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {} const Type_handler *type_handler() const override { return &type_handler_bool; } const Type_handler *fixed_type_handler() const override { return &type_handler_bool; } CHARSET_INFO *compare_collation() const override { return NULL; } longlong val_int() override final { DBUG_ASSERT(!is_cond()); return val_bool(); } bool val_bool() override= 0; bool fix_length_and_dec() override { decimals=0; max_length=1; return FALSE; } decimal_digits_t decimal_precision() const override { return 1; } bool need_parentheses_in_default() override { return true; } }; /** Abstract Item class, to represent X IS [NOT] (TRUE | FALSE) boolean predicates. */ class Item_func_truth : public Item_bool_func { public: bool val_bool() override; bool fix_length_and_dec() override; void print(String *str, enum_query_type query_type) override; enum precedence precedence() const override { return CMP_PRECEDENCE; } protected: Item_func_truth(THD *thd, Item *a, bool a_value, bool a_affirmative): Item_bool_func(thd, a), value(a_value), affirmative(a_affirmative) {} ~Item_func_truth() = default; private: /** True for X IS [NOT] TRUE, false for X IS [NOT] FALSE predicates. */ const bool value; /** True for X IS Y, false for X IS NOT Y predicates. */ const bool affirmative; }; /** This Item represents a X IS TRUE boolean predicate. */ class Item_func_istrue : public Item_func_truth { public: Item_func_istrue(THD *thd, Item *a): Item_func_truth(thd, a, true, true) {} ~Item_func_istrue() = default; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("istrue") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /** This Item represents a X IS NOT TRUE boolean predicate. */ class Item_func_isnottrue : public Item_func_truth { public: Item_func_isnottrue(THD *thd, Item *a): Item_func_truth(thd, a, true, false) {} ~Item_func_isnottrue() = default; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("isnottrue") }; return name; } bool find_not_null_fields(table_map allowed) override { return false; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } bool eval_not_null_tables(void *) override { not_null_tables_cache= 0; return false; } }; /** This Item represents a X IS FALSE boolean predicate. */ class Item_func_isfalse : public Item_func_truth { public: Item_func_isfalse(THD *thd, Item *a): Item_func_truth(thd, a, false, true) {} ~Item_func_isfalse() = default; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("isfalse") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /** This Item represents a X IS NOT FALSE boolean predicate. */ class Item_func_isnotfalse : public Item_func_truth { public: Item_func_isnotfalse(THD *thd, Item *a): Item_func_truth(thd, a, false, false) {} ~Item_func_isnotfalse() = default; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("isnotfalse") }; return name; } bool find_not_null_fields(table_map allowed) override { return false; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } bool eval_not_null_tables(void *) override { not_null_tables_cache= 0; return false; } }; class Item_cache; #define UNKNOWN (-1) /* Item_in_optimizer(left_expr, Item_in_subselect(...)) Item_in_optimizer is used to wrap an instance of Item_in_subselect. This class does the following: - Evaluate the left expression and store it in Item_cache_* object (to avoid re-evaluating it many times during subquery execution) - Shortcut the evaluation of "NULL IN (...)" to NULL in the cases where we don't care if the result is NULL or FALSE. NOTE It is not quite clear why the above listed functionality should be placed into a separate class called 'Item_in_optimizer'. */ class Item_in_optimizer: public Item_bool_func { protected: Item_cache *cache; Item *expr_cache; /* Stores the value of "NULL IN (SELECT ...)" for uncorrelated subqueries: UNKNOWN - "NULL in (SELECT ...)" has not yet been evaluated FALSE - result is FALSE TRUE - result is NULL */ int result_for_null_param; public: Item_in_optimizer(THD *thd, Item *a, Item *b): Item_bool_func(thd, a, b), cache(0), expr_cache(0), result_for_null_param(UNKNOWN) { with_flags|= item_with_t::SUBQUERY; } bool fix_fields(THD *, Item **) override; bool fix_left(THD *thd); table_map not_null_tables() const override { return 0; } bool is_null() override; bool val_bool() override; void cleanup() override; enum Functype functype() const override { return IN_OPTIMIZER_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("") }; return name; } Item_cache **get_cache() { return &cache; } Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override; Item *expr_cache_insert_transformer(THD *thd, uchar *unused) override; bool is_expensive_processor(void *arg) override; bool is_expensive() override; void set_join_tab_idx(uint8 join_tab_idx_arg) override { args[1]->set_join_tab_idx(join_tab_idx_arg); } void get_cache_parameters(List ¶meters) override; bool is_top_level_item() const override; bool eval_not_null_tables(void *opt_arg) override; bool find_not_null_fields(table_map allowed) override; void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; bool invisible_mode(); bool walk(Item_processor processor, bool walk_subquery, void *arg) override; void reset_cache() { cache= NULL; } void print(String *str, enum_query_type query_type) override; void restore_first_argument(); Item* get_wrapped_in_subselect_item() { return args[1]; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } enum precedence precedence() const override { return args[1]->precedence(); } }; /* Functions and operators with two arguments that can use range optimizer. */ class Item_bool_func2 :public Item_bool_func { /* Bool with 2 string args */ protected: void add_key_fields_optimize_op(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables, bool equal_func); public: Item_bool_func2(THD *thd, Item *a, Item *b): Item_bool_func(thd, a, b) { } bool is_null() override { return MY_TEST(args[0]->is_null() || args[1]->is_null()); } COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value, bool top_level) override; bool count_sargable_conds(void *arg) override; /* Specifies which result type the function uses to compare its arguments. This method is used in equal field propagation. */ virtual const Type_handler *compare_type_handler() const { /* Have STRING_RESULT by default, which means the function compares val_str() results of the arguments. This is suitable for Item_func_like and for Item_func_spatial_rel. Note, Item_bool_rowready_func2 overrides this default behaviour. */ return &type_handler_varchar; } SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) override { DBUG_ENTER("Item_bool_func2::get_mm_tree"); DBUG_ASSERT(arg_count == 2); SEL_TREE *ftree= get_full_func_mm_tree_for_args(param, args[0], args[1]); if (!ftree) ftree= Item_func::get_mm_tree(param, cond_ptr); DBUG_RETURN(ftree); } }; /** A class for functions and operators that can use the range optimizer and have a reverse function/operator that can also use the range optimizer, so this condition: WHERE value OP field can be optimized as equivalent to: WHERE field REV_OP value This class covers: - scalar comparison predicates: <, <=, =, <=>, >=, > - MBR and precise spatial relation predicates (e.g. SP_TOUCHES(x,y)) For example: WHERE 10 > field can be optimized as: WHERE field < 10 */ class Item_bool_func2_with_rev :public Item_bool_func2 { protected: SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value) override { DBUG_ENTER("Item_bool_func2_with_rev::get_func_mm_tree"); Item_func::Functype func_type= (value != arguments()[0]) ? functype() : rev_functype(); DBUG_RETURN(get_mm_parts(param, field, func_type, value)); } public: Item_bool_func2_with_rev(THD *thd, Item *a, Item *b): Item_bool_func2(thd, a, b) { } virtual enum Functype rev_functype() const= 0; SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) override { DBUG_ENTER("Item_bool_func2_with_rev::get_mm_tree"); DBUG_ASSERT(arg_count == 2); SEL_TREE *ftree; /* Even if get_full_func_mm_tree_for_args(param, args[0], args[1]) will not return a range predicate it may still be possible to create one by reversing the order of the operands. Note that this only applies to predicates where both operands are fields. Example: A query of the form WHERE t1.a OP t2.b In this case, args[0] == t1.a and args[1] == t2.b. When creating range predicates for t2, get_full_func_mm_tree_for_args(param, args[0], args[1]) will return NULL because 'field' belongs to t1 and only predicates that applies to t2 are of interest. In this case a call to get_full_func_mm_tree_for_args() with reversed operands may succeed. */ if (!(ftree= get_full_func_mm_tree_for_args(param, args[0], args[1])) && !(ftree= get_full_func_mm_tree_for_args(param, args[1], args[0]))) ftree= Item_func::get_mm_tree(param, cond_ptr); DBUG_RETURN(ftree); } }; class Item_bool_rowready_func2 :public Item_bool_func2_with_rev { protected: Arg_comparator cmp; bool check_arguments() const override { return check_argument_types_like_args0(); } public: Item_bool_rowready_func2(THD *thd, Item *a, Item *b): Item_bool_func2_with_rev(thd, a, b), cmp(tmp_arg, tmp_arg + 1) { } Sql_mode_dependency value_depends_on_sql_mode() const override; void print(String *str, enum_query_type query_type) override { Item_func::print_op(str, query_type); } enum precedence precedence() const override { return CMP_PRECEDENCE; } Item *neg_transformer(THD *thd) override; virtual Item *negated_item(THD *thd); Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { Item_args::propagate_equal_fields(thd, Context(ANY_SUBST, cmp.compare_type_handler(), compare_collation()), cond); return this; } bool fix_length_and_dec() override; bool fix_length_and_dec_generic(THD *thd, const Type_handler *compare_handler) { DBUG_ASSERT(args == tmp_arg); return cmp.set_cmp_func(thd, this, compare_handler, tmp_arg, tmp_arg + 1, true/*set_null*/); } int set_cmp_func(THD *thd) { DBUG_ASSERT(args == tmp_arg); return cmp.set_cmp_func(thd, this, tmp_arg, tmp_arg + 1, true/*set_null*/); } CHARSET_INFO *compare_collation() const override { return cmp.compare_collation(); } const Type_handler *compare_type_handler() const override { return cmp.compare_type_handler(); } Arg_comparator *get_comparator() { return &cmp; } void cleanup() override { Item_bool_func2::cleanup(); cmp.cleanup(); } void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override { return add_key_fields_optimize_op(join, key_fields, and_level, usable_tables, sargables, false); } Item *do_build_clone(THD *thd) const override { Item_bool_rowready_func2 *clone= (Item_bool_rowready_func2 *) Item_func::do_build_clone(thd); if (clone) { clone->cmp.comparators= 0; } return clone; } }; /** XOR inherits from Item_bool_func because it is not optimized yet. Later, when XOR is optimized, it needs to inherit from Item_cond instead. See WL#5800. */ class Item_func_xor :public Item_bool_func { public: Item_func_xor(THD *thd, Item *i1, Item *i2): Item_bool_func(thd, i1, i2) {} enum Functype functype() const override { return XOR_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("xor") }; return name; } enum precedence precedence() const override { return XOR_PRECEDENCE; } void print(String *str, enum_query_type query_type) override { Item_func::print_op(str, query_type); } bool val_bool() override; bool find_not_null_fields(table_map allowed) override { return false; } Item *neg_transformer(THD *thd) override; Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { Item_args::propagate_equal_fields(thd, Context_boolean(), cond); return this; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_not :public Item_bool_func { bool abort_on_null; public: Item_func_not(THD *thd, Item *a): Item_bool_func(thd, a), abort_on_null(FALSE) {} void top_level_item() override { abort_on_null= 1; } bool is_top_level_item() const override { return abort_on_null; } bool val_bool() override; enum Functype functype() const override { return NOT_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("not") }; return name; } bool find_not_null_fields(table_map allowed) override { return false; } enum precedence precedence() const override { return NEG_PRECEDENCE; } Item *neg_transformer(THD *thd) override; bool fix_fields(THD *, Item **) override; void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_maxmin_subselect; /* trigcond(arg) ::= param? arg : TRUE The class Item_func_trig_cond is used for guarded predicates which are employed only for internal purposes. A guarded predicate is an object consisting of an a regular or a guarded predicate P and a pointer to a boolean guard variable g. A guarded predicate P/g is evaluated to true if the value of the guard g is false, otherwise it is evaluated to the same value that the predicate P: val(P/g)= g ? val(P):true. Guarded predicates allow us to include predicates into a conjunction conditionally. Currently they are utilized for pushed down predicates in queries with outer join operations. In the future, probably, it makes sense to extend this class to the objects consisting of three elements: a predicate P, a pointer to a variable g and a firing value s with following evaluation rule: val(P/g,s)= g==s? val(P) : true. It will allow us to build only one item for the objects of the form P/g1/g2... Objects of this class are built only for query execution after the execution plan has been already selected. That's why this class needs only val_int out of generic methods. Current uses of Item_func_trig_cond objects: - To wrap selection conditions when executing outer joins - To wrap condition that is pushed down into subquery */ class Item_func_trig_cond: public Item_bool_func { bool *trig_var; public: Item_func_trig_cond(THD *thd, Item *a, bool *f): Item_bool_func(thd, a) { trig_var= f; } bool val_bool() override { return *trig_var ? args[0]->val_bool() : true; } enum Functype functype() const override { return TRIG_COND_FUNC; }; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("trigcond") }; return name; } bool const_item() const override { return FALSE; } bool *get_trig_var() { return trig_var; } void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_not_all :public Item_func_not { /* allow to check presence of values in max/min optimization */ Item_sum_min_max *test_sum_item; Item_maxmin_subselect *test_sub_item; public: bool show; Item_func_not_all(THD *thd, Item *a): Item_func_not(thd, a), test_sum_item(0), test_sub_item(0), show(0) {} table_map not_null_tables() const override { return 0; } bool val_bool() override; enum Functype functype() const override { return NOT_ALL_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("") }; return name; } enum precedence precedence() const override { return show ? Item_func::precedence() : args[0]->precedence(); } bool fix_fields(THD *thd, Item **ref) override { return Item_func::fix_fields(thd, ref);} void print(String *str, enum_query_type query_type) override; void set_sum_test(Item_sum_min_max *item) { test_sum_item= item; test_sub_item= 0; }; void set_sub_test(Item_maxmin_subselect *item) { test_sub_item= item; test_sum_item= 0;}; bool empty_underlying_subquery(); Item *neg_transformer(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_nop_all :public Item_func_not_all { public: Item_func_nop_all(THD *thd, Item *a): Item_func_not_all(thd, a) {} bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("") }; return name; } Item *neg_transformer(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_eq :public Item_bool_rowready_func2 { bool abort_on_null; public: Item_func_eq(THD *thd, Item *a, Item *b): Item_bool_rowready_func2(thd, a, b), abort_on_null(false), in_equality_no(UINT_MAX) {} bool val_bool() override; enum Functype functype() const override { return EQ_FUNC; } enum Functype rev_functype() const override { return EQ_FUNC; } cond_result eq_cmp_result() const override { return COND_TRUE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("=") }; return name; } void top_level_item() override { abort_on_null= true; } Item *negated_item(THD *thd) override; COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) override; void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override { return add_key_fields_optimize_op(join, key_fields, and_level, usable_tables, sargables, true); } bool check_equality(THD *thd, COND_EQUAL *cond, List *eq_list) override; /* - If this equality is created from the subquery's IN-equality: number of the item it was created from, e.g. for (a,b) IN (SELECT c,d ...) a=c will have in_equality_no=0, and b=d will have in_equality_no=1. - Otherwise, UINT_MAX */ uint in_equality_no; uint exists2in_reserved_items() override { return 1; }; friend class Arg_comparator; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override; }; class Item_func_equal final :public Item_bool_rowready_func2 { public: Item_func_equal(THD *thd, Item *a, Item *b): Item_bool_rowready_func2(thd, a, b) {} bool val_bool() override; bool fix_length_and_dec() override; table_map not_null_tables() const override { return 0; } bool find_not_null_fields(table_map allowed) override { return false; } enum Functype functype() const override { return EQUAL_FUNC; } enum Functype rev_functype() const override { return EQUAL_FUNC; } cond_result eq_cmp_result() const override { return COND_TRUE; } bool is_null() override { return false; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("<=>") }; return name; } Item *neg_transformer(THD *thd) override { return 0; } void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override { return add_key_fields_optimize_op(join, key_fields, and_level, usable_tables, sargables, true); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_ge :public Item_bool_rowready_func2 { public: Item_func_ge(THD *thd, Item *a, Item *b): Item_bool_rowready_func2(thd, a, b) {}; bool val_bool() override; enum Functype functype() const override { return GE_FUNC; } enum Functype rev_functype() const override { return LE_FUNC; } cond_result eq_cmp_result() const override { return COND_TRUE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN(">=") }; return name; } Item *negated_item(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_gt :public Item_bool_rowready_func2 { public: Item_func_gt(THD *thd, Item *a, Item *b): Item_bool_rowready_func2(thd, a, b) {}; bool val_bool() override; enum Functype functype() const override { return GT_FUNC; } enum Functype rev_functype() const override { return LT_FUNC; } cond_result eq_cmp_result() const override { return COND_FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN(">") }; return name; } Item *negated_item(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_le :public Item_bool_rowready_func2 { public: Item_func_le(THD *thd, Item *a, Item *b): Item_bool_rowready_func2(thd, a, b) {}; bool val_bool() override; enum Functype functype() const override { return LE_FUNC; } enum Functype rev_functype() const override { return GE_FUNC; } cond_result eq_cmp_result() const override { return COND_TRUE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("<=") }; return name; } Item *negated_item(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_lt :public Item_bool_rowready_func2 { public: Item_func_lt(THD *thd, Item *a, Item *b): Item_bool_rowready_func2(thd, a, b) {} bool val_bool() override; enum Functype functype() const override { return LT_FUNC; } enum Functype rev_functype() const override { return GT_FUNC; } cond_result eq_cmp_result() const override { return COND_FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("<") }; return name; } Item *negated_item(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_ne :public Item_bool_rowready_func2 { protected: SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value) override; public: Item_func_ne(THD *thd, Item *a, Item *b): Item_bool_rowready_func2(thd, a, b) {} bool val_bool() override; enum Functype functype() const override { return NE_FUNC; } enum Functype rev_functype() const override { return NE_FUNC; } cond_result eq_cmp_result() const override { return COND_FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("<>") }; return name; } Item *negated_item(THD *thd) override; void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* The class Item_func_opt_neg is defined to factor out the functionality common for the classes Item_func_between and Item_func_in. The objects of these classes can express predicates or there negations. The alternative approach would be to create pairs Item_func_between, Item_func_notbetween and Item_func_in, Item_func_notin. */ class Item_func_opt_neg :public Item_bool_func { protected: /* The data type handler that will be used for comparison. Data type handlers of all arguments are mixed to here. */ Type_handler_hybrid_field_type m_comparator; /* The collation that will be used for comparison in case when m_compare_type is STRING_RESULT. */ DTCollation cmp_collation; public: bool negated; /* <=> the item represents NOT */ bool pred_level; /* <=> [NOT] is used on a predicate level */ public: Item_func_opt_neg(THD *thd, Item *a, Item *b, Item *c): Item_bool_func(thd, a, b, c), negated(0), pred_level(0) {} Item_func_opt_neg(THD *thd, List &list): Item_bool_func(thd, list), negated(0), pred_level(0) {} public: void top_level_item() override { pred_level= 1; } bool is_top_level_item() const override { return pred_level; } Item *neg_transformer(THD *thd) override { negated= !negated; return this; } bool eq(const Item *item, bool binary_cmp) const override; CHARSET_INFO *compare_collation() const override { return cmp_collation.collation; } Item *propagate_equal_fields(THD *, const Context &, COND_EQUAL *) override= 0; }; class Item_func_between :public Item_func_opt_neg { protected: SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value) override; bool val_int_cmp_int_finalize(longlong value, longlong a, longlong b); public: String value0,value1,value2; Item_func_between(THD *thd, Item *a, Item *b, Item *c): Item_func_opt_neg(thd, a, b, c) { } bool val_bool() override { DBUG_ASSERT(fixed()); return m_comparator.type_handler()->Item_func_between_val_int(this); } enum Functype functype() const override { return BETWEEN; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("between") }; return name; } enum precedence precedence() const override { return BETWEEN_PRECEDENCE; } bool fix_length_and_dec() override; bool fix_length_and_dec_string(THD *) { return agg_arg_charsets_for_comparison(cmp_collation, args, 3); } bool fix_length_and_dec_temporal(THD *); bool fix_length_and_dec_numeric(THD *); void print(String *str, enum_query_type query_type) override; bool eval_not_null_tables(void *opt_arg) override; bool find_not_null_fields(table_map allowed) override; void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; bool count_sargable_conds(void *arg) override; void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override; SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) override; Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { Item_args::propagate_equal_fields(thd, Context(ANY_SUBST, m_comparator.type_handler(), compare_collation()), cond); return this; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } longlong val_int_cmp_string(); longlong val_int_cmp_datetime(); longlong val_int_cmp_time(); longlong val_int_cmp_native(); longlong val_int_cmp_int(); longlong val_int_cmp_real(); longlong val_int_cmp_decimal(); }; class Item_func_strcmp :public Item_long_func { bool check_arguments() const override { return check_argument_types_can_return_str(0, 2); } String value1, value2; DTCollation cmp_collation; public: Item_func_strcmp(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} longlong val_int() override; decimal_digits_t decimal_precision() const override { return 1; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("strcmp") }; return name; } bool fix_length_and_dec() override { if (agg_arg_charsets_for_comparison(cmp_collation, args, 2)) return TRUE; fix_char_length(2); // returns "1" or "0" or "-1" return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; struct interval_range { Item_result type; double dbl; my_decimal dec; }; class Item_func_interval :public Item_long_func { Item_row *row; bool use_decimal_comparison; interval_range *intervals; bool check_arguments() const override { return check_argument_types_like_args0(); } public: Item_func_interval(THD *thd, Item_row *a): Item_long_func(thd, a), row(a), intervals(0) { } longlong val_int() override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("interval") }; return name; } decimal_digits_t decimal_precision() const override { return 2; } void print(String *str, enum_query_type query_type) override { str->append(func_name_cstring()); print_args(str, 0, query_type); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_coalesce :public Item_func_case_expression { public: Item_func_coalesce(THD *thd, Item *a, Item *b): Item_func_case_expression(thd, a, b) {} Item_func_coalesce(THD *thd, List &list): Item_func_case_expression(thd, list) {} double real_op() override; longlong int_op() override; String *str_op(String *) override; my_decimal *decimal_op(my_decimal *) override; bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool time_op(THD *thd, MYSQL_TIME *ltime) override; bool native_op(THD *thd, Native *to) override; bool fix_length_and_dec() override { if (aggregate_for_result(func_name_cstring(), args, arg_count, true)) return TRUE; fix_attributes(args, arg_count); return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("coalesce") }; return name; } table_map not_null_tables() const override { return 0; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Case abbreviations that aggregate its result field type by two arguments: IFNULL(arg1, arg2) IF(switch, arg1, arg2) NVL2(switch, arg1, arg2) */ class Item_func_case_abbreviation2 :public Item_func_case_expression { protected: bool fix_length_and_dec2(Item **items) { if (aggregate_for_result(func_name_cstring(), items, 2, true)) return TRUE; fix_attributes(items, 2); return FALSE; } void cache_type_info(const Item *source, bool maybe_null_arg) { Type_std_attributes::set(source); set_handler(source->type_handler()); set_maybe_null(maybe_null_arg); } bool fix_length_and_dec2_eliminate_null(Item **items) { // Let IF(cond, expr, NULL) and IF(cond, NULL, expr) inherit type from expr. if (items[0]->type() == NULL_ITEM) { cache_type_info(items[1], true); // If both arguments are NULL, make resulting type BINARY(0). if (items[1]->type() == NULL_ITEM) set_handler(&type_handler_string); } else if (items[1]->type() == NULL_ITEM) { cache_type_info(items[0], true); } else { if (fix_length_and_dec2(items)) return TRUE; } return FALSE; } public: Item_func_case_abbreviation2(THD *thd, Item *a, Item *b): Item_func_case_expression(thd, a, b) { } Item_func_case_abbreviation2(THD *thd, Item *a, Item *b, Item *c): Item_func_case_expression(thd, a, b, c) { } }; class Item_func_ifnull :public Item_func_case_abbreviation2 { public: Item_func_ifnull(THD *thd, Item *a, Item *b): Item_func_case_abbreviation2(thd, a, b) {} double real_op() override; longlong int_op() override; String *str_op(String *str) override; my_decimal *decimal_op(my_decimal *) override; bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool time_op(THD *thd, MYSQL_TIME *ltime) override; bool native_op(THD *thd, Native *to) override; bool fix_length_and_dec() override { /* Set nullability from args[1] by default. Note, some type handlers may reset maybe_null in Item_hybrid_func_fix_attributes() if args[1] is NOT NULL but cannot always be converted to the data type of "this" safely. E.g. Type_handler_inet6 does: IFNULL(inet6_not_null_expr, 'foo') -> INET6 NULL IFNULL(inet6_not_null_expr, '::1') -> INET6 NOT NULL */ copy_flags(args[1], item_base_t::MAYBE_NULL); if (Item_func_case_abbreviation2::fix_length_and_dec2(args)) return TRUE; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("ifnull") }; return name; } table_map not_null_tables() const override { return 0; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /** Case abbreviations that have a switch argument and two return arguments to choose from. Returns the value of either of the two return arguments depending on the switch argument value. IF(switch, arg1, arg2) NVL(switch, arg1, arg2) */ class Item_func_case_abbreviation2_switch: public Item_func_case_abbreviation2 { protected: virtual Item *find_item() const= 0; public: Item_func_case_abbreviation2_switch(THD *thd, Item *a, Item *b, Item *c) :Item_func_case_abbreviation2(thd, a, b, c) { } bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { Datetime_truncation_not_needed dt(thd, find_item(), fuzzydate); return (null_value= dt.copy_to_mysql_time(ltime, mysql_timestamp_type())); } bool time_op(THD *thd, MYSQL_TIME *ltime) override { return (null_value= Time(find_item()).copy_to_mysql_time(ltime)); } longlong int_op() override { return val_int_from_item(find_item()); } double real_op() override { return val_real_from_item(find_item()); } my_decimal *decimal_op(my_decimal *decimal_value) override { return val_decimal_from_item(find_item(), decimal_value); } String *str_op(String *str) override { return val_str_from_item(find_item(), str); } bool native_op(THD *thd, Native *to) override { return val_native_with_conversion_from_item(thd, find_item(), to, type_handler()); } }; class Item_func_if :public Item_func_case_abbreviation2_switch { protected: Item *find_item() const override { return args[0]->val_bool() ? args[1] : args[2]; } public: Item_func_if(THD *thd, Item *a, Item *b, Item *c): Item_func_case_abbreviation2_switch(thd, a, b, c) {} bool fix_fields(THD *, Item **) override; bool fix_length_and_dec() override { return fix_length_and_dec2_eliminate_null(args + 1); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("if") }; return name; } bool eval_not_null_tables(void *opt_arg) override; void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } private: void cache_type_info(Item *source); }; class Item_func_nvl2 :public Item_func_case_abbreviation2_switch { protected: Item *find_item() const override { return args[0]->is_null() ? args[2] : args[1]; } public: Item_func_nvl2(THD *thd, Item *a, Item *b, Item *c): Item_func_case_abbreviation2_switch(thd, a, b, c) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("nvl2") }; return name; } bool fix_length_and_dec() override { return fix_length_and_dec2_eliminate_null(args + 1); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_nullif :public Item_func_case_expression { Arg_comparator cmp; /* NULLIF(a,b) is a short for: CASE WHEN a=b THEN NULL ELSE a END The left "a" is for comparison purposes. The right "a" is for return value purposes. These are two different "a" and they can be replaced to different items. The left "a" is in a comparison and can be replaced by: - Item_func::convert_const_compared_to_int_field() - agg_item_set_converter() in set_cmp_func() - cache_converted_constant() in set_cmp_func() Both "a"s are subject to equal fields propagation and can be replaced by: - Item_field::propagate_equal_fields(ANY_SUBST) for the left "a" - Item_field::propagate_equal_fields(IDENTITY_SUBST) for the right "a" */ Item_cache *m_cache; int compare(); void reset_first_arg_if_needed() { if (arg_count == 3 && args[0] != args[2]) args[0]= args[2]; } Item *m_arg0; public: /* Here we pass three arguments to the parent constructor, as NULLIF is a three-argument function, it needs two copies of the first argument (see above). But fix_fields() will be confused if we try to prepare the same Item twice (if args[0]==args[2]), so we hide the third argument (decrementing arg_count) and copy args[2]=args[0] again after fix_fields(). See also Item_func_nullif::fix_length_and_dec(). */ Item_func_nullif(THD *thd, Item *a, Item *b): Item_func_case_expression(thd, a, b, a), m_cache(NULL), m_arg0(NULL) { arg_count--; } void cleanup() override { Item_func_hybrid_field_type::cleanup(); arg_count= 2; // See the comment to the constructor } bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool time_op(THD *thd, MYSQL_TIME *ltime) override; double real_op() override; longlong int_op() override; String *str_op(String *str) override; my_decimal *decimal_op(my_decimal *) override; bool native_op(THD *thd, Native *to) override; bool fix_length_and_dec() override; bool walk(Item_processor processor, bool walk_subquery, void *arg) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("nullif") }; return name; } void print(String *str, enum_query_type query_type) override; void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, uint flags) override; void update_used_tables() override; table_map not_null_tables() const override { return 0; } bool is_null() override; Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { Context cmpctx(ANY_SUBST, cmp.compare_type_handler(), cmp.compare_collation()); const Item *old0= args[0]; args[0]->propagate_equal_fields_and_change_item_tree(thd, cmpctx, cond, &args[0]); args[1]->propagate_equal_fields_and_change_item_tree(thd, cmpctx, cond, &args[1]); /* MDEV-9712 Performance degradation of nested NULLIF ANY_SUBST is more relaxed than IDENTITY_SUBST. If ANY_SUBST did not change args[0], then we can skip propagation for args[2]. */ if (old0 != args[0]) args[2]->propagate_equal_fields_and_change_item_tree(thd, Context_identity(), cond, &args[2]); return this; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *derived_field_transformer_for_having(THD *thd, uchar *arg) override { reset_first_arg_if_needed(); return this; } Item *derived_field_transformer_for_where(THD *thd, uchar *arg) override { reset_first_arg_if_needed(); return this; } Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) override { reset_first_arg_if_needed(); return this; } Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) override { reset_first_arg_if_needed(); return this; } Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) override { reset_first_arg_if_needed(); return this; } }; /* Functions to handle the optimized IN */ /* A vector of values of some type */ class in_vector :public Sql_alloc { public: char *base; uint size; qsort_cmp2 compare; CHARSET_INFO *collation; uint count; uint used_count; in_vector() = default; in_vector(THD *thd, uint elements, uint element_length, qsort_cmp2 cmp_func, CHARSET_INFO *cmp_coll) :base((char*) thd_calloc(thd, elements * element_length)), size(element_length), compare(cmp_func), collation(cmp_coll), count(elements), used_count(elements) {} virtual ~in_vector() = default; /* Store an Item value at the given position. @returns false - the Item was not NULL, and the conversion from the Item data type to the cmp_item data type went without errors @returns true - the Item was NULL, or data type conversion returned NULL */ virtual bool set(uint pos, Item *item)=0; virtual uchar *get_value(Item *item)=0; void sort() { my_qsort2(base,used_count,size,compare,(void*)collation); } bool find(Item *item); /* Create an instance of Item_{type} (e.g. Item_decimal) constant object which type allows it to hold an element of this vector without any conversions. The purpose of this function is to be able to get elements of this vector in form of Item_xxx constants without creating Item_xxx object for every array element you get (i.e. this implements "FlyWeight" pattern) */ virtual Item* create_item(THD *thd) { return NULL; } /* Store the value at position #pos into provided item object SYNOPSIS value_to_item() pos Index of value to store item Constant item to store value into. The item must be of the same type that create_item() returns. */ virtual void value_to_item(uint pos, Item *item) { } /* Compare values number pos1 and pos2 for equality */ bool compare_elems(uint pos1, uint pos2) { return MY_TEST(compare(const_cast(collation), base + pos1 * size, base + pos2 * size)); } virtual const Type_handler *type_handler() const= 0; }; class in_string :public in_vector { char buff[STRING_BUFFER_USUAL_SIZE]; String tmp; class Item_string_for_in_vector: public Item_string { public: Item_string_for_in_vector(THD *thd, CHARSET_INFO *cs): Item_string(thd, cs) { } void set_value(const String *str) { str_value= *str; collation.set(str->charset()); } }; public: in_string(THD *thd, uint elements, qsort_cmp2 cmp_func, CHARSET_INFO *cs); ~in_string(); bool set(uint pos, Item *item) override; uchar *get_value(Item *item) override; Item* create_item(THD *thd) override; void value_to_item(uint pos, Item *item) override { String *str=((String*) base)+pos; Item_string_for_in_vector *to= (Item_string_for_in_vector*) item; to->set_value(str); } const Type_handler *type_handler() const override { return &type_handler_varchar; } }; class in_longlong :public in_vector { protected: /* Here we declare a temporary variable (tmp) of the same type as the elements of this vector. tmp is used in finding if a given value is in the list. */ struct packed_longlong { longlong val; longlong unsigned_flag; // Use longlong, not bool, to preserve alignment } tmp; public: in_longlong(THD *thd, uint elements); bool set(uint pos, Item *item) override; uchar *get_value(Item *item) override; Item* create_item(THD *thd) override; void value_to_item(uint pos, Item *item) override { ((Item_int*) item)->value= ((packed_longlong*) base)[pos].val; ((Item_int*) item)->unsigned_flag= (bool) ((packed_longlong*) base)[pos].unsigned_flag; } const Type_handler *type_handler() const override { return &type_handler_slonglong; } friend int cmp_longlong(void *cmp_arg, const void *a, const void *b); }; class in_timestamp :public in_vector { Timestamp_or_zero_datetime tmp; public: in_timestamp(THD *thd, uint elements); bool set(uint pos, Item *item) override; uchar *get_value(Item *item) override; Item* create_item(THD *thd) override; void value_to_item(uint pos, Item *item) override; const Type_handler *type_handler() const override { return &type_handler_timestamp2; } }; /* Class to represent a vector of constant DATE/DATETIME values. */ class in_temporal :public in_longlong { public: /* Cache for the left item. */ in_temporal(THD *thd, uint elements) :in_longlong(thd, elements) {}; Item *create_item(THD *thd) override; void value_to_item(uint pos, Item *item) override { packed_longlong *val= reinterpret_cast(base)+pos; Item_datetime *dt= static_cast(item); dt->set(val->val, type_handler()->mysql_timestamp_type()); } friend int cmp_longlong(void *cmp_arg, const void *a, const void *b); }; class in_datetime :public in_temporal { public: in_datetime(THD *thd, uint elements) :in_temporal(thd, elements) {} bool set(uint pos, Item *item) override; uchar *get_value(Item *item) override; const Type_handler *type_handler() const override { return &type_handler_datetime2; } }; class in_time :public in_temporal { public: in_time(THD *thd, uint elements) :in_temporal(thd, elements) {} bool set(uint pos, Item *item) override; uchar *get_value(Item *item) override; const Type_handler *type_handler() const override { return &type_handler_time2; } }; class in_double :public in_vector { double tmp; public: in_double(THD *thd, uint elements); bool set(uint pos, Item *item) override; uchar *get_value(Item *item) override; Item *create_item(THD *thd) override; void value_to_item(uint pos, Item *item) override { ((Item_float*)item)->value= ((double*) base)[pos]; } const Type_handler *type_handler() const override { return &type_handler_double; } }; class in_decimal :public in_vector { my_decimal val; public: in_decimal(THD *thd, uint elements); bool set(uint pos, Item *item) override; uchar *get_value(Item *item) override; Item *create_item(THD *thd) override; void value_to_item(uint pos, Item *item) override { my_decimal *dec= ((my_decimal *)base) + pos; Item_decimal *item_dec= (Item_decimal*)item; item_dec->set_decimal_value(dec); } const Type_handler *type_handler() const override { return &type_handler_newdecimal; } }; /* ** Classes for easy comparing of non const items */ class cmp_item :public Sql_alloc { public: CHARSET_INFO *cmp_charset; cmp_item() { cmp_charset= &my_charset_bin; } virtual ~cmp_item() = default; virtual void store_value(Item *item)= 0; /** @returns result (TRUE, FALSE or UNKNOWN) of "stored argument's value <> item's value" */ virtual int cmp(Item *item)= 0; virtual int cmp_not_null(const Value *value)= 0; // for optimized IN with row virtual int compare(const cmp_item *item) const= 0; virtual cmp_item *make_same(THD *thd)= 0; /* Store a scalar or a ROW value into "this". @returns false - the value (or every component in case of ROW) was not NULL and the data type conversion went without errors. @returns true - the value (or some of its components) was NULL, or the data type conversion of a not-NULL value returned NULL. */ virtual bool store_value_by_template(THD *thd, cmp_item *tmpl, Item *item)=0; }; /// cmp_item which stores a scalar (i.e. non-ROW). class cmp_item_scalar : public cmp_item { protected: bool m_null_value; ///< If stored value is NULL bool store_value_by_template(THD *thd, cmp_item *tmpl, Item *item) override { store_value(item); return m_null_value; } }; class cmp_item_string : public cmp_item_scalar { protected: String *value_res; public: cmp_item_string () = default; cmp_item_string (CHARSET_INFO *cs) { cmp_charset= cs; } void set_charset(CHARSET_INFO *cs) { cmp_charset= cs; } friend class cmp_item_sort_string; friend class cmp_item_sort_string_in_static; }; class cmp_item_sort_string :public cmp_item_string { protected: char value_buff[STRING_BUFFER_USUAL_SIZE]; String value; public: cmp_item_sort_string(): cmp_item_string() {} cmp_item_sort_string(CHARSET_INFO *cs): cmp_item_string(cs), value(value_buff, sizeof(value_buff), cs) {} void store_value(Item *item) override { value_res= item->val_str(&value); m_null_value= item->null_value; // Make sure to cache the result String inside "value" if (value_res && value_res != &value) { if (value.copy(*value_res)) value.set("", 0, item->collation.collation); value_res= &value; } } int cmp_not_null(const Value *val) override { DBUG_ASSERT(!val->is_null()); DBUG_ASSERT(val->is_string()); return sortcmp(value_res, &val->m_string, cmp_charset) != 0; } int cmp(Item *arg) override { char buff[STRING_BUFFER_USUAL_SIZE]; String tmp(buff, sizeof(buff), cmp_charset), *res= arg->val_str(&tmp); if (m_null_value || arg->null_value) return UNKNOWN; if (value_res && res) return sortcmp(value_res, res, cmp_charset) != 0; else if (!value_res && !res) return FALSE; else return TRUE; } int compare(const cmp_item *ci) const override { cmp_item_string *l_cmp= (cmp_item_string *) ci; return sortcmp(value_res, l_cmp->value_res, cmp_charset); } cmp_item *make_same(THD *thd) override; void set_charset(CHARSET_INFO *cs) { cmp_charset= cs; value.set_buffer_if_not_allocated(value_buff, sizeof(value_buff), cs); } }; class cmp_item_int : public cmp_item_scalar { longlong value; public: cmp_item_int() = default; /* Remove gcc warning */ void store_value(Item *item) override { value= item->val_int(); m_null_value= item->null_value; } int cmp_not_null(const Value *val) override { DBUG_ASSERT(!val->is_null()); DBUG_ASSERT(val->is_longlong()); return value != val->value.m_longlong; } int cmp(Item *arg) override { const bool rc= value != arg->val_int(); return (m_null_value || arg->null_value) ? UNKNOWN : rc; } int compare(const cmp_item *ci) const override { cmp_item_int *l_cmp= (cmp_item_int *)ci; return (value < l_cmp->value) ? -1 : ((value == l_cmp->value) ? 0 : 1); } cmp_item *make_same(THD *thd) override; }; /* Compare items in the DATETIME context. */ class cmp_item_temporal: public cmp_item_scalar { protected: longlong value; public: cmp_item_temporal() = default; int compare(const cmp_item *ci) const override; }; class cmp_item_datetime: public cmp_item_temporal { public: cmp_item_datetime() :cmp_item_temporal() { } void store_value(Item *item) override { value= item->val_datetime_packed(current_thd); m_null_value= item->null_value; } int cmp_not_null(const Value *val) override; int cmp(Item *arg) override; cmp_item *make_same(THD *thd) override; }; class cmp_item_time: public cmp_item_temporal { public: cmp_item_time() :cmp_item_temporal() { } void store_value(Item *item) override { value= item->val_time_packed(current_thd); m_null_value= item->null_value; } int cmp_not_null(const Value *val) override; int cmp(Item *arg) override; cmp_item *make_same(THD *thd) override; }; class cmp_item_timestamp: public cmp_item_scalar { Timestamp_or_zero_datetime_native m_native; public: cmp_item_timestamp() :cmp_item_scalar() { } void store_value(Item *item) override; int cmp_not_null(const Value *val) override; int cmp(Item *arg) override; int compare(const cmp_item *ci) const override; cmp_item *make_same(THD *thd) override; }; class cmp_item_real : public cmp_item_scalar { double value; public: cmp_item_real() = default; /* Remove gcc warning */ void store_value(Item *item) override { value= item->val_real(); m_null_value= item->null_value; } int cmp_not_null(const Value *val) override { DBUG_ASSERT(!val->is_null()); DBUG_ASSERT(val->is_double()); return value != val->value.m_double; } int cmp(Item *arg) override { const bool rc= value != arg->val_real(); return (m_null_value || arg->null_value) ? UNKNOWN : rc; } int compare(const cmp_item *ci) const override { cmp_item_real *l_cmp= (cmp_item_real *) ci; return (value < l_cmp->value)? -1 : ((value == l_cmp->value) ? 0 : 1); } cmp_item *make_same(THD *thd) override; }; class cmp_item_decimal : public cmp_item_scalar { my_decimal value; public: cmp_item_decimal() = default; /* Remove gcc warning */ void store_value(Item *item) override; int cmp(Item *arg) override; int cmp_not_null(const Value *val) override; int compare(const cmp_item *c) const override; cmp_item *make_same(THD *thd) override; }; /* cmp_item for optimized IN with row (right part string, which never be changed) */ class cmp_item_sort_string_in_static :public cmp_item_string { protected: String value; public: cmp_item_sort_string_in_static(CHARSET_INFO *cs): cmp_item_string(cs) {} void store_value(Item *item) override { value_res= item->val_str(&value); m_null_value= item->null_value; } int cmp_not_null(const Value *val) override { DBUG_ASSERT(false); return TRUE; } int cmp(Item *item) override { // Should never be called DBUG_ASSERT(false); return TRUE; } int compare(const cmp_item *ci) const override { cmp_item_string *l_cmp= (cmp_item_string *) ci; return sortcmp(value_res, l_cmp->value_res, cmp_charset); } cmp_item *make_same(THD *) override { return new cmp_item_sort_string_in_static(cmp_charset); } }; /** A helper class to handle situations when some item "pred" (the predicant) is consequently compared to a list of other items value0..valueN (the values). Currently used to handle: - pred IN (value0, value1, value2) - CASE pred WHEN value0 .. WHEN value1 .. WHEN value2 .. END Every pair {pred,valueN} can be compared by its own Type_handler. Some pairs can use the same Type_handler. In cases when all pairs use exactly the same Type_handler, we say "all types are compatible". For example, for an expression 1 IN (1, 1e0, 1.0, 2) - pred is 1 - value0 is 1 - value1 is 1e0 - value2 is 1.1 - value3 is 2 Pairs (pred,valueN) are compared as follows: N expr1 Type - ----- ---- 0 1 INT 1 1e0 DOUBLE 2 1.0 DECIMAL 3 2 INT Types are not compatible in this example. During add_value() calls, each pair {pred,valueN} is analysed: - If valueN is an explicit NULL, it can be ignored in the caller asks to do so - If valueN is not an explicit NULL (or if the caller didn't ask to skip NULLs), then the value add an element in the array m_comparators[]. Every element m_comparators[] stores the following information: 1. m_arg_index - the position of the value expression in the original argument array, e.g. in Item_func_in::args[] or Item_func_case::args[]. 2. m_handler - the pointer to the data type handler that the owner will use to compare the pair {args[m_predicate_index],args[m_arg_index]}. 3. m_handler_index - the index of an m_comparators[] element corresponding to the leftmost pair that uses exactly the same Type_handler for comparison. m_handler_index helps to maintain unique data type handlers. - m_comparators[i].m_handler_index==i means that this is the leftmost pair that uses the Type_handler m_handler for comparision. - If m_comparators[i].m_handlex_index!=i, it means that some earlier element m_comparators[jm_cmp_item; DBUG_ASSERT(in_item); /* If this is the leftmost pair that uses the data type handler pointed by m_comparators[i].m_handler, then we need to cache the predicant value representation used by this handler. */ if (m_comparators[i].m_handler_index == i) in_item->store_value(args->arguments()[m_predicant_index]); /* If the predicant item has null_value==true then: - In case of scalar expression we can returns UNKNOWN immediately. No needs to check the result of the value item. - In case of ROW, null_value==true means that *some* row elements returned NULL, but *some* elements can still be non-NULL! We need to get the result of the value item and test if non-NULL elements in the predicant and the value produce TRUE (not equal), or UNKNOWN. */ if (args->arguments()[m_predicant_index]->null_value && m_comparators[i].m_handler != &type_handler_row) return UNKNOWN; return in_item->cmp(args->arguments()[m_comparators[i].m_arg_index]); } int cmp_args_nulls_equal(THD *thd, Item_args *args, uint i) { Predicant_to_value_comparator *cmp= &m_comparators[m_comparators[i].m_handler_index]; cmp_item *in_item= cmp->m_cmp_item; DBUG_ASSERT(in_item); Item *predicant= args->arguments()[m_predicant_index]; Item *arg= args->arguments()[m_comparators[i].m_arg_index]; ValueBuffer val; if (m_comparators[i].m_handler_index == i) in_item->store_value(predicant); m_comparators[i].m_handler->Item_save_in_value(thd, arg, &val); if (predicant->null_value && val.is_null()) return FALSE; // Two nulls are equal if (predicant->null_value || val.is_null()) return UNKNOWN; return in_item->cmp_not_null(&val); } /** Predicant_to_value_comparator - a comparator for one pair (pred,valueN). See comments above. */ struct Predicant_to_value_comparator { const Type_handler *m_handler; cmp_item *m_cmp_item; uint m_arg_index; uint m_handler_index; void cleanup() { if (m_cmp_item) delete m_cmp_item; memset(this, 0, sizeof(*this)); } }; Predicant_to_value_comparator *m_comparators; // The comparator array uint m_comparator_count;// The number of elements in m_comparators[] uint m_predicant_index; // The position of the predicant in its argument list, // e.g. for Item_func_in m_predicant_index is 0, // as predicant is stored in Item_func_in::args[0]. // For Item_func_case m_predicant_index is // set to Item_func_case::first_expr_num. public: Predicant_to_list_comparator(THD *thd, uint nvalues) :m_comparator_count(0), m_predicant_index(0) { alloc_comparators(thd, nvalues); } uint comparator_count() const { return m_comparator_count; } const Type_handler *get_comparator_type_handler(uint i) const { DBUG_ASSERT(i < m_comparator_count); return m_comparators[i].m_handler; } uint get_comparator_arg_index(uint i) const { DBUG_ASSERT(i < m_comparator_count); return m_comparators[i].m_arg_index; } cmp_item *get_comparator_cmp_item(uint i) const { DBUG_ASSERT(i < m_comparator_count); return m_comparators[i].m_cmp_item; } #ifndef DBUG_OFF void debug_print(THD *thd) { for (uint i= 0; i < m_comparator_count; i++) { DBUG_EXECUTE_IF("Predicant_to_list_comparator", push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR, "DBUG: [%d] arg=%d handler=%d (%s)", i, m_comparators[i].m_arg_index, m_comparators[i].m_handler_index, m_comparators[m_comparators[i].m_handler_index]. m_handler->name().ptr());); } } #endif void add_predicant(Item_args *args, uint predicant_index) { DBUG_ASSERT(m_comparator_count == 0); // Set in constructor DBUG_ASSERT(m_predicant_index == 0); // Set in constructor DBUG_ASSERT(predicant_index < args->argument_count()); m_predicant_index= predicant_index; } /** Add a new element into m_comparators[], using a {pred,valueN} pair. @param funcname - the name of the operation, for error reporting @param args - the owner function's argument list @param value_index - the value position in args @retval true - could not add an element because of non-comparable arguments (e.g. ROWs with size) @retval false - a new element was successfully added. */ bool add_value(const LEX_CSTRING &funcname, Item_args *args, uint value_index); /** Add a new element into m_comparators[], ignoring explicit NULL values. If the value appeared to be an explicit NULL, nulls_found[0] is set to true. */ bool add_value_skip_null(const LEX_CSTRING &funcname, Item_args *args, uint value_index, bool *nulls_found); /** Signal "this" that there will be no new add_value*() calls, so it can prepare its internal structures for comparison. @param [OUT] compatible - If all comparators are compatible, their data type handler is returned here. @param [OUT] unuque_cnt - The number of unique data type handlers found. If the value returned in *unique_cnt is 0, it means all values were explicit NULLs: expr0 IN (NULL,NULL,..,NULL) @param [OUT] found_type - The bit mask for all found cmp_type()'s. */ void all_values_added(Type_handler_hybrid_field_type *compatible, uint *unique_cnt, uint *found_types) { detect_unique_handlers(compatible, unique_cnt, found_types); } /** Creates cmp_item instances for all unique handlers and stores them into m_comparators[].m_cmp_item, using the information previously populated by add_predicant(), add_value() and detect_unque_handlers(). */ bool make_unique_cmp_items(THD *thd, CHARSET_INFO *cs); void cleanup() { DBUG_ASSERT(m_comparators); for (uint i= 0; i < m_comparator_count; i++) m_comparators[i].cleanup(); memset(m_comparators, 0, sizeof(m_comparators[0]) * m_comparator_count); m_comparator_count= 0; m_predicant_index= 0; } bool init_clone(THD *thd, uint nvalues) { m_comparator_count= 0; m_predicant_index= 0; return alloc_comparators(thd, nvalues); } /** @param [IN] args - The argument list that was previously used with add_predicant() and add_value(). @param [OUT] idx - In case if a value that is equal to the predicant was found, the index of the matching value is returned here. Otherwise, *idx is not changed. @param [IN/OUT] found_unknown_values - how to handle UNKNOWN results. If found_unknown_values is NULL (e.g. Item_func_case), cmp() returns immediately when the first UNKNOWN result is found. If found_unknown_values is non-NULL (Item_func_in), cmp() does not return when an UNKNOWN result is found, sets *found_unknown_values to true, and continues to compare the remaining pairs to find FALSE (i.e. the value that is equal to the predicant). @retval false - Found a value that is equal to the predicant @retval true - Didn't find an equal value */ bool cmp(Item_args *args, uint *idx, bool *found_unknown_values) { for (uint i= 0 ; i < m_comparator_count ; i++) { DBUG_ASSERT(m_comparators[i].m_handler != NULL); const int rc= cmp_arg(args, i); if (rc == FALSE) { *idx= m_comparators[i].m_arg_index; return false; // Found a matching value } if (rc == UNKNOWN) { if (!found_unknown_values) return true; *found_unknown_values= true; } } return true; // Not found } /* Same as above, but treats two NULLs as equal, e.g. as in DECODE_ORACLE(). */ bool cmp_nulls_equal(THD *thd, Item_args *args, uint *idx) { for (uint i= 0 ; i < m_comparator_count ; i++) { DBUG_ASSERT(m_comparators[i].m_handler != NULL); if (cmp_args_nulls_equal(thd, args, i) == FALSE) { *idx= m_comparators[i].m_arg_index; return false; // Found a matching value } } return true; // Not found } }; /* The class Item_func_case is the CASE ... WHEN ... THEN ... END function implementation. */ class Item_func_case :public Item_func_case_expression { protected: String tmp_value; DTCollation cmp_collation; bool aggregate_then_and_else_arguments(THD *thd, uint count); virtual Item **else_expr_addr() const= 0; virtual Item *find_item()= 0; inline void print_when_then_arguments(String *str, enum_query_type query_type, Item **items, uint count); inline void print_else_argument(String *str, enum_query_type query_type, Item *item); void reorder_args(uint start); public: Item_func_case(THD *thd, List &list) :Item_func_case_expression(thd, list) { } double real_op() override; longlong int_op() override; String *str_op(String *) override; my_decimal *decimal_op(my_decimal *) override; bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool time_op(THD *thd, MYSQL_TIME *ltime) override; bool native_op(THD *thd, Native *to) override; bool fix_fields(THD *thd, Item **ref) override; table_map not_null_tables() const override { return 0; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("case") }; return name; } CHARSET_INFO *compare_collation() const { return cmp_collation.collation; } bool need_parentheses_in_default() override { return true; } }; /* CASE WHEN cond THEN res [WHEN cond THEN res...] [ELSE res] END Searched CASE checks all WHEN expressions one after another. When some WHEN expression evaluated to TRUE then the value of the corresponding THEN expression is returned. */ class Item_func_case_searched: public Item_func_case { uint when_count() const { return arg_count / 2; } bool with_else() const { return arg_count % 2; } Item **else_expr_addr() const override { return with_else() ? &args[arg_count - 1] : 0; } public: Item_func_case_searched(THD *thd, List &list) :Item_func_case(thd, list) { DBUG_ASSERT(arg_count >= 2); reorder_args(0); } enum Functype functype() const override { return CASE_SEARCHED_FUNC; } void print(String *str, enum_query_type query_type) override; bool fix_length_and_dec() override; Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { // None of the arguments are in a comparison context Item_args::propagate_equal_fields(thd, Context_identity(), cond); return this; } Item *find_item() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* CASE pred WHEN value THEN res [WHEN value THEN res...] [ELSE res] END When the predicant expression is specified then it is compared to each WHEN expression individually. When an equal WHEN expression is found the corresponding THEN expression is returned. In order to do correct comparisons several comparators are used. One for each result type. Different result types that are used in particular CASE ... END expression are collected in the fix_length_and_dec() member function and only comparators for there result types are used. */ class Item_func_case_simple: public Item_func_case, public Predicant_to_list_comparator { protected: uint m_found_types; uint when_count() const { return (arg_count - 1) / 2; } bool with_else() const { return arg_count % 2 == 0; } Item **else_expr_addr() const override { return with_else() ? &args[arg_count - 1] : 0; } bool aggregate_switch_and_when_arguments(THD *thd, bool nulls_equal); bool prepare_predicant_and_values(THD *thd, uint *found_types, bool nulls_equal); public: Item_func_case_simple(THD *thd, List &list) :Item_func_case(thd, list), Predicant_to_list_comparator(thd, arg_count), m_found_types(0) { DBUG_ASSERT(arg_count >= 3); reorder_args(1); } void cleanup() override { DBUG_ENTER("Item_func_case_simple::cleanup"); Item_func::cleanup(); Predicant_to_list_comparator::cleanup(); DBUG_VOID_RETURN; } enum Functype functype() const override { return CASE_SIMPLE_FUNC; } void print(String *str, enum_query_type query_type) override; bool fix_length_and_dec() override; Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override; Item *find_item() override; Item *do_build_clone(THD *thd) const override { Item_func_case_simple *clone= (Item_func_case_simple *) Item_func_case::do_build_clone(thd); uint ncases= when_count(); if (clone && clone->Predicant_to_list_comparator::init_clone(thd, ncases)) return NULL; return clone; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_decode_oracle: public Item_func_case_simple { public: Item_func_decode_oracle(THD *thd, List &list) :Item_func_case_simple(thd, list) { } const Schema *schema() const override { return &oracle_schema_ref; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("decode") }; return name; } void print(String *str, enum_query_type query_type) override; bool fix_length_and_dec() override; Item *find_item() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* The Item_func_in class implements in_expr IN () and in_expr NOT IN () The current implementation distinguishes 2 cases: 1) all items in are constants and have the same result type. This case is handled by in_vector class, implementing fast bisection search. 2) otherwise Item_func_in employs several cmp_item objects to perform comparisons of in_expr and an item from . One cmp_item object for each result type. Different result types are collected in the fix_length_and_dec() member function by means of collect_cmp_types() function. Bisection is possible when: 1. All types are similar 2. All expressions in are const In the presence of NULLs, the correct result of evaluating this item must be UNKNOWN or FALSE. To achieve that: - If type is scalar, we can use bisection and the "have_null" boolean. - If type is ROW, we will need to scan all of when searching, so bisection is impossible. Unless: 3. UNKNOWN and FALSE are equivalent results 4. Neither left expression nor contain any NULL value */ class Item_func_in :public Item_func_opt_neg, public Predicant_to_list_comparator { /** Usable if is made only of constants. Returns true if one of these constants contains a NULL. Example: IN ( (-5, (12,NULL)), ... ). */ bool list_contains_null(); bool all_items_are_consts(Item **items, uint nitems) const { for (uint i= 0; i < nitems; i++) { if (!items[i]->can_eval_in_optimize()) return false; } return true; } bool prepare_predicant_and_values(THD *thd, uint *found_types); bool check_arguments() const override { return check_argument_types_like_args0(); } protected: SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value) override; bool transform_into_subq; bool transform_into_subq_checked; public: /// An array of values, created when the bisection lookup method is used in_vector *array; /** If there is some NULL among , during a val_int() call; for example IN ( (1,(3,'col')), ... ), where 'col' is a column which evaluates to NULL. */ bool have_null; /** true when all arguments of the IN list are of compatible types and can be used safely as comparisons for key conditions */ bool arg_types_compatible; TABLE_LIST *emb_on_expr_nest; Item_func_in(THD *thd, List &list): Item_func_opt_neg(thd, list), Predicant_to_list_comparator(thd, arg_count - 1), transform_into_subq(false), transform_into_subq_checked(false), array(0), have_null(0), arg_types_compatible(FALSE), emb_on_expr_nest(0) { } bool val_bool() override; bool fix_fields(THD *, Item **) override; bool fix_length_and_dec() override; bool compatible_types_scalar_bisection_possible() { DBUG_ASSERT(m_comparator.cmp_type() != ROW_RESULT); return all_items_are_consts(args + 1, arg_count - 1); // Bisection #2 } bool compatible_types_row_bisection_possible() { DBUG_ASSERT(m_comparator.cmp_type() == ROW_RESULT); return all_items_are_consts(args + 1, arg_count - 1) && // Bisection #2 ((is_top_level_item() && !negated) || // Bisection #3 (!list_contains_null() && !args[0]->maybe_null())); // Bisection #4 } bool agg_all_arg_charsets_for_comparison() { return agg_arg_charsets_for_comparison(cmp_collation, args, arg_count); } void fix_in_vector(); bool value_list_convert_const_to_int(THD *thd); bool fix_for_scalar_comparison_using_bisection(THD *thd) { array= m_comparator.type_handler()->make_in_vector(thd, this, arg_count - 1); if (!array) // OOM return true; fix_in_vector(); return false; } bool fix_for_scalar_comparison_using_cmp_items(THD *thd, uint found_types); bool fix_for_row_comparison_using_cmp_items(THD *thd); bool fix_for_row_comparison_using_bisection(THD *thd); void cleanup() override { DBUG_ENTER("Item_func_in::cleanup"); Item_int_func::cleanup(); delete array; array= 0; Predicant_to_list_comparator::cleanup(); DBUG_VOID_RETURN; } void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override; SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) override; SEL_TREE *get_func_row_mm_tree(RANGE_OPT_PARAM *param, Item_row *key_row); Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { /* Note, we pass ANY_SUBST, this makes sure that non of the args will be replaced to a zero-filled Item_string. Such a change would require rebuilding of cmp_items. */ if (arg_types_compatible) { Context cmpctx(ANY_SUBST, m_comparator.type_handler(), Item_func_in::compare_collation()); args[0]->propagate_equal_fields_and_change_item_tree(thd, cmpctx, cond, &args[0]); } for (uint i= 0; i < comparator_count(); i++) { Context cmpctx(ANY_SUBST, get_comparator_type_handler(i), Item_func_in::compare_collation()); uint idx= get_comparator_arg_index(i); args[idx]->propagate_equal_fields_and_change_item_tree(thd, cmpctx, cond, &args[idx]); } return this; } void print(String *str, enum_query_type query_type) override; enum Functype functype() const override { return IN_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("in") }; return name; } enum precedence precedence() const override { return IN_PRECEDENCE; } bool eval_not_null_tables(void *opt_arg) override; bool find_not_null_fields(table_map allowed) override; void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; bool count_sargable_conds(void *arg) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } Item *do_build_clone(THD *thd) const override { Item_func_in *clone= (Item_func_in *) Item_func::do_build_clone(thd); if (clone) { clone->array= 0; if (clone->Predicant_to_list_comparator::init_clone(thd, arg_count - 1)) return NULL; } return clone; } void mark_as_condition_AND_part(TABLE_LIST *embedding) override; bool to_be_transformed_into_in_subq(THD *thd); bool create_value_list_for_tvc(THD *thd, List< List > *values); Item *in_predicate_to_in_subs_transformer(THD *thd, uchar *arg) override; Item *in_predicate_to_equality_transformer(THD *thd, uchar *arg) override; uint32 max_length_of_left_expr(); }; class cmp_item_row :public cmp_item { cmp_item **comparators; uint n; bool alloc_comparators(THD *thd, uint n); bool aggregate_row_elements_for_comparison(THD *thd, Type_handler_hybrid_field_type *cmp, Item_args *tmp, const LEX_CSTRING &funcname, uint col, uint level); public: cmp_item_row(): comparators(0), n(0) {} ~cmp_item_row(); void store_value(Item *item) override; bool prepare_comparators(THD *, const LEX_CSTRING &funcname, const Item_args *args, uint level); int cmp(Item *arg) override; int cmp_not_null(const Value *) override { DBUG_ASSERT(false); return TRUE; } int compare(const cmp_item *arg) const override; cmp_item *make_same(THD *thd) override; bool store_value_by_template(THD *thd, cmp_item *tmpl, Item *) override; friend class Item_func_in; cmp_item *get_comparator(uint i) { return comparators[i]; } }; class in_row :public in_vector { cmp_item_row tmp; public: in_row(THD *thd, uint elements, Item *); ~in_row(); bool set(uint pos, Item *item) override; uchar *get_value(Item *item) override; friend class Item_func_in; const Type_handler *type_handler() const override { return &type_handler_row; } cmp_item *get_cmp_item() { return &tmp; } }; /* Functions used by where clause */ class Item_func_null_predicate :public Item_bool_func { protected: SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value) override { DBUG_ENTER("Item_func_null_predicate::get_func_mm_tree"); DBUG_RETURN(get_mm_parts(param, field, functype(), value)); } SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, Field *field, KEY_PART *key_part, Item_func::Functype type, Item *value) override; public: Item_func_null_predicate(THD *thd, Item *a): Item_bool_func(thd, a) { } void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override; SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) override { DBUG_ENTER("Item_func_null_predicate::get_mm_tree"); SEL_TREE *ftree= get_full_func_mm_tree_for_args(param, args[0], NULL); if (!ftree) ftree= Item_func::get_mm_tree(param, cond_ptr); DBUG_RETURN(ftree); } CHARSET_INFO *compare_collation() const override { return args[0]->collation.collation; } bool fix_length_and_dec() override { decimals=0; max_length=1; base_flags&= ~item_base_t::MAYBE_NULL; return FALSE; } bool count_sargable_conds(void *arg) override; }; class Item_func_isnull :public Item_func_null_predicate { public: Item_func_isnull(THD *thd, Item *a): Item_func_null_predicate(thd, a) {} bool val_bool() override; enum Functype functype() const override { return ISNULL_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("isnull") }; return name; } void print(String *str, enum_query_type query_type) override; enum precedence precedence() const override { return CMP_PRECEDENCE; } bool arg_is_datetime_notnull_field() { Item **args= arguments(); if (args[0]->real_item()->type() == Item::FIELD_ITEM) { Field *field=((Item_field*) args[0]->real_item())->field; if ((field->flags & NOT_NULL_FLAG) && field->type_handler()->cond_notnull_field_isnull_to_field_eq_zero()) return true; } return false; } /* Optimize case of not_null_column IS NULL */ void update_used_tables() override { if (!args[0]->maybe_null() && !arg_is_datetime_notnull_field()) { used_tables_cache= 0; /* is always false */ const_item_cache= 1; } else { args[0]->update_used_tables(); used_tables_cache= args[0]->used_tables(); const_item_cache= args[0]->const_item(); } } COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value, bool top_level) override; table_map not_null_tables() const override { return 0; } bool find_not_null_fields(table_map allowed) override; Item *neg_transformer(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Functions used by HAVING for rewriting IN subquery */ class Item_in_subselect; /* This is like IS NOT NULL but it also remembers if it ever has encountered a NULL. */ class Item_is_not_null_test :public Item_func_isnull { Item_in_subselect* owner; public: Item_is_not_null_test(THD *thd, Item_in_subselect* ow, Item *a): Item_func_isnull(thd, a), owner(ow) {} enum Functype functype() const override { return ISNOTNULLTEST_FUNC; } bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("") }; return name; } void update_used_tables() override; /* we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE */ table_map used_tables() const override { return used_tables_cache | RAND_TABLE_BIT; } bool const_item() const override { return FALSE; } }; class Item_func_isnotnull :public Item_func_null_predicate { bool abort_on_null; public: Item_func_isnotnull(THD *thd, Item *a): Item_func_null_predicate(thd, a), abort_on_null(0) { } bool val_bool() override; enum Functype functype() const override { return ISNOTNULL_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("isnotnull") }; return name; } enum precedence precedence() const override { return CMP_PRECEDENCE; } table_map not_null_tables() const override { return abort_on_null ? not_null_tables_cache : 0; } Item *neg_transformer(THD *thd) override; void print(String *str, enum_query_type query_type) override; void top_level_item() override { abort_on_null=1; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_like :public Item_bool_func2 { // Turbo Boyer-Moore data bool canDoTurboBM; // pattern is '%abcd%' case const char* pattern; int pattern_len; // TurboBM buffers, *this is owner int* bmGs; // good suffix shift table, size is pattern_len + 1 int* bmBc; // bad character shift table, size is alphabet_size void turboBM_compute_suffixes(int* suff); void turboBM_compute_good_suffix_shifts(int* suff); void turboBM_compute_bad_character_shifts(); bool turboBM_matches(const char* text, int text_len) const; enum { alphabet_size = 256 }; Item *escape_item; bool escape_used_in_parsing; bool use_sampling; DTCollation cmp_collation; String cmp_value1, cmp_value2; bool with_sargable_pattern() const; protected: SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value) override { DBUG_ENTER("Item_func_like::get_func_mm_tree"); DBUG_RETURN(get_mm_parts(param, field, LIKE_FUNC, value)); } SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, Field *field, KEY_PART *key_part, Item_func::Functype type, Item *value) override; public: int escape; bool negated; Item_func_like(THD *thd, Item *a, Item *b, Item *escape_arg, bool escape_used): Item_bool_func2(thd, a, b), canDoTurboBM(FALSE), pattern(0), pattern_len(0), bmGs(0), bmBc(0), escape_item(escape_arg), escape_used_in_parsing(escape_used), use_sampling(0), negated(0) {} bool get_negated() const { return negated; } // Used by ColumnStore Sql_mode_dependency value_depends_on_sql_mode() const override; bool val_bool() override; enum Functype functype() const override { return LIKE_FUNC; } void print(String *str, enum_query_type query_type) override; CHARSET_INFO *compare_collation() const override { return cmp_collation.collation; } cond_result eq_cmp_result() const override { /** We cannot always rewrite conditions as follows: from: WHERE expr1=const AND expr1 LIKE expr2 to: WHERE expr1=const AND const LIKE expr2 or from: WHERE expr1=const AND expr2 LIKE expr1 to: WHERE expr1=const AND expr2 LIKE const because LIKE works differently comparing to the regular "=" operator: 1. LIKE performs a stricter one-character-to-one-character comparison and does not recognize contractions and expansions. Replacing "expr1" to "const in LIKE would make the condition stricter in case of a complex collation. 2. LIKE does not ignore trailing spaces and thus works differently from the "=" operator in case of "PAD SPACE" collations (which are the majority in MariaDB). So, for "PAD SPACE" collations: - expr1=const - ignores trailing spaces - const LIKE expr2 - does not ignore trailing spaces - expr2 LIKE const - does not ignore trailing spaces Allow only "binary" for now. It neither ignores trailing spaces nor has contractions/expansions. TODO: We could still replace "expr1" to "const" in "expr1 LIKE expr2" in case of a "PAD SPACE" collation, but only if "expr2" has '%' at the end. */ return compare_collation() == &my_charset_bin ? COND_TRUE : COND_OK; } void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override; SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) override; Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { /* LIKE differs from the regular comparison operator ('=') in the following: - LIKE never ignores trailing spaces (even for PAD SPACE collations) Propagation of equal fields with a PAD SPACE collation into LIKE is not safe. Example: WHERE a='a ' AND a LIKE 'a' - returns true for 'a' cannot be rewritten to: WHERE a='a ' AND 'a ' LIKE 'a' - returns false for 'a' Note, binary collations in MySQL/MariaDB, e.g. latin1_bin, still have the PAD SPACE attribute and ignore trailing spaces! - LIKE does not take into account contractions, expansions, and ignorable characters. Propagation of equal fields with contractions/expansions/ignorables is also not safe. It's safe to propagate my_charset_bin (BINARY/VARBINARY/BLOB) values, because they do not ignore trailing spaces and have one-to-one mapping between a string and its weights. The below condition should be true only for my_charset_bin (as of version 10.1.7). */ uint flags= Item_func_like::compare_collation()->state; if ((flags & MY_CS_NOPAD) && !(flags & MY_CS_NON1TO1)) Item_args::propagate_equal_fields(thd, Context(ANY_SUBST, &type_handler_long_blob, compare_collation()), cond); return this; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("like") }; return name; } enum precedence precedence() const override { return IN_PRECEDENCE; } bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override { max_length= 1; Item_args old_predicant(args[0]); if (agg_arg_charsets_for_comparison(cmp_collation, args, 2)) return true; raise_note_if_key_become_unused(current_thd, old_predicant); return false; } void cleanup() override; Item *neg_transformer(THD *thd) override { negated= !negated; return this; } bool walk(Item_processor processor, bool walk_subquery, void *arg) override { return (walk_args(processor, walk_subquery, arg) || escape_item->walk(processor, walk_subquery, arg) || (this->*processor)(arg)); } bool find_selective_predicates_list_processor(void *arg) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; typedef struct pcre2_real_code_8 pcre2_code; typedef struct pcre2_real_match_data_8 pcre2_match_data; #define PCRE2_SIZE size_t class Regexp_processor_pcre { pcre2_code *m_pcre; pcre2_match_data *m_pcre_match_data; bool m_conversion_is_needed; bool m_is_const; int m_library_flags; CHARSET_INFO *m_library_charset; String m_prev_pattern; int m_pcre_exec_rc; PCRE2_SIZE *m_SubStrVec; void pcre_exec_warn(int rc) const; int pcre_exec_with_warn(const pcre2_code *code, pcre2_match_data *data, const char *subject, int length, int startoffset, int options); public: String *convert_if_needed(String *src, String *converter); String subject_converter; String pattern_converter; String replace_converter; Regexp_processor_pcre() : m_pcre(NULL), m_pcre_match_data(NULL), m_conversion_is_needed(true), m_is_const(0), m_library_flags(0), m_library_charset(&my_charset_utf8mb4_general_ci) {} int default_regex_flags(); void init(CHARSET_INFO *data_charset, int extra_flags); bool fix_owner(Item_func *owner, Item *subject_arg, Item *pattern_arg); bool compile(String *pattern, bool send_error); bool compile(Item *item, bool send_error); bool recompile(Item *item) { return !m_is_const && compile(item, false); } bool exec(const char *str, size_t length, size_t offset); bool exec(String *str, int offset, uint n_result_offsets_to_convert); bool exec(Item *item, int offset, uint n_result_offsets_to_convert); bool match() const { return m_pcre_exec_rc < 0 ? 0 : 1; } int nsubpatterns() const { return m_pcre_exec_rc <= 0 ? 0 : m_pcre_exec_rc; } size_t subpattern_start(int n) const { return m_pcre_exec_rc <= 0 ? 0 : m_SubStrVec[n * 2]; } size_t subpattern_end(int n) const { return m_pcre_exec_rc <= 0 ? 0 : m_SubStrVec[n * 2 + 1]; } size_t subpattern_length(int n) const { return subpattern_end(n) - subpattern_start(n); } void reset() { m_pcre= NULL; m_pcre_match_data= NULL; m_prev_pattern.length(0); } void cleanup(); bool is_compiled() const { return m_pcre != NULL; } bool is_const() const { return m_is_const; } void set_const(bool arg) { m_is_const= arg; } CHARSET_INFO * library_charset() const { return m_library_charset; } }; class Item_func_regex :public Item_bool_func { Regexp_processor_pcre re; DTCollation cmp_collation; public: Item_func_regex(THD *thd, Item *a, Item *b): Item_bool_func(thd, a, b) {} void cleanup() override { DBUG_ENTER("Item_func_regex::cleanup"); Item_bool_func::cleanup(); re.cleanup(); DBUG_VOID_RETURN; } bool val_bool() override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("regexp") }; return name; } enum precedence precedence() const override { return IN_PRECEDENCE; } Item *do_get_copy(THD *thd) const override { return 0; } void print(String *str, enum_query_type query_type) override { print_op(str, query_type); } CHARSET_INFO *compare_collation() const override { return cmp_collation.collation; } }; /* In the corner case REGEXP_INSTR could return (2^32 + 1), which would not fit into Item_long_func range. But string lengths are limited with max_allowed_packet, which cannot be bigger than 1024*1024*1024. */ class Item_func_regexp_instr :public Item_long_func { bool check_arguments() const override { return (args[0]->check_type_can_return_str(func_name_cstring()) || args[1]->check_type_can_return_text(func_name_cstring())); } Regexp_processor_pcre re; DTCollation cmp_collation; public: Item_func_regexp_instr(THD *thd, Item *a, Item *b) :Item_long_func(thd, a, b) {} void cleanup() override { DBUG_ENTER("Item_func_regexp_instr::cleanup"); Item_int_func::cleanup(); re.cleanup(); DBUG_VOID_RETURN; } longlong val_int() override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("regexp_instr") }; return name; } Item *do_get_copy(THD *thd) const override { return 0; } }; typedef class Item COND; class Item_cond :public Item_bool_func { protected: List list; bool abort_on_null; table_map and_tables_cache; public: /* Item_cond() is only used to create top level items */ Item_cond(THD *thd): Item_bool_func(thd), abort_on_null(1) { const_item_cache=0; } Item_cond(THD *thd, Item *i1, Item *i2); Item_cond(THD *thd, Item_cond *item); Item_cond(THD *thd, List &nlist): Item_bool_func(thd), list(nlist), abort_on_null(0) {} bool add(Item *item, MEM_ROOT *root) { DBUG_ASSERT(item); return list.push_back(item, root); } bool add_at_head(Item *item, MEM_ROOT *root) { DBUG_ASSERT(item); return list.push_front(item, root); } void add_at_head(List *nlist) { DBUG_ASSERT(nlist->elements); list.prepend(nlist); } void add_at_end(List *nlist) { DBUG_ASSERT(nlist->elements); list.append(nlist); } bool fix_fields(THD *, Item **ref) override; void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) override; enum Type type() const override { return COND_ITEM; } List* argument_list() { return &list; } table_map used_tables() const override; void update_used_tables() override { used_tables_and_const_cache_init(); used_tables_and_const_cache_update_and_join(list); } COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) override; COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value, bool top_level) override; void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override; SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) override; void print(String *str, enum_query_type query_type) override; void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, uint flags) override; friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds); void top_level_item() override { abort_on_null=1; } bool top_level() { return abort_on_null; } void copy_andor_arguments(THD *thd, Item_cond *item); bool walk(Item_processor processor, bool walk_subquery, void *arg) override; Item *do_transform(THD *thd, Item_transformer transformer, uchar *arg, bool toplevel); Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override { return do_transform(thd, transformer, arg, 0); } Item *top_level_transform(THD *thd, Item_transformer transformer, uchar *arg) override { return do_transform(thd, transformer, arg, 1); } void traverse_cond(Cond_traverser, void *arg, traverse_order order) override; void neg_arguments(THD *thd); Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *) override; Item *do_compile(THD *thd, Item_analyzer analyzer, uchar **arg_p, Item_transformer transformer, uchar *arg_t, bool toplevel); Item *compile(THD *thd, Item_analyzer analyzer, uchar **arg_p, Item_transformer transformer, uchar *arg_t) override { return do_compile(thd, analyzer, arg_p, transformer, arg_t, 0); } Item* top_level_compile(THD *thd, Item_analyzer analyzer, uchar **arg_p, Item_transformer transformer, uchar *arg_t) override { return do_compile(thd, analyzer, arg_p, transformer, arg_t, 1); } bool eval_not_null_tables(void *opt_arg) override; bool find_not_null_fields(table_map allowed) override; Item *do_build_clone(THD *thd) const override; bool excl_dep_on_table(table_map tab_map) override; bool excl_dep_on_grouping_fields(st_select_lex *sel) override; private: void merge_sub_condition(List_iterator& li); }; template class LI, class T> class Item_equal_iterator; /* The class Item_equal is used to represent conjunctions of equality predicates of the form field1 = field2, and field=const in where conditions and on expressions. All equality predicates of the form field1=field2 contained in a conjunction are substituted for a sequence of items of this class. An item of this class Item_equal(f1,f2,...fk) represents a multiple equality f1=f2=...=fk.l If a conjunction contains predicates f1=f2 and f2=f3, a new item of this class is created Item_equal(f1,f2,f3) representing the multiple equality f1=f2=f3 that substitutes the above equality predicates in the conjunction. A conjunction of the predicates f2=f1 and f3=f1 and f3=f2 will be substituted for the item representing the same multiple equality f1=f2=f3. An item Item_equal(f1,f2) can appear instead of a conjunction of f2=f1 and f1=f2, or instead of just the predicate f1=f2. An item of the class Item_equal inherits equalities from outer conjunctive levels. Suppose we have a where condition of the following form: WHERE f1=f2 AND f3=f4 AND f3=f5 AND ... AND (...OR (f1=f3 AND ...)). In this case: f1=f2 will be substituted for Item_equal(f1,f2); f3=f4 and f3=f5 will be substituted for Item_equal(f3,f4,f5); f1=f3 will be substituted for Item_equal(f1,f2,f3,f4,f5); An object of the class Item_equal can contain an optional constant item c. Then it represents a multiple equality of the form c=f1=...=fk. Objects of the class Item_equal are used for the following: 1. An object Item_equal(t1.f1,...,tk.fk) allows us to consider any pair of tables ti and tj as joined by an equi-condition. Thus it provide us with additional access paths from table to table. 2. An object Item_equal(t1.f1,...,tk.fk) is applied to deduce new SARGable predicates: f1=...=fk AND P(fi) => f1=...=fk AND P(fi) AND P(fj). It also can give us additional index scans and can allow us to improve selectivity estimates. 3. An object Item_equal(t1.f1,...,tk.fk) is used to optimize the selected execution plan for the query: if table ti is accessed before the table tj then in any predicate P in the where condition the occurrence of tj.fj is substituted for ti.fi. This can allow an evaluation of the predicate at an earlier step. When feature 1 is supported they say that join transitive closure is employed. When feature 2 is supported they say that search argument transitive closure is employed. Both features are usually supported by preprocessing original query and adding additional predicates. We do not just add predicates, we rather dynamically replace some predicates that can not be used to access tables in the investigated plan for those, obtained by substitution of some fields for equal fields, that can be used. Prepared Statements/Stored Procedures note: instances of class Item_equal are created only at the time a PS/SP is executed and are deleted in the end of execution. All changes made to these objects need not be registered in the list of changes of the parse tree and do not harm PS/SP re-execution. Item equal objects are employed only at the optimize phase. Usually they are not supposed to be evaluated. Yet in some cases we call the method val_int() for them. We have to take care of restricting the predicate such an object represents f1=f2= ...=fn to the projection of known fields fi1=...=fik. */ class Item_equal: public Item_bool_func { /* The list of equal items. Currently the list can contain: - Item_fields items for references to table columns - Item_direct_view_ref items for references to view columns - one const item If the list contains a constant item this item is always first in the list. The list contains at least two elements. Currently all Item_fields/Item_direct_view_ref items in the list should refer to table columns with equavalent type definitions. In particular if these are string columns they should have the same charset/collation. Use objects of the companion class Item_equal_fields_iterator to iterate over all items from the list of the Item_field/Item_direct_view_ref classes. */ List equal_items; /* TRUE <-> one of the items is a const item. Such item is always first in in the equal_items list */ bool with_const; /* The field eval_item is used when this item is evaluated with the method val_int() */ cmp_item *eval_item; /* This initially is set to FALSE. It becomes TRUE when this item is evaluated as being always false. If the flag is TRUE the contents of the list the equal_items should be ignored. */ bool cond_false; /* This initially is set to FALSE. It becomes TRUE when this item is evaluated as being always true. If the flag is TRUE the contents of the list the equal_items should be ignored. */ bool cond_true; /* For Item_equal objects inside an OR clause: one of the fields that were used in the original equality. */ Item_field *context_field; bool link_equal_fields; const Type_handler *m_compare_handler; CHARSET_INFO *m_compare_collation; public: COND_EQUAL *upper_levels; /* multiple equalities of upper and levels */ Item_equal(THD *thd, const Type_handler *handler, Item *f1, Item *f2, bool with_const_item); Item_equal(THD *thd, Item_equal *item_equal); /* Currently the const item is always the first in the list of equal items */ inline Item* get_const() { return with_const ? equal_items.head() : NULL; } void add_const(THD *thd, Item *c); /** Add a non-constant item to the multiple equality */ void add(Item *f, MEM_ROOT *root) { equal_items.push_back(f, root); } bool contains(Field *field); Item* get_first(struct st_join_table *context, Item *field); /** Get number of field items / references to field items in this object */ uint n_field_items() { return equal_items.elements - MY_TEST(with_const); } void merge(THD *thd, Item_equal *item); bool merge_with_check(THD *thd, Item_equal *equal_item, bool save_merged); void merge_into_list(THD *thd, List *list, bool save_merged, bool only_intersected); void update_const(THD *thd); enum Functype functype() const override { return MULT_EQUAL_FUNC; } bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("multiple equal") }; return name; } void sort(Item_field_cmpfunc compare, void *arg); bool fix_length_and_dec() override; bool fix_fields(THD *thd, Item **ref) override; void cleanup() override { delete eval_item; eval_item= NULL; } void update_used_tables() override; bool find_not_null_fields(table_map allowed) override; COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) override; void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override; SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) override; bool walk(Item_processor processor, bool walk_subquery, void *arg) override; Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override; void print(String *str, enum_query_type query_type) override; const Type_handler *compare_type_handler() const { return m_compare_handler; } CHARSET_INFO *compare_collation() const override { return m_compare_collation; } void set_context_field(Item_field *ctx_field) { context_field= ctx_field; } void set_link_equal_fields(bool flag) { link_equal_fields= flag; } Item* do_get_copy(THD *thd) const override { return 0; } /* This does not comply with the specification of the virtual method, but Item_equal items are processed distinguishly anyway */ bool excl_dep_on_table(table_map tab_map) override { return used_tables() & tab_map; } bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override; bool excl_dep_on_grouping_fields(st_select_lex *sel) override; bool create_pushable_equalities(THD *thd, List *equalities, Pushdown_checker checker, uchar *arg, bool clone_const); /* Return the number of elements in this multiple equality */ uint elements_count() { return equal_items.elements; } friend class Item_equal_fields_iterator; bool count_sargable_conds(void *arg) override; Item *multiple_equality_transformer(THD *thd, uchar *arg) override; friend class Item_equal_iterator; friend class Item_equal_iterator; friend Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels, Item_equal *item_equal); friend bool setup_sj_materialization_part1(struct st_join_table *tab); friend bool setup_sj_materialization_part2(struct st_join_table *tab); }; class COND_EQUAL: public Sql_alloc { public: uint max_members; /* max number of members the current level list and all lower level lists */ COND_EQUAL *upper_levels; /* multiple equalities of upper and levels */ List current_level; /* list of multiple equalities of the current and level */ COND_EQUAL() { upper_levels= 0; } COND_EQUAL(Item_equal *item, MEM_ROOT *mem_root) :upper_levels(0) { current_level.push_back(item, mem_root); } void copy(COND_EQUAL &cond_equal) { max_members= cond_equal.max_members; upper_levels= cond_equal.upper_levels; if (cond_equal.current_level.is_empty()) current_level.empty(); else current_level= cond_equal.current_level; } bool is_empty() { return (current_level.elements == 0); } }; /* The template Item_equal_iterator is used to define classes Item_equal_fields_iterator and Item_equal_fields_iterator_slow. These are helper classes for the class Item equal Both classes are used to iterate over references to table/view columns from the list of equal items that included in an Item_equal object. The second class supports the operation of removal of the current member from the list when performing an iteration. */ template class LI, typename T> class Item_equal_iterator : public LI { protected: Item_equal *item_equal; Item *curr_item= nullptr; public: Item_equal_iterator(Item_equal &item_eq) :LI (item_eq.equal_items), item_equal(&item_eq) { if (item_eq.with_const) { LI *list_it= this; curr_item= (*list_it)++; } } Item* operator++(int) { LI *list_it= this; curr_item= (*list_it)++; return curr_item; } void rewind(void) { LI *list_it= this; list_it->rewind(); if (item_equal->with_const) curr_item= (*list_it)++; } Field *get_curr_field() { Item_field *item= (Item_field *) (curr_item->real_item()); return item->field; } }; typedef Item_equal_iterator Item_equal_iterator_fast; class Item_equal_fields_iterator :public Item_equal_iterator_fast { public: Item_equal_fields_iterator(Item_equal &item_eq) :Item_equal_iterator_fast(item_eq) { } Item ** ref() { return List_iterator_fast::ref(); } }; typedef Item_equal_iterator Item_equal_iterator_iterator_slow; class Item_equal_fields_iterator_slow :public Item_equal_iterator_iterator_slow { public: Item_equal_fields_iterator_slow(Item_equal &item_eq) :Item_equal_iterator_iterator_slow(item_eq) { } void remove() { List_iterator::remove(); } }; class Item_cond_and final :public Item_cond { public: COND_EQUAL m_cond_equal; /* contains list of Item_equal objects for the current and level and reference to multiple equalities of upper and levels */ Item_cond_and(THD *thd): Item_cond(thd) {} Item_cond_and(THD *thd, Item *i1,Item *i2): Item_cond(thd, i1, i2) {} Item_cond_and(THD *thd, Item_cond_and *item): Item_cond(thd, item) {} Item_cond_and(THD *thd, List &list_arg): Item_cond(thd, list_arg) {} enum Functype functype() const override { return COND_AND_FUNC; } bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("and") }; return name; } enum precedence precedence() const override { return AND_PRECEDENCE; } table_map not_null_tables() const override { return abort_on_null ? not_null_tables_cache: and_tables_cache; } Item *copy_andor_structure(THD *thd) override; Item *neg_transformer(THD *thd) override; void mark_as_condition_AND_part(TABLE_LIST *embedding) override; uint exists2in_reserved_items() override { return list.elements; }; COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) override; bool set_format_by_check_constraint(Send_field_extended_metadata *to) const override; void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables) override; SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; inline bool is_cond_and(Item *item) { Item_func *func_item= item->get_item_func(); return func_item && func_item->functype() == Item_func::COND_AND_FUNC; } class Item_cond_or final :public Item_cond { public: Item_cond_or(THD *thd): Item_cond(thd) {} Item_cond_or(THD *thd, Item *i1,Item *i2): Item_cond(thd, i1, i2) {} Item_cond_or(THD *thd, Item_cond_or *item): Item_cond(thd, item) {} Item_cond_or(THD *thd, List &list_arg): Item_cond(thd, list_arg) {} enum Functype functype() const override { return COND_OR_FUNC; } bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("or") }; return name; } enum precedence precedence() const override { return OR_PRECEDENCE; } table_map not_null_tables() const override { return and_tables_cache; } Item *copy_andor_structure(THD *thd) override; Item *neg_transformer(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_dyncol_check :public Item_bool_func { public: Item_func_dyncol_check(THD *thd, Item *str): Item_bool_func(thd, str) {} bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("column_check") }; return name; } bool need_parentheses_in_default() override { return false; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_dyncol_exists :public Item_bool_func { public: Item_func_dyncol_exists(THD *thd, Item *str, Item *num): Item_bool_func(thd, str, num) {} bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("column_exists") }; return name; } bool need_parentheses_in_default() override { return false; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_cursor_bool_attr: public Item_bool_func, public Cursor_ref { public: Item_func_cursor_bool_attr(THD *thd, const LEX_CSTRING *name, uint offset) :Item_bool_func(thd), Cursor_ref(name, offset) { } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), arg, VCOL_SESSION_FUNC); } void print(String *str, enum_query_type query_type) override { Cursor_ref::print_func(str, func_name_cstring()); } }; class Item_func_cursor_isopen: public Item_func_cursor_bool_attr { public: Item_func_cursor_isopen(THD *thd, const LEX_CSTRING *name, uint offset) :Item_func_cursor_bool_attr(thd, name, offset) { } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("%ISOPEN") }; return name; } bool val_bool() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_cursor_found: public Item_func_cursor_bool_attr { public: Item_func_cursor_found(THD *thd, const LEX_CSTRING *name, uint offset) :Item_func_cursor_bool_attr(thd, name, offset) { set_maybe_null(); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("%FOUND") }; return name; } bool val_bool() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_cursor_notfound: public Item_func_cursor_bool_attr { public: Item_func_cursor_notfound(THD *thd, const LEX_CSTRING *name, uint offset) :Item_func_cursor_bool_attr(thd, name, offset) { set_maybe_null(); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("%NOTFOUND") }; return name; } bool val_bool() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; inline bool is_cond_or(Item *item) { Item_func *func_item= item->get_item_func(); return func_item && func_item->functype() == Item_func::COND_OR_FUNC; } Item *and_expressions(Item *a, Item *b, Item **org_item); class Comp_creator { public: Comp_creator() = default; /* Remove gcc warning */ virtual ~Comp_creator() = default; /* Remove gcc warning */ /** Create operation with given arguments. */ virtual Item_bool_rowready_func2* create(THD *thd, Item *a, Item *b) const = 0; /** Create operation with given arguments in swap order. */ virtual Item_bool_rowready_func2* create_swap(THD *thd, Item *a, Item *b) const = 0; virtual const char* symbol(bool invert) const = 0; virtual bool eqne_op() const = 0; virtual bool l_op() const = 0; }; class Eq_creator :public Comp_creator { public: Eq_creator() = default; /* Remove gcc warning */ virtual ~Eq_creator() = default; /* Remove gcc warning */ Item_bool_rowready_func2* create(THD *thd, Item *a, Item *b) const override; Item_bool_rowready_func2* create_swap(THD *thd, Item *a, Item *b) const override; const char* symbol(bool invert) const override { return invert? "<>" : "="; } bool eqne_op() const override { return 1; } bool l_op() const override { return 0; } }; class Ne_creator :public Comp_creator { public: Ne_creator() = default; /* Remove gcc warning */ virtual ~Ne_creator() = default; /* Remove gcc warning */ Item_bool_rowready_func2* create(THD *thd, Item *a, Item *b) const override; Item_bool_rowready_func2* create_swap(THD *thd, Item *a, Item *b) const override; const char* symbol(bool invert) const override { return invert? "=" : "<>"; } bool eqne_op() const override { return 1; } bool l_op() const override { return 0; } }; class Gt_creator :public Comp_creator { public: Gt_creator() = default; /* Remove gcc warning */ virtual ~Gt_creator() = default; /* Remove gcc warning */ Item_bool_rowready_func2* create(THD *thd, Item *a, Item *b) const override; Item_bool_rowready_func2* create_swap(THD *thd, Item *a, Item *b) const override; const char* symbol(bool invert) const override { return invert? "<=" : ">"; } bool eqne_op() const override { return 0; } bool l_op() const override { return 0; } }; class Lt_creator :public Comp_creator { public: Lt_creator() = default; /* Remove gcc warning */ virtual ~Lt_creator() = default; /* Remove gcc warning */ Item_bool_rowready_func2* create(THD *thd, Item *a, Item *b) const override; Item_bool_rowready_func2* create_swap(THD *thd, Item *a, Item *b) const override; const char* symbol(bool invert) const override { return invert? ">=" : "<"; } bool eqne_op() const override { return 0; } bool l_op() const override { return 1; } }; class Ge_creator :public Comp_creator { public: Ge_creator() = default; /* Remove gcc warning */ virtual ~Ge_creator() = default; /* Remove gcc warning */ Item_bool_rowready_func2* create(THD *thd, Item *a, Item *b) const override; Item_bool_rowready_func2* create_swap(THD *thd, Item *a, Item *b) const override; const char* symbol(bool invert) const override { return invert? "<" : ">="; } bool eqne_op() const override { return 0; } bool l_op() const override { return 0; } }; class Le_creator :public Comp_creator { public: Le_creator() = default; /* Remove gcc warning */ virtual ~Le_creator() = default; /* Remove gcc warning */ Item_bool_rowready_func2* create(THD *thd, Item *a, Item *b) const override; Item_bool_rowready_func2* create_swap(THD *thd, Item *a, Item *b) const override; const char* symbol(bool invert) const override { return invert? ">" : "<="; } bool eqne_op() const override { return 0; } bool l_op() const override { return 1; } }; /* These need definitions from this file but the variables are defined in mysqld.h. The variables really belong in this component, but for the time being we leave them in mysqld.cc to avoid merge problems. */ extern Eq_creator eq_creator; extern Ne_creator ne_creator; extern Gt_creator gt_creator; extern Lt_creator lt_creator; extern Ge_creator ge_creator; extern Le_creator le_creator; #endif /* ITEM_CMPFUNC_INCLUDED */ server/private/winservice.h000064400000002252151031265040012051 0ustar00/* Copyright (c) 2011, 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Extract properties of a windows service binary path */ #ifdef __cplusplus extern "C" { #endif #include typedef struct mysqld_service_properties_st { char mysqld_exe[MAX_PATH]; char inifile[MAX_PATH]; char datadir[MAX_PATH]; int version_major; int version_minor; int version_patch; } mysqld_service_properties; extern int get_mysql_service_properties(const wchar_t *bin_path, mysqld_service_properties *props); #ifdef __cplusplus } #endif server/private/heap.h000064400000022410151031265040010606 0ustar00/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file should be included when using heap_database_functions */ /* Author: Michael Widenius */ #ifndef _heap_h #define _heap_h #ifdef __cplusplus extern "C" { #endif #ifndef _my_base_h #include #endif #include #include #include "my_compare.h" #include "my_tree.h" /* defines used by heap-functions */ #define HP_MAX_LEVELS 4 /* 128^5 records is enough */ #define HP_PTRS_IN_NOD 128 /* struct used with heap_functions */ typedef struct st_heapinfo /* Struct from heap_info */ { ulong records; /* Records in database */ ulong deleted; /* Deleted records in database */ ulong max_records; ulonglong data_length; ulonglong index_length; uint reclength; /* Length of one record */ int errkey; ulonglong auto_increment; time_t create_time; } HEAPINFO; /* Structs used by heap-database-handler */ typedef struct st_heap_ptrs { uchar *blocks[HP_PTRS_IN_NOD]; /* pointers to HP_PTRS or records */ } HP_PTRS; struct st_level_info { /* Number of unused slots in *last_blocks HP_PTRS block (0 for 0th level) */ uint free_ptrs_in_block; /* Maximum number of records that can be 'contained' inside of each element of last_blocks array. For level 0 - 1, for level 1 - HP_PTRS_IN_NOD, for level 2 - HP_PTRS_IN_NOD^2 and so forth. */ ulong records_under_level; /* Ptr to last allocated HP_PTRS (or records buffer for level 0) on this level. */ HP_PTRS *last_blocks; }; /* Heap table records and hash index entries are stored in HP_BLOCKs. HP_BLOCK is used as a 'growable array' of fixed-size records. Size of record is recbuffer bytes. The internal representation is as follows: HP_BLOCK is a hierarchical structure of 'blocks'. A block at level 0 is an array records_in_block records. A block at higher level is an HP_PTRS structure with pointers to blocks at lower levels. At the highest level there is one top block. It is stored in HP_BLOCK::root. See hp_find_block for a description of how record pointer is obtained from its index. See hp_get_new_block */ typedef struct st_heap_block { HP_PTRS *root; /* Top-level block */ struct st_level_info level_info[HP_MAX_LEVELS+1]; uint levels; /* number of used levels */ uint recbuffer; /* Length of one saved record */ ulong records_in_block; /* Records in one heap-block */ ulong last_allocated; /* number of records there is allocated space for */ size_t alloc_size; /* Allocate blocks of this size */ } HP_BLOCK; struct st_heap_info; /* For reference */ typedef struct st_hp_keydef /* Key definition with open */ { uint flag; /* HA_NOSAME | HA_NULL_PART_KEY */ uint keysegs; /* Number of key-segment */ uint length; /* Length of key (automatic) */ uint8 algorithm; /* HASH / BTREE */ HA_KEYSEG *seg; HP_BLOCK block; /* Where keys are saved */ /* Number of buckets used in hash table. Used only to provide #records estimates for heap key scans. */ ha_rows hash_buckets; TREE rb_tree; int (*write_key)(struct st_heap_info *info, struct st_hp_keydef *keyinfo, const uchar *record, uchar *recpos); int (*delete_key)(struct st_heap_info *info, struct st_hp_keydef *keyinfo, const uchar *record, uchar *recpos, int flag); uint (*get_key_length)(struct st_hp_keydef *keydef, const uchar *key); } HP_KEYDEF; typedef struct st_heap_share { HP_BLOCK block; HP_KEYDEF *keydef; ulonglong data_length,index_length,max_table_size; ulonglong auto_increment; ulong min_records,max_records; /* Params to open */ ulong records; /* records */ ulong blength; /* records rounded up to 2^n */ ulong deleted; /* Deleted records in database */ uint key_stat_version; /* version to indicate insert/delete */ uint key_version; /* Updated on key change */ uint file_version; /* Update on clear */ uint reclength; /* Length of one record */ uint visible; /* Offset to the visible/deleted mark */ uint changed; uint keys,max_key_length; uint currently_disabled_keys; /* saved value from "keys" when disabled */ uint open_count; uchar *del_link; /* Link to next block with del. rec */ char * name; /* Name of "memory-file" */ time_t create_time; THR_LOCK lock; my_bool delete_on_close; my_bool internal; /* Internal temporary table */ LIST open_list; uint auto_key; uint auto_key_type; /* real type of the auto key segment */ } HP_SHARE; struct st_hp_hash_info; typedef struct st_heap_info { HP_SHARE *s; uchar *current_ptr; struct st_hp_hash_info *current_hash_ptr; ulong current_record,next_block; int lastinx,errkey; int mode; /* Mode of file (READONLY..) */ uint opt_flag,update; uchar *lastkey; /* Last used key with rkey */ uchar *recbuf; /* Record buffer for rb-tree keys */ enum ha_rkey_function last_find_flag; TREE_ELEMENT *parents[MAX_TREE_HEIGHT+1]; TREE_ELEMENT **last_pos; uint key_version; /* Version at last read */ uint file_version; /* Version at scan */ uint lastkey_len; my_bool implicit_emptied; THR_LOCK_DATA lock; LIST open_list; } HP_INFO; typedef struct st_heap_create_info { HP_KEYDEF *keydef; uint auto_key; /* keynr [1 - maxkey] for auto key */ uint auto_key_type; uint keys; uint reclength; ulong max_records; ulong min_records; ulonglong max_table_size; ulonglong auto_increment; my_bool with_auto_increment; my_bool internal_table; /* TRUE if heap_create should 'pin' the created share by setting open_count to 1. Is only looked at if not internal_table. */ my_bool pin_share; } HP_CREATE_INFO; /* Prototypes for heap-functions */ extern HP_INFO *heap_open(const char *name, int mode); extern HP_INFO *heap_open_from_share(HP_SHARE *share, int mode); extern HP_INFO *heap_open_from_share_and_register(HP_SHARE *share, int mode); extern void heap_release_share(HP_SHARE *share, my_bool internal_table); extern int heap_close(HP_INFO *info); extern int heap_write(HP_INFO *info,const uchar *buff); extern int heap_update(HP_INFO *info,const uchar *old,const uchar *newdata); extern int heap_rrnd(HP_INFO *info,uchar *buf,uchar *pos); extern int heap_scan_init(HP_INFO *info); extern int heap_scan(HP_INFO *info, uchar *record); extern int heap_delete(HP_INFO *info,const uchar *buff); extern int heap_info(HP_INFO *info,HEAPINFO *x,int flag); extern int heap_create(const char *name, HP_CREATE_INFO *create_info, HP_SHARE **share, my_bool *created_new_share); extern int heap_delete_table(const char *name); extern void heap_drop_table(HP_INFO *info); extern int heap_extra(HP_INFO *info,enum ha_extra_function function); extern int heap_reset(HP_INFO *info); extern int heap_rename(const char *old_name,const char *new_name); extern int heap_panic(enum ha_panic_function flag); extern int heap_rsame(HP_INFO *info,uchar *record,int inx); extern int heap_rnext(HP_INFO *info,uchar *record); extern int heap_rprev(HP_INFO *info,uchar *record); extern int heap_rfirst(HP_INFO *info,uchar *record,int inx); extern int heap_rlast(HP_INFO *info,uchar *record,int inx); extern void heap_clear(HP_INFO *info); extern void heap_clear_keys(HP_INFO *info); extern int heap_disable_indexes(HP_INFO *info); extern int heap_enable_indexes(HP_INFO *info); extern int heap_indexes_are_disabled(HP_INFO *info); extern void heap_update_auto_increment(HP_INFO *info, const uchar *record); ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, const key_range *min_key, const key_range *max_key); int hp_panic(enum ha_panic_function flag); int heap_rkey(HP_INFO *info, uchar *record, int inx, const uchar *key, key_part_map keypart_map, enum ha_rkey_function find_flag); extern uchar * heap_find(HP_INFO *info,int inx,const uchar *key); extern int heap_check_heap(const HP_INFO *info, my_bool print_status); extern uchar *heap_position(HP_INFO *info); /* The following is for programs that uses the old HEAP interface where pointer to rows where a long instead of a (uchar*). */ #if defined(WANT_OLD_HEAP_VERSION) || defined(OLD_HEAP_VERSION) extern int heap_rrnd_old(HP_INFO *info,uchar *buf,ulong pos); extern ulong heap_position_old(HP_INFO *info); #endif #ifdef OLD_HEAP_VERSION typedef ulong HEAP_PTR; #define heap_position(A) heap_position_old(A) #define heap_rrnd(A,B,C) heap_rrnd_old(A,B,C) #else typedef uchar *HEAP_PTR; #endif #ifdef __cplusplus } #endif #endif server/private/wsrep_on.h000064400000003266151031265040011535 0ustar00/* Copyright 2022 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #ifndef WSREP_ON_H #define WSREP_ON_H #ifdef WITH_WSREP extern bool WSREP_ON_; extern bool WSREP_PROVIDER_EXISTS_; extern my_bool wsrep_emulate_bin_log; extern ulong wsrep_forced_binlog_format; #define WSREP_ON unlikely(WSREP_ON_) /* use xxxxxx_NNULL macros when thd pointer is guaranteed to be non-null to * avoid compiler warnings (GCC 6 and later) */ #define WSREP_NNULL(thd) \ (WSREP_PROVIDER_EXISTS_ && thd->variables.wsrep_on) #define WSREP(thd) \ (thd && WSREP_NNULL(thd)) #define WSREP_CLIENT_NNULL(thd) \ (WSREP_NNULL(thd) && thd->wsrep_client_thread) #define WSREP_CLIENT(thd) \ (WSREP(thd) && thd->wsrep_client_thread) #define WSREP_EMULATE_BINLOG_NNULL(thd) \ (WSREP_NNULL(thd) && wsrep_emulate_bin_log) #define WSREP_EMULATE_BINLOG(thd) \ (WSREP(thd) && wsrep_emulate_bin_log) #else #define WSREP_ON false #define WSREP(T) (0) #define WSREP_NNULL(T) (0) #define WSREP_EMULATE_BINLOG(thd) (0) #define WSREP_EMULATE_BINLOG_NNULL(thd) (0) #endif #endif server/private/lex_hash.h000064400000425727151031265040011506 0ustar00/* Do not edit this file directly! */ /* Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. */ /* Do not edit this file! This is generated by gen_lex_hash.cc that seeks for a perfect hash function */ #include "lex.h" static uchar sql_functions_map[16228]= { 0, 0, 179, 2, '!', '|', 29, 0, '<', 'X', 157, 0, 'B', 'Y', 57, 1, 'A', 'W', 45, 3, 'A', 'W', 190, 4, 'A', 'W', 165, 6, 'C', 'Z', 0, 9, 'A', 'V', 19, 11, 'A', 'Y', 31, 12, 'C', 'U', 37, 13, 'C', 'V', 199, 13, 'C', 'W', 96, 14, 'A', 'U', 168, 14, 'A', 'S', 249, 14, 'D', 'U', 59, 15, 'C', 'S', 81, 15, 'C', 'S', 151, 15, 0, 0, 54, 2, 'M', 'M', 199, 15, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 78, 1, 0, 0, 80, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 75, 1, 0, 0, 3, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 0, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, '<', '>', 121, 0, 0, 0, 179, 2, '=', '>', 124, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'T', 126, 0, 0, 0, 49, 0, 0, 0, 179, 2, 0, 0, 149, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'S', 128, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 122, 1, 'F', 'R', 144, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 109, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 173, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 178, 2, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 23, 0, 0, 0, 27, 0, 0, 0, 236, 0, 0, 0, 179, 2, 0, 0, 238, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 246, 0, 0, 0, 12, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 15, 1, 0, 0, 138, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 141, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 150, 1, 0, 0, 7, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'V', 186, 0, 0, 0, 41, 0, 0, 0, 102, 0, 'A', 'I', 227, 0, 0, 0, 164, 0, 0, 0, 205, 0, 0, 0, 217, 0, 0, 0, 179, 2, 'N', 'P', 236, 0, 0, 0, 179, 2, 0, 0, 24, 1, 0, 0, 238, 255, 'A', 'O', 239, 0, 'O', 'O', 9, 1, 'N', 'U', 14, 1, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'O', 22, 1, 'E', 'U', 37, 1, 0, 0, 179, 2, 0, 0, 136, 2, 0, 0, 152, 2, 0, 0, 179, 2, 'M', 'O', 54, 1, 0, 0, 11, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 16, 0, 0, 0, 179, 2, 'D', 'Y', 205, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 24, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 32, 0, 0, 0, 21, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 22, 0, 0, 0, 122, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 128, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 148, 0, 0, 0, 2, 1, 0, 0, 179, 2, 0, 0, 14, 1, 0, 0, 236, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'N', 254, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 104, 1, 0, 0, 234, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 233, 255, 'T', 'W', 10, 1, 0, 0, 131, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 232, 255, 0, 0, 142, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 154, 1, 0, 0, 200, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 253, 1, 0, 0, 21, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 47, 2, 0, 0, 179, 2, 0, 0, 66, 2, 0, 0, 222, 255, 0, 0, 215, 255, 0, 0, 174, 2, 0, 0, 179, 2, 0, 0, 172, 2, 'L', 'Y', 81, 1, 'A', 'U', 112, 1, 'A', 'U', 157, 1, 'A', 'X', 184, 1, 'A', 'U', 226, 1, 0, 0, 219, 0, 'A', 'O', 247, 1, 'N', 'N', 11, 2, 'O', 'S', 44, 2, 'E', 'I', 49, 2, 'A', 'O', 54, 2, 0, 0, 105, 1, 'A', 'U', 112, 2, 'N', 'V', 133, 2, 'A', 'R', 142, 2, 0, 0, 179, 2, 'A', 'O', 174, 2, 'H', 'T', 211, 2, 'E', 'Y', 232, 2, 'N', 'S', 24, 3, 0, 0, 153, 2, 'A', 'O', 30, 3, 0, 0, 171, 2, 0, 0, 175, 2, 0, 0, 42, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'T', 95, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 50, 0, 0, 0, 44, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 45, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 47, 0, 'L', 'S', 133, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 60, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 69, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 72, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 105, 0, 0, 0, 52, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'T', 141, 1, 0, 0, 55, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 251, 255, 'T', 'T', 178, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 137, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 145, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 152, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 153, 0, 'A', 'E', 179, 1, 0, 0, 116, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 120, 0, 0, 0, 157, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 158, 0, 0, 0, 179, 2, 'D', 'U', 208, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 183, 0, 0, 0, 165, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 168, 0, 0, 0, 191, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 196, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 210, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 211, 0, 'R', 'S', 6, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 227, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'U', 8, 2, 0, 0, 224, 0, 0, 0, 225, 0, 0, 0, 230, 0, 0, 0, 179, 2, 0, 0, 232, 0, 'T', 'T', 12, 2, '1', 'O', 13, 2, 0, 0, 3, 1, 0, 0, 4, 1, 0, 0, 5, 1, 0, 0, 6, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 7, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 11, 1, 0, 0, 21, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 22, 1, 0, 0, 25, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 27, 1, 0, 0, 29, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'S', 69, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'K', 'S', 88, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'O', 97, 2, 0, 0, 237, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 35, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 36, 1, 0, 0, 38, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 42, 1, 0, 0, 43, 1, 0, 0, 179, 2, 0, 0, 47, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 51, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 52, 1, 0, 0, 55, 1, 0, 0, 113, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 120, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 130, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 134, 1, 0, 0, 144, 1, 0, 0, 179, 2, 0, 0, 145, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 157, 1, 'G', 'T', 160, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 177, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 184, 1, 0, 0, 162, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 166, 1, 0, 0, 225, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'A', 189, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'W', 199, 2, 'D', 'L', 190, 2, 0, 0, 201, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 205, 1, 0, 0, 249, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 0, 2, 0, 0, 24, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 29, 2, 0, 0, 33, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'F', 'M', 224, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 75, 2, 0, 0, 37, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 38, 2, 0, 0, 98, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'E', 253, 2, 'E', 'M', 2, 3, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'I', 'U', 11, 3, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 118, 2, 0, 0, 99, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 100, 2, 0, 0, 101, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 102, 2, 0, 0, 213, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 116, 2, 0, 0, 124, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 137, 2, 0, 0, 157, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 159, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 161, 2, 0, 0, 165, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 168, 2, 'D', 'S', 68, 3, 'E', 'T', 84, 3, 'A', 'Y', 100, 3, 0, 0, 179, 2, 'L', 'V', 130, 3, 'A', 'O', 147, 3, 'R', 'R', 180, 3, 0, 0, 231, 0, 'N', 'N', 196, 3, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'O', 209, 3, 'A', 'Y', 0, 4, 'A', 'T', 25, 4, 'R', 'W', 45, 4, 'H', 'U', 51, 4, 'U', 'U', 65, 4, 'A', 'T', 71, 4, 'H', 'W', 118, 4, 0, 0, 90, 2, 'N', 'S', 147, 4, 0, 0, 144, 2, 'H', 'R', 174, 4, 0, 0, 12, 0, 0, 0, 179, 2, 0, 0, 13, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 18, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 25, 0, 0, 0, 36, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 43, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 48, 0, 0, 0, 51, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'E', 125, 3, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 70, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 250, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 104, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 115, 0, 0, 0, 57, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 63, 0, 0, 0, 160, 0, 0, 0, 161, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 169, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'E', 141, 3, 'N', 'R', 142, 3, 0, 0, 173, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 175, 0, 0, 0, 190, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 194, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'X', 162, 3, 0, 0, 179, 2, 0, 0, 179, 2, 'O', 'U', 169, 3, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'U', 176, 3, 0, 0, 197, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 198, 0, 0, 0, 199, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 202, 0, 0, 0, 206, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 209, 0, 'A', 'O', 181, 3, 0, 0, 220, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 222, 0, 'D', 'O', 197, 3, 0, 0, 248, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 252, 0, 0, 0, 253, 0, 'A', 'V', 220, 3, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'M', 'N', 242, 3, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', 'C', 244, 3, 0, 0, 33, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 37, 1, 0, 0, 39, 1, 0, 0, 41, 1, 'A', 'K', 245, 3, 0, 0, 44, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 49, 1, 0, 0, 79, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 93, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 98, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 109, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 110, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 111, 1, 0, 0, 114, 1, 0, 0, 179, 2, 0, 0, 117, 1, 0, 0, 179, 2, 0, 0, 119, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 230, 255, 0, 0, 151, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 155, 1, 0, 0, 179, 2, 0, 0, 159, 1, 0, 0, 174, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 193, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 194, 1, 'E', 'I', 66, 4, 0, 0, 196, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 197, 1, 'I', 'N', 91, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'U', 97, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 247, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 248, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 4, 2, 0, 0, 198, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 199, 1, 0, 0, 204, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 214, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 234, 1, 0, 0, 179, 2, 0, 0, 244, 1, 0, 0, 23, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 30, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'A', 134, 4, 0, 0, 83, 2, 0, 0, 179, 2, 0, 0, 85, 2, 'G', 'R', 135, 4, 0, 0, 42, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 67, 2, 'I', 'T', 153, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'I', 165, 4, 0, 0, 126, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 132, 2, 0, 0, 135, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 140, 2, 'E', 'I', 185, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 170, 2, 0, 0, 162, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 163, 2, 'C', 'T', 213, 4, 'A', 'I', 231, 4, 'H', 'U', 10, 5, 'E', 'O', 26, 5, 'L', 'X', 37, 5, 'A', 'O', 78, 5, 'L', 'R', 101, 5, 0, 0, 226, 0, 'G', 'S', 108, 5, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'O', 140, 5, 'A', 'O', 151, 5, 'E', 'U', 198, 5, 'F', 'T', 215, 5, 'A', 'L', 230, 5, 0, 0, 179, 2, 'E', 'O', 242, 5, 'C', 'Y', 37, 6, 0, 0, 92, 2, 'N', 'P', 150, 6, 0, 0, 145, 2, 'I', 'I', 157, 6, 0, 0, 10, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 19, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 28, 0, 0, 0, 34, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 35, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'G', 'T', 240, 4, 0, 0, 38, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'L', 254, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 253, 255, 0, 0, 39, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 40, 0, 0, 0, 58, 0, 0, 0, 66, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 68, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'M', 24, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 103, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 113, 0, 0, 0, 75, 0, 0, 0, 84, 0, 0, 0, 135, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 150, 0, 0, 0, 159, 0, 0, 0, 179, 2, 'A', 'G', 50, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 170, 0, 0, 0, 171, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 174, 0, 0, 0, 179, 2, 'C', 'P', 57, 5, 0, 0, 162, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 166, 0, 0, 0, 177, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 182, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'I', 'O', 71, 5, 0, 0, 185, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 186, 0, 0, 0, 192, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 195, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'O', 'O', 93, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 208, 0, 'A', 'A', 94, 5, 'T', 'T', 95, 5, '4', '8', 96, 5, 0, 0, 200, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 201, 0, 0, 0, 218, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 221, 0, 0, 0, 239, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 244, 0, 'F', 'S', 121, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'O', 'S', 135, 5, 0, 0, 250, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 255, 0, 0, 0, 17, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 18, 1, 0, 0, 34, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 40, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 48, 1, 0, 0, 57, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'M', 166, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 99, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 107, 1, 'I', 'I', 176, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 92, 1, 'A', 'U', 177, 5, 0, 0, 235, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 88, 1, 0, 0, 118, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 128, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 135, 1, 0, 0, 139, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 143, 1, 0, 0, 179, 2, 0, 0, 148, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 153, 1, 0, 0, 164, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 167, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 175, 1, 'G', 'V', 253, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'W', 25, 6, 0, 0, 213, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 220, 1, 0, 0, 221, 1, 0, 0, 222, 1, 0, 0, 179, 2, 'A', 'L', 13, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 239, 1, 0, 0, 241, 1, 0, 0, 179, 2, 0, 0, 246, 1, 0, 0, 224, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 232, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 227, 1, 0, 0, 251, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 255, 1, 0, 0, 7, 2, 0, 0, 179, 2, 'C', 'T', 60, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'G', 'M', 92, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 31, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', 'U', 105, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'R', 129, 6, 0, 0, 217, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 88, 2, 0, 0, 10, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 13, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'I', 'V', 78, 6, 0, 0, 179, 2, 0, 0, 22, 2, 0, 0, 17, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 20, 2, 'N', 'N', 99, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 28, 2, 'A', 'E', 100, 6, 0, 0, 26, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 27, 2, 0, 0, 36, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 39, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'N', 'R', 124, 6, 0, 0, 40, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 41, 2, 'R', 'T', 147, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 221, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 43, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 78, 2, 0, 0, 69, 2, 0, 0, 179, 2, 0, 0, 74, 2, 'I', 'L', 153, 6, 0, 0, 179, 2, 0, 0, 133, 2, 0, 0, 127, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 129, 2, 'N', 'T', 158, 6, 0, 0, 164, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 166, 2, 'C', 'U', 188, 6, 'E', 'O', 207, 6, 'A', 'U', 244, 6, 'E', 'Y', 53, 7, 'N', 'X', 101, 7, 'O', 'O', 130, 7, 0, 0, 214, 0, 'A', 'I', 138, 7, 'G', 'T', 147, 7, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'O', 180, 7, 'I', 'O', 195, 7, 'A', 'U', 202, 7, 'P', 'U', 21, 8, 'A', 'R', 27, 8, 0, 0, 195, 1, 'E', 'O', 76, 8, 'C', 'Y', 137, 8, 'H', 'R', 185, 8, 'N', 'S', 196, 8, 'A', 'I', 205, 8, 'I', 'R', 246, 8, 0, 0, 9, 0, 0, 0, 255, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 14, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 20, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 29, 0, 0, 0, 37, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'T', 'T', 218, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 46, 0, '_', '_', 219, 6, 'A', 'X', 220, 6, 0, 0, 254, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 252, 255, 0, 0, 53, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'A', 9, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'N', 15, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'R', 35, 7, 'N', 'R', 10, 7, 0, 0, 59, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 62, 0, 'L', 'U', 18, 7, 'M', 'P', 28, 7, 'T', 'V', 32, 7, 0, 0, 73, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 77, 0, 0, 0, 83, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 86, 0, 0, 0, 98, 0, 0, 0, 179, 2, 0, 0, 101, 0, 'D', 'T', 36, 7, 0, 0, 248, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 106, 0, 0, 0, 179, 2, 0, 0, 247, 255, 'C', 'L', 74, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'S', 97, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 156, 0, 'I', 'L', 84, 7, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'I', 88, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 133, 0, 0, 0, 129, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 130, 0, 0, 0, 131, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 132, 0, 'A', 'C', 98, 7, 0, 0, 143, 0, 0, 0, 179, 2, 0, 0, 144, 0, 0, 0, 167, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 172, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', 'T', 112, 7, 0, 0, 179, 0, 0, 0, 179, 2, 0, 0, 180, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 187, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 243, 255, 'L', 'R', 131, 7, 0, 0, 204, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 207, 0, 0, 0, 223, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 229, 0, 0, 0, 240, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'V', 161, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 19, 1, 0, 0, 249, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 1, 1, 0, 0, 8, 1, 0, 0, 179, 2, 0, 0, 20, 1, 0, 0, 31, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 32, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 50, 1, 0, 0, 97, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 108, 1, 0, 0, 116, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 121, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', '_', 223, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 136, 1, 'A', 'Y', 252, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 127, 1, 0, 0, 125, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 126, 1, 0, 0, 147, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 156, 1, 'C', 'R', 45, 8, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 176, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 178, 1, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'O', 61, 8, 0, 0, 160, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 168, 1, 0, 0, 182, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 186, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', 'F', 72, 8, 0, 0, 189, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 191, 1, 'B', 'V', 87, 8, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'U', 'W', 134, 8, 0, 0, 206, 1, 0, 0, 207, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 219, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'L', 108, 8, 0, 0, 233, 1, 0, 0, 179, 2, 'T', 'T', 118, 8, 0, 0, 243, 1, 0, 0, 179, 2, 0, 0, 245, 1, 'A', 'I', 109, 8, 0, 0, 226, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 228, 1, 'A', 'O', 119, 8, 0, 0, 236, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 237, 1, 0, 0, 252, 1, 0, 0, 179, 2, 0, 0, 1, 2, 0, 0, 9, 2, 0, 0, 179, 2, 0, 0, 19, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 44, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 76, 2, 'B', 'S', 160, 8, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 87, 2, 'D', 'J', 178, 8, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 84, 2, 0, 0, 218, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 80, 2, 0, 0, 113, 2, 0, 0, 107, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 114, 2, 'I', 'K', 202, 8, 0, 0, 179, 2, 0, 0, 134, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 139, 2, 0, 0, 125, 2, 0, 0, 179, 2, 0, 0, 128, 2, 'R', 'R', 214, 8, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'S', 244, 8, 'C', '_', 215, 8, 0, 0, 147, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 151, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 210, 255, 0, 0, 154, 2, 0, 0, 155, 2, 0, 0, 167, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 169, 2, 'A', 'O', 24, 9, 'A', 'U', 63, 9, 'N', 'X', 131, 9, 'U', 'U', 162, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 9, 1, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'O', 166, 9, 'A', 'O', 202, 9, 'A', 'V', 241, 9, 'P', 'V', 7, 10, 'A', 'R', 14, 10, 0, 0, 179, 2, 'E', 'O', 63, 10, 'C', 'W', 114, 10, 'I', 'R', 150, 10, 'N', 'T', 202, 10, 'A', 'A', 244, 10, 0, 0, 158, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 177, 2, 0, 0, 54, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 65, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'N', 39, 9, 0, 0, 71, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'T', 'T', 53, 9, 'A', 'I', 54, 9, 0, 0, 97, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 99, 0, 'T', 'Y', 84, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 138, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 146, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 154, 0, 'A', 'E', 90, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 123, 0, 'B', 'F', 95, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'T', '_', 100, 9, 0, 0, 117, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 119, 0, 0, 0, 121, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'S', 112, 9, 0, 0, 246, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 245, 255, 0, 0, 163, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'T', 142, 9, 0, 0, 176, 0, 0, 0, 179, 2, 0, 0, 178, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 188, 0, 'L', 'N', 163, 9, 0, 0, 212, 0, 0, 0, 179, 2, 0, 0, 213, 0, 0, 0, 28, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'N', 'N', 181, 9, 'G', 'G', 182, 9, 'B', 'T', 183, 9, 0, 0, 53, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 54, 1, 'X', 'X', 217, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'N', 'N', 230, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 106, 1, 'V', '_', 218, 9, 0, 0, 87, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'S', 228, 9, 0, 0, 82, 1, 0, 0, 83, 1, 'V', '_', 231, 9, 0, 0, 102, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 103, 1, 0, 0, 115, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 132, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 137, 1, 0, 0, 146, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 158, 1, 0, 0, 172, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 229, 255, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'O', 32, 10, 'C', 'V', 43, 10, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 192, 1, 0, 0, 179, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 183, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 185, 1, 'D', 'S', 74, 10, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'W', 102, 10, 0, 0, 210, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 215, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 229, 1, 0, 0, 179, 2, 0, 0, 179, 2, 'I', 'T', 90, 10, 0, 0, 235, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 238, 1, 0, 0, 250, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 254, 1, 0, 0, 6, 2, 0, 0, 179, 2, 'C', 'Q', 135, 10, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 25, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 35, 2, 0, 0, 34, 2, 0, 0, 179, 2, 0, 0, 45, 2, 0, 0, 49, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 68, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 86, 2, 0, 0, 12, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 16, 2, 'N', 'N', 160, 10, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'U', 181, 10, 'Y', 'Y', 161, 10, 'B', 'T', 162, 10, 0, 0, 106, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 108, 2, 0, 0, 110, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 115, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 117, 2, 'D', 'S', 209, 10, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', 'C', 225, 10, 0, 0, 123, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 131, 2, '_', '_', 226, 10, 'D', 'T', 227, 10, 0, 0, 141, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 142, 2, 'R', 'R', 245, 10, 'C', '_', 246, 10, 0, 0, 149, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 211, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 209, 255, 'G', 'L', 41, 11, 0, 0, 179, 2, 'H', 'U', 47, 11, 'A', 'U', 64, 11, 'X', 'X', 85, 11, 'E', 'O', 100, 11, 0, 0, 215, 0, 0, 0, 179, 2, 'M', 'S', 111, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 45, 1, 'E', 'I', 138, 11, 'O', 'T', 143, 11, 0, 0, 179, 2, 'A', 'R', 149, 11, 0, 0, 179, 2, 'E', 'O', 200, 11, 'A', 'U', 231, 11, 'E', 'I', 255, 11, 'N', 'N', 12, 12, 'A', 'A', 21, 12, 0, 0, 15, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 17, 0, 0, 0, 61, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'N', 61, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 249, 255, 0, 0, 74, 0, 0, 0, 85, 0, 0, 0, 90, 0, 0, 0, 118, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 142, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 155, 0, 'C', 'P', 86, 11, 0, 0, 181, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 184, 0, 0, 0, 193, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 203, 0, 0, 0, 243, 0, 'C', 'V', 118, 11, 0, 0, 13, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 16, 1, 0, 0, 247, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 245, 0, 0, 0, 179, 2, 0, 0, 10, 1, 0, 0, 90, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 96, 1, 0, 0, 129, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 231, 255, 'C', 'R', 167, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'O', 183, 11, 0, 0, 161, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 169, 1, 'C', 'C', 194, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 188, 1, 'E', 'I', 195, 11, 0, 0, 180, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 181, 1, 'A', 'T', 211, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 2, 2, 0, 0, 202, 1, 0, 0, 179, 2, 0, 0, 208, 1, 0, 0, 211, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 242, 1, 0, 0, 5, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'N', 'P', 252, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 32, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 53, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 70, 2, 0, 0, 216, 255, 0, 0, 14, 2, 0, 0, 179, 2, 0, 0, 15, 2, 'M', 'M', 4, 12, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 103, 2, 'P', 'P', 5, 12, 'O', 'T', 6, 12, 0, 0, 95, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 96, 2, 'B', 'I', 13, 12, 0, 0, 119, 2, 0, 0, 179, 2, 0, 0, 121, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 130, 2, 'R', 'R', 22, 12, 'B', 'I', 23, 12, 0, 0, 146, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 150, 2, 'C', 'S', 56, 12, 0, 0, 179, 2, 'H', 'O', 73, 12, 'A', 'E', 132, 12, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 216, 0, 0, 0, 179, 2, 0, 0, 237, 0, 0, 0, 23, 1, 0, 0, 179, 2, 0, 0, 30, 1, 'A', 'E', 160, 12, 'O', 'O', 188, 12, 'P', 'R', 199, 12, 'A', 'R', 202, 12, 0, 0, 179, 2, 'E', 'O', 220, 12, 'Q', 'T', 2, 13, 'A', 'E', 16, 13, 0, 0, 179, 2, 0, 0, 156, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 176, 2, 0, 0, 8, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 26, 0, 0, 0, 64, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'N', 81, 12, 'U', 'U', 84, 12, 'P', 'P', 95, 12, 'C', 'S', 103, 12, 'M', 'M', 85, 12, 'N', 'N', 86, 12, '_', '_', 87, 12, 'A', 'G', 88, 12, 0, 0, 78, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 82, 0, 'L', 'R', 96, 12, 0, 0, 87, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 88, 0, 0, 0, 89, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 91, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'I', 'T', 120, 12, 0, 0, 92, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 93, 0, 'Y', 'Y', 137, 12, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'N', 146, 12, '_', '_', 138, 12, 'M', 'S', 139, 12, 0, 0, 125, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 126, 0, 0, 0, 127, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 244, 255, 0, 0, 67, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'D', 165, 12, 'I', 'I', 166, 12, 'U', 'U', 167, 12, 'M', 'M', 168, 12, 'B', 'T', 169, 12, 0, 0, 89, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 91, 1, 'M', 'M', 189, 12, 'A', 'I', 190, 12, 0, 0, 123, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 124, 1, 0, 0, 149, 1, 0, 0, 179, 2, 0, 0, 152, 1, 0, 0, 171, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 173, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 187, 1, 'A', 'P', 231, 12, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'W', 'W', 247, 12, 0, 0, 203, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 212, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 223, 1, 0, 0, 225, 1, '_', '_', 248, 12, 'F', 'N', 249, 12, 0, 0, 3, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 224, 255, 'L', 'L', 6, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 220, 255, 'W', '_', 7, 13, 0, 0, 50, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 57, 2, 'B', 'B', 21, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 97, 2, 'L', 'L', 22, 13, 'E', 'E', 23, 13, 'S', '_', 24, 13, 0, 0, 93, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 91, 2, 'O', 'U', 56, 13, 'I', 'I', 66, 13, 0, 0, 189, 0, 0, 0, 242, 255, 0, 0, 179, 2, 'O', 'O', 86, 13, 0, 0, 254, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'Y', 97, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 190, 1, 0, 0, 179, 2, 'E', 'E', 141, 13, 'C', 'Y', 159, 13, 'R', 'R', 189, 13, 0, 0, 120, 2, 0, 0, 76, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'R', 63, 13, 'R', 'S', 64, 13, 0, 0, 108, 0, 0, 0, 114, 0, 'A', 'S', 67, 13, 0, 0, 141, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 147, 0, 'U', 'U', 87, 13, 'R', 'R', 88, 13, '_', '_', 89, 13, 'M', 'S', 90, 13, 0, 0, 234, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 235, 0, 'S', 'S', 122, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 95, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 112, 1, 'T', 'T', 123, 13, 'E', 'E', 124, 13, 'R', 'R', 125, 13, '_', '_', 126, 13, 'H', 'U', 127, 13, 0, 0, 61, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 65, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 76, 1, 'P', 'P', 142, 13, 'L', 'L', 143, 13, 'I', 'I', 144, 13, 'C', 'C', 145, 13, 'A', 'A', 146, 13, 'T', '_', 147, 13, 0, 0, 231, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 230, 1, 0, 0, 8, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 61, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 219, 255, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'S', 182, 13, 'T', 'T', 183, 13, 'E', 'E', 184, 13, 'M', 'M', 185, 13, '_', '_', 186, 13, 'T', 'U', 187, 13, 0, 0, 89, 2, 0, 0, 214, 255, 'A', 'I', 190, 13, 0, 0, 111, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 212, 255, 'A', 'U', 219, 13, 0, 0, 139, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 241, 255, 0, 0, 179, 2, 0, 0, 251, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 56, 1, 'A', 'E', 11, 14, 0, 0, 179, 2, 0, 0, 140, 1, 'A', 'E', 16, 14, 0, 0, 179, 2, 0, 0, 218, 1, 'E', 'U', 21, 14, 0, 0, 104, 2, 0, 0, 179, 2, 0, 0, 148, 2, 0, 0, 56, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 67, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'N', 240, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'R', 243, 13, 0, 0, 79, 0, 0, 0, 179, 2, 0, 0, 100, 0, 'R', 'R', 244, 13, 'E', 'E', 245, 13, 'N', 'N', 246, 13, 'T', 'T', 247, 13, '_', '_', 248, 13, 'D', 'U', 249, 13, 0, 0, 107, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 109, 0, 0, 0, 179, 2, 0, 0, 110, 0, 0, 0, 112, 0, 0, 0, 59, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 94, 1, 0, 0, 170, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 228, 255, 'R', 'S', 38, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'L', 40, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 81, 2, 0, 0, 18, 2, 0, 0, 223, 255, 'E', '_', 41, 14, 0, 0, 48, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'N', 'T', 68, 14, 0, 0, 55, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'S', 75, 14, 'I', 'I', 76, 14, '_', '_', 77, 14, 'H', 'Y', 78, 14, 0, 0, 60, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 62, 2, 0, 0, 179, 2, 0, 0, 65, 2, 'O', 'O', 117, 14, 'E', 'O', 125, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 228, 0, 0, 0, 0, 1, 0, 0, 240, 255, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'I', 136, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 163, 1, 0, 0, 179, 2, 'E', 'E', 145, 14, 'Q', 'U', 153, 14, 'I', 'R', 158, 14, 0, 0, 143, 2, 0, 0, 179, 2, 0, 0, 160, 2, 'L', 'L', 118, 14, 'U', 'U', 119, 14, 'M', 'M', 120, 14, 'N', 'N', 121, 14, '_', '_', 122, 14, 'C', 'D', 123, 14, 0, 0, 80, 0, 0, 0, 81, 0, 0, 0, 140, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 151, 0, 0, 0, 68, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 101, 1, 'F', 'L', 146, 14, 0, 0, 46, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 217, 1, 0, 0, 63, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 77, 2, 0, 0, 82, 2, 0, 0, 105, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 112, 2, 'U', 'V', 189, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 239, 255, 0, 0, 26, 1, 0, 0, 46, 1, 'A', 'A', 191, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 216, 1, 'Q', 'Q', 217, 14, 0, 0, 94, 2, 0, 0, 138, 2, 0, 0, 30, 0, 0, 0, 33, 0, 'S', 'S', 192, 14, 'T', 'T', 193, 14, 'E', 'E', 194, 14, 'R', 'R', 195, 14, '_', '_', 196, 14, 'L', 'S', 197, 14, 0, 0, 63, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'S', 205, 14, 'L', 'L', 206, 14, '_', '_', 207, 14, 'C', 'K', 208, 14, 0, 0, 72, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 74, 1, 'L', 'L', 218, 14, '_', '_', 219, 14, 'B', 'T', 220, 14, 0, 0, 51, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'S', 239, 14, 'I', 'I', 240, 14, '_', '_', 241, 14, 'M', 'S', 242, 14, 0, 0, 59, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 58, 2, 0, 0, 31, 0, 0, 0, 179, 2, 0, 0, 95, 0, 'A', 'E', 12, 15, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'A', 17, 15, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'E', 38, 15, 0, 0, 179, 2, 0, 0, 179, 2, 'Q', 'U', 54, 15, 0, 0, 124, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 134, 0, 'S', 'S', 18, 15, 'T', 'T', 19, 15, 'E', 'E', 20, 15, 'R', 'R', 21, 15, '_', '_', 22, 15, 'G', 'U', 23, 15, 0, 0, 60, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 62, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 64, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 70, 1, 0, 0, 179, 2, 0, 0, 77, 1, 0, 0, 165, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'R', 43, 15, 'C', 'C', 44, 15, 'E', 'E', 45, 15, 'N', 'N', 46, 15, 'T', 'T', 47, 15, 'I', 'I', 48, 15, 'L', 'L', 49, 15, 'E', 'E', 50, 15, '_', '_', 51, 15, 'C', 'D', 52, 15, 0, 0, 227, 255, 0, 0, 226, 255, 0, 0, 64, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 79, 2, 0, 0, 136, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 233, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 66, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 209, 1, 'Q', 'T', 77, 15, 0, 0, 179, 2, 0, 0, 122, 2, 0, 0, 56, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 72, 2, 'O', 'U', 98, 15, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'G', 'G', 105, 15, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'A', 127, 15, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 240, 1, 'Q', 'T', 147, 15, 0, 0, 96, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 111, 0, 'N', 'N', 106, 15, 'O', 'O', 107, 15, 'R', 'R', 108, 15, 'E', 'E', 109, 15, '_', '_', 110, 15, 'D', 'S', 111, 15, 0, 0, 241, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 242, 0, 'S', 'S', 128, 15, 'T', 'T', 129, 15, 'E', 'E', 130, 15, 'R', 'R', 131, 15, '_', '_', 132, 15, 'S', 'S', 133, 15, 'S', 'S', 134, 15, 'L', 'L', 135, 15, '_', '_', 136, 15, 'C', 'C', 137, 15, 'A', 'I', 138, 15, 0, 0, 69, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 71, 1, 0, 0, 52, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 71, 2, 0, 0, 94, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'I', 168, 15, 0, 0, 133, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'T', 183, 15, 'S', 'X', 177, 15, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 100, 1, 0, 0, 73, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 84, 1, 0, 0, 11, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 73, 2, 'A', 'A', 200, 15, 'S', 'X', 201, 15, 0, 0, 58, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, '_', '_', 207, 15, 'Q', 'U', 208, 15, 0, 0, 81, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'P', 'S', 213, 15, 0, 0, 85, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 86, 1, }; static uchar symbols_map[14956]= { 0, 0, 179, 2, '!', '|', 29, 0, '<', 'X', 157, 0, 'B', 'Y', 24, 1, 'A', 'W', 230, 2, 'A', 'W', 104, 4, 'A', 'W', 51, 6, 'C', 'Z', 81, 8, 'A', 'V', 38, 10, 'A', 'Y', 37, 11, 'C', 'U', 15, 12, 'C', 'V', 160, 12, 'C', 'W', 50, 13, 'A', 'U', 122, 13, 'A', 'S', 203, 13, 'D', 'U', 253, 13, 'C', 'S', 19, 14, 'C', 'S', 89, 14, 0, 0, 54, 2, 'M', 'M', 137, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 78, 1, 0, 0, 80, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 75, 1, 0, 0, 3, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 0, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, '<', '>', 121, 0, 0, 0, 179, 2, '=', '>', 124, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'T', 126, 0, 0, 0, 49, 0, 0, 0, 179, 2, 0, 0, 149, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'S', 128, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 122, 1, 'F', 'R', 144, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 109, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 173, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 178, 2, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 23, 0, 0, 0, 27, 0, 0, 0, 236, 0, 0, 0, 179, 2, 0, 0, 238, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 246, 0, 0, 0, 12, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 15, 1, 0, 0, 138, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 141, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 150, 1, 0, 0, 7, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'V', 186, 0, 0, 0, 41, 0, 0, 0, 102, 0, 'A', 'I', 227, 0, 0, 0, 164, 0, 0, 0, 205, 0, 0, 0, 217, 0, 0, 0, 179, 2, 'N', 'P', 236, 0, 0, 0, 179, 2, 0, 0, 24, 1, 0, 0, 179, 2, 0, 0, 104, 1, 0, 0, 131, 1, 'N', 'U', 239, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'O', 247, 0, 'E', 'S', 6, 1, 0, 0, 179, 2, 0, 0, 136, 2, 0, 0, 152, 2, 0, 0, 179, 2, 'M', 'O', 21, 1, 0, 0, 11, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 16, 0, 0, 0, 179, 2, 'D', 'Y', 205, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 24, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 32, 0, 0, 0, 21, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 22, 0, 0, 0, 122, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 128, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 148, 0, 0, 0, 2, 1, 0, 0, 179, 2, 0, 0, 14, 1, 0, 0, 142, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 154, 1, 0, 0, 200, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 253, 1, 0, 0, 21, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 47, 2, 0, 0, 179, 2, 0, 0, 66, 2, 0, 0, 174, 2, 0, 0, 179, 2, 0, 0, 172, 2, 'L', 'Y', 48, 1, 'A', 'U', 79, 1, 'A', 'U', 108, 1, 'A', 'X', 135, 1, 'A', 'U', 177, 1, 0, 0, 219, 0, 'A', 'O', 198, 1, 'N', 'N', 218, 1, 'O', 'S', 251, 1, 'E', 'I', 0, 2, 'A', 'O', 5, 2, 0, 0, 105, 1, 'A', 'U', 58, 2, 'N', 'V', 79, 2, 'A', 'R', 88, 2, 0, 0, 179, 2, 'E', 'O', 120, 2, 'H', 'T', 153, 2, 'E', 'Y', 174, 2, 'N', 'S', 209, 2, 0, 0, 153, 2, 'A', 'O', 215, 2, 0, 0, 171, 2, 0, 0, 175, 2, 0, 0, 42, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'T', 62, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 50, 0, 0, 0, 44, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 45, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 47, 0, 'L', 'S', 100, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 60, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 69, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 72, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 105, 0, 0, 0, 52, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 55, 0, 'T', 'T', 129, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 137, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 145, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 152, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 153, 0, 'A', 'E', 130, 1, 0, 0, 116, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 120, 0, 0, 0, 157, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 158, 0, 0, 0, 179, 2, 'D', 'U', 159, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 183, 0, 0, 0, 165, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 168, 0, 0, 0, 191, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 196, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 210, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 211, 0, 'R', 'S', 213, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 227, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'U', 215, 1, 0, 0, 224, 0, 0, 0, 225, 0, 0, 0, 230, 0, 0, 0, 179, 2, 0, 0, 232, 0, 'T', 'T', 219, 1, '1', 'O', 220, 1, 0, 0, 3, 1, 0, 0, 4, 1, 0, 0, 5, 1, 0, 0, 6, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 7, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 11, 1, 0, 0, 21, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 22, 1, 0, 0, 25, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 27, 1, 0, 0, 29, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'F', 'S', 20, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'K', 'S', 34, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'O', 43, 2, 0, 0, 35, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 36, 1, 0, 0, 38, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 42, 1, 0, 0, 43, 1, 0, 0, 179, 2, 0, 0, 47, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 51, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 52, 1, 0, 0, 55, 1, 0, 0, 113, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 120, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 130, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 134, 1, 0, 0, 144, 1, 0, 0, 179, 2, 0, 0, 145, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 157, 1, 'G', 'T', 106, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 177, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 184, 1, 0, 0, 162, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 166, 1, 'A', 'A', 131, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'W', 141, 2, 'D', 'L', 132, 2, 0, 0, 201, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 205, 1, 0, 0, 249, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 0, 2, 0, 0, 24, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 29, 2, 0, 0, 33, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'F', 'M', 166, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 75, 2, 0, 0, 37, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 38, 2, 0, 0, 98, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'E', 195, 2, 'E', 'M', 200, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 116, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 118, 2, 0, 0, 99, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 100, 2, 0, 0, 101, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 102, 2, 0, 0, 124, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 137, 2, 0, 0, 157, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 159, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 161, 2, 0, 0, 165, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 168, 2, 'D', 'S', 253, 2, 'E', 'T', 13, 3, 'A', 'Y', 29, 3, 0, 0, 179, 2, 'L', 'V', 59, 3, 'A', 'O', 76, 3, 'R', 'R', 109, 3, 0, 0, 231, 0, 'N', 'N', 125, 3, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'O', 138, 3, 'A', 'Y', 185, 3, 'A', 'E', 210, 3, 'R', 'W', 215, 3, 'H', 'U', 221, 3, 'U', 'U', 235, 3, 'A', 'T', 241, 3, 'H', 'W', 32, 4, 0, 0, 90, 2, 'N', 'S', 61, 4, 0, 0, 144, 2, 'H', 'R', 88, 4, 0, 0, 12, 0, 0, 0, 179, 2, 0, 0, 13, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 18, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 25, 0, 0, 0, 36, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 43, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 48, 0, 0, 0, 51, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'E', 54, 3, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 70, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 104, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 115, 0, 0, 0, 57, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 63, 0, 0, 0, 160, 0, 0, 0, 161, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 169, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'E', 70, 3, 'N', 'R', 71, 3, 0, 0, 173, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 175, 0, 0, 0, 190, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 194, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'X', 91, 3, 0, 0, 179, 2, 0, 0, 179, 2, 'O', 'U', 98, 3, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'U', 105, 3, 0, 0, 197, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 198, 0, 0, 0, 199, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 202, 0, 0, 0, 206, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 209, 0, 'A', 'O', 110, 3, 0, 0, 220, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 222, 0, 'D', 'O', 126, 3, 0, 0, 248, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 252, 0, 0, 0, 253, 0, 'A', 'V', 149, 3, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'M', 'N', 171, 3, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', 'C', 173, 3, 0, 0, 33, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 37, 1, 0, 0, 39, 1, 0, 0, 41, 1, 'A', 'K', 174, 3, 0, 0, 44, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 49, 1, 0, 0, 79, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 93, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 98, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 109, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 110, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 111, 1, 0, 0, 114, 1, 0, 0, 179, 2, 0, 0, 117, 1, 0, 0, 179, 2, 0, 0, 119, 1, 0, 0, 151, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 155, 1, 0, 0, 179, 2, 0, 0, 159, 1, 0, 0, 174, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 193, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 194, 1, 'E', 'I', 236, 3, 0, 0, 196, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 197, 1, 'I', 'N', 5, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'U', 11, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 247, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 248, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 4, 2, 0, 0, 198, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 199, 1, 0, 0, 204, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 214, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 234, 1, 0, 0, 179, 2, 0, 0, 244, 1, 0, 0, 23, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 30, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'A', 48, 4, 0, 0, 83, 2, 0, 0, 179, 2, 0, 0, 85, 2, 'G', 'R', 49, 4, 0, 0, 42, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 67, 2, 'I', 'T', 67, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'I', 79, 4, 0, 0, 126, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 132, 2, 0, 0, 135, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 140, 2, 'E', 'I', 99, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 170, 2, 0, 0, 162, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 163, 2, 'C', 'T', 127, 4, 'A', 'I', 145, 4, 'H', 'U', 174, 4, 'E', 'O', 190, 4, 'L', 'X', 201, 4, 'A', 'O', 242, 4, 'L', 'R', 9, 5, 0, 0, 226, 0, 'G', 'S', 16, 5, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'O', 48, 5, 'A', 'O', 59, 5, 'E', 'U', 84, 5, 'F', 'T', 101, 5, 'A', 'L', 116, 5, 0, 0, 179, 2, 'E', 'O', 128, 5, 'C', 'Y', 179, 5, 0, 0, 92, 2, 'N', 'P', 36, 6, 0, 0, 145, 2, 'I', 'I', 43, 6, 0, 0, 10, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 19, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 28, 0, 0, 0, 34, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 35, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'G', 'N', 154, 4, 0, 0, 38, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'L', 162, 4, 0, 0, 39, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 40, 0, 0, 0, 58, 0, 0, 0, 66, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 68, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'M', 188, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 103, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 113, 0, 0, 0, 75, 0, 0, 0, 84, 0, 0, 0, 135, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 150, 0, 0, 0, 159, 0, 0, 0, 179, 2, 'A', 'G', 214, 4, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 170, 0, 0, 0, 171, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 174, 0, 0, 0, 179, 2, 'C', 'P', 221, 4, 0, 0, 162, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 166, 0, 0, 0, 177, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 182, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'I', 'O', 235, 4, 0, 0, 185, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 186, 0, 0, 0, 192, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 195, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'O', 'O', 1, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 208, 0, 'A', 'A', 2, 5, 'T', 'T', 3, 5, '4', '8', 4, 5, 0, 0, 200, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 201, 0, 0, 0, 218, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 221, 0, 0, 0, 239, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 244, 0, 'F', 'S', 29, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'O', 'S', 43, 5, 0, 0, 250, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 255, 0, 0, 0, 17, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 18, 1, 0, 0, 34, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 40, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 48, 1, 0, 0, 57, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'M', 74, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 99, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 107, 1, 0, 0, 88, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 92, 1, 0, 0, 118, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 128, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 135, 1, 0, 0, 139, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 143, 1, 0, 0, 179, 2, 0, 0, 148, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 153, 1, 0, 0, 164, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 167, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 175, 1, 'G', 'V', 139, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'W', 167, 5, 0, 0, 213, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 220, 1, 0, 0, 221, 1, 0, 0, 222, 1, 0, 0, 179, 2, 'A', 'L', 155, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 239, 1, 0, 0, 241, 1, 0, 0, 179, 2, 0, 0, 246, 1, 0, 0, 224, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 232, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 227, 1, 0, 0, 251, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 255, 1, 0, 0, 7, 2, 0, 0, 179, 2, 'C', 'T', 202, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'G', 'M', 234, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 31, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', 'U', 247, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'R', 15, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 88, 2, 0, 0, 10, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 13, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'I', 'V', 220, 5, 0, 0, 179, 2, 0, 0, 22, 2, 0, 0, 17, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 20, 2, 'N', 'N', 241, 5, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 28, 2, 'A', 'E', 242, 5, 0, 0, 26, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 27, 2, 0, 0, 36, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 39, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'N', 'R', 10, 6, 0, 0, 40, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 41, 2, 'R', 'T', 33, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 43, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 78, 2, 0, 0, 69, 2, 0, 0, 179, 2, 0, 0, 74, 2, 'I', 'L', 39, 6, 0, 0, 179, 2, 0, 0, 133, 2, 0, 0, 127, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 129, 2, 'N', 'T', 44, 6, 0, 0, 164, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 166, 2, 'C', 'U', 74, 6, 'E', 'O', 93, 6, 'A', 'U', 104, 6, 'E', 'Y', 151, 6, 'N', 'X', 199, 6, 'O', 'O', 224, 6, 0, 0, 214, 0, 'A', 'I', 232, 6, 'G', 'T', 241, 6, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'O', 18, 7, 'I', 'O', 33, 7, 'A', 'U', 40, 7, 'P', 'U', 115, 7, 'A', 'R', 121, 7, 0, 0, 195, 1, 'E', 'O', 170, 7, 'C', 'Y', 231, 7, 'H', 'R', 16, 8, 'N', 'S', 27, 8, 'A', 'I', 36, 8, 'I', 'R', 71, 8, 0, 0, 9, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 14, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 20, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 29, 0, 0, 0, 37, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 46, 0, 0, 0, 53, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'A', 125, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'N', 131, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 106, 0, 'N', 'R', 126, 6, 0, 0, 59, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 62, 0, 'L', 'U', 134, 6, 'M', 'P', 144, 6, 'T', 'V', 148, 6, 0, 0, 73, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 77, 0, 0, 0, 83, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 86, 0, 0, 0, 98, 0, 0, 0, 179, 2, 0, 0, 101, 0, 'C', 'L', 172, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'S', 195, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 156, 0, 'I', 'L', 182, 6, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'I', 186, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 133, 0, 0, 0, 129, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 130, 0, 0, 0, 131, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 132, 0, 'A', 'C', 196, 6, 0, 0, 143, 0, 0, 0, 179, 2, 0, 0, 144, 0, 0, 0, 167, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 172, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', 'P', 210, 6, 0, 0, 179, 0, 0, 0, 179, 2, 0, 0, 180, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 187, 0, 'L', 'R', 225, 6, 0, 0, 204, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 207, 0, 0, 0, 223, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 229, 0, 0, 0, 240, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'V', 255, 6, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 19, 1, 0, 0, 249, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 1, 1, 0, 0, 8, 1, 0, 0, 179, 2, 0, 0, 20, 1, 0, 0, 31, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 32, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 50, 1, 0, 0, 97, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 108, 1, 0, 0, 116, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 121, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', '_', 61, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 136, 1, 'A', 'Y', 90, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 127, 1, 0, 0, 125, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 126, 1, 0, 0, 147, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 156, 1, 'C', 'R', 139, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 176, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 178, 1, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'O', 155, 7, 0, 0, 160, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 168, 1, 0, 0, 182, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 186, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', 'F', 166, 7, 0, 0, 189, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 191, 1, 'B', 'V', 181, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'U', 'W', 228, 7, 0, 0, 206, 1, 0, 0, 207, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 219, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'L', 202, 7, 0, 0, 233, 1, 0, 0, 179, 2, 'T', 'T', 212, 7, 0, 0, 243, 1, 0, 0, 179, 2, 0, 0, 245, 1, 'A', 'I', 203, 7, 0, 0, 226, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 228, 1, 'A', 'O', 213, 7, 0, 0, 236, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 237, 1, 0, 0, 252, 1, 0, 0, 179, 2, 0, 0, 1, 2, 0, 0, 9, 2, 0, 0, 179, 2, 0, 0, 19, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 44, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 76, 2, 'B', 'S', 254, 7, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 87, 2, 0, 0, 80, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 84, 2, 0, 0, 113, 2, 0, 0, 107, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 114, 2, 'I', 'K', 33, 8, 0, 0, 179, 2, 0, 0, 134, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 139, 2, 0, 0, 125, 2, 0, 0, 179, 2, 0, 0, 128, 2, 'R', 'R', 45, 8, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'S', 69, 8, 'C', 'Y', 46, 8, 0, 0, 147, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 151, 2, 0, 0, 154, 2, 0, 0, 155, 2, 0, 0, 167, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 169, 2, 'A', 'O', 105, 8, 'A', 'U', 144, 8, 'N', 'X', 181, 8, 'U', 'U', 212, 8, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 9, 1, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'O', 216, 8, 'A', 'O', 252, 8, 'A', 'V', 35, 9, 'P', 'V', 57, 9, 'A', 'R', 64, 9, 0, 0, 179, 2, 'E', 'O', 113, 9, 'C', 'W', 164, 9, 'I', 'R', 200, 9, 'N', 'T', 252, 9, 0, 0, 149, 2, 0, 0, 158, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 177, 2, 0, 0, 54, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 65, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'N', 120, 8, 0, 0, 71, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'T', 'T', 134, 8, 'A', 'I', 135, 8, 0, 0, 97, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 99, 0, 'T', 'Y', 165, 8, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 138, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 146, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 154, 0, 'A', 'E', 171, 8, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 123, 0, 'B', 'F', 176, 8, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 121, 0, 0, 0, 117, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 119, 0, 0, 0, 163, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'T', 192, 8, 0, 0, 176, 0, 0, 0, 179, 2, 0, 0, 178, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 188, 0, 'L', 'N', 213, 8, 0, 0, 212, 0, 0, 0, 179, 2, 0, 0, 213, 0, 0, 0, 28, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'N', 'N', 231, 8, 'G', 'G', 232, 8, 'B', 'T', 233, 8, 0, 0, 53, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 54, 1, 'X', 'X', 11, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'N', 'N', 24, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 106, 1, 'V', '_', 12, 9, 0, 0, 87, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'S', 22, 9, 0, 0, 82, 1, 0, 0, 83, 1, 'V', '_', 25, 9, 0, 0, 102, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 103, 1, 0, 0, 115, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 132, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 137, 1, 0, 0, 146, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 158, 1, 0, 0, 172, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'O', 82, 9, 'C', 'V', 93, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 192, 1, 0, 0, 179, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 183, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 185, 1, 'D', 'S', 124, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'W', 152, 9, 0, 0, 210, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 215, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 229, 1, 0, 0, 179, 2, 0, 0, 179, 2, 'I', 'T', 140, 9, 0, 0, 235, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 238, 1, 0, 0, 250, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 254, 1, 0, 0, 6, 2, 0, 0, 179, 2, 'C', 'Q', 185, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 25, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 35, 2, 0, 0, 34, 2, 0, 0, 179, 2, 0, 0, 45, 2, 0, 0, 49, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 68, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 86, 2, 0, 0, 12, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 16, 2, 'N', 'N', 210, 9, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'U', 231, 9, 'Y', 'Y', 211, 9, 'B', 'T', 212, 9, 0, 0, 106, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 108, 2, 0, 0, 110, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 115, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 117, 2, 'D', 'S', 3, 10, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'C', 'C', 19, 10, 0, 0, 123, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 131, 2, '_', '_', 20, 10, 'D', 'T', 21, 10, 0, 0, 141, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 142, 2, 'G', 'L', 60, 10, 0, 0, 179, 2, 'H', 'O', 66, 10, 'A', 'U', 77, 10, 'X', 'X', 98, 10, 'E', 'O', 113, 10, 0, 0, 215, 0, 0, 0, 179, 2, 'M', 'S', 124, 10, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 45, 1, 'E', 'I', 151, 10, 0, 0, 129, 1, 0, 0, 179, 2, 'A', 'R', 156, 10, 0, 0, 179, 2, 'E', 'O', 207, 10, 'A', 'T', 238, 10, 'E', 'I', 5, 11, 'N', 'N', 18, 11, 'A', 'A', 27, 11, 0, 0, 15, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 17, 0, 0, 0, 61, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'N', 74, 10, 0, 0, 74, 0, 0, 0, 85, 0, 0, 0, 90, 0, 0, 0, 118, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 142, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 155, 0, 'C', 'P', 99, 10, 0, 0, 181, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 184, 0, 0, 0, 193, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 203, 0, 0, 0, 243, 0, 'C', 'V', 131, 10, 0, 0, 13, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 16, 1, 0, 0, 247, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 245, 0, 0, 0, 179, 2, 0, 0, 10, 1, 0, 0, 90, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 96, 1, 'C', 'R', 174, 10, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'O', 190, 10, 0, 0, 161, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 169, 1, 'C', 'C', 201, 10, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 188, 1, 'E', 'I', 202, 10, 0, 0, 180, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 181, 1, 'A', 'T', 218, 10, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 2, 2, 0, 0, 202, 1, 0, 0, 179, 2, 0, 0, 208, 1, 0, 0, 211, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 242, 1, 0, 0, 5, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'N', 'P', 2, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 32, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 53, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 70, 2, 0, 0, 14, 2, 0, 0, 179, 2, 0, 0, 15, 2, 'M', 'M', 10, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 103, 2, 'P', 'P', 11, 11, 'O', 'T', 12, 11, 0, 0, 95, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 96, 2, 'B', 'I', 19, 11, 0, 0, 119, 2, 0, 0, 179, 2, 0, 0, 121, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 130, 2, 'R', 'R', 28, 11, 'B', 'I', 29, 11, 0, 0, 146, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 150, 2, 'C', 'S', 62, 11, 0, 0, 179, 2, 'H', 'O', 79, 11, 'A', 'E', 138, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 216, 0, 0, 0, 179, 2, 0, 0, 237, 0, 0, 0, 23, 1, 0, 0, 179, 2, 0, 0, 30, 1, 'A', 'E', 152, 11, 'O', 'O', 180, 11, 'P', 'R', 191, 11, 'A', 'R', 194, 11, 0, 0, 179, 2, 'E', 'O', 212, 11, 'Q', 'Q', 239, 11, 'A', 'E', 250, 11, 0, 0, 179, 2, 0, 0, 156, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 176, 2, 0, 0, 8, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 26, 0, 0, 0, 64, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'N', 87, 11, 'U', 'U', 90, 11, 'P', 'P', 101, 11, 'C', 'S', 109, 11, 'M', 'M', 91, 11, 'N', 'N', 92, 11, '_', '_', 93, 11, 'A', 'G', 94, 11, 0, 0, 78, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 82, 0, 'L', 'R', 102, 11, 0, 0, 87, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 88, 0, 0, 0, 89, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 91, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'I', 'T', 126, 11, 0, 0, 92, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 93, 0, 'Y', 'Y', 143, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 127, 0, '_', '_', 144, 11, 'M', 'S', 145, 11, 0, 0, 125, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 126, 0, 0, 0, 67, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'D', 'D', 157, 11, 'I', 'I', 158, 11, 'U', 'U', 159, 11, 'M', 'M', 160, 11, 'B', 'T', 161, 11, 0, 0, 89, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 91, 1, 'M', 'M', 181, 11, 'A', 'I', 182, 11, 0, 0, 123, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 124, 1, 0, 0, 149, 1, 0, 0, 179, 2, 0, 0, 152, 1, 0, 0, 171, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 173, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 187, 1, 'A', 'P', 223, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 3, 2, 0, 0, 203, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 212, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 223, 1, 0, 0, 225, 1, 'L', 'L', 240, 11, 'W', '_', 241, 11, 0, 0, 50, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 57, 2, 'B', 'B', 255, 11, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 97, 2, 'L', 'L', 0, 12, 'E', 'E', 1, 12, 'S', '_', 2, 12, 0, 0, 93, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 91, 2, 'O', 'U', 34, 12, 'I', 'I', 44, 12, 0, 0, 189, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'O', 'O', 64, 12, 0, 0, 254, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'Y', 75, 12, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 190, 1, 0, 0, 179, 2, 'E', 'E', 119, 12, 'C', 'Y', 137, 12, 0, 0, 111, 2, 0, 0, 120, 2, 0, 0, 76, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'R', 41, 12, 'R', 'S', 42, 12, 0, 0, 108, 0, 0, 0, 114, 0, 'A', 'S', 45, 12, 0, 0, 141, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 147, 0, 'U', 'U', 65, 12, 'R', 'R', 66, 12, '_', '_', 67, 12, 'M', 'S', 68, 12, 0, 0, 234, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 235, 0, 'S', 'S', 100, 12, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 95, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 112, 1, 'T', 'T', 101, 12, 'E', 'E', 102, 12, 'R', 'R', 103, 12, '_', '_', 104, 12, 'H', 'U', 105, 12, 0, 0, 61, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 65, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 76, 1, 'P', 'P', 120, 12, 'L', 'L', 121, 12, 'I', 'I', 122, 12, 'C', 'C', 123, 12, 'A', 'A', 124, 12, 'T', '_', 125, 12, 0, 0, 231, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 230, 1, 0, 0, 8, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 61, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 89, 2, 'A', 'U', 180, 12, 0, 0, 139, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 251, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 56, 1, 'A', 'E', 228, 12, 0, 0, 179, 2, 0, 0, 140, 1, 0, 0, 170, 1, 0, 0, 179, 2, 0, 0, 218, 1, 'E', 'U', 233, 12, 0, 0, 104, 2, 0, 0, 179, 2, 0, 0, 148, 2, 0, 0, 56, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 67, 0, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'N', 201, 12, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'R', 'R', 204, 12, 0, 0, 79, 0, 0, 0, 179, 2, 0, 0, 100, 0, 'R', 'R', 205, 12, 'E', 'E', 206, 12, 'N', 'N', 207, 12, 'T', 'T', 208, 12, '_', '_', 209, 12, 'D', 'U', 210, 12, 0, 0, 107, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 109, 0, 0, 0, 179, 2, 0, 0, 110, 0, 0, 0, 112, 0, 0, 0, 59, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 94, 1, 0, 0, 18, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'L', 'L', 250, 12, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 81, 2, 'E', '_', 251, 12, 0, 0, 48, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'N', 'T', 22, 13, 0, 0, 55, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'S', 29, 13, 'I', 'I', 30, 13, '_', '_', 31, 13, 'H', 'Y', 32, 13, 0, 0, 60, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 62, 2, 0, 0, 179, 2, 0, 0, 65, 2, 'O', 'O', 71, 13, 'E', 'O', 79, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 228, 0, 0, 0, 0, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'I', 90, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 163, 1, 0, 0, 179, 2, 'E', 'E', 99, 13, 'Q', 'U', 107, 13, 'I', 'R', 112, 13, 0, 0, 143, 2, 0, 0, 179, 2, 0, 0, 160, 2, 'L', 'L', 72, 13, 'U', 'U', 73, 13, 'M', 'M', 74, 13, 'N', 'N', 75, 13, '_', '_', 76, 13, 'C', 'D', 77, 13, 0, 0, 80, 0, 0, 0, 81, 0, 0, 0, 140, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 151, 0, 0, 0, 68, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 101, 1, 'F', 'L', 100, 13, 0, 0, 46, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 217, 1, 0, 0, 63, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 77, 2, 0, 0, 82, 2, 0, 0, 105, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 112, 2, 'U', 'V', 143, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 26, 1, 0, 0, 46, 1, 'A', 'A', 145, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 216, 1, 'Q', 'Q', 171, 13, 0, 0, 94, 2, 0, 0, 138, 2, 0, 0, 30, 0, 0, 0, 33, 0, 'S', 'S', 146, 13, 'T', 'T', 147, 13, 'E', 'E', 148, 13, 'R', 'R', 149, 13, '_', '_', 150, 13, 'L', 'S', 151, 13, 0, 0, 63, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'S', 159, 13, 'L', 'L', 160, 13, '_', '_', 161, 13, 'C', 'K', 162, 13, 0, 0, 72, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 74, 1, 'L', 'L', 172, 13, '_', '_', 173, 13, 'B', 'T', 174, 13, 0, 0, 51, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'S', 'S', 193, 13, 'I', 'I', 194, 13, '_', '_', 195, 13, 'M', 'S', 196, 13, 0, 0, 59, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 58, 2, 0, 0, 31, 0, 0, 0, 179, 2, 0, 0, 95, 0, 'A', 'E', 222, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'A', 227, 13, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 165, 1, 0, 0, 179, 2, 0, 0, 179, 2, 'Q', 'U', 248, 13, 0, 0, 124, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 134, 0, 'S', 'S', 228, 13, 'T', 'T', 229, 13, 'E', 'E', 230, 13, 'R', 'R', 231, 13, '_', '_', 232, 13, 'G', 'U', 233, 13, 0, 0, 60, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 62, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 64, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 70, 1, 0, 0, 179, 2, 0, 0, 77, 1, 0, 0, 64, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 79, 2, 0, 0, 136, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 233, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 66, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 209, 1, 'Q', 'T', 15, 14, 0, 0, 179, 2, 0, 0, 122, 2, 0, 0, 56, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 72, 2, 'O', 'U', 36, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'G', 'G', 43, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'A', 65, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 240, 1, 'Q', 'T', 85, 14, 0, 0, 96, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 111, 0, 'N', 'N', 44, 14, 'O', 'O', 45, 14, 'R', 'R', 46, 14, 'E', 'E', 47, 14, '_', '_', 48, 14, 'D', 'S', 49, 14, 0, 0, 241, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 242, 0, 'S', 'S', 66, 14, 'T', 'T', 67, 14, 'E', 'E', 68, 14, 'R', 'R', 69, 14, '_', '_', 70, 14, 'S', 'S', 71, 14, 'S', 'S', 72, 14, 'L', 'L', 73, 14, '_', '_', 74, 14, 'C', 'C', 75, 14, 'A', 'I', 76, 14, 0, 0, 69, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 71, 1, 0, 0, 52, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 71, 2, 0, 0, 94, 0, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'A', 'I', 106, 14, 0, 0, 133, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'E', 'T', 121, 14, 'S', 'X', 115, 14, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 100, 1, 0, 0, 73, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 84, 1, 0, 0, 11, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 73, 2, 'A', 'A', 138, 14, 'S', 'X', 139, 14, 0, 0, 58, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, '_', '_', 145, 14, 'Q', 'U', 146, 14, 0, 0, 81, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 179, 2, 'P', 'S', 151, 14, 0, 0, 85, 1, 0, 0, 179, 2, 0, 0, 179, 2, 0, 0, 86, 1, }; static unsigned int sql_functions_max_len=29; static unsigned int symbols_max_len=29; static SYMBOL *get_hash_symbol(const char *s, unsigned int len,bool function) { uchar *hash_map; const char *cur_str= s; if (len == 0) { DBUG_PRINT("warning", ("get_hash_symbol() received a request for a zero-length symbol, which is probably a mistake.")); return(NULL); } if (function){ if (len>sql_functions_max_len) return 0; hash_map= sql_functions_map; uint32 cur_struct= uint4korr(hash_map+((len-1)*4)); for (;;){ uchar first_char= (uchar)cur_struct; if (first_char == 0) { int16 ires= (int16)(cur_struct>>16); if (ires==array_elements(symbols)) return 0; SYMBOL *res; if (ires>=0) res= symbols+ires; else res= sql_functions-ires-1; uint count= (uint) (cur_str - s); return lex_casecmp(cur_str,res->name+count,len-count) ? 0 : res; } uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str]; if (cur_char>=8; if (cur_char>(uchar)cur_struct) return 0; cur_struct>>=8; cur_struct= uint4korr(hash_map+ (((uint16)cur_struct + cur_char - first_char)*4)); cur_str++; } }else{ if (len>symbols_max_len) return 0; hash_map= symbols_map; uint32 cur_struct= uint4korr(hash_map+((len-1)*4)); for (;;){ uchar first_char= (uchar)cur_struct; if (first_char==0) { int16 ires= (int16)(cur_struct>>16); if (ires==array_elements(symbols)) return 0; SYMBOL *res= symbols+ires; uint count= (uint) (cur_str - s); return lex_casecmp(cur_str,res->name+count,len-count)!=0 ? 0 : res; } uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str]; if (cur_char>=8; if (cur_char>(uchar)cur_struct) return 0; cur_struct>>=8; cur_struct= uint4korr(hash_map+ (((uint16)cur_struct + cur_char - first_char)*4)); cur_str++; } } } server/private/sql_delete.h000064400000002477151031265040012025 0ustar00/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_DELETE_INCLUDED #define SQL_DELETE_INCLUDED #include "my_base.h" /* ha_rows */ class THD; struct TABLE_LIST; class Item; class select_result; typedef class Item COND; template class SQL_I_List; int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds, bool *delete_while_scanning); bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_I_List *order, ha_rows rows, ulonglong options, select_result *result); #endif /* SQL_DELETE_INCLUDED */ server/private/proxy_protocol.h000064400000001044151031265040012773 0ustar00#include "my_net.h" struct proxy_peer_info { struct sockaddr_storage peer_addr; int port; bool is_local_command; }; extern bool has_proxy_protocol_header(NET *net); extern int parse_proxy_protocol_header(NET *net, proxy_peer_info *peer_info); extern bool is_proxy_protocol_allowed(const sockaddr *remote_addr); extern int init_proxy_protocol_networks(const char *spec); extern void destroy_proxy_protocol_networks(); extern int set_proxy_protocol_networks(const char *spec); extern bool proxy_protocol_networks_valid(const char *spec); server/private/item_timefunc.h000064400000176147151031265040012542 0ustar00#ifndef ITEM_TIMEFUNC_INCLUDED #define ITEM_TIMEFUNC_INCLUDED /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. Copyright (c) 2009-2011, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Function items used by mysql */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif class MY_LOCALE; bool get_interval_value(THD *thd, Item *args, interval_type int_type, INTERVAL *interval); class Item_long_func_date_field: public Item_long_ge0_func { bool check_arguments() const override { return args[0]->check_type_can_return_date(func_name_cstring()); } public: Item_long_func_date_field(THD *thd, Item *a) :Item_long_ge0_func(thd, a) { } }; class Item_long_func_time_field: public Item_long_ge0_func { bool check_arguments() const override { return args[0]->check_type_can_return_time(func_name_cstring()); } public: Item_long_func_time_field(THD *thd, Item *a) :Item_long_ge0_func(thd, a) { } }; class Item_func_period_add :public Item_long_func { bool check_arguments() const override { return check_argument_types_can_return_int(0, 2); } public: Item_func_period_add(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("period_add") }; return name; } bool fix_length_and_dec() override { max_length=6*MY_CHARSET_BIN_MB_MAXLEN; return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_period_diff :public Item_long_func { bool check_arguments() const override { return check_argument_types_can_return_int(0, 2); } public: Item_func_period_diff(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("period_diff") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=6*MY_CHARSET_BIN_MB_MAXLEN; return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_to_days :public Item_long_func_date_field { public: Item_func_to_days(THD *thd, Item *a): Item_long_func_date_field(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("to_days") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=6*MY_CHARSET_BIN_MB_MAXLEN; set_maybe_null(); return FALSE; } enum_monotonicity_info get_monotonicity_info() const override; longlong val_int_endpoint(bool left_endp, bool *incl_endp) override; bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_to_seconds :public Item_longlong_func { bool check_arguments() const override { return check_argument_types_can_return_date(0, arg_count); } public: Item_func_to_seconds(THD *thd, Item *a): Item_longlong_func(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("to_seconds") }; return name; } bool fix_length_and_dec() override { decimals=0; fix_char_length(12); set_maybe_null(); return FALSE; } enum_monotonicity_info get_monotonicity_info() const override; longlong val_int_endpoint(bool left_endp, bool *incl_endp) override; bool check_partition_func_processor(void *bool_arg) override { return FALSE;} /* Only meaningful with date part and optional time part */ bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_dayofmonth :public Item_long_func_date_field { public: Item_func_dayofmonth(THD *thd, Item *a): Item_long_func_date_field(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("dayofmonth") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=2*MY_CHARSET_BIN_MB_MAXLEN; set_maybe_null(); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_month :public Item_long_ge0_func { public: Item_func_month(THD *thd, Item *a): Item_long_ge0_func(thd, a) { } longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("month") }; return name; } bool fix_length_and_dec() override { decimals= 0; fix_char_length(2); set_maybe_null(); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_monthname :public Item_str_func { MY_LOCALE *locale; public: Item_func_monthname(THD *thd, Item *a): Item_str_func(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("monthname") }; return name; } String *val_str(String *str) override; bool fix_length_and_dec() override; bool check_partition_func_processor(void *int_arg) override {return TRUE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_dayofyear :public Item_long_func_date_field { public: Item_func_dayofyear(THD *thd, Item *a): Item_long_func_date_field(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("dayofyear") }; return name; } bool fix_length_and_dec() override { decimals= 0; fix_char_length(3); set_maybe_null(); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_hour :public Item_long_func_time_field { public: Item_func_hour(THD *thd, Item *a): Item_long_func_time_field(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("hour") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=2*MY_CHARSET_BIN_MB_MAXLEN; set_maybe_null(); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_time_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_minute :public Item_long_func_time_field { public: Item_func_minute(THD *thd, Item *a): Item_long_func_time_field(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("minute") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=2*MY_CHARSET_BIN_MB_MAXLEN; set_maybe_null(); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_time_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_quarter :public Item_long_func_date_field { public: Item_func_quarter(THD *thd, Item *a): Item_long_func_date_field(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("quarter") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=1*MY_CHARSET_BIN_MB_MAXLEN; set_maybe_null(); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_second :public Item_long_func_time_field { public: Item_func_second(THD *thd, Item *a): Item_long_func_time_field(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("second") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=2*MY_CHARSET_BIN_MB_MAXLEN; set_maybe_null(); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_time_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_week :public Item_long_ge0_func { bool check_arguments() const override { return args[0]->check_type_can_return_date(func_name_cstring()) || (arg_count > 1 && args[1]->check_type_can_return_int(func_name_cstring())); } public: Item_func_week(THD *thd, Item *a): Item_long_ge0_func(thd, a) {} Item_func_week(THD *thd, Item *a, Item *b): Item_long_ge0_func(thd, a, b) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("week") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=2*MY_CHARSET_BIN_MB_MAXLEN; set_maybe_null(); return FALSE; } bool check_vcol_func_processor(void *arg) override { if (arg_count == 2) return FALSE; return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); } bool check_valid_arguments_processor(void *int_arg) override { return arg_count == 2; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_yearweek :public Item_long_func { bool check_arguments() const override { return args[0]->check_type_can_return_date(func_name_cstring()) || args[1]->check_type_can_return_int(func_name_cstring()); } public: Item_func_yearweek(THD *thd, Item *a, Item *b) :Item_long_func(thd, a, b) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("yearweek") }; return name; } bool fix_length_and_dec() override { decimals=0; max_length=6*MY_CHARSET_BIN_MB_MAXLEN; set_maybe_null(); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_year :public Item_long_func_date_field { public: Item_func_year(THD *thd, Item *a): Item_long_func_date_field(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("year") }; return name; } enum_monotonicity_info get_monotonicity_info() const override; longlong val_int_endpoint(bool left_endp, bool *incl_endp) override; bool fix_length_and_dec() override { decimals=0; max_length=4*MY_CHARSET_BIN_MB_MAXLEN; set_maybe_null(); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_weekday :public Item_long_func { bool odbc_type; public: Item_func_weekday(THD *thd, Item *a, bool type_arg): Item_long_func(thd, a), odbc_type(type_arg) { } longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING dayofweek= {STRING_WITH_LEN("dayofweek") }; static LEX_CSTRING weekday= {STRING_WITH_LEN("weekday") }; return (odbc_type ? dayofweek : weekday); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } bool fix_length_and_dec() override { decimals= 0; fix_char_length(1); set_maybe_null(); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_dayname :public Item_str_func { MY_LOCALE *locale; public: Item_func_dayname(THD *thd, Item *a): Item_str_func(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("dayname") }; return name; } String *val_str(String *str) override; const Type_handler *type_handler() const override { return &type_handler_varchar; } bool fix_length_and_dec() override; bool check_partition_func_processor(void *int_arg) override {return TRUE;} bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); } bool check_valid_arguments_processor(void *int_arg) override { return !has_date_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_seconds_hybrid: public Item_func_numhybrid { public: Item_func_seconds_hybrid(THD *thd): Item_func_numhybrid(thd) {} Item_func_seconds_hybrid(THD *thd, Item *a): Item_func_numhybrid(thd, a) {} void fix_length_and_dec_generic(uint dec) { DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); decimals= dec; max_length=17 + (decimals ? decimals + 1 : 0); set_maybe_null(); if (decimals) set_handler(&type_handler_newdecimal); else set_handler(type_handler_long_or_longlong()); } double real_op() override { DBUG_ASSERT(0); return 0; } String *str_op(String *str) override { DBUG_ASSERT(0); return 0; } bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { DBUG_ASSERT(0); return true; } }; class Item_func_unix_timestamp :public Item_func_seconds_hybrid { bool get_timestamp_value(my_time_t *seconds, ulong *second_part); public: Item_func_unix_timestamp(THD *thd): Item_func_seconds_hybrid(thd) {} Item_func_unix_timestamp(THD *thd, Item *a): Item_func_seconds_hybrid(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("unix_timestamp") }; return name; } enum_monotonicity_info get_monotonicity_info() const override; longlong val_int_endpoint(bool left_endp, bool *incl_endp) override; bool check_partition_func_processor(void *int_arg) override {return FALSE;} /* UNIX_TIMESTAMP() depends on the current timezone (and thus may not be used as a partitioning function) when its argument is NOT of the TIMESTAMP type. */ bool check_valid_arguments_processor(void *int_arg) override { return !has_timestamp_args(); } bool check_vcol_func_processor(void *arg) override { if (arg_count) return FALSE; return mark_unsupported_function(func_name(), "()", arg, VCOL_TIME_FUNC); } bool fix_length_and_dec() override { fix_length_and_dec_generic(arg_count ? args[0]->datetime_precision(current_thd) : 0); return FALSE; } longlong int_op() override; my_decimal *decimal_op(my_decimal* buf) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_time_to_sec :public Item_func_seconds_hybrid { public: Item_func_time_to_sec(THD *thd, Item *item): Item_func_seconds_hybrid(thd, item) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("time_to_sec") }; return name; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_time_args(); } bool fix_length_and_dec() override { fix_length_and_dec_generic(args[0]->time_precision(current_thd)); return FALSE; } longlong int_op() override; my_decimal *decimal_op(my_decimal* buf) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_datefunc :public Item_func { public: Item_datefunc(THD *thd): Item_func(thd) { } Item_datefunc(THD *thd, Item *a): Item_func(thd, a) { } Item_datefunc(THD *thd, Item *a, Item *b): Item_func(thd, a, b) { } const Type_handler *type_handler() const override { return &type_handler_newdate; } longlong val_int() override { DBUG_ASSERT(!is_cond()); return Date(this).to_longlong(); } double val_real() override { return Date(this).to_double(); } String *val_str(String *to) override { return Date(this).to_string(to); } my_decimal *val_decimal(my_decimal *to) override { return Date(this).to_decimal(to); } bool fix_length_and_dec() override { fix_attributes_date(); set_maybe_null(arg_count > 0); return FALSE; } }; class Item_timefunc :public Item_func { public: Item_timefunc(THD *thd): Item_func(thd) {} Item_timefunc(THD *thd, Item *a): Item_func(thd, a) {} Item_timefunc(THD *thd, Item *a, Item *b): Item_func(thd, a, b) {} Item_timefunc(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b ,c) {} const Type_handler *type_handler() const override { return &type_handler_time2; } longlong val_int() override { DBUG_ASSERT(!is_cond()); return Time(this).to_longlong(); } double val_real() override { return Time(this).to_double(); } String *val_str(String *to) override { return Time(this).to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) override { return Time(this).to_decimal(to); } bool val_native(THD *thd, Native *to) override { return Time(thd, this).to_native(to, decimals); } }; class Item_datetimefunc :public Item_func { public: Item_datetimefunc(THD *thd): Item_func(thd) {} Item_datetimefunc(THD *thd, Item *a): Item_func(thd, a) {} Item_datetimefunc(THD *thd, Item *a, Item *b): Item_func(thd, a, b) {} Item_datetimefunc(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b ,c) {} const Type_handler *type_handler() const override { return &type_handler_datetime2; } longlong val_int() override { DBUG_ASSERT(!is_cond()); return Datetime(this).to_longlong(); } double val_real() override { return Datetime(this).to_double(); } String *val_str(String *to) override { return Datetime(this).to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) override { return Datetime(this).to_decimal(to); } }; /* Abstract CURTIME function. Children should define what time zone is used */ class Item_func_curtime :public Item_timefunc { MYSQL_TIME ltime; query_id_t last_query_id; public: Item_func_curtime(THD *thd, uint dec): Item_timefunc(thd), last_query_id(0) { decimals= dec; } bool fix_fields(THD *, Item **) override; bool fix_length_and_dec() override { fix_attributes_time(decimals); return FALSE; } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; /* Abstract method that defines which time zone is used for conversion. Converts time current time in my_time_t representation to broken-down MYSQL_TIME representation using UTC-SYSTEM or per-thread time zone. */ virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_TIME_FUNC); } void print(String *str, enum_query_type query_type) override; }; class Item_func_curtime_local :public Item_func_curtime { public: Item_func_curtime_local(THD *thd, uint dec): Item_func_curtime(thd, dec) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("curtime") }; return name; } void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_curtime_utc :public Item_func_curtime { public: Item_func_curtime_utc(THD *thd, uint dec): Item_func_curtime(thd, dec) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("utc_time") }; return name; } void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Abstract CURDATE function. See also Item_func_curtime. */ class Item_func_curdate :public Item_datefunc { query_id_t last_query_id; MYSQL_TIME ltime; public: Item_func_curdate(THD *thd): Item_datefunc(thd), last_query_id(0) {} bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_TIME_FUNC); } }; class Item_func_curdate_local :public Item_func_curdate { public: Item_func_curdate_local(THD *thd): Item_func_curdate(thd) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("curdate") }; return name; } void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_curdate_utc :public Item_func_curdate { public: Item_func_curdate_utc(THD *thd): Item_func_curdate(thd) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("utc_date") }; return name; } void store_now_in_TIME(THD* thd, MYSQL_TIME *now_time) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Abstract CURRENT_TIMESTAMP function. See also Item_func_curtime */ class Item_func_now :public Item_datetimefunc { MYSQL_TIME ltime; query_id_t last_query_id; public: Item_func_now(THD *thd, uint dec): Item_datetimefunc(thd), last_query_id(0) { decimals= dec; } bool fix_fields(THD *, Item **) override; bool fix_length_and_dec() override { fix_attributes_datetime(decimals); return FALSE;} bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0; bool check_vcol_func_processor(void *arg) override { /* NOW is safe for replication as slaves will run with same time as master */ return mark_unsupported_function(func_name(), "()", arg, VCOL_TIME_FUNC); } void print(String *str, enum_query_type query_type) override; }; class Item_func_now_local :public Item_func_now { public: Item_func_now_local(THD *thd, uint dec): Item_func_now(thd, dec) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("current_timestamp") }; return name; } int save_in_field(Field *field, bool no_conversions) override; void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) override; enum Functype functype() const override { return NOW_FUNC; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_now_utc :public Item_func_now { public: Item_func_now_utc(THD *thd, uint dec): Item_func_now(thd, dec) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("utc_timestamp") }; return name; } void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) override; enum Functype functype() const override { return NOW_UTC_FUNC; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_TIME_FUNC | VCOL_NON_DETERMINISTIC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* This is like NOW(), but always uses the real current time, not the query_start(). This matches the Oracle behavior. */ class Item_func_sysdate_local :public Item_func_now { public: Item_func_sysdate_local(THD *thd, uint dec): Item_func_now(thd, dec) {} bool const_item() const override { return 0; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("sysdate") }; return name; } void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time) override; bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; table_map used_tables() const override { return RAND_TABLE_BIT; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_TIME_FUNC | VCOL_NON_DETERMINISTIC); } enum Functype functype() const override { return SYSDATE_FUNC; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_from_days :public Item_datefunc { bool check_arguments() const override { return args[0]->check_type_can_return_int(func_name_cstring()); } public: Item_func_from_days(THD *thd, Item *a): Item_datefunc(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("from_days") }; return name; } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return has_date_args() || has_time_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_date_format :public Item_str_func { bool check_arguments() const override { return args[0]->check_type_can_return_date(func_name_cstring()) || check_argument_types_can_return_text(1, arg_count); } const MY_LOCALE *locale; int fixed_length; String value; protected: bool is_time_format; public: Item_func_date_format(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b), locale(0), is_time_format(false) {} Item_func_date_format(THD *thd, Item *a, Item *b, Item *c): Item_str_func(thd, a, b, c), locale(0), is_time_format(false) {} String *val_str(String *str) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("date_format") }; return name; } bool fix_length_and_dec() override; uint format_length(const String *format); bool eq(const Item *item, bool binary_cmp) const override; bool check_vcol_func_processor(void *arg) override { if (arg_count > 2) return false; return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_time_format: public Item_func_date_format { public: Item_func_time_format(THD *thd, Item *a, Item *b): Item_func_date_format(thd, a, b) { is_time_format= true; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("time_format") }; return name; } bool check_vcol_func_processor(void *arg) override { return false; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* the max length of datetime format models string in Oracle is 144 */ #define MAX_DATETIME_FORMAT_MODEL_LEN 144 class Item_func_tochar :public Item_str_func { const MY_LOCALE *locale; THD *thd; String warning_message; bool fixed_length; /* When datetime format models is parsed, use uint16 integers to represent the format models and store in fmt_array. */ uint16 fmt_array[MAX_DATETIME_FORMAT_MODEL_LEN+1]; bool check_arguments() const override { return (args[0]->check_type_can_return_date(func_name_cstring()) && args[0]->check_type_can_return_time(func_name_cstring())) || check_argument_types_can_return_text(1, arg_count); } public: Item_func_tochar(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b), locale(0) { /* NOTE: max length of warning message is 64 */ warning_message.alloc(64); warning_message.length(0); } ~Item_func_tochar() { warning_message.free(); } String *val_str(String *str) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("to_char") }; return name; } bool fix_length_and_dec() override; bool parse_format_string(const String *format, uint *fmt_len); bool check_vcol_func_processor(void *arg) override { if (arg_count > 2) return false; return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_from_unixtime :public Item_datetimefunc { bool check_arguments() const override { return args[0]->check_type_can_return_decimal(func_name_cstring()); } Time_zone *tz; public: Item_func_from_unixtime(THD *thd, Item *a): Item_datetimefunc(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("from_unixtime") }; return name; } bool fix_length_and_dec() override; bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* We need Time_zone class declaration for storing pointers in Item_func_convert_tz. */ class Time_zone; /* This class represents CONVERT_TZ() function. The important fact about this function that it is handled in special way. When such function is met in expression time_zone system tables are added to global list of tables to open, so later those already opened and locked tables can be used during this function calculation for loading time zone descriptions. */ class Item_func_convert_tz :public Item_datetimefunc { bool check_arguments() const override { return args[0]->check_type_can_return_date(func_name_cstring()) || check_argument_types_can_return_text(1, arg_count); } /* If time zone parameters are constants we are caching objects that represent them (we use separate from_tz_cached/to_tz_cached members to indicate this fact, since NULL is legal value for from_tz/to_tz members. */ bool from_tz_cached, to_tz_cached; Time_zone *from_tz, *to_tz; public: Item_func_convert_tz(THD *thd, Item *a, Item *b, Item *c): Item_datetimefunc(thd, a, b, c), from_tz_cached(0), to_tz_cached(0) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("convert_tz") }; return name; } bool fix_length_and_dec() override { fix_attributes_datetime(args[0]->datetime_precision(current_thd)); set_maybe_null(); return FALSE; } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; void cleanup() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_sec_to_time :public Item_timefunc { bool check_arguments() const override { return args[0]->check_type_can_return_decimal(func_name_cstring()); } public: Item_func_sec_to_time(THD *thd, Item *item): Item_timefunc(thd, item) {} bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; bool fix_length_and_dec() override { fix_attributes_time(args[0]->decimals); set_maybe_null(); return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("sec_to_time") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_date_add_interval :public Item_handled_func { public: const interval_type int_type; // keep it public const bool date_sub_interval; // keep it public Item_date_add_interval(THD *thd, Item *a, Item *b, interval_type type_arg, bool neg_arg): Item_handled_func(thd, a, b), int_type(type_arg), date_sub_interval(neg_arg) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("date_add_interval") }; return name; } bool fix_length_and_dec() override; bool eq(const Item *item, bool binary_cmp) const override; void print(String *str, enum_query_type query_type) override; enum precedence precedence() const override { return INTERVAL_PRECEDENCE; } bool need_parentheses_in_default() override { return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_extract :public Item_int_func, public Type_handler_hybrid_field_type { date_mode_t m_date_mode; const Type_handler_int_result *handler_by_length(uint32 length, uint32 threashold) { if (length >= threashold) return &type_handler_slonglong; return &type_handler_slong; } void set_date_length(uint32 length) { /* DATE components (e.g. YEAR, YEAR_MONTH, QUARTER, MONTH, WEEK) return non-negative values but historically EXTRACT for date components always returned the signed int data type. So do equivalent functions YEAR(), QUARTER(), MONTH(), WEEK(). Let's set the data type to "signed int, but not negative", so "this" produces better data types in VARCHAR and DECIMAL context by using the fact that all of the max_length characters are spent for digits (non of them are spent for the sign). */ set_handler(&type_handler_slong_ge0); fix_char_length(length); m_date_mode= date_mode_t(0); } void set_day_length(uint32 length) { /* Units starting with DAY can be negative: EXTRACT(DAY FROM '-24:00:00') -> -1 */ set_handler(handler_by_length(max_length= length + 1/*sign*/, 11)); m_date_mode= Temporal::Options(TIME_INTERVAL_DAY, current_thd); } void set_time_length(uint32 length) { set_handler(handler_by_length(max_length= length + 1/*sign*/, 11)); m_date_mode= Temporal::Options(TIME_INTERVAL_hhmmssff, current_thd); } public: const interval_type int_type; // keep it public Item_extract(THD *thd, interval_type type_arg, Item *a): Item_int_func(thd, a), Type_handler_hybrid_field_type(&type_handler_slonglong), m_date_mode(date_mode_t(0)), int_type(type_arg) { } const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } longlong val_int() override; enum Functype functype() const override { return EXTRACT_FUNC; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("extract") }; return name; } bool check_arguments() const override; bool fix_length_and_dec() override; bool eq(const Item *item, bool binary_cmp) const override; void print(String *str, enum_query_type query_type) override; bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { if (int_type != INTERVAL_WEEK) return FALSE; return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); } bool check_valid_arguments_processor(void *int_arg) override { switch (int_type) { case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: case INTERVAL_QUARTER: case INTERVAL_MONTH: /* case INTERVAL_WEEK: Not allowed as partitioning function, bug#57071 */ case INTERVAL_DAY: return !has_date_args(); case INTERVAL_DAY_HOUR: case INTERVAL_DAY_MINUTE: case INTERVAL_DAY_SECOND: case INTERVAL_DAY_MICROSECOND: return !has_datetime_args(); case INTERVAL_HOUR: case INTERVAL_HOUR_MINUTE: case INTERVAL_HOUR_SECOND: case INTERVAL_MINUTE: case INTERVAL_MINUTE_SECOND: case INTERVAL_SECOND: case INTERVAL_MICROSECOND: case INTERVAL_HOUR_MICROSECOND: case INTERVAL_MINUTE_MICROSECOND: case INTERVAL_SECOND_MICROSECOND: return !has_time_args(); default: /* INTERVAL_LAST is only an end marker, INTERVAL_WEEK depends on default_week_format which is a session variable and cannot be used for partitioning. See bug#57071. */ break; } return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_char_typecast :public Item_handled_func { uint cast_length; CHARSET_INFO *cast_cs, *from_cs; bool charset_conversion; String tmp_value; bool m_suppress_warning_to_error_escalation; public: bool has_explicit_length() const { return cast_length != ~0U; } private: String *reuse(String *src, size_t length); String *copy(String *src, CHARSET_INFO *cs); uint adjusted_length_with_warn(uint length); void check_truncation_with_warn(String *src, size_t dstlen); void fix_length_and_dec_internal(CHARSET_INFO *fromcs); public: // Methods used by ColumnStore uint get_cast_length() const { return cast_length; } public: Item_char_typecast(THD *thd, Item *a, uint length_arg, CHARSET_INFO *cs_arg): Item_handled_func(thd, a), cast_length(length_arg), cast_cs(cs_arg), m_suppress_warning_to_error_escalation(false) {} enum Functype functype() const override { return CHAR_TYPECAST_FUNC; } bool eq(const Item *item, bool binary_cmp) const override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("cast_as_char") }; return name; } CHARSET_INFO *cast_charset() const { return cast_cs; } String *val_str_generic(String *a); String *val_str_binary_from_native(String *a); void fix_length_and_dec_generic(); void fix_length_and_dec_numeric(); void fix_length_and_dec_str(); void fix_length_and_dec_native_to_binary(uint32 octet_length); bool fix_length_and_dec() override { return args[0]->type_handler()->Item_char_typecast_fix_length_and_dec(this); } void print(String *str, enum_query_type query_type) override; bool need_parentheses_in_default() override { return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_interval_DDhhmmssff_typecast :public Item_char_typecast { uint m_fsp; public: Item_interval_DDhhmmssff_typecast(THD *thd, Item *a, uint fsp) :Item_char_typecast(thd, a,Interval_DDhhmmssff::max_char_length(fsp), &my_charset_latin1), m_fsp(fsp) { } String *val_str(String *to) override { Interval_DDhhmmssff it(current_thd, args[0], m_fsp); null_value= !it.is_valid_interval_DDhhmmssff(); return it.to_string(to, m_fsp); } }; class Item_date_typecast :public Item_datefunc { public: Item_date_typecast(THD *thd, Item *a): Item_datefunc(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("cast_as_date") }; return name; } void print(String *str, enum_query_type query_type) override { print_cast_temporal(str, query_type); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool fix_length_and_dec() override { return args[0]->type_handler()->Item_date_typecast_fix_length_and_dec(this); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_time_typecast :public Item_timefunc { public: Item_time_typecast(THD *thd, Item *a, uint dec_arg): Item_timefunc(thd, a) { decimals= dec_arg; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("cast_as_time") }; return name; } void print(String *str, enum_query_type query_type) override { print_cast_temporal(str, query_type); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool fix_length_and_dec() override { return args[0]->type_handler()-> Item_time_typecast_fix_length_and_dec(this); } Sql_mode_dependency value_depends_on_sql_mode() const override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_datetime_typecast :public Item_datetimefunc { public: Item_datetime_typecast(THD *thd, Item *a, uint dec_arg): Item_datetimefunc(thd, a) { decimals= dec_arg; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("cast_as_datetime") }; return name; } void print(String *str, enum_query_type query_type) override { print_cast_temporal(str, query_type); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; bool fix_length_and_dec() override { return args[0]->type_handler()-> Item_datetime_typecast_fix_length_and_dec(this); } Sql_mode_dependency value_depends_on_sql_mode() const override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_makedate :public Item_datefunc { bool check_arguments() const override { return check_argument_types_can_return_int(0, arg_count); } public: Item_func_makedate(THD *thd, Item *a, Item *b): Item_datefunc(thd, a, b) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("makedate") }; return name; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_timestamp :public Item_datetimefunc { bool check_arguments() const override { return args[0]->check_type_can_return_date(func_name_cstring()) || args[1]->check_type_can_return_time(func_name_cstring()); } public: Item_func_timestamp(THD *thd, Item *a, Item *b) :Item_datetimefunc(thd, a, b) { } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("timestamp") }; return name; } bool fix_length_and_dec() override { THD *thd= current_thd; uint dec0= args[0]->datetime_precision(thd); uint dec1= Interval_DDhhmmssff::fsp(thd, args[1]); fix_attributes_datetime(MY_MAX(dec0, dec1)); set_maybe_null(); return false; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { Datetime dt(thd, args[0], Datetime::Options(TIME_CONV_NONE, thd)); if (!dt.is_valid_datetime()) return (null_value= 1); Interval_DDhhmmssff it(thd, args[1]); if (!it.is_valid_interval_DDhhmmssff()) return (null_value= true); return (null_value= Sec6_add(dt.get_mysql_time(), it.get_mysql_time(), 1). to_datetime(ltime)); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /** ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a time/datetime value t: time_or_datetime_expression a: time_expression Result: Time value or datetime value */ class Item_func_add_time :public Item_handled_func { int sign; public: // Methods used by ColumnStore int get_sign() const { return sign; } public: Item_func_add_time(THD *thd, Item *a, Item *b, bool neg_arg) :Item_handled_func(thd, a, b), sign(neg_arg ? -1 : 1) { } bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING addtime= { STRING_WITH_LEN("addtime") }; static LEX_CSTRING subtime= { STRING_WITH_LEN("subtime") }; return sign > 0 ? addtime : subtime; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_timediff :public Item_timefunc { bool check_arguments() const override { return check_argument_types_can_return_time(0, arg_count); } public: Item_func_timediff(THD *thd, Item *a, Item *b): Item_timefunc(thd, a, b) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("timediff") }; return name; } bool fix_length_and_dec() override { THD *thd= current_thd; uint dec= MY_MAX(args[0]->time_precision(thd), args[1]->time_precision(thd)); fix_attributes_time(dec); set_maybe_null(); return FALSE; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_maketime :public Item_timefunc { bool check_arguments() const override { return check_argument_types_can_return_int(0, 2) || args[2]->check_type_can_return_decimal(func_name_cstring()); } public: Item_func_maketime(THD *thd, Item *a, Item *b, Item *c): Item_timefunc(thd, a, b, c) {} bool fix_length_and_dec() override { fix_attributes_time(args[2]->decimals); set_maybe_null(); return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("maketime") }; return name; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_microsecond :public Item_long_func_time_field { public: Item_func_microsecond(THD *thd, Item *a): Item_long_func_time_field(thd, a) {} longlong val_int() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("microsecond") }; return name; } bool fix_length_and_dec() override { decimals=0; set_maybe_null(); fix_char_length(6); return FALSE; } bool check_partition_func_processor(void *int_arg) override {return FALSE;} bool check_vcol_func_processor(void *arg) override { return FALSE;} bool check_valid_arguments_processor(void *int_arg) override { return !has_time_args(); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_timestamp_diff :public Item_longlong_func { bool check_arguments() const override { return check_argument_types_can_return_date(0, arg_count); } const interval_type int_type; public: // Methods used by ColumnStore interval_type get_int_type() const { return int_type; }; public: Item_func_timestamp_diff(THD *thd, Item *a, Item *b, interval_type type_arg): Item_longlong_func(thd, a, b), int_type(type_arg) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("timestampdiff") }; return name; } longlong val_int() override; bool fix_length_and_dec() override { decimals=0; set_maybe_null(); return FALSE; } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; enum date_time_format { USA_FORMAT, JIS_FORMAT, ISO_FORMAT, EUR_FORMAT, INTERNAL_FORMAT }; class Item_func_get_format :public Item_str_ascii_func { public: const timestamp_type type; // keep it public Item_func_get_format(THD *thd, timestamp_type type_arg, Item *a): Item_str_ascii_func(thd, a), type(type_arg) {} String *val_str_ascii(String *str) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("get_format") }; return name; } bool fix_length_and_dec() override { set_maybe_null(); decimals=0; fix_length_and_charset(17, default_charset()); return FALSE; } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_str_to_date :public Item_handled_func { bool const_item; String subject_converter; String format_converter; CHARSET_INFO *internal_charset; public: Item_func_str_to_date(THD *thd, Item *a, Item *b): Item_handled_func(thd, a, b), const_item(false), internal_charset(NULL) {} bool get_date_common(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate, timestamp_type); LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("str_to_date") }; return name; } bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_last_day :public Item_datefunc { bool check_arguments() const override { return args[0]->check_type_can_return_date(func_name_cstring()); } public: Item_func_last_day(THD *thd, Item *a): Item_datefunc(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("last_day") }; return name; } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /*****************************************************************************/ class Func_handler_date_add_interval { protected: static uint interval_dec(const Item *item, interval_type int_type) { if (int_type == INTERVAL_MICROSECOND || (int_type >= INTERVAL_DAY_MICROSECOND && int_type <= INTERVAL_SECOND_MICROSECOND)) return TIME_SECOND_PART_DIGITS; if (int_type == INTERVAL_SECOND && item->decimals > 0) return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); return 0; } interval_type int_type(const Item_handled_func *item) const { return static_cast(item)->int_type; } bool sub(const Item_handled_func *item) const { return static_cast(item)->date_sub_interval; } bool add(THD *thd, Item *item, interval_type type, bool sub, MYSQL_TIME *to) const { INTERVAL interval; if (get_interval_value(thd, item, type, &interval)) return true; if (sub) interval.neg = !interval.neg; return date_add_interval(thd, to, type, interval); } }; class Func_handler_date_add_interval_datetime: public Item_handled_func::Handler_datetime, public Func_handler_date_add_interval { public: bool fix_length_and_dec(Item_handled_func *item) const override { uint dec= MY_MAX(item->arguments()[0]->datetime_precision(current_thd), interval_dec(item->arguments()[1], int_type(item))); item->fix_attributes_datetime(dec); return false; } bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { Datetime::Options opt(TIME_CONV_NONE, thd); Datetime dt(thd, item->arguments()[0], opt); if (!dt.is_valid_datetime() || dt.check_date_with_warn(thd, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)) return (item->null_value= true); dt.copy_to_mysql_time(to); return (item->null_value= add(thd, item->arguments()[1], int_type(item), sub(item), to)); } }; class Func_handler_date_add_interval_datetime_arg0_time: public Func_handler_date_add_interval_datetime { public: bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override; }; class Func_handler_date_add_interval_date: public Item_handled_func::Handler_date, public Func_handler_date_add_interval { public: bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { /* The first argument is known to be of the DATE data type (not DATETIME). We don't need rounding here. */ Date d(thd, item->arguments()[0], TIME_CONV_NONE); if (!d.is_valid_date() || d.check_date_with_warn(thd, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE)) return (item->null_value= true); d.copy_to_mysql_time(to); return (item->null_value= add(thd, item->arguments()[1], int_type(item), sub(item), to)); } }; class Func_handler_date_add_interval_time: public Item_handled_func::Handler_time, public Func_handler_date_add_interval { public: bool fix_length_and_dec(Item_handled_func *item) const override { uint dec= MY_MAX(item->arguments()[0]->time_precision(current_thd), interval_dec(item->arguments()[1], int_type(item))); item->fix_attributes_time(dec); return false; } bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { Time t(thd, item->arguments()[0]); if (!t.is_valid_time()) return (item->null_value= true); t.copy_to_mysql_time(to); return (item->null_value= add(thd, item->arguments()[1], int_type(item), sub(item), to)); } }; class Func_handler_date_add_interval_string: public Item_handled_func::Handler_temporal_string, public Func_handler_date_add_interval { public: bool fix_length_and_dec(Item_handled_func *item) const override { uint dec= MY_MAX(item->arguments()[0]->datetime_precision(current_thd), interval_dec(item->arguments()[1], int_type(item))); item->Type_std_attributes::set( Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH, dec, false), DTCollation(item->default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII)); item->fix_char_length(item->max_length); return false; } bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { if (item->arguments()[0]-> get_date(thd, to, Datetime::Options(TIME_CONV_NONE, thd)) || (to->time_type != MYSQL_TIMESTAMP_TIME && check_date_with_warn(thd, to, TIME_NO_ZEROS, MYSQL_TIMESTAMP_ERROR))) return (item->null_value= true); return (item->null_value= add(thd, item->arguments()[1], int_type(item), sub(item), to)); } }; class Func_handler_sign { protected: int m_sign; Func_handler_sign(int sign) :m_sign(sign) { } }; class Func_handler_add_time_datetime: public Item_handled_func::Handler_datetime, public Func_handler_sign { public: Func_handler_add_time_datetime(int sign) :Func_handler_sign(sign) { } bool fix_length_and_dec(Item_handled_func *item) const override { THD *thd= current_thd; uint dec0= item->arguments()[0]->datetime_precision(thd); uint dec1= Interval_DDhhmmssff::fsp(thd, item->arguments()[1]); item->fix_attributes_datetime(MY_MAX(dec0, dec1)); return false; } bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { DBUG_ASSERT(item->fixed()); Datetime::Options opt(TIME_CONV_NONE, thd); Datetime dt(thd, item->arguments()[0], opt); if (!dt.is_valid_datetime()) return (item->null_value= true); Interval_DDhhmmssff it(thd, item->arguments()[1]); if (!it.is_valid_interval_DDhhmmssff()) return (item->null_value= true); return (item->null_value= (Sec6_add(dt.get_mysql_time(), it.get_mysql_time(), m_sign). to_datetime(to))); } }; class Func_handler_add_time_time: public Item_handled_func::Handler_time, public Func_handler_sign { public: Func_handler_add_time_time(int sign) :Func_handler_sign(sign) { } bool fix_length_and_dec(Item_handled_func *item) const override { THD *thd= current_thd; uint dec0= item->arguments()[0]->time_precision(thd); uint dec1= Interval_DDhhmmssff::fsp(thd, item->arguments()[1]); item->fix_attributes_time(MY_MAX(dec0, dec1)); return false; } bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { DBUG_ASSERT(item->fixed()); Time t(thd, item->arguments()[0]); if (!t.is_valid_time()) return (item->null_value= true); Interval_DDhhmmssff i(thd, item->arguments()[1]); if (!i.is_valid_interval_DDhhmmssff()) return (item->null_value= true); return (item->null_value= (Sec6_add(t.get_mysql_time(), i.get_mysql_time(), m_sign). to_time(thd, to, item->decimals))); } }; class Func_handler_add_time_string: public Item_handled_func::Handler_temporal_string, public Func_handler_sign { public: Func_handler_add_time_string(int sign) :Func_handler_sign(sign) { } bool fix_length_and_dec(Item_handled_func *item) const override { uint dec0= item->arguments()[0]->decimals; uint dec1= Interval_DDhhmmssff::fsp(current_thd, item->arguments()[1]); uint dec= MY_MAX(dec0, dec1); item->Type_std_attributes::set( Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH, dec, false), DTCollation(item->default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII)); item->fix_char_length(item->max_length); return false; } bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { DBUG_ASSERT(item->fixed()); // Detect a proper timestamp type based on the argument values Temporal_hybrid l_time1(thd, item->arguments()[0], Temporal::Options(TIME_TIME_ONLY, thd)); if (!l_time1.is_valid_temporal()) return (item->null_value= true); Interval_DDhhmmssff l_time2(thd, item->arguments()[1]); if (!l_time2.is_valid_interval_DDhhmmssff()) return (item->null_value= true); Sec6_add add(l_time1.get_mysql_time(), l_time2.get_mysql_time(), m_sign); return (item->null_value= (l_time1.get_mysql_time()->time_type == MYSQL_TIMESTAMP_TIME ? add.to_time(thd, to, item->decimals) : add.to_datetime(to))); } }; class Func_handler_str_to_date_datetime_sec: public Item_handled_func::Handler_datetime { public: bool fix_length_and_dec(Item_handled_func *item) const override { item->fix_attributes_datetime(0); return false; } bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { return static_cast(item)-> get_date_common(thd, to, fuzzy, MYSQL_TIMESTAMP_DATETIME); } }; class Func_handler_str_to_date_datetime_usec: public Item_handled_func::Handler_datetime { public: bool fix_length_and_dec(Item_handled_func *item) const override { item->fix_attributes_datetime(TIME_SECOND_PART_DIGITS); return false; } bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { return static_cast(item)-> get_date_common(thd, to, fuzzy, MYSQL_TIMESTAMP_DATETIME); } }; class Func_handler_str_to_date_date: public Item_handled_func::Handler_date { public: bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { return static_cast(item)-> get_date_common(thd, to, fuzzy, MYSQL_TIMESTAMP_DATE); } }; class Func_handler_str_to_date_time: public Item_handled_func::Handler_time { public: bool get_date(THD *thd, Item_handled_func *item, MYSQL_TIME *to, date_mode_t fuzzy) const override { if (static_cast(item)-> get_date_common(thd, to, fuzzy, MYSQL_TIMESTAMP_TIME)) return true; if (to->day) { /* Day part for time type can be nonzero value and so we should add hours from day part to hour part to keep valid time value. */ to->hour+= to->day * 24; to->day= 0; } return false; } }; class Func_handler_str_to_date_time_sec: public Func_handler_str_to_date_time { public: bool fix_length_and_dec(Item_handled_func *item) const override { item->fix_attributes_time(0); return false; } }; class Func_handler_str_to_date_time_usec: public Func_handler_str_to_date_time { public: bool fix_length_and_dec(Item_handled_func *item) const override { item->fix_attributes_time(TIME_SECOND_PART_DIGITS); return false; } }; #endif /* ITEM_TIMEFUNC_INCLUDED */ server/private/sql_limit.h000064400000006163151031265040011675 0ustar00/* Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef INCLUDES_MARIADB_SQL_LIMIT_H #define INCLUDES_MARIADB_SQL_LIMIT_H /** LIMIT/OFFSET parameters for execution. */ class Select_limit_counters { ha_rows select_limit_cnt, offset_limit_cnt; bool with_ties; public: Select_limit_counters(): select_limit_cnt(0), offset_limit_cnt(0), with_ties(false) {}; Select_limit_counters(const Select_limit_counters &orig): select_limit_cnt(orig.select_limit_cnt), offset_limit_cnt(orig.offset_limit_cnt), with_ties(orig.with_ties) {}; void set_limit(ha_rows limit, ha_rows offset, bool with_ties_arg) { if (limit == 0) offset= 0; offset_limit_cnt= offset; select_limit_cnt= limit; with_ties= with_ties_arg; /* Guard against an overflow condition, where limit + offset exceede ha_rows value range. This case covers unreasonably large parameter values that do not have any practical use so assuming in this case that the query does not have a limit is fine. */ if (select_limit_cnt + offset_limit_cnt >= select_limit_cnt) select_limit_cnt+= offset_limit_cnt; else select_limit_cnt= HA_POS_ERROR; } void set_single_row() { offset_limit_cnt= 0; select_limit_cnt= 1; with_ties= false; } /* Send the first row, still honoring offset_limit_cnt */ void send_first_row() { /* Guard against overflow */ if ((select_limit_cnt= offset_limit_cnt +1 ) == 0) select_limit_cnt= offset_limit_cnt; // with_ties= false; Remove // on merge to 10.6 } bool is_unlimited() const { return select_limit_cnt == HA_POS_ERROR; } /* Set the limit to allow returning an unlimited number of rows. Useful for cases when we want to continue execution indefinitely after the limit is reached (for example for SQL_CALC_ROWS extension). */ void set_unlimited() { select_limit_cnt= HA_POS_ERROR; } /* Reset the limit entirely. */ void clear() { select_limit_cnt= HA_POS_ERROR; offset_limit_cnt= 0; with_ties= false;} bool check_offset(ha_rows sent) const { return sent < offset_limit_cnt; } void remove_offset() { offset_limit_cnt= 0; } ha_rows get_select_limit() const { return select_limit_cnt; } ha_rows get_offset_limit() const { return offset_limit_cnt; } bool is_with_ties() const { return with_ties; } }; #endif // INCLUDES_MARIADB_SQL_LIMIT_H server/private/spatial.h000064400000053441151031265040011336 0ustar00/* Copyright (c) 2002, 2013, Oracle and/or its affiliates. Copyright (c) 2009, 2013, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _spatial_h #define _spatial_h #include "sql_string.h" /* String, LEX_STRING */ #include #include #ifdef HAVE_SPATIAL class Gis_read_stream; #include "gcalc_tools.h" const uint SRID_SIZE= 4; const uint SIZEOF_STORED_DOUBLE= 8; const uint POINT_DATA_SIZE= (SIZEOF_STORED_DOUBLE * 2); const uint WKB_HEADER_SIZE= 1+4; const uint32 GET_SIZE_ERROR= ((uint32) -1); struct st_point_2d { double x; double y; }; struct st_linear_ring { uint32 n_points; st_point_2d points; }; /***************************** MBR *******************************/ /* It's ok that a lot of the functions are inline as these are only used once in MySQL */ struct MBR { double xmin, ymin, xmax, ymax; MBR() { xmin= ymin= DBL_MAX; xmax= ymax= -DBL_MAX; } MBR(const double xmin_arg, const double ymin_arg, const double xmax_arg, const double ymax_arg) :xmin(xmin_arg), ymin(ymin_arg), xmax(xmax_arg), ymax(ymax_arg) {} MBR(const st_point_2d &min, const st_point_2d &max) :xmin(min.x), ymin(min.y), xmax(max.x), ymax(max.y) {} MBR(const MBR &mbr1, const MBR &mbr2) :xmin(mbr1.xmin), ymin(mbr1.ymin), xmax(mbr1.xmax), ymax(mbr1.ymax) { add_mbr(&mbr2); } inline void add_xy(double x, double y) { /* Not using "else" for proper one point MBR calculation */ if (x < xmin) xmin= x; if (x > xmax) xmax= x; if (y < ymin) ymin= y; if (y > ymax) ymax= y; } void add_xy(const char *px, const char *py) { double x, y; float8get(x, px); float8get(y, py); add_xy(x,y); } void add_mbr(const MBR *mbr) { if (mbr->xmin < xmin) xmin= mbr->xmin; if (mbr->xmax > xmax) xmax= mbr->xmax; if (mbr->ymin < ymin) ymin= mbr->ymin; if (mbr->ymax > ymax) ymax= mbr->ymax; } void buffer(double d) { xmin-= d; ymin-= d; xmax+= d; ymax+= d; } int equals(const MBR *mbr) { /* The following should be safe, even if we compare doubles */ return ((mbr->xmin == xmin) && (mbr->ymin == ymin) && (mbr->xmax == xmax) && (mbr->ymax == ymax)); } int disjoint(const MBR *mbr) { /* The following should be safe, even if we compare doubles */ return ((mbr->xmin > xmax) || (mbr->ymin > ymax) || (mbr->xmax < xmin) || (mbr->ymax < ymin)); } int intersects(const MBR *mbr) { return !disjoint(mbr); } int touches(const MBR *mbr) { /* The following should be safe, even if we compare doubles */ return ((mbr->xmin == xmax || mbr->xmax == xmin) && ((mbr->ymin >= ymin && mbr->ymin <= ymax) || (mbr->ymax >= ymin && mbr->ymax <= ymax))) || ((mbr->ymin == ymax || mbr->ymax == ymin) && ((mbr->xmin >= xmin && mbr->xmin <= xmax) || (mbr->xmax >= xmin && mbr->xmax <= xmax))); } int within(const MBR *mbr); int contains(const MBR *mbr) { /* The following should be safe, even if we compare doubles */ return ((mbr->xmin >= xmin) && (mbr->ymin >= ymin) && (mbr->xmax <= xmax) && (mbr->ymax <= ymax)); } bool inner_point(double x, double y) const { /* The following should be safe, even if we compare doubles */ return (xminx) && (yminy); } /** The dimension maps to an integer as: - Polygon -> 2 - Horizontal or vertical line -> 1 - Point -> 0 - Invalid MBR -> -1 */ int dimension() const { int d= 0; if (xmin > xmax) return -1; else if (xmin < xmax) d++; if (ymin > ymax) return -1; else if (ymin < ymax) d++; return d; } int overlaps(const MBR *mbr) { /* overlaps() requires that some point inside *this is also inside *mbr, and that both geometries and their intersection are of the same dimension. */ int d = dimension(); if (d != mbr->dimension() || d <= 0 || contains(mbr) || within(mbr)) return 0; MBR intersection(MY_MAX(xmin, mbr->xmin), MY_MAX(ymin, mbr->ymin), MY_MIN(xmax, mbr->xmax), MY_MIN(ymax, mbr->ymax)); return (d == intersection.dimension()); } int valid() const { return xmin <= xmax && ymin <= ymax; } }; /***************************** Geometry *******************************/ struct Geometry_buffer; class Geometry { public: Geometry() = default; /* Remove gcc warning */ virtual ~Geometry() = default; /* Remove gcc warning */ static void *operator new(size_t size, void *buffer) { return buffer; } static void operator delete(void *ptr, void *buffer) {} static void operator delete(void *buffer) {} enum wkbType { wkb_point= 1, wkb_linestring= 2, wkb_polygon= 3, wkb_multipoint= 4, wkb_multilinestring= 5, wkb_multipolygon= 6, wkb_geometrycollection= 7, wkb_last=7 }; enum wkbByteOrder { wkb_xdr= 0, /* Big Endian */ wkb_ndr= 1 /* Little Endian */ }; enum geojson_errors { GEOJ_INCORRECT_GEOJSON= 1, GEOJ_TOO_FEW_POINTS= 2, GEOJ_POLYGON_NOT_CLOSED= 3, GEOJ_DIMENSION_NOT_SUPPORTED= 4, GEOJ_EMPTY_COORDINATES= 5, }; /** Callback which creates Geometry objects on top of a given placement. */ typedef Geometry *(*create_geom_t)(char *); class Class_info { public: LEX_STRING m_name; LEX_STRING m_geojson_name; int m_type_id; create_geom_t m_create_func; Class_info(const char *name, const char *gejson_name, int type_id, create_geom_t create_func); }; virtual const Class_info *get_class_info() const=0; virtual uint32 get_data_size() const=0; virtual bool init_from_wkt(Gis_read_stream *trs, String *wkb)=0; /* returns the length of the wkb that was read */ virtual uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res)=0; virtual uint init_from_opresult(String *bin, const char *opres, uint res_len) { return init_from_wkb(opres + 4, UINT_MAX32, wkb_ndr, bin) + 4; } virtual bool init_from_json(json_engine_t *je, bool er_on_3D, String *wkb) { return true; } virtual bool get_data_as_wkt(String *txt, const char **end) const=0; virtual bool get_data_as_json(String *txt, uint max_dec_digits, const char **end) const=0; virtual bool get_mbr(MBR *mbr, const char **end) const=0; virtual bool dimension(uint32 *dim, const char **end) const=0; virtual int get_x(double *x) const { return -1; } virtual int get_y(double *y) const { return -1; } virtual int geom_length(double *len, const char **end) const { return -1; } virtual int area(double *ar, const char **end) const { return -1;} virtual int is_closed(int *closed) const { return -1; } virtual int num_interior_ring(uint32 *n_int_rings) const { return -1; } virtual int num_points(uint32 *n_points) const { return -1; } virtual int num_geometries(uint32 *num) const { return -1; } virtual int start_point(String *point) const { return -1; } virtual int end_point(String *point) const { return -1; } virtual int exterior_ring(String *ring) const { return -1; } virtual int centroid(String *point) const { return -1; } virtual int point_n(uint32 num, String *result) const { return -1; } virtual int interior_ring_n(uint32 num, String *result) const { return -1; } virtual int geometry_n(uint32 num, String *result) const { return -1; } virtual int store_shapes(Gcalc_shape_transporter *trn) const=0; public: static Geometry *create_by_typeid(Geometry_buffer *buffer, int type_id); static Geometry *construct(Geometry_buffer *buffer, const char *data, uint32 data_len); static Geometry *create_from_wkt(Geometry_buffer *buffer, Gis_read_stream *trs, String *wkt, bool init_stream=1); static Geometry *create_from_wkb(Geometry_buffer *buffer, const char *wkb, uint32 len, String *res); static Geometry *create_from_json(Geometry_buffer *buffer, json_engine_t *je, bool er_on_3D, String *res); static Geometry *create_from_opresult(Geometry_buffer *g_buf, String *res, Gcalc_result_receiver &rr); static uint get_key_image_itMBR(LEX_CSTRING &src, uchar *buff, uint length); int as_wkt(String *wkt, const char **end); int as_json(String *wkt, uint max_dec_digits, const char **end); int bbox_as_json(String *wkt); inline void set_data_ptr(const char *data, uint32 data_len) { m_data= data; m_data_end= data + data_len; } inline void shift_wkb_header() { m_data+= WKB_HEADER_SIZE; } const char *get_data_ptr() const { return m_data; } bool envelope(String *result) const; static Class_info *ci_collection[wkb_last+1]; static bool create_point(String *result, double x, double y); protected: static Class_info *find_class(int type_id) { return ((type_id < wkb_point) || (type_id > wkb_last)) ? NULL : ci_collection[type_id]; } static Class_info *find_class(const char *name, size_t len); const char *append_points(String *txt, uint32 n_points, const char *data, uint32 offset) const; bool create_point(String *result, const char *data) const; const char *get_mbr_for_points(MBR *mbr, const char *data, uint offset) const; public: /** Check if there're enough data remaining as requested @arg cur_data pointer to the position in the binary form @arg data_amount number of points expected @return true if not enough data */ inline bool no_data(const char *cur_data, size_t data_amount) const { return (cur_data + data_amount > m_data_end); } /** Check if there're enough points remaining as requested Need to perform the calculation in logical units, since multiplication can overflow the size data type. @arg data pointer to the beginning of the points array @arg expected_points number of points expected @arg extra_point_space extra space for each point element in the array @return true if there are not enough points */ inline bool not_enough_points(const char *data, uint32 expected_points, uint32 extra_point_space = 0) const { return (m_data_end < data || (expected_points > ((m_data_end - data) / (POINT_DATA_SIZE + extra_point_space)))); } protected: const char *m_data; const char *m_data_end; }; /***************************** Point *******************************/ class Gis_point: public Geometry { public: Gis_point() = default; /* Remove gcc warning */ virtual ~Gis_point() = default; /* Remove gcc warning */ uint32 get_data_size() const override; bool init_from_wkt(Gis_read_stream *trs, String *wkb) override; uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) override; bool init_from_json(json_engine_t *je, bool er_on_3D, String *wkb) override; bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_json(String *txt, uint max_dec_digits, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override; int get_xy(double *x, double *y) const { const char *data= m_data; if (no_data(data, SIZEOF_STORED_DOUBLE * 2)) return 1; float8get(*x, data); float8get(*y, data + SIZEOF_STORED_DOUBLE); return 0; } int get_xy_radian(double *x, double *y) const { if (!get_xy(x, y)) { *x= (*x)*M_PI/180; *y= (*y)*M_PI/180; return 0; } return 1; } int get_x(double *x) const override { if (no_data(m_data, SIZEOF_STORED_DOUBLE)) return 1; float8get(*x, m_data); return 0; } int get_y(double *y) const override { const char *data= m_data; if (no_data(data, SIZEOF_STORED_DOUBLE * 2)) return 1; float8get(*y, data + SIZEOF_STORED_DOUBLE); return 0; } int geom_length(double *len, const char **end) const override; int area(double *ar, const char **end) const override; bool dimension(uint32 *dim, const char **end) const override { *dim= 0; *end= 0; /* No default end */ return 0; } int store_shapes(Gcalc_shape_transporter *trn) const override; const Class_info *get_class_info() const override; double calculate_haversine(const Geometry *g, const double sphere_radius, int *error); int spherical_distance_multipoints(Geometry *g, const double r, double *result, int *error); }; /***************************** LineString *******************************/ class Gis_line_string: public Geometry { public: Gis_line_string() = default; /* Remove gcc warning */ virtual ~Gis_line_string() = default; /* Remove gcc warning */ uint32 get_data_size() const override; bool init_from_wkt(Gis_read_stream *trs, String *wkb) override; uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) override; bool init_from_json(json_engine_t *je, bool er_on_3D, String *wkb) override; bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_json(String *txt, uint max_dec_digits, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override; int geom_length(double *len, const char **end) const override; int area(double *ar, const char **end) const override; int is_closed(int *closed) const override; int num_points(uint32 *n_points) const override; int start_point(String *point) const override; int end_point(String *point) const override; int point_n(uint32 n, String *result) const override; bool dimension(uint32 *dim, const char **end) const override { *dim= 1; *end= 0; /* No default end */ return 0; } int store_shapes(Gcalc_shape_transporter *trn) const override; const Class_info *get_class_info() const override; }; /***************************** Polygon *******************************/ class Gis_polygon: public Geometry { public: Gis_polygon() = default; /* Remove gcc warning */ virtual ~Gis_polygon() = default; /* Remove gcc warning */ uint32 get_data_size() const override; bool init_from_wkt(Gis_read_stream *trs, String *wkb) override; uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) override; uint init_from_opresult(String *bin, const char *opres, uint res_len) override; bool init_from_json(json_engine_t *je, bool er_on_3D, String *wkb) override; bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_json(String *txt, uint max_dec_digits, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override; int area(double *ar, const char **end) const override; int exterior_ring(String *result) const override; int num_interior_ring(uint32 *n_int_rings) const override; int interior_ring_n(uint32 num, String *result) const override; int centroid_xy(double *x, double *y) const; int centroid(String *result) const override; bool dimension(uint32 *dim, const char **end) const override { *dim= 2; *end= 0; /* No default end */ return 0; } int store_shapes(Gcalc_shape_transporter *trn) const override; const Class_info *get_class_info() const override; }; /***************************** MultiPoint *******************************/ class Gis_multi_point: public Geometry { // Maximum number of points in MultiPoint that can fit into String static const uint32 max_n_points= (uint32) (UINT_MAX32 - WKB_HEADER_SIZE - 4 /* n_points */) / (WKB_HEADER_SIZE + POINT_DATA_SIZE); public: Gis_multi_point() = default; /* Remove gcc warning */ virtual ~Gis_multi_point() = default; /* Remove gcc warning */ uint32 get_data_size() const override; bool init_from_wkt(Gis_read_stream *trs, String *wkb) override; uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) override; uint init_from_opresult(String *bin, const char *opres, uint res_len) override; bool init_from_json(json_engine_t *je, bool er_on_3D, String *wkb) override; bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_json(String *txt, uint max_dec_digits, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override; int num_geometries(uint32 *num) const override; int geometry_n(uint32 num, String *result) const override; bool dimension(uint32 *dim, const char **end) const override { *dim= 0; *end= 0; /* No default end */ return 0; } int store_shapes(Gcalc_shape_transporter *trn) const override; const Class_info *get_class_info() const override; int spherical_distance_multipoints(Geometry *g, const double r, double *res, int *error); }; /***************************** MultiLineString *******************************/ class Gis_multi_line_string: public Geometry { public: Gis_multi_line_string() = default; /* Remove gcc warning */ virtual ~Gis_multi_line_string() = default; /* Remove gcc warning */ uint32 get_data_size() const override; bool init_from_wkt(Gis_read_stream *trs, String *wkb) override; uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) override; uint init_from_opresult(String *bin, const char *opres, uint res_len) override; bool init_from_json(json_engine_t *je, bool er_on_3D, String *wkb) override; bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_json(String *txt, uint max_dec_digits, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override; int num_geometries(uint32 *num) const override; int geometry_n(uint32 num, String *result) const override; int geom_length(double *len, const char **end) const override; int is_closed(int *closed) const override; bool dimension(uint32 *dim, const char **end) const override { *dim= 1; *end= 0; /* No default end */ return 0; } int store_shapes(Gcalc_shape_transporter *trn) const override; const Class_info *get_class_info() const override; }; /***************************** MultiPolygon *******************************/ class Gis_multi_polygon: public Geometry { public: Gis_multi_polygon() = default; /* Remove gcc warning */ virtual ~Gis_multi_polygon() = default; /* Remove gcc warning */ uint32 get_data_size() const override; bool init_from_wkt(Gis_read_stream *trs, String *wkb) override; uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) override; bool init_from_json(json_engine_t *je, bool er_on_3D, String *wkb) override; bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_json(String *txt, uint max_dec_digits, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override; int num_geometries(uint32 *num) const override; int geometry_n(uint32 num, String *result) const override; int area(double *ar, const char **end) const override; int centroid(String *result) const override; bool dimension(uint32 *dim, const char **end) const override { *dim= 2; *end= 0; /* No default end */ return 0; } int store_shapes(Gcalc_shape_transporter *trn) const override; const Class_info *get_class_info() const override; uint init_from_opresult(String *bin, const char *opres, uint res_len) override; }; /*********************** GeometryCollection *******************************/ class Gis_geometry_collection: public Geometry { public: Gis_geometry_collection() = default; /* Remove gcc warning */ virtual ~Gis_geometry_collection() = default; /* Remove gcc warning */ uint32 get_data_size() const override; bool init_from_wkt(Gis_read_stream *trs, String *wkb) override; uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) override; uint init_from_opresult(String *bin, const char *opres, uint res_len) override; bool init_from_json(json_engine_t *je, bool er_on_3D, String *wkb) override; bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_json(String *txt, uint max_dec_digits, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override; int area(double *ar, const char **end) const override; int geom_length(double *len, const char **end) const override; int num_geometries(uint32 *num) const override; int geometry_n(uint32 num, String *result) const override; bool dimension(uint32 *dim, const char **end) const override; int store_shapes(Gcalc_shape_transporter *trn) const override; const Class_info *get_class_info() const override; }; struct Geometry_buffer : public my_aligned_storage {}; #endif /*HAVE_SPATIAL*/ #endif server/private/sql_debug.h000064400000013016151031265050011641 0ustar00#ifndef SQL_DEBUG_INCLUDED #define SQL_DEBUG_INCLUDED /* Copyright (c) 2022, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ class Debug_key: public String { public: Debug_key() = default; void print(THD *thd) const { push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR, "DBUG: %.*s", length(), ptr()); } bool append_key_type(ha_base_keytype type) { static LEX_CSTRING names[20]= { {STRING_WITH_LEN("END")}, {STRING_WITH_LEN("TEXT")}, {STRING_WITH_LEN("BINARY")}, {STRING_WITH_LEN("SHORT_INT")}, {STRING_WITH_LEN("LONG_INT")}, {STRING_WITH_LEN("FLOAT")}, {STRING_WITH_LEN("DOUBLE")}, {STRING_WITH_LEN("NUM")}, {STRING_WITH_LEN("USHORT_INT")}, {STRING_WITH_LEN("ULONG_INT")}, {STRING_WITH_LEN("LONGLONG")}, {STRING_WITH_LEN("ULONGLONG")}, {STRING_WITH_LEN("INT24")}, {STRING_WITH_LEN("UINT24")}, {STRING_WITH_LEN("INT8")}, {STRING_WITH_LEN("VARTEXT1")}, {STRING_WITH_LEN("VARBINARY1")}, {STRING_WITH_LEN("VARTEXT2")}, {STRING_WITH_LEN("VARBINARY2")}, {STRING_WITH_LEN("BIT")} }; if ((uint) type >= array_elements(names)) return append(STRING_WITH_LEN("???")); return append(names[(uint) type]); } bool append_KEY_flag_names(ulong flags) { static LEX_CSTRING names[17]= { {STRING_WITH_LEN("HA_NOSAME")}, // 1 {STRING_WITH_LEN("HA_PACK_KEY")}, // 2; also in HA_KEYSEG {STRING_WITH_LEN("HA_SPACE_PACK_USED")}, // 4 {STRING_WITH_LEN("HA_VAR_LENGTH_KEY")}, // 8 {STRING_WITH_LEN("HA_AUTO_KEY")}, // 16 {STRING_WITH_LEN("HA_BINARY_PACK_KEY")}, // 32 {STRING_WITH_LEN("HA_NULL_PART_KEY")}, // 64 {STRING_WITH_LEN("HA_FULLTEXT")}, // 128 {STRING_WITH_LEN("HA_UNIQUE_CHECK")}, // 256 {STRING_WITH_LEN("HA_SORT_ALLOWS_SAME")}, // 512 {STRING_WITH_LEN("HA_SPATIAL")}, // 1024 {STRING_WITH_LEN("HA_NULL_ARE_EQUAL")}, // 2048 {STRING_WITH_LEN("HA_USES_COMMENT")}, // 4096 {STRING_WITH_LEN("HA_GENERATED_KEY")}, // 8192 {STRING_WITH_LEN("HA_USES_PARSER")}, // 16384 {STRING_WITH_LEN("HA_USES_BLOCK_SIZE")}, // 32768 {STRING_WITH_LEN("HA_KEY_HAS_PART_KEY_SEG")}// 65536 }; return append_flag32_names((uint) flags, names, array_elements(names)); } bool append_HA_KEYSEG_flag_names(uint32 flags) { static LEX_CSTRING names[]= { {STRING_WITH_LEN("HA_SPACE_PACK")}, // 1 {STRING_WITH_LEN("HA_PACK_KEY")}, // 2; also in KEY/MI/KEY_DEF {STRING_WITH_LEN("HA_PART_KEY_SEG")}, // 4 {STRING_WITH_LEN("HA_VAR_LENGTH_PART")}, // 8 {STRING_WITH_LEN("HA_NULL_PART")}, // 16 {STRING_WITH_LEN("HA_BLOB_PART")}, // 32 {STRING_WITH_LEN("HA_SWAP_KEY")}, // 64 {STRING_WITH_LEN("HA_REVERSE_SORT")}, // 128 {STRING_WITH_LEN("HA_NO_SORT")}, // 256 {STRING_WITH_LEN("??? 512 ???")}, // 512 {STRING_WITH_LEN("HA_BIT_PART")}, // 1024 {STRING_WITH_LEN("HA_CAN_MEMCMP")} // 2048 }; return append_flag32_names(flags, names, array_elements(names)); } bool append_HA_KEYSEG_type(ha_base_keytype type) { return append_ulonglong(type) || append(' ') || append_key_type(type); } bool append_HA_KEYSEG_flags(uint32 flags) { return append_hex_uint32(flags) || append(' ') || append_HA_KEYSEG_flag_names(flags); } bool append_key(const LEX_CSTRING &name, uint32 flags) { return append_name_value(Lex_cstring(STRING_WITH_LEN("name")), name, '`') || append(Lex_cstring(STRING_WITH_LEN(" flags="))) || append_hex_uint32(flags) || append(' ') || append_KEY_flag_names(flags); } bool append_KEY(const KEY &key) { return append_key(key.name, key.flags); } static void print_keysegs(THD *thd, const HA_KEYSEG *seg, uint count) { for (uint i= 0; i < count; i++) { Debug_key tmp; if (!tmp.append(Lex_cstring(STRING_WITH_LEN(" seg["))) && !tmp.append_ulonglong(i) && !tmp.append(Lex_cstring(STRING_WITH_LEN("].type="))) && !tmp.append_HA_KEYSEG_type((ha_base_keytype) seg[i].type)) tmp.print(thd); tmp.length(0); if (!tmp.append(Lex_cstring(STRING_WITH_LEN(" seg["))) && !tmp.append_ulonglong(i) && !tmp.append(Lex_cstring(STRING_WITH_LEN("].flag="))) && !tmp.append_HA_KEYSEG_flags(seg[i].flag)) tmp.print(thd); } } static void print_keys(THD *thd, const char *where, const KEY *keys, uint key_count) { for (uint i= 0; i < key_count; i++) { Debug_key tmp; if (!tmp.append(where, strlen(where)) && !tmp.append_KEY(keys[i])) tmp.print(thd); } } }; #endif // SQL_DEBUG_INCLUDED server/private/my_base.h000064400000065112151031265050011317 0ustar00/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. Copyright (c) 1995, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file includes constants used with all databases */ #ifndef _my_base_h #define _my_base_h #include /* This includes types */ #include #include #include #ifndef EOVERFLOW #define EOVERFLOW 84 #endif #include /* The following is bits in the flag parameter to ha_open() */ #define HA_OPEN_ABORT_IF_LOCKED 0U /* default */ #define HA_OPEN_WAIT_IF_LOCKED 1U #define HA_OPEN_IGNORE_IF_LOCKED 2U #define HA_OPEN_TMP_TABLE 4U /* Table is a temp table */ #define HA_OPEN_DELAY_KEY_WRITE 8U /* Don't update index */ #define HA_OPEN_ABORT_IF_CRASHED 16U #define HA_OPEN_FOR_REPAIR 32U /* open even if crashed */ #define HA_OPEN_FROM_SQL_LAYER 64U #define HA_OPEN_MMAP 128U /* open memory mapped */ #define HA_OPEN_COPY 256U /* Open copy (for repair) */ /* Internal temp table, used for temporary results */ #define HA_OPEN_INTERNAL_TABLE 512U #define HA_OPEN_NO_PSI_CALL 1024U /* Don't call/connect PSI */ #define HA_OPEN_MERGE_TABLE 2048U #define HA_OPEN_FOR_CREATE 4096U #define HA_OPEN_FOR_DROP (1U << 13) /* Open part of drop */ #define HA_OPEN_GLOBAL_TMP_TABLE (1U << 14) /* TMP table used by repliction */ /* Allow opening even if table is incompatible as this is for ALTER TABLE which will fix the table structure. */ #define HA_OPEN_FOR_ALTER 8192U /* Open table for FLUSH */ #define HA_OPEN_FOR_FLUSH 8192U /* The following is parameter to ha_rkey() how to use key */ /* We define a complete-field prefix of a key value as a prefix where the last included field in the prefix contains the full field, not just some bytes from the start of the field. A partial-field prefix is allowed to contain only a few first bytes from the last included field. Below HA_READ_KEY_EXACT, ..., HA_READ_BEFORE_KEY can take a complete-field prefix of a key value as the search key. HA_READ_PREFIX and HA_READ_PREFIX_LAST could also take a partial-field prefix, but currently (4.0.10) they are only used with complete-field prefixes. MySQL uses a padding trick to implement LIKE 'abc%' queries. NOTE that in InnoDB HA_READ_PREFIX_LAST will NOT work with a partial-field prefix because InnoDB currently strips spaces from the end of varchar fields! */ enum ha_rkey_function { HA_READ_KEY_EXACT, /* Find first record else error */ HA_READ_KEY_OR_NEXT, /* Record or next record */ HA_READ_KEY_OR_PREV, /* Record or previous */ HA_READ_AFTER_KEY, /* Find next rec. after key-record */ HA_READ_BEFORE_KEY, /* Find next rec. before key-record */ HA_READ_PREFIX, /* Key which as same prefix */ HA_READ_PREFIX_LAST, /* Last key with the same prefix */ HA_READ_PREFIX_LAST_OR_PREV, /* Last or prev key with the same prefix */ HA_READ_MBR_CONTAIN, HA_READ_MBR_INTERSECT, HA_READ_MBR_WITHIN, HA_READ_MBR_DISJOINT, HA_READ_MBR_EQUAL }; /* Key algorithm types */ enum ha_key_alg { HA_KEY_ALG_UNDEF= 0, /* Not specified (old file) */ HA_KEY_ALG_BTREE= 1, /* B-tree, default one */ HA_KEY_ALG_RTREE= 2, /* R-tree, for spatial searches */ HA_KEY_ALG_HASH= 3, /* HASH keys (HEAP tables) */ HA_KEY_ALG_FULLTEXT= 4, /* FULLTEXT (MyISAM tables) */ HA_KEY_ALG_LONG_HASH= 5 /* long BLOB keys */ }; /* Storage media types */ enum ha_storage_media { HA_SM_DEFAULT= 0, /* Not specified (engine default) */ HA_SM_DISK= 1, /* DISK storage */ HA_SM_MEMORY= 2 /* MAIN MEMORY storage */ }; /* The following is parameter to ha_extra() */ enum ha_extra_function { HA_EXTRA_NORMAL=0, /* Optimize for space (def) */ HA_EXTRA_QUICK=1, /* Optimize for speed */ HA_EXTRA_NOT_USED=2, /* Should be ignored by handler */ HA_EXTRA_CACHE=3, /* Cache record in HA_rrnd() */ HA_EXTRA_NO_CACHE=4, /* End caching of records (def) */ HA_EXTRA_NO_READCHECK=5, /* No readcheck on update */ HA_EXTRA_READCHECK=6, /* Use readcheck (def) */ HA_EXTRA_KEYREAD=7, /* Read only key to database */ HA_EXTRA_NO_KEYREAD=8, /* Normal read of records (def) */ HA_EXTRA_NO_USER_CHANGE=9, /* No user is allowed to write */ HA_EXTRA_KEY_CACHE=10, HA_EXTRA_NO_KEY_CACHE=11, HA_EXTRA_WAIT_LOCK=12, /* Wait until file is available (def) */ HA_EXTRA_NO_WAIT_LOCK=13, /* If file is locked, return quickly */ HA_EXTRA_WRITE_CACHE=14, /* Use write cache in ha_write() */ HA_EXTRA_FLUSH_CACHE=15, /* flush write_record_cache */ HA_EXTRA_NO_KEYS=16, /* Remove all update of keys */ HA_EXTRA_KEYREAD_CHANGE_POS=17, /* Keyread, but change pos */ /* xxxxchk -r must be used */ HA_EXTRA_REMEMBER_POS=18, /* Remember pos for next/prev */ HA_EXTRA_RESTORE_POS=19, HA_EXTRA_REINIT_CACHE=20, /* init cache from current record */ HA_EXTRA_FORCE_REOPEN=21, /* Datafile have changed on disk */ HA_EXTRA_FLUSH, /* Flush tables to disk */ HA_EXTRA_NO_ROWS, /* Don't write rows */ HA_EXTRA_RESET_STATE, /* Reset positions */ HA_EXTRA_IGNORE_DUP_KEY, /* Dup keys don't rollback everything*/ HA_EXTRA_NO_IGNORE_DUP_KEY, HA_EXTRA_PREPARE_FOR_DROP, HA_EXTRA_PREPARE_FOR_UPDATE, /* Remove read cache if problems */ HA_EXTRA_PRELOAD_BUFFER_SIZE, /* Set buffer size for preloading */ /* On-the-fly switching between unique and non-unique key inserting. */ HA_EXTRA_CHANGE_KEY_TO_UNIQUE, HA_EXTRA_CHANGE_KEY_TO_DUP, /* When using HA_EXTRA_KEYREAD, overwrite only key member fields and keep other fields intact. When this is off (by default) InnoDB will use memcpy to overwrite entire row. */ HA_EXTRA_KEYREAD_PRESERVE_FIELDS, HA_EXTRA_MMAP, /* Ignore if the a tuple is not found, continue processing the transaction and ignore that 'row'. Needed for idempotency handling on the slave */ HA_EXTRA_IGNORE_NO_KEY, HA_EXTRA_NO_IGNORE_NO_KEY, /* Mark the table as a log table. For some handlers (e.g. CSV) this results in a special locking for the table. */ HA_EXTRA_MARK_AS_LOG_TABLE, /* Informs handler that write_row() which tries to insert new row into the table and encounters some already existing row with same primary/unique key can replace old row with new row instead of reporting error (basically it informs handler that we do REPLACE instead of simple INSERT). Off by default. */ HA_EXTRA_WRITE_CAN_REPLACE, HA_EXTRA_WRITE_CANNOT_REPLACE, /* Inform handler that delete_row()/update_row() cannot batch deletes/updates and should perform them immediately. This may be needed when table has AFTER DELETE/UPDATE triggers which access to subject table. These flags are reset by the handler::extra(HA_EXTRA_RESET) call. */ HA_EXTRA_DELETE_CANNOT_BATCH, HA_EXTRA_UPDATE_CANNOT_BATCH, /* Inform handler that an "INSERT...ON DUPLICATE KEY UPDATE" will be executed. This condition is unset by HA_EXTRA_NO_IGNORE_DUP_KEY. */ HA_EXTRA_INSERT_WITH_UPDATE, /* Inform handler that we will do a rename */ HA_EXTRA_PREPARE_FOR_RENAME, /* Special actions for MERGE tables. */ HA_EXTRA_ADD_CHILDREN_LIST, HA_EXTRA_ATTACH_CHILDREN, HA_EXTRA_IS_ATTACHED_CHILDREN, HA_EXTRA_DETACH_CHILDREN, HA_EXTRA_DETACH_CHILD, /* Inform handler we will force a close as part of flush */ HA_EXTRA_PREPARE_FOR_FORCED_CLOSE, /* Inform handler that we will do an alter table */ HA_EXTRA_PREPARE_FOR_ALTER_TABLE, /* Used in ha_partition::handle_ordered_index_scan() to inform engine that we are starting an ordered index scan. Needed by Spider */ HA_EXTRA_STARTING_ORDERED_INDEX_SCAN, /** Start writing rows during ALTER TABLE...ALGORITHM=COPY. */ HA_EXTRA_BEGIN_ALTER_COPY, /** Finish writing rows during ALTER TABLE...ALGORITHM=COPY. */ HA_EXTRA_END_ALTER_COPY }; /* Compatible option, to be deleted in 6.0 */ #define HA_EXTRA_PREPARE_FOR_DELETE HA_EXTRA_PREPARE_FOR_DROP /* The following is parameter to ha_panic() */ enum ha_panic_function { HA_PANIC_CLOSE, /* Close all databases */ HA_PANIC_WRITE, /* Unlock and write status */ HA_PANIC_READ /* Lock and read keyinfo */ }; /* The following is parameter to ha_create(); keytypes */ enum ha_base_keytype { HA_KEYTYPE_END=0, HA_KEYTYPE_TEXT=1, /* Key is sorted as letters */ HA_KEYTYPE_BINARY=2, /* Key is sorted as unsigned chars */ HA_KEYTYPE_SHORT_INT=3, HA_KEYTYPE_LONG_INT=4, HA_KEYTYPE_FLOAT=5, HA_KEYTYPE_DOUBLE=6, HA_KEYTYPE_NUM=7, /* Not packed num with pre-space */ HA_KEYTYPE_USHORT_INT=8, HA_KEYTYPE_ULONG_INT=9, HA_KEYTYPE_LONGLONG=10, HA_KEYTYPE_ULONGLONG=11, HA_KEYTYPE_INT24=12, HA_KEYTYPE_UINT24=13, HA_KEYTYPE_INT8=14, /* Varchar (0-255 bytes) with length packed with 1 byte */ HA_KEYTYPE_VARTEXT1=15, /* Key is sorted as letters */ HA_KEYTYPE_VARBINARY1=16, /* Key is sorted as unsigned chars */ /* Varchar (0-65535 bytes) with length packed with 2 bytes */ HA_KEYTYPE_VARTEXT2=17, /* Key is sorted as letters */ HA_KEYTYPE_VARBINARY2=18, /* Key is sorted as unsigned chars */ HA_KEYTYPE_BIT=19 }; #define HA_MAX_KEYTYPE 31 /* Must be log2-1 */ /* These flags kan be OR:ed to key-flag Note that these can only be up to 16 bits! */ #define HA_NOSAME 1U /* Set if not dupplicated records */ #define HA_PACK_KEY 2U /* Pack string key to previous key */ #define HA_AUTO_KEY 16U /* MEMORY/MyISAM/Aria internal */ #define HA_BINARY_PACK_KEY 32U /* Packing of all keys to prev key */ #define HA_FULLTEXT 128U /* For full-text search */ #define HA_SPATIAL 1024U /* For spatial search */ #define HA_NULL_ARE_EQUAL 2048U /* NULL in key are cmp as equal */ #define HA_GENERATED_KEY 8192U /* Automatically generated key */ /* The combination of the above can be used for key type comparison. */ #define HA_KEYFLAG_MASK (HA_NOSAME | HA_AUTO_KEY | HA_FULLTEXT | \ HA_SPATIAL | HA_NULL_ARE_EQUAL | HA_GENERATED_KEY) /* Key contains partial segments. This flag is internal to the MySQL server by design. It is not supposed neither to be saved in FRM-files, nor to be passed to storage engines. It is intended to pass information into internal static sort_keys(KEY *, KEY *) function. This flag can be calculated -- it's based on key lengths comparison. */ #define HA_KEY_HAS_PART_KEY_SEG 65536 /* Internal Flag Can be calculated */ #define HA_INVISIBLE_KEY 2<<18 /* Automatic bits in key-flag */ #define HA_SPACE_PACK_USED 4 /* Test for if SPACE_PACK used */ #define HA_VAR_LENGTH_KEY 8 #define HA_NULL_PART_KEY 64 #define HA_USES_COMMENT 4096 #define HA_USES_PARSER 16384 /* Fulltext index uses [pre]parser */ #define HA_USES_BLOCK_SIZE ((uint) 32768) #define HA_SORT_ALLOWS_SAME 512 /* Intern bit when sorting records */ /* This flag can be used only in KEY::ext_key_flags */ #define HA_EXT_NOSAME 131072 /* These flags can be added to key-seg-flag */ #define HA_SPACE_PACK 1 /* Pack space in key-seg */ #define HA_PART_KEY_SEG 4 /* Used by MySQL for part-key-cols */ #define HA_VAR_LENGTH_PART 8 #define HA_NULL_PART 16 #define HA_BLOB_PART 32 #define HA_SWAP_KEY 64 #define HA_REVERSE_SORT 128 /* Sort key in reverse order */ #define HA_NO_SORT 256 /* do not bother sorting on this keyseg */ #define HA_BIT_PART 1024 #define HA_CAN_MEMCMP 2048 /* internal, never stored in frm */ /* optionbits for database */ #define HA_OPTION_PACK_RECORD 1U #define HA_OPTION_PACK_KEYS 2U #define HA_OPTION_COMPRESS_RECORD 4U #define HA_OPTION_LONG_BLOB_PTR 8U /* new ISAM format */ #define HA_OPTION_TMP_TABLE 16U #define HA_OPTION_CHECKSUM 32U #define HA_OPTION_DELAY_KEY_WRITE 64U #define HA_OPTION_NO_PACK_KEYS 128U /* Reserved for MySQL */ /* unused 256 */ #define HA_OPTION_RELIES_ON_SQL_LAYER 512U #define HA_OPTION_NULL_FIELDS 1024U #define HA_OPTION_PAGE_CHECKSUM 2048U /* STATS_PERSISTENT=1 has been specified in the SQL command (either CREATE or ALTER TABLE). Table and index statistics that are collected by the storage engine and used by the optimizer for query optimization will be stored on disk and will not change after a server restart. */ #define HA_OPTION_STATS_PERSISTENT 4096U /* STATS_PERSISTENT=0 has been specified in CREATE/ALTER TABLE. Statistics for the table will be wiped away on server shutdown and new ones recalculated after the server is started again. If none of HA_OPTION_STATS_PERSISTENT or HA_OPTION_NO_STATS_PERSISTENT is set, this means that the setting is not explicitly set at table level and the corresponding table will use whatever is the global server default. */ #define HA_OPTION_NO_STATS_PERSISTENT 8192U /* .frm has extra create options in linked-list format */ #define HA_OPTION_TEXT_CREATE_OPTIONS_legacy (1U << 14) /* 5.2 to 5.5, unused since 10.0 */ #define HA_OPTION_TEMP_COMPRESS_RECORD (1U << 15) /* set by isamchk */ #define HA_OPTION_READ_ONLY_DATA (1U << 16) /* Set by isamchk */ #define HA_OPTION_NO_CHECKSUM (1U << 17) #define HA_OPTION_NO_DELAY_KEY_WRITE (1U << 18) /* Bits in flag to create() */ #define HA_DONT_TOUCH_DATA 1U /* Don't empty datafile (isamchk) */ #define HA_PACK_RECORD 2U /* Request packed record format */ #define HA_CREATE_TMP_TABLE 4U #define HA_CREATE_CHECKSUM 8U #define HA_CREATE_KEEP_FILES 16U /* don't overwrite .MYD and MYI */ #define HA_CREATE_PAGE_CHECKSUM 32U #define HA_CREATE_DELAY_KEY_WRITE 64U #define HA_CREATE_RELIES_ON_SQL_LAYER 128U #define HA_CREATE_INTERNAL_TABLE 256U #define HA_PRESERVE_INSERT_ORDER 512U #define HA_CREATE_NO_ROLLBACK 1024U /* A temporary table that can be used by different threads, eg. replication threads. This flag ensure that memory is not allocated with THREAD_SPECIFIC, as we do for other temporary tables. */ #define HA_CREATE_GLOBAL_TMP_TABLE 2048U /* Flags used by start_bulk_insert */ #define HA_CREATE_UNIQUE_INDEX_BY_SORT 1U /* The following flags (OR-ed) are passed to handler::info() method. The method copies misc handler information out of the storage engine to data structures accessible from MySQL Same flags are also passed down to mi_status, myrg_status, etc. */ /* this one is not used */ #define HA_STATUS_POS 1U /* assuming the table keeps shared actual copy of the 'info' and local, possibly outdated copy, the following flag means that it should not try to get the actual data (locking the shared structure) slightly outdated version will suffice */ #define HA_STATUS_NO_LOCK 2U /* update the time of the last modification (in handler::update_time) */ #define HA_STATUS_TIME 4U /* update the 'constant' part of the info: handler::max_data_file_length, max_index_file_length, create_time sortkey, ref_length, block_size, data_file_name, index_file_name. handler::table->s->keys_in_use, keys_for_keyread, rec_per_key */ #define HA_STATUS_CONST 8U /* update the 'variable' part of the info: handler::records, deleted, data_file_length, index_file_length, check_time, mean_rec_length */ #define HA_STATUS_VARIABLE 16U /* get the information about the key that caused last duplicate value error update handler::errkey and handler::dupp_ref see handler::get_dup_key() */ #define HA_STATUS_ERRKEY 32U /* update handler::auto_increment_value */ #define HA_STATUS_AUTO 64U /* Get also delete_length when HA_STATUS_VARIABLE is called. It's ok to set it also when only HA_STATUS_VARIABLE but it won't be used. */ #define HA_STATUS_VARIABLE_EXTRA 128U /* Treat empty table as empty (ignore HA_STATUS_TIME hack). */ #define HA_STATUS_OPEN 256U /* Errorcodes given by handler functions opt_sum_query() assumes these codes are > 1 Do not add error numbers before HA_ERR_FIRST. If necessary to add lower numbers, change HA_ERR_FIRST accordingly. */ #define HA_ERR_FIRST 120 /* Copy of first error nr.*/ #define HA_ERR_KEY_NOT_FOUND 120 /* Didn't find key on read or update */ #define HA_ERR_FOUND_DUPP_KEY 121 /* Duplicate key on write */ #define HA_ERR_INTERNAL_ERROR 122 /* Internal error */ #define HA_ERR_RECORD_CHANGED 123 /* Update with is recoverable */ #define HA_ERR_WRONG_INDEX 124 /* Wrong index given to function */ #define HA_ERR_CRASHED 126 /* Indexfile is crashed */ #define HA_ERR_WRONG_IN_RECORD 127 /* Record-file is crashed */ #define HA_ERR_OUT_OF_MEM 128 /* Out of memory */ #define HA_ERR_RETRY_INIT 129 /* Initialization failed and should be retried */ #define HA_ERR_NOT_A_TABLE 130 /* not a MYI file - no signature */ #define HA_ERR_WRONG_COMMAND 131 /* Command not supported */ #define HA_ERR_OLD_FILE 132 /* old databasfile */ #define HA_ERR_NO_ACTIVE_RECORD 133 /* No record read in update() */ #define HA_ERR_RECORD_DELETED 134 /* A record is not there */ #define HA_ERR_RECORD_FILE_FULL 135 /* No more room in file */ #define HA_ERR_INDEX_FILE_FULL 136 /* No more room in file */ #define HA_ERR_END_OF_FILE 137 /* end in next/prev/first/last */ #define HA_ERR_UNSUPPORTED 138 /* unsupported extension used */ #define HA_ERR_TO_BIG_ROW 139 /* Too big row */ #define HA_WRONG_CREATE_OPTION 140 /* Wrong create option */ #define HA_ERR_FOUND_DUPP_UNIQUE 141 /* Duplicate unique on write */ #define HA_ERR_UNKNOWN_CHARSET 142 /* Can't open charset */ #define HA_ERR_WRONG_MRG_TABLE_DEF 143 /* conflicting tables in MERGE */ #define HA_ERR_CRASHED_ON_REPAIR 144 /* Last (automatic?) repair failed */ #define HA_ERR_CRASHED_ON_USAGE 145 /* Table must be repaired */ #define HA_ERR_LOCK_WAIT_TIMEOUT 146 #define HA_ERR_LOCK_TABLE_FULL 147 #define HA_ERR_READ_ONLY_TRANSACTION 148 /* Updates not allowed */ #define HA_ERR_LOCK_DEADLOCK 149 #define HA_ERR_CANNOT_ADD_FOREIGN 150 /* Cannot add a foreign key constr. */ #define HA_ERR_NO_REFERENCED_ROW 151 /* Cannot add a child row */ #define HA_ERR_ROW_IS_REFERENCED 152 /* Cannot delete a parent row */ #define HA_ERR_NO_SAVEPOINT 153 /* No savepoint with that name */ #define HA_ERR_NON_UNIQUE_BLOCK_SIZE 154 /* Non unique key block size */ #define HA_ERR_NO_SUCH_TABLE 155 /* The table does not exist in engine */ #define HA_ERR_TABLE_EXIST 156 /* The table existed in storage engine */ #define HA_ERR_NO_CONNECTION 157 /* Could not connect to storage engine */ /* NULLs are not supported in spatial index */ #define HA_ERR_NULL_IN_SPATIAL 158 #define HA_ERR_TABLE_DEF_CHANGED 159 /* The table changed in storage engine */ /* There's no partition in table for given value */ #define HA_ERR_NO_PARTITION_FOUND 160 #define HA_ERR_RBR_LOGGING_FAILED 161 /* Row-based binlogging of row failed */ #define HA_ERR_DROP_INDEX_FK 162 /* Index needed in foreign key constr */ /* Upholding foreign key constraints would lead to a duplicate key error in some other table. */ #define HA_ERR_FOREIGN_DUPLICATE_KEY 163 /* The table changed in storage engine */ #define HA_ERR_TABLE_NEEDS_UPGRADE 164 #define HA_ERR_TABLE_READONLY 165 /* The table is not writable */ #define HA_ERR_AUTOINC_READ_FAILED 166 /* Failed to get next autoinc value */ #define HA_ERR_AUTOINC_ERANGE 167 /* Failed to set row autoinc value */ #define HA_ERR_GENERIC 168 /* Generic error */ /* row not actually updated: new values same as the old values */ #define HA_ERR_RECORD_IS_THE_SAME 169 #define HA_ERR_LOGGING_IMPOSSIBLE 170 /* It is not possible to log this statement */ #define HA_ERR_CORRUPT_EVENT 171 /* The event was corrupt, leading to illegal data being read */ #define HA_ERR_NEW_FILE 172 /* New file format */ #define HA_ERR_ROWS_EVENT_APPLY 173 /* The event could not be processed no other handler error happened */ #define HA_ERR_INITIALIZATION 174 /* Error during initialization */ #define HA_ERR_FILE_TOO_SHORT 175 /* File too short */ #define HA_ERR_WRONG_CRC 176 /* Wrong CRC on page */ #define HA_ERR_TOO_MANY_CONCURRENT_TRXS 177 /*Too many active concurrent transactions */ /* There's no explicitly listed partition in table for the given value */ #define HA_ERR_NOT_IN_LOCK_PARTITIONS 178 #define HA_ERR_INDEX_COL_TOO_LONG 179 /* Index column length exceeds limit */ #define HA_ERR_INDEX_CORRUPT 180 /* Index corrupted */ #define HA_ERR_UNDO_REC_TOO_BIG 181 /* Undo log record too big */ #define HA_FTS_INVALID_DOCID 182 /* Invalid InnoDB Doc ID */ /* #define HA_ERR_TABLE_IN_FK_CHECK 183 */ /* Table being used in foreign key check */ #define HA_ERR_TABLESPACE_EXISTS 184 /* The tablespace existed in storage engine */ #define HA_ERR_TOO_MANY_FIELDS 185 /* Table has too many columns */ #define HA_ERR_ROW_IN_WRONG_PARTITION 186 /* Row in wrong partition */ #define HA_ERR_ROW_NOT_VISIBLE 187 #define HA_ERR_ABORTED_BY_USER 188 #define HA_ERR_DISK_FULL 189 #define HA_ERR_INCOMPATIBLE_DEFINITION 190 #define HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE 191 /* Too many words in a phrase */ #define HA_ERR_DECRYPTION_FAILED 192 /* Table encrypted but decrypt failed */ #define HA_ERR_FK_DEPTH_EXCEEDED 193 /* FK cascade depth exceeded */ #define HA_ERR_TABLESPACE_MISSING 194 /* Missing Tablespace */ #define HA_ERR_SEQUENCE_INVALID_DATA 195 #define HA_ERR_SEQUENCE_RUN_OUT 196 #define HA_ERR_COMMIT_ERROR 197 #define HA_ERR_PARTITION_LIST 198 #define HA_ERR_NO_ENCRYPTION 199 #define HA_ERR_ROLLBACK 200 /* Automatic rollback done */ #define HA_ERR_LAST 200 /* Copy of last error nr * */ /* Number of different errors */ #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) /* aliases */ #define HA_ERR_TABLE_CORRUPT HA_ERR_WRONG_IN_RECORD #define HA_ERR_QUERY_INTERRUPTED HA_ERR_ABORTED_BY_USER #define HA_ERR_NOT_ALLOWED_COMMAND HA_ERR_WRONG_COMMAND /* Other constants */ #define HA_NAMELEN 64 /* Max length of saved filename */ #define NO_SUCH_KEY (~(uint)0) /* used as a key no. */ typedef ulong key_part_map; #define HA_WHOLE_KEY (~(key_part_map)0) /* Intern constants in databases */ /* bits in _search */ #define SEARCH_FIND 1U #define SEARCH_NO_FIND 2U #define SEARCH_SAME 4U #define SEARCH_BIGGER 8U #define SEARCH_SMALLER 16U #define SEARCH_SAVE_BUFF 32U #define SEARCH_UPDATE 64U #define SEARCH_PREFIX 128U #define SEARCH_LAST 256U #define MBR_CONTAIN 512U #define MBR_INTERSECT 1024U #define MBR_WITHIN 2048U #define MBR_DISJOINT 4096U #define MBR_EQUAL 8192U #define MBR_DATA 16384U #define SEARCH_NULL_ARE_EQUAL 32768U /* NULL in keys are equal */ #define SEARCH_NULL_ARE_NOT_EQUAL 65536U/* NULL in keys are not equal */ /* Use this when inserting a key in position order */ #define SEARCH_INSERT (SEARCH_NULL_ARE_NOT_EQUAL*2) /* Only part of the key is specified while reading */ #define SEARCH_PART_KEY (SEARCH_INSERT*2) /* Used when user key (key 2) contains transaction id's */ #define SEARCH_USER_KEY_HAS_TRANSID (SEARCH_PART_KEY*2) /* Used when page key (key 1) contains transaction id's */ #define SEARCH_PAGE_KEY_HAS_TRANSID (SEARCH_USER_KEY_HAS_TRANSID*2) /* bits in opt_flag */ #define QUICK_USED 1U #define READ_CACHE_USED 2U #define READ_CHECK_USED 4U #define KEY_READ_USED 8U #define WRITE_CACHE_USED 16U #define OPT_NO_ROWS 32U /* bits in update */ #define HA_STATE_CHANGED 1U /* Database has changed */ #define HA_STATE_AKTIV 2U /* Has a current record */ #define HA_STATE_WRITTEN 4U /* Record is written */ #define HA_STATE_DELETED 8U #define HA_STATE_NEXT_FOUND 16U /* Next found record (record before) */ #define HA_STATE_PREV_FOUND 32U /* Prev found record (record after) */ #define HA_STATE_NO_KEY 64U /* Last read didn't find record */ #define HA_STATE_KEY_CHANGED 128U #define HA_STATE_WRITE_AT_END 256U /* set in _ps_find_writepos */ #define HA_STATE_BUFF_SAVED 512U /* If current keybuff is info->buff */ #define HA_STATE_ROW_CHANGED 1024U /* To invalidate ROW cache */ #define HA_STATE_EXTEND_BLOCK 2048U #define HA_STATE_RNEXT_SAME 4096U /* rnext_same occupied lastkey2 */ /* myisampack expects no more than 32 field types. */ enum en_fieldtype { FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE, FIELD_SKIP_ZERO,FIELD_BLOB,FIELD_CONSTANT,FIELD_INTERVALL,FIELD_ZERO, FIELD_VARCHAR,FIELD_CHECK, FIELD_enum_val_count }; enum data_file_type { STATIC_RECORD, DYNAMIC_RECORD, COMPRESSED_RECORD, BLOCK_RECORD, NO_RECORD }; /* For key ranges */ #define NO_MIN_RANGE 1U #define NO_MAX_RANGE 2U #define NEAR_MIN 4U #define NEAR_MAX 8U #define UNIQUE_RANGE 16U #define EQ_RANGE 32U #define NULL_RANGE 64U #define GEOM_FLAG 128U typedef struct st_key_range { const uchar *key; uint length; key_part_map keypart_map; enum ha_rkey_function flag; } key_range; typedef void *range_id_t; typedef struct st_key_multi_range { key_range start_key; key_range end_key; range_id_t ptr; /* Free to use by caller (ptr to row etc) */ /* A set of range flags that describe both endpoints: UNIQUE_RANGE, NULL_RANGE, EQ_RANGE, GEOM_FLAG. (Flags that describe one endpoint, NO_{MIN|MAX}_RANGE, NEAR_{MIN|MAX} will not be set here) */ uint range_flag; } KEY_MULTI_RANGE; /* Store first and last leaf page accessed by records_in_range */ typedef struct st_page_range { ulonglong first_page; ulonglong last_page; } page_range; #define UNUSED_PAGE_NO ULONGLONG_MAX #define unused_page_range { UNUSED_PAGE_NO, UNUSED_PAGE_NO } /* For number of records */ #ifdef BIG_TABLES #define rows2double(A) ulonglong2double(A) typedef my_off_t ha_rows; #else #define rows2double(A) (double) (A) typedef ulong ha_rows; #endif #define HA_POS_ERROR (~ (ha_rows) 0) #define HA_OFFSET_ERROR (~ (my_off_t) 0) #define HA_ROWS_MAX HA_POS_ERROR #if SIZEOF_OFF_T == 4 #define MAX_FILE_SIZE INT_MAX32 #else #define MAX_FILE_SIZE LONGLONG_MAX #endif #define HA_VARCHAR_PACKLENGTH(field_length) ((field_length) < 256 ? 1 :2) /* invalidator function reference for Query Cache */ C_MODE_START typedef void (* invalidator_by_filename)(const char * filename); C_MODE_END #endif /* _my_base_h */ server/private/myisamchk.h000064400000011154151031265050011662 0ustar00/* Copyright (C) 2006 MySQL AB Copyright (c) 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Definitions needed for myisamchk/mariachk.c */ #ifndef _myisamchk_h #define _myisamchk_h #include /* Flags used by xxxxchk.c or/and ha_xxxx.cc that are NOT passed to xxxcheck.c follows: */ #define TT_USEFRM 1U #define TT_FOR_UPGRADE 2U #define TT_FROM_MYSQL 4U /* Bits set in out_flag */ #define O_NEW_DATA 2U #define O_DATA_LOST 4U /* MARIA/MYISAM supports several statistics collection methods. Currently statistics collection method is not stored in MARIA file and has to be specified for each table analyze/repair operation in MI_CHECK::stats_method. */ typedef enum { /* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */ MI_STATS_METHOD_NULLS_NOT_EQUAL, /* Treat NULLs as equal when collecting statistics (like 4.0 did) */ MI_STATS_METHOD_NULLS_EQUAL, /* Ignore NULLs - count only tuples without NULLs in the index components */ MI_STATS_METHOD_IGNORE_NULLS } enum_handler_stats_method; struct st_myisam_info; typedef struct st_handler_check_param { char *isam_file_name; MY_TMPDIR *tmpdir; void *thd; const char *db_name, *table_name, *op_name; ulonglong auto_increment_value; ulonglong max_data_file_length; ulonglong keys_in_use; ulonglong max_record_length; /* The next two are used to collect statistics, see update_key_parts for description. */ ulonglong unique_count[HA_MAX_KEY_SEG + 1]; ulonglong notnull_count[HA_MAX_KEY_SEG + 1]; ulonglong max_allowed_lsn; my_off_t search_after_block; my_off_t new_file_pos, key_file_blocks; my_off_t keydata, totaldata, key_blocks, start_check_pos; my_off_t used, empty, splits, del_length, link_used, lost; ha_rows total_records, total_deleted, records,del_blocks; ha_rows full_page_count, tail_count; ha_checksum record_checksum, glob_crc; ha_checksum key_crc[HA_MAX_POSSIBLE_KEY]; ha_checksum tmp_key_crc[HA_MAX_POSSIBLE_KEY]; ha_checksum tmp_record_checksum; ulonglong org_key_map; ulonglong testflag; /* Following is used to check if rows are visible */ ulonglong max_trid, max_found_trid; ulonglong not_visible_rows_found; ulonglong sort_buffer_length, orig_sort_buffer_length; ulonglong use_buffers; /* Used as param to getopt() */ size_t read_buffer_length, write_buffer_length, sort_key_blocks; time_t backup_time; /* To sign backup files */ ulong rec_per_key_part[HA_MAX_KEY_SEG * HA_MAX_POSSIBLE_KEY]; double new_rec_per_key_part[HA_MAX_KEY_SEG * HA_MAX_POSSIBLE_KEY]; uint out_flag, error_printed, verbose; uint opt_sort_key, total_files, max_level; uint key_cache_block_size, pagecache_block_size; uint skip_lsn_error_count; int tmpfile_createflag, err_count; myf myf_rw; uint16 language; my_bool warning_printed, note_printed, wrong_trd_printed; my_bool using_global_keycache, opt_lock_memory, opt_follow_links; my_bool retry_repair, force_sort, calc_checksum, static_row_size; char temp_filename[FN_REFLEN]; IO_CACHE read_cache; void **stack_end_ptr; enum_handler_stats_method stats_method; /* For reporting progress */ uint stage, max_stage; uint progress_counter; /* How often to call _report_progress() */ ulonglong progress, max_progress; void (*init_fix_record)(void *); int (*fix_record)(struct st_myisam_info *info, uchar *record, int keynum); mysql_mutex_t print_msg_mutex; my_bool need_print_msg_lock; myf malloc_flags; } HA_CHECK; typedef struct st_buffpek { my_off_t file_pos; /* Where we are in the sort file */ uchar *base, *key; /* Key pointers */ ha_rows count; /* Number of rows in table */ ha_rows mem_count; /* Numbers of keys in memory */ ha_rows max_keys; /* Max keys in buffert */ } BUFFPEK; #endif /* _myisamchk_h */ server/private/semisync_master.h000064400000062246151031265050013112 0ustar00/* Copyright (C) 2007 Google Inc. Copyright (c) 2008 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SEMISYNC_MASTER_H #define SEMISYNC_MASTER_H #include "semisync.h" #include "semisync_master_ack_receiver.h" #ifdef HAVE_PSI_INTERFACE extern PSI_mutex_key key_LOCK_rpl_semi_sync_master_enabled; extern PSI_mutex_key key_LOCK_binlog; extern PSI_cond_key key_COND_binlog_send; #endif struct Tranx_node { char log_name[FN_REFLEN]; bool thd_valid; /* thd is valid for signalling */ my_off_t log_pos; THD *thd; /* The thread awaiting an ACK */ struct Tranx_node *next; /* the next node in the sorted list */ struct Tranx_node *hash_next; /* the next node during hash collision */ }; /** @class Tranx_node_allocator This class provides memory allocating and freeing methods for Tranx_node. The main target is performance. @section ALLOCATE How to allocate a node The pointer of the first node after 'last_node' in current_block is returned. current_block will move to the next free Block when all nodes of it are in use. A new Block is allocated and is put into the rear of the Block link table if no Block is free. The list starts up empty (ie, there is no allocated Block). After some nodes are freed, there probably are some free nodes before the sequence of the allocated nodes, but we do not reuse it. It is better to keep the allocated nodes are in the sequence, for it is more efficient for allocating and freeing Tranx_node. @section FREENODE How to free nodes There are two methods for freeing nodes. They are free_all_nodes and free_nodes_before. 'A Block is free' means all of its nodes are free. @subsection free_nodes_before As all allocated nodes are in the sequence, 'Before one node' means all nodes before given node in the same Block and all Blocks before the Block which containing the given node. As such, all Blocks before the given one ('node') are free Block and moved into the rear of the Block link table. The Block containing the given 'node', however, is not. For at least the given 'node' is still in use. This will waste at most one Block, but it is more efficient. */ #define BLOCK_TRANX_NODES 16 class Tranx_node_allocator { public: /** @param reserved_nodes The number of reserved Tranx_nodes. It is used to set 'reserved_blocks' which can contain at least 'reserved_nodes' number of Tranx_nodes. When freeing memory, we will reserve at least reserved_blocks of Blocks not freed. */ Tranx_node_allocator(uint reserved_nodes) : reserved_blocks(reserved_nodes/BLOCK_TRANX_NODES + (reserved_nodes%BLOCK_TRANX_NODES > 1 ? 2 : 1)), first_block(NULL), last_block(NULL), current_block(NULL), last_node(-1), block_num(0) {} ~Tranx_node_allocator() { Block *block= first_block; while (block != NULL) { Block *next= block->next; free_block(block); block= next; } } /** The pointer of the first node after 'last_node' in current_block is returned. current_block will move to the next free Block when all nodes of it are in use. A new Block is allocated and is put into the rear of the Block link table if no Block is free. @return Return a Tranx_node *, or NULL if an error occurred. */ Tranx_node *allocate_node() { Tranx_node *trx_node; Block *block= current_block; if (last_node == BLOCK_TRANX_NODES-1) { current_block= current_block->next; last_node= -1; } if (current_block == NULL && allocate_block()) { current_block= block; if (current_block) last_node= BLOCK_TRANX_NODES-1; return NULL; } trx_node= &(current_block->nodes[++last_node]); trx_node->log_name[0] = '\0'; trx_node->thd_valid= false; trx_node->log_pos= 0; trx_node->thd= nullptr; trx_node->next= 0; trx_node->hash_next= 0; return trx_node; } /** All nodes are freed. @return Return 0, or 1 if an error occurred. */ int free_all_nodes() { current_block= first_block; last_node= -1; free_blocks(); return 0; } /** All Blocks before the given 'node' are free Block and moved into the rear of the Block link table. @param node All nodes before 'node' will be freed @return Return 0, or 1 if an error occurred. */ int free_nodes_before(Tranx_node* node) { Block *block; Block *prev_block= NULL; block= first_block; while (block != current_block->next) { /* Find the Block containing the given node */ if (&(block->nodes[0]) <= node && &(block->nodes[BLOCK_TRANX_NODES]) >= node) { /* All Blocks before the given node are put into the rear */ if (first_block != block) { last_block->next= first_block; first_block= block; last_block= prev_block; last_block->next= NULL; free_blocks(); } return 0; } prev_block= block; block= block->next; } /* Node does not find should never happen */ DBUG_ASSERT(0); return 1; } private: uint reserved_blocks; /** A sequence memory which contains BLOCK_TRANX_NODES Tranx_nodes. BLOCK_TRANX_NODES The number of Tranx_nodes which are in a Block. next Every Block has a 'next' pointer which points to the next Block. These linking Blocks constitute a Block link table. */ struct Block { Block *next; Tranx_node nodes[BLOCK_TRANX_NODES]; }; /** The 'first_block' is the head of the Block link table; */ Block *first_block; /** The 'last_block' is the rear of the Block link table; */ Block *last_block; /** current_block always points the Block in the Block link table in which the last allocated node is. The Blocks before it are all in use and the Blocks after it are all free. */ Block *current_block; /** It always points to the last node which has been allocated in the current_block. */ int last_node; /** How many Blocks are in the Block link table. */ uint block_num; /** Allocate a block and then assign it to current_block. */ int allocate_block() { Block *block= (Block *)my_malloc(PSI_INSTRUMENT_ME, sizeof(Block), MYF(0)); if (block) { block->next= NULL; if (first_block == NULL) first_block= block; else last_block->next= block; /* New Block is always put into the rear */ last_block= block; /* New Block is always the current_block */ current_block= block; ++block_num; return 0; } return 1; } /** Free a given Block. @param block The Block will be freed. */ void free_block(Block *block) { my_free(block); --block_num; } /** If there are some free Blocks and the total number of the Blocks in the Block link table is larger than the 'reserved_blocks', Some free Blocks will be freed until the total number of the Blocks is equal to the 'reserved_blocks' or there is only one free Block behind the 'current_block'. */ void free_blocks() { if (current_block == NULL || current_block->next == NULL) return; /* One free Block is always kept behind the current block */ Block *block= current_block->next->next; while (block_num > reserved_blocks && block != NULL) { Block *next= block->next; free_block(block); block= next; } current_block->next->next= block; if (block == NULL) last_block= current_block->next; } }; /** Function pointer type to run on the contents of an Active_tranx node. Return 0 for success, 1 for error. Note Repl_semi_sync_master::LOCK_binlog is not guaranteed to be held for its invocation. See the context in which it is called to know. */ typedef int (*active_tranx_action)(THD *trx_thd, bool thd_valid, const char *log_file_name, my_off_t trx_log_file_pos); /** This class manages memory for active transaction list. We record each active transaction with a Tranx_node, each session can have only one open transaction. Because of EVENT, the total active transaction nodes can exceed the maximum allowed connections. */ class Active_tranx :public Trace { private: Tranx_node_allocator m_allocator; /* These two record the active transaction list in sort order. */ Tranx_node *m_trx_front, *m_trx_rear; Tranx_node **m_trx_htb; /* A hash table on active transactions. */ int m_num_entries; /* maximum hash table entries */ mysql_mutex_t *m_lock; /* mutex lock */ mysql_cond_t *m_cond_empty; /* signalled when cleared all Tranx_node */ inline void assert_lock_owner(); inline unsigned int calc_hash(const unsigned char *key, size_t length); unsigned int get_hash_value(const char *log_file_name, my_off_t log_file_pos); int compare(const char *log_file_name1, my_off_t log_file_pos1, const Tranx_node *node2) { return compare(log_file_name1, log_file_pos1, node2->log_name, node2->log_pos); } int compare(const Tranx_node *node1, const char *log_file_name2, my_off_t log_file_pos2) { return compare(node1->log_name, node1->log_pos, log_file_name2, log_file_pos2); } int compare(const Tranx_node *node1, const Tranx_node *node2) { return compare(node1->log_name, node1->log_pos, node2->log_name, node2->log_pos); } public: Active_tranx(mysql_mutex_t *lock, mysql_cond_t *cond, unsigned long trace_level); ~Active_tranx(); /* Insert an active transaction node with the specified position. * * Return: * 0: success; non-zero: error */ int insert_tranx_node(THD *thd_to_wait, const char *log_file_name, my_off_t log_file_pos); /* Clear the active transaction nodes until(inclusive) the specified * position. * If log_file_name is NULL, everything will be cleared: the sorted * list and the hash table will be reset to empty. * * The pre_delete_hook parameter is a function pointer that will be invoked * for each Active_tranx node, in order, from m_trx_front to m_trx_rear, * e.g. to signal their wakeup condition. Repl_semi_sync_binlog::LOCK_binlog * is held while this is invoked. */ void clear_active_tranx_nodes(const char *log_file_name, my_off_t log_file_pos, active_tranx_action pre_delete_hook); /* Unlinks a thread from a Tranx_node, so it will not be referenced/signalled * if it is separately killed. Note that this keeps the Tranx_node itself in * the cache so it can still be awaited by await_all_slave_replies(), e.g. * as is done by SHUTDOWN WAIT FOR ALL SLAVES. */ void unlink_thd_as_waiter(const char *log_file_name, my_off_t log_file_pos); /* Uses DBUG_ASSERT statements to ensure that the argument thd_to_check * matches the thread of the respective Tranx_node::thd of the passed in * log_file_name and log_file_pos. */ Tranx_node * is_thd_waiter(THD *thd_to_check, const char *log_file_name, my_off_t log_file_pos); /* Given a position, check to see whether the position is an active * transaction's ending position by probing the hash table. */ bool is_tranx_end_pos(const char *log_file_name, my_off_t log_file_pos); /* Given two binlog positions, compare which one is bigger based on * (file_name, file_position). */ static int compare(const char *log_file_name1, my_off_t log_file_pos1, const char *log_file_name2, my_off_t log_file_pos2); /* Check if there are no transactions actively awaiting ACKs. Returns true * if the internal linked list has no entries, false otherwise. */ bool is_empty() { return m_trx_front == NULL; } }; /** The extension class for the master of semi-synchronous replication */ class Repl_semi_sync_master :public Repl_semi_sync_base { Active_tranx *m_active_tranxs; /* active transaction list: the list will be cleared when semi-sync switches off. */ /* True when init_object has been called */ bool m_init_done; /* This cond variable is signaled when enough binlog has been sent to slave, * so that a waiting trx can return the 'ok' to the client for a commit. */ mysql_cond_t COND_binlog_send; /* Mutex that protects the following state variables and the active * transaction list. * Under no cirumstances we can acquire mysql_bin_log.LOCK_log if we are * already holding m_LOCK_binlog because it can cause deadlocks. */ mysql_mutex_t LOCK_binlog; /* This is set to true when m_reply_file_name contains meaningful data. */ bool m_reply_file_name_inited; /* The binlog name up to which we have received replies from any slaves. */ char m_reply_file_name[FN_REFLEN]; /* The position in that file up to which we have the reply from any slaves. */ my_off_t m_reply_file_pos; /* This is set to true when we know the 'smallest' wait position. */ bool m_wait_file_name_inited; /* NULL, or the 'smallest' filename that a transaction is waiting for * slave replies. */ char m_wait_file_name[FN_REFLEN]; /* The smallest position in that file that a trx is waiting for: the trx * can proceed and send an 'ok' to the client when the master has got the * reply from the slave indicating that it already got the binlog events. */ my_off_t m_wait_file_pos; /* This is set to true when we know the 'largest' transaction commit * position in the binlog file. * We always maintain the position no matter whether semi-sync is switched * on switched off. When a transaction wait timeout occurs, semi-sync will * switch off. Binlog-dump thread can use the three fields to detect when * slaves catch up on replication so that semi-sync can switch on again. */ bool m_commit_file_name_inited; /* The 'largest' binlog filename that a commit transaction is seeing. */ char m_commit_file_name[FN_REFLEN]; /* The 'largest' position in that file that a commit transaction is seeing. */ my_off_t m_commit_file_pos; /* All global variables which can be set by parameters. */ volatile bool m_master_enabled; /* semi-sync is enabled on the master */ unsigned long m_wait_timeout; /* timeout period(ms) during tranx wait */ bool m_state; /* whether semi-sync is switched */ /*Waiting for ACK before/after innodb commit*/ ulong m_wait_point; void lock(); void unlock(); /* Is semi-sync replication on? */ bool is_on() { return (m_state); } void set_master_enabled(bool enabled) { m_master_enabled = enabled; } /* Switch semi-sync off because of timeout in transaction waiting. */ void switch_off(); /* Switch semi-sync on when slaves catch up. */ int try_switch_on(int server_id, const char *log_file_name, my_off_t log_file_pos); public: Repl_semi_sync_master(); ~Repl_semi_sync_master() = default; void cleanup(); bool get_master_enabled() { return m_master_enabled; } void set_trace_level(unsigned long trace_level) { m_trace_level = trace_level; if (m_active_tranxs) m_active_tranxs->m_trace_level = trace_level; } /* Set the transaction wait timeout period, in milliseconds. */ void set_wait_timeout(unsigned long wait_timeout) { m_wait_timeout = wait_timeout; } /* Calculates a timeout that is m_wait_timeout after start_arg and saves it in out. If start_arg is NULL, the timeout is m_wait_timeout after the current system time. */ void create_timeout(struct timespec *out, struct timespec *start_arg); /* Blocks the calling thread until the ack_receiver either receives ACKs for all transactions awaiting ACKs, or times out (from rpl_semi_sync_master_timeout). If info_msg is provided, it will be output via sql_print_information when there are transactions awaiting ACKs; info_msg is not output if there are no transasctions to await. */ void await_all_slave_replies(const char *msg); /*set the ACK point, after binlog sync or after transaction commit*/ void set_wait_point(unsigned long ack_point) { m_wait_point = ack_point; } ulong wait_point() //no cover line { return m_wait_point; //no cover line } /* Initialize this class after MySQL parameters are initialized. this * function should be called once at bootstrap time. */ int init_object(); /* Enable the object to enable semi-sync replication inside the master. */ int enable_master(); /* Disable the object to disable semi-sync replication inside the master. */ void disable_master(); /* Add a semi-sync replication slave */ void add_slave(); /* Remove a semi-sync replication slave */ void remove_slave(); /* It parses a reply packet and call report_reply_binlog to handle it. */ int report_reply_packet(uint32 server_id, const uchar *packet, ulong packet_len); /* In semi-sync replication, reports up to which binlog position we have * received replies from the slave indicating that it already get the events. * * Input: * server_id - (IN) master server id number * log_file_name - (IN) binlog file name * end_offset - (IN) the offset in the binlog file up to which we have * the replies from the slave * * Return: * 0: success; non-zero: error */ int report_reply_binlog(uint32 server_id, const char* log_file_name, my_off_t end_offset); /* Commit a transaction in the final step. This function is called from * InnoDB before returning from the low commit. If semi-sync is switch on, * the function will wait to see whether binlog-dump thread get the reply for * the events of the transaction. Remember that this is not a direct wait, * instead, it waits to see whether the binlog-dump thread has reached the * point. If the wait times out, semi-sync status will be switched off and * all other transaction would not wait either. * * Input: (the transaction events' ending binlog position) * trx_wait_binlog_name - (IN) ending position's file name * trx_wait_binlog_pos - (IN) ending position's file offset * * Return: * 0: success; non-zero: error */ int commit_trx(const char* trx_wait_binlog_name, my_off_t trx_wait_binlog_pos); /*Wait for ACK after writing/sync binlog to file*/ int wait_after_sync(const char* log_file, my_off_t log_pos); /*Wait for ACK after commting the transaction*/ int wait_after_commit(THD* thd, bool all); /*Wait after the transaction is rollback*/ int wait_after_rollback(THD *thd, bool all); /* Store the current binlog position in m_active_tranxs. This position should * be acked by slave. * * Inputs: * trans_thd Thread of the transaction which is executing the * transaction. * waiter_thd Thread that will wait for the ACK from the replica, * which depends on the semi-sync wait point. If AFTER_SYNC, * and also using binlog group commit, this will be the leader * thread of the binlog commit. Otherwise, it is the thread that * is executing the transaction, i.e. the same as trans_thd. * log_file Name of the binlog file that the transaction is written into * log_pos Offset within the binlog file that the transaction is written * at */ int report_binlog_update(THD *trans_thd, THD *waiter_thd, const char *log_file, my_off_t log_pos); int dump_start(THD* thd, const char *log_file, my_off_t log_pos); void dump_end(THD* thd); /* Reserve space in the replication event packet header: * . slave semi-sync off: 1 byte - (0) * . slave semi-sync on: 3 byte - (0, 0xef, 0/1} * * Input: * packet - (IN) the header buffer * * Return: * size of the bytes reserved for header */ int reserve_sync_header(String* packet); /* Update the sync bit in the packet header to indicate to the slave whether * the master will wait for the reply of the event. If semi-sync is switched * off and we detect that the slave is catching up, we switch semi-sync on. * * Input: * THD - (IN) current dump thread * packet - (IN) the packet containing the replication event * log_file_name - (IN) the event ending position's file name * log_file_pos - (IN) the event ending position's file offset * need_sync - (IN) identify if flush_net is needed to call. * server_id - (IN) master server id number * * Return: * 0: success; non-zero: error */ int update_sync_header(THD* thd, unsigned char *packet, const char *log_file_name, my_off_t log_file_pos, bool* need_sync); /* Called when a transaction finished writing binlog events. * . update the 'largest' transactions' binlog event position * . insert the ending position in the active transaction list if * semi-sync is on * * Input: (the transaction events' ending binlog position) * THD - (IN) thread that will wait for an ACK. This can be the * binlog leader thread when using wait_point * AFTER_SYNC with binlog group commit. In all other * cases, this is the user thread executing the * transaction. * log_file_name - (IN) transaction ending position's file name * log_file_pos - (IN) transaction ending position's file offset * * Return: * 0: success; non-zero: error */ int write_tranx_in_binlog(THD *thd, const char *log_file_name, my_off_t log_file_pos); /* Read the slave's reply so that we know how much progress the slave makes * on receive replication events. */ int flush_net(THD* thd, const char *event_buf); /* Export internal statistics for semi-sync replication. */ void set_export_stats(); /* 'reset master' command is issued from the user and semi-sync need to * go off for that. */ int after_reset_master(); /*called before reset master*/ int before_reset_master(); mysql_mutex_t LOCK_rpl_semi_sync_master_enabled; }; enum rpl_semi_sync_master_wait_point_t { SEMI_SYNC_MASTER_WAIT_POINT_AFTER_BINLOG_SYNC, SEMI_SYNC_MASTER_WAIT_POINT_AFTER_STORAGE_COMMIT, }; extern Repl_semi_sync_master repl_semisync_master; extern Ack_receiver ack_receiver; /* System and status variables for the master component */ extern my_bool rpl_semi_sync_master_enabled; extern my_bool rpl_semi_sync_master_status; extern ulong rpl_semi_sync_master_wait_point; extern ulong rpl_semi_sync_master_clients; extern ulong rpl_semi_sync_master_timeout; extern ulong rpl_semi_sync_master_trace_level; extern ulong rpl_semi_sync_master_yes_transactions; extern ulong rpl_semi_sync_master_no_transactions; extern ulong rpl_semi_sync_master_off_times; extern ulong rpl_semi_sync_master_wait_timeouts; extern ulong rpl_semi_sync_master_timefunc_fails; extern ulong rpl_semi_sync_master_num_timeouts; extern ulong rpl_semi_sync_master_wait_sessions; extern ulong rpl_semi_sync_master_wait_pos_backtraverse; extern ulong rpl_semi_sync_master_avg_trx_wait_time; extern ulong rpl_semi_sync_master_avg_net_wait_time; extern ulonglong rpl_semi_sync_master_net_wait_num; extern ulonglong rpl_semi_sync_master_trx_wait_num; extern ulonglong rpl_semi_sync_master_net_wait_time; extern ulonglong rpl_semi_sync_master_trx_wait_time; extern unsigned long long rpl_semi_sync_master_request_ack; extern unsigned long long rpl_semi_sync_master_get_ack; /* This indicates whether we should keep waiting if no semi-sync slave is available. 0 : stop waiting if detected no avaialable semi-sync slave. 1 (default) : keep waiting until timeout even no available semi-sync slave. */ extern char rpl_semi_sync_master_wait_no_slave; extern Repl_semi_sync_master repl_semisync_master; extern PSI_stage_info stage_waiting_for_semi_sync_ack_from_slave; extern PSI_stage_info stage_reading_semi_sync_ack; extern PSI_stage_info stage_waiting_for_semi_sync_slave; void semi_sync_master_deinit(); #endif /* SEMISYNC_MASTER_H */ server/private/ilist.h000064400000015610151031265050011022 0ustar00/* Copyright (c) 2019, 2020, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef ILIST_H #define ILIST_H #include "my_dbug.h" #include #include // Derive your class from this struct to insert to a linked list. template struct ilist_node { #ifndef DBUG_OFF ilist_node() noexcept : next(NULL), prev(NULL) {} #else ilist_node() = default; #endif ilist_node(ilist_node *next, ilist_node *prev) noexcept : next(next), prev(prev) { } ilist_node *next; ilist_node *prev; }; // Modelled after std::list template class ilist { public: typedef ilist_node ListNode; class Iterator; // All containers in C++ should define these types to implement generic // container interface. typedef T value_type; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef value_type &reference; typedef const value_type &const_reference; typedef T *pointer; typedef const T *const_pointer; typedef Iterator iterator; typedef Iterator const_iterator; /* FIXME */ typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; class Iterator { public: // All iterators in C++ should define these types to implement generic // iterator interface. typedef std::bidirectional_iterator_tag iterator_category; typedef T value_type; typedef std::ptrdiff_t difference_type; typedef T *pointer; typedef T &reference; explicit Iterator(ListNode *node) noexcept : node_(node) { DBUG_ASSERT(node_ != nullptr); } Iterator &operator++() noexcept { node_= node_->next; DBUG_ASSERT(node_ != nullptr); return *this; } Iterator operator++(int) noexcept { Iterator tmp(*this); operator++(); return tmp; } Iterator &operator--() noexcept { node_= node_->prev; DBUG_ASSERT(node_ != nullptr); return *this; } Iterator operator--(int) noexcept { Iterator tmp(*this); operator--(); return tmp; } reference operator*() noexcept { return *static_cast(node_); } pointer operator->() noexcept { return static_cast(node_); } friend bool operator==(const Iterator &lhs, const Iterator &rhs) noexcept { return lhs.node_ == rhs.node_; } friend bool operator!=(const Iterator &lhs, const Iterator &rhs) noexcept { return !(lhs == rhs); } private: ListNode *node_; friend class ilist; }; ilist() noexcept : sentinel_(&sentinel_, &sentinel_) {} reference front() noexcept { return *begin(); } reference back() noexcept { return *--end(); } const_reference front() const noexcept { return *begin(); } const_reference back() const noexcept { return *--end(); } iterator begin() noexcept { return iterator(sentinel_.next); } const_iterator begin() const noexcept { return iterator(const_cast(sentinel_.next)); } iterator end() noexcept { return iterator(&sentinel_); } const_iterator end() const noexcept { return iterator(const_cast(&sentinel_)); } reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } const_reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } reverse_iterator rend() noexcept { return reverse_iterator(begin()); } const_reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } bool empty() const noexcept { return sentinel_.next == &sentinel_; } // Not implemented because it's O(N) // size_type size() const // { // return static_cast(std::distance(begin(), end())); // } void clear() noexcept { sentinel_.next= &sentinel_; sentinel_.prev= &sentinel_; } iterator insert(iterator pos, reference value) noexcept { ListNode *curr= pos.node_; ListNode *prev= pos.node_->prev; prev->next= &value; curr->prev= &value; static_cast(value).prev= prev; static_cast(value).next= curr; return iterator(&value); } iterator erase(iterator pos) noexcept { ListNode *prev= pos.node_->prev; ListNode *next= pos.node_->next; prev->next= next; next->prev= prev; #ifndef DBUG_OFF ListNode *curr= pos.node_; curr->prev= nullptr; curr->next= nullptr; #endif return Iterator(next); } void push_back(reference value) noexcept { insert(end(), value); } void pop_back() noexcept { erase(end()); } void push_front(reference value) noexcept { insert(begin(), value); } void pop_front() noexcept { erase(begin()); } // STL version is O(n) but this is O(1) because an element can't be inserted // several times in the same ilist. void remove(reference value) noexcept { erase(iterator(&value)); } private: ListNode sentinel_; }; // Similar to ilist but also has O(1) size() method. template class sized_ilist : public ilist { typedef ilist BASE; public: // All containers in C++ should define these types to implement generic // container interface. typedef T value_type; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef value_type &reference; typedef const value_type &const_reference; typedef T *pointer; typedef const T *const_pointer; typedef typename BASE::Iterator iterator; typedef const typename BASE::Iterator const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; sized_ilist() noexcept : size_(0) {} size_type size() const noexcept { return size_; } void clear() noexcept { BASE::clear(); size_= 0; } iterator insert(iterator pos, reference value) noexcept { ++size_; return BASE::insert(pos, value); } iterator erase(iterator pos) noexcept { --size_; return BASE::erase(pos); } void push_back(reference value) noexcept { insert(BASE::end(), value); } void pop_back() noexcept { erase(BASE::end()); } void push_front(reference value) noexcept { insert(BASE::begin(), value); } void pop_front() noexcept { erase(BASE::begin()); } void remove(reference value) noexcept { erase(iterator(&value)); } private: size_type size_; }; #endif server/private/table.h000064400000342301151031265050010765 0ustar00#ifndef TABLE_INCLUDED #define TABLE_INCLUDED /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. Copyright (c) 2009, 2022, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "sql_plist.h" #include "sql_list.h" /* Sql_alloc */ #include "mdl.h" #include "datadict.h" #include "sql_string.h" /* String */ #include "lex_string.h" #include "lex_ident.h" #ifndef MYSQL_CLIENT #include "my_cpu.h" /* LF_BACKOFF() */ #include "hash.h" /* HASH */ #include "handler.h" /* row_type, ha_choice, handler */ #include "mysql_com.h" /* enum_field_types */ #include "thr_lock.h" /* thr_lock_type */ #include "filesort_utils.h" #include "parse_file.h" #include "sql_i_s.h" #include "sql_type.h" /* vers_kind_t */ #include "privilege.h" /* privilege_t */ #include "my_bit.h" /* Buffer for unix timestamp in microseconds: 9,223,372,036,854,775,807 (signed int64 maximal value) 1 234 567 890 123 456 789 Note: we can use unsigned for calculation, but practically they are the same by probability to overflow them (signed int64 in microseconds is enough for almost 3e5 years) and signed allow to avoid increasing the buffer (the old buffer for human readable date was 19+1). */ #define MICROSECOND_TIMESTAMP_BUFFER_SIZE (19 + 1) /* Structs that defines the TABLE */ class Item; /* Needed by ORDER */ typedef Item (*Item_ptr); class Item_subselect; class Item_field; class Item_func_hash; class GRANT_TABLE; class st_select_lex_unit; class st_select_lex; class partition_info; class COND_EQUAL; class Security_context; struct TABLE_LIST; class ACL_internal_schema_access; class ACL_internal_table_access; class Field; class Table_statistics; class With_element; struct TDC_element; class Virtual_column_info; class Table_triggers_list; class TMP_TABLE_PARAM; class SEQUENCE; class Range_rowid_filter_cost_info; class derived_handler; class Pushdown_derived; struct Name_resolution_context; class Table_function_json_table; /* Used to identify NESTED_JOIN structures within a join (applicable only to structures that have not been simplified away and embed more the one element) */ typedef ulonglong nested_join_map; #define VIEW_MD5_LEN 32 #define tmp_file_prefix "#sql" /**< Prefix for tmp tables */ #define tmp_file_prefix_length 4 #define TMP_TABLE_KEY_EXTRA 8 /** Enumerate possible types of a table from re-execution standpoint. TABLE_LIST class has a member of this type. At prepared statement prepare, this member is assigned a value as of the current state of the database. Before (re-)execution of a prepared statement, we check that the value recorded at prepare matches the type of the object we obtained from the table definition cache. @sa check_and_update_table_version() @sa Execute_observer @sa Prepared_statement::reprepare() */ enum enum_table_ref_type { /** Initial value set by the parser */ TABLE_REF_NULL= 0, TABLE_REF_VIEW, TABLE_REF_BASE_TABLE, TABLE_REF_I_S_TABLE, TABLE_REF_TMP_TABLE }; /*************************************************************************/ /** Object_creation_ctx -- interface for creation context of database objects (views, stored routines, events, triggers). Creation context -- is a set of attributes, that should be fixed at the creation time and then be used each time the object is parsed or executed. */ class Object_creation_ctx { public: Object_creation_ctx *set_n_backup(THD *thd); void restore_env(THD *thd, Object_creation_ctx *backup_ctx); protected: Object_creation_ctx() = default; virtual Object_creation_ctx *create_backup_ctx(THD *thd) const = 0; virtual void change_env(THD *thd) const = 0; public: virtual ~Object_creation_ctx() = default; }; /*************************************************************************/ /** Default_object_creation_ctx -- default implementation of Object_creation_ctx. */ class Default_object_creation_ctx : public Object_creation_ctx { public: CHARSET_INFO *get_client_cs() { return m_client_cs; } CHARSET_INFO *get_connection_cl() { return m_connection_cl; } protected: Default_object_creation_ctx(THD *thd); Default_object_creation_ctx(CHARSET_INFO *client_cs, CHARSET_INFO *connection_cl); protected: Object_creation_ctx *create_backup_ctx(THD *thd) const override; void change_env(THD *thd) const override; protected: /** client_cs stores the value of character_set_client session variable. The only character set attribute is used. Client character set is included into query context, because we save query in the original character set, which is client character set. So, in order to parse the query properly we have to switch client character set on parsing. */ CHARSET_INFO *m_client_cs; /** connection_cl stores the value of collation_connection session variable. Both character set and collation attributes are used. Connection collation is included into query context, becase it defines the character set and collation of text literals in internal representation of query (item-objects). */ CHARSET_INFO *m_connection_cl; }; class Query_arena; /*************************************************************************/ /** View_creation_ctx -- creation context of view objects. */ class View_creation_ctx : public Default_object_creation_ctx, public Sql_alloc { public: static View_creation_ctx *create(THD *thd); static View_creation_ctx *create(THD *thd, TABLE_LIST *view); private: View_creation_ctx(THD *thd) : Default_object_creation_ctx(thd) { } }; /*************************************************************************/ /* Order clause list element */ typedef int (*fast_field_copier)(Field *to, Field *from); typedef struct st_order { struct st_order *next; Item **item; /* Point at item in select fields */ Item *item_ptr; /* Storage for initial item */ /* Reference to the function we are trying to optimize copy to a temporary table */ fast_field_copier fast_field_copier_func; /* Field for which above optimizer function setup */ Field *fast_field_copier_setup; int counter; /* position in SELECT list, correct only if counter_used is true*/ enum enum_order { ORDER_NOT_RELEVANT, ORDER_ASC, ORDER_DESC }; enum_order direction; /* Requested direction of ordering */ bool in_field_list; /* true if in select field list */ bool counter_used; /* parameter was counter of columns */ Field *field; /* If tmp-table group */ char *buff; /* If tmp-table group */ table_map used; /* NOTE: the below is only set to 0 but is still used by eq_ref_table */ table_map depend_map; } ORDER; /** State information for internal tables grants. This structure is part of the TABLE_LIST, and is updated during the ACL check process. @sa GRANT_INFO */ struct st_grant_internal_info { /** True if the internal lookup by schema name was done. */ bool m_schema_lookup_done; /** Cached internal schema access. */ const ACL_internal_schema_access *m_schema_access; /** True if the internal lookup by table name was done. */ bool m_table_lookup_done; /** Cached internal table access. */ const ACL_internal_table_access *m_table_access; }; typedef struct st_grant_internal_info GRANT_INTERNAL_INFO; /** @brief The current state of the privilege checking process for the current user, SQL statement and SQL object. @details The privilege checking process is divided into phases depending on the level of the privilege to be checked and the type of object to be accessed. Due to the mentioned scattering of privilege checking functionality, it is necessary to keep track of the state of the process. This information is stored in privilege, want_privilege, and orig_want_privilege. A GRANT_INFO also serves as a cache of the privilege hash tables. Relevant members are grant_table and version. */ typedef struct st_grant_info { /** @brief A copy of the privilege information regarding the current host, database, object and user. @details The version of this copy is found in GRANT_INFO::version. */ GRANT_TABLE *grant_table_user; GRANT_TABLE *grant_table_role; /** @brief Used for cache invalidation when caching privilege information. @details The privilege information is stored on disk, with dedicated caches residing in memory: table-level and column-level privileges, respectively, have their own dedicated caches. The GRANT_INFO works as a level 1 cache with this member updated to the current value of the global variable @c grant_version (@c static variable in sql_acl.cc). It is updated Whenever the GRANT_INFO is refreshed from the level 2 cache. The level 2 cache is the @c column_priv_hash structure (@c static variable in sql_acl.cc) @see grant_version */ uint version; /** @brief The set of privileges that the current user has fulfilled for a certain host, database, and object. @details This field is continually updated throughout the access checking process. In each step the "wanted privilege" is checked against the fulfilled privileges. When/if the intersection of these sets is empty, access is granted. The set is implemented as a bitmap, with the bits defined in sql_acl.h. */ privilege_t privilege; /** @brief the set of privileges that the current user needs to fulfil in order to carry out the requested operation. */ privilege_t want_privilege; /** Stores the requested access acl of top level tables list. Is used to check access rights to the underlying tables of a view. */ privilege_t orig_want_privilege; /** The grant state for internal tables. */ GRANT_INTERNAL_INFO m_internal; st_grant_info() :privilege(NO_ACL), want_privilege(NO_ACL), orig_want_privilege(NO_ACL) { } /* OR table and all column privileges */ privilege_t all_privilege(); } GRANT_INFO; enum tmp_table_type { NO_TMP_TABLE= 0, NON_TRANSACTIONAL_TMP_TABLE, TRANSACTIONAL_TMP_TABLE, INTERNAL_TMP_TABLE, SYSTEM_TMP_TABLE }; enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP }; enum vcol_init_mode { VCOL_INIT_DEPENDENCY_FAILURE_IS_WARNING= 1, VCOL_INIT_DEPENDENCY_FAILURE_IS_ERROR= 2 /* There may be new flags here. e.g. to automatically remove sql_mode dependency: GENERATED ALWAYS AS (char_col) -> GENERATED ALWAYS AS (RTRIM(char_col)) */ }; enum enum_vcol_update_mode { VCOL_UPDATE_FOR_READ= 0, VCOL_UPDATE_FOR_WRITE, VCOL_UPDATE_FOR_DELETE, VCOL_UPDATE_INDEXED, VCOL_UPDATE_INDEXED_FOR_UPDATE, VCOL_UPDATE_FOR_REPLACE }; /* Field visibility enums */ enum __attribute__((packed)) field_visibility_t { VISIBLE= 0, INVISIBLE_USER, /* automatically added by the server. Can be queried explicitly in SELECT, otherwise invisible from anything" */ INVISIBLE_SYSTEM, INVISIBLE_FULL }; #define INVISIBLE_MAX_BITS 3 #define HA_HASH_FIELD_LENGTH 8 #define HA_HASH_KEY_LENGTH_WITHOUT_NULL 8 #define HA_HASH_KEY_LENGTH_WITH_NULL 9 int fields_in_hash_keyinfo(KEY *keyinfo); void setup_keyinfo_hash(KEY *key_info); void re_setup_keyinfo_hash(KEY *key_info); /** Category of table found in the table share. */ enum enum_table_category { /** Unknown value. */ TABLE_UNKNOWN_CATEGORY=0, /** Temporary table. The table is visible only in the session. Therefore, - FLUSH TABLES WITH READ LOCK - SET GLOBAL READ_ONLY = ON do not apply to this table. Note that LOCK TABLE t FOR READ/WRITE can be used on temporary tables. Temporary tables are not part of the table cache. */ TABLE_CATEGORY_TEMPORARY=1, /** User table. These tables do honor: - LOCK TABLE t FOR READ/WRITE - FLUSH TABLES WITH READ LOCK - SET GLOBAL READ_ONLY = ON User tables are cached in the table cache. */ TABLE_CATEGORY_USER=2, /** System table, maintained by the server. These tables do honor: - LOCK TABLE t FOR READ/WRITE - FLUSH TABLES WITH READ LOCK - SET GLOBAL READ_ONLY = ON Typically, writes to system tables are performed by the server implementation, not explicitly be a user. System tables are cached in the table cache. */ TABLE_CATEGORY_SYSTEM=3, /** Log tables. These tables are an interface provided by the system to inspect the system logs. These tables do *not* honor: - LOCK TABLE t FOR READ/WRITE - FLUSH TABLES WITH READ LOCK - SET GLOBAL READ_ONLY = ON as there is no point in locking explicitly a LOG table. An example of LOG tables are: - mysql.slow_log - mysql.general_log, which *are* updated even when there is either a GLOBAL READ LOCK or a GLOBAL READ_ONLY in effect. User queries do not write directly to these tables (there are exceptions for log tables). The server implementation perform writes. Log tables are cached in the table cache. */ TABLE_CATEGORY_LOG=4, /* Types below are read only tables, not affected by FLUSH TABLES or MDL locks. */ /** Information schema tables. These tables are an interface provided by the system to inspect the system metadata. These tables do *not* honor: - LOCK TABLE t FOR READ/WRITE - FLUSH TABLES WITH READ LOCK - SET GLOBAL READ_ONLY = ON as there is no point in locking explicitly an INFORMATION_SCHEMA table. Nothing is directly written to information schema tables. Note that this value is not used currently, since information schema tables are not shared, but implemented as session specific temporary tables. */ /* TODO: Fixing the performance issues of I_S will lead to I_S tables in the table cache, which should use this table type. */ TABLE_CATEGORY_INFORMATION=5, /** Performance schema tables. These tables are an interface provided by the system to inspect the system performance data. These tables do *not* honor: - LOCK TABLE t FOR READ/WRITE - FLUSH TABLES WITH READ LOCK - SET GLOBAL READ_ONLY = ON as there is no point in locking explicitly a PERFORMANCE_SCHEMA table. An example of PERFORMANCE_SCHEMA tables are: - performance_schema.* which *are* updated (but not using the handler interface) even when there is either a GLOBAL READ LOCK or a GLOBAL READ_ONLY in effect. User queries do not write directly to these tables (there are exceptions for SETUP_* tables). The server implementation perform writes. Performance tables are cached in the table cache. */ TABLE_CATEGORY_PERFORMANCE=6 }; typedef enum enum_table_category TABLE_CATEGORY; TABLE_CATEGORY get_table_category(const Lex_ident_db &db, const Lex_ident_table &name); typedef struct st_table_field_type { LEX_CSTRING name; LEX_CSTRING type; LEX_CSTRING cset; } TABLE_FIELD_TYPE; typedef struct st_table_field_def { uint count; const TABLE_FIELD_TYPE *field; uint primary_key_parts; const uint *primary_key_columns; } TABLE_FIELD_DEF; class Table_check_intact { protected: bool has_keys; virtual void report_error(uint code, const char *fmt, ...)= 0; public: Table_check_intact(bool keys= false) : has_keys(keys) {} virtual ~Table_check_intact() = default; /** Checks whether a table is intact. */ bool check(TABLE *table, const TABLE_FIELD_DEF *table_def); }; /* If the table isn't valid, report the error to the server log only. */ class Table_check_intact_log_error : public Table_check_intact { protected: void report_error(uint, const char *fmt, ...) override; public: Table_check_intact_log_error() : Table_check_intact(true) {} }; /** Class representing the fact that some thread waits for table share to be flushed. Is used to represent information about such waits in MDL deadlock detector. */ class Wait_for_flush : public MDL_wait_for_subgraph { MDL_context *m_ctx; TABLE_SHARE *m_share; uint m_deadlock_weight; public: Wait_for_flush(MDL_context *ctx_arg, TABLE_SHARE *share_arg, uint deadlock_weight_arg) : m_ctx(ctx_arg), m_share(share_arg), m_deadlock_weight(deadlock_weight_arg) {} MDL_context *get_ctx() const { return m_ctx; } bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor) override; uint get_deadlock_weight() const override; /** Pointers for participating in the list of waiters for table share. */ Wait_for_flush *next_in_share; Wait_for_flush **prev_in_share; }; typedef I_P_List > Wait_for_flush_list; enum open_frm_error { OPEN_FRM_OK = 0, OPEN_FRM_OPEN_ERROR, OPEN_FRM_READ_ERROR, OPEN_FRM_CORRUPTED, OPEN_FRM_DISCOVER, OPEN_FRM_ERROR_ALREADY_ISSUED, OPEN_FRM_NOT_A_VIEW, OPEN_FRM_NOT_A_TABLE, OPEN_FRM_NEEDS_REBUILD }; /** Control block to access table statistics loaded from persistent statistical tables */ #define TABLE_STAT_NO_STATS 0 #define TABLE_STAT_TABLE 1 #define TABLE_STAT_COLUMN 2 #define TABLE_STAT_INDEX 4 #define TABLE_STAT_HISTOGRAM 8 /* EITS statistics information for a table. This data is loaded from mysql.{table|index|column}_stats tables and then most of the time is owned by table's TABLE_SHARE object. Individual TABLE objects also have pointer to this object, and we do reference counting to know when to free it. See TABLE::update_engine_stats(), TABLE::free_engine_stats(), TABLE_SHARE::update_engine_stats(), TABLE_SHARE::destroy(). These implement a "shared pointer"-like functionality. When new statistics is loaded, we create new TABLE_STATISTICS_CB and make the TABLE_SHARE point to it. Some TABLE object may still be using older TABLE_STATISTICS_CB objects. Reference counting allows to free TABLE_STATISTICS_CB when it is no longer used. */ class TABLE_STATISTICS_CB { uint usage_count; // Instances of this stat public: TABLE_STATISTICS_CB(); ~TABLE_STATISTICS_CB(); MEM_ROOT mem_root; /* MEM_ROOT to allocate statistical data for the table */ Table_statistics *table_stats; /* Structure to access the statistical data */ ulong total_hist_size; /* Total size of all histograms */ uint stats_available; bool histograms_exists() const { return total_hist_size != 0; } bool unused() { return usage_count == 0; } /* Copy (latest) state from TABLE_SHARE to TABLE */ void update_stats_in_table(TABLE *table); friend struct TABLE; friend struct TABLE_SHARE; }; /** This structure is shared between different table objects. There is one instance of table share per one table in the database. */ struct TABLE_SHARE { TABLE_SHARE() = default; /* Remove gcc warning */ /** Category of this table. */ TABLE_CATEGORY table_category; /* hash of field names (contains pointers to elements of field array) */ HASH name_hash; /* hash of field names */ MEM_ROOT mem_root; TYPELIB keynames; /* Pointers to keynames */ TYPELIB fieldnames; /* Pointer to fieldnames */ TYPELIB *intervals; /* pointer to interval info */ mysql_mutex_t LOCK_ha_data; /* To protect access to ha_data */ mysql_mutex_t LOCK_share; /* To protect TABLE_SHARE */ mysql_mutex_t LOCK_statistics; /* To protect against concurrent load */ TDC_element *tdc; LEX_CUSTRING tabledef_version; engine_option_value *option_list; /* text options for table */ ha_table_option_struct *option_struct; /* structure with parsed options */ /* The following is copied to each TABLE on OPEN */ Field **field; Field **found_next_number_field; KEY *key_info; /* data of keys in database */ Virtual_column_info **check_constraints; uint *blob_field; /* Index to blobs in Field arrray*/ LEX_CUSTRING vcol_defs; /* definitions of generated columns */ /* EITS statistics data from the last time the table was opened or ANALYZE table was run. This is typically same as any related TABLE::stats_cb until ANALYZE table is run. This pointer is only to be de-referenced under LOCK_share as the pointer can change by another thread running ANALYZE TABLE. Without using a LOCK_share one can check if the statistics has been updated by checking if TABLE::stats_cb != TABLE_SHARE::stats_cb. */ TABLE_STATISTICS_CB *stats_cb; uchar *default_values; /* row with default values */ LEX_CSTRING comment; /* Comment about table */ CHARSET_INFO *table_charset; /* Default charset of string fields */ MY_BITMAP *check_set; /* Fields used by check constrant */ MY_BITMAP all_set; /* Key which is used for looking-up table in table cache and in the list of thread's temporary tables. Has the form of: "database_name\0table_name\0" + optional part for temporary tables. Note that all three 'table_cache_key', 'db' and 'table_name' members must be set (and be non-zero) for tables in table cache. They also should correspond to each other. To ensure this one can use set_table_cache() methods. */ LEX_CSTRING table_cache_key; LEX_CSTRING db; /* Pointer to db */ LEX_CSTRING table_name; /* Table name (for open) */ LEX_CSTRING path; /* Path to .frm file (from datadir) */ LEX_CSTRING normalized_path; /* unpack_filename(path) */ LEX_CSTRING connect_string; /* Set of keys in use, implemented as a Bitmap. Excludes keys disabled by ALTER TABLE ... DISABLE KEYS. */ key_map keys_in_use; /* The set of ignored indexes for a table. */ key_map ignored_indexes; key_map keys_for_keyread; ha_rows min_rows, max_rows; /* create information */ ulong avg_row_length; /* create information */ ulong mysql_version; /* 0 if .frm is created before 5.0 */ ulong reclength; /* Recordlength */ /* Stored record length. No generated-only virtual fields are included */ ulong stored_rec_length; plugin_ref db_plugin; /* storage engine plugin */ inline handlerton *db_type() const /* table_type for handler */ { return is_view ? view_pseudo_hton : db_plugin ? plugin_hton(db_plugin) : NULL; } enum row_type row_type; /* How rows are stored */ enum Table_type table_type; enum tmp_table_type tmp_table; /** Transactional or not. */ enum ha_choice transactional; /** Per-page checksums or not. */ enum ha_choice page_checksum; uint key_block_size; /* create key_block_size, if used */ uint stats_sample_pages; /* number of pages to sample during stats estimation, if used, otherwise 0. */ enum_stats_auto_recalc stats_auto_recalc; /* Automatic recalc of stats. */ uint null_bytes, last_null_bit_pos; /* Same as null_bytes, except that if there is only a 'delete-marker' in the record then this value is 0. */ uint null_bytes_for_compare; uint fields; /* number of fields */ /* number of stored fields, purely virtual not included */ uint stored_fields; uint virtual_fields; /* number of purely virtual fields */ /* number of purely virtual not stored blobs */ uint virtual_not_stored_blob_fields; uint null_fields; /* number of null fields */ uint blob_fields; /* number of blob fields */ uint varchar_fields; /* number of varchar fields */ uint default_fields; /* number of default fields */ uint visible_fields; /* number of visible fields */ uint default_expressions; uint table_check_constraints, field_check_constraints; uint rec_buff_length; /* Size of table->record[] buffer */ uint keys, key_parts; uint ext_key_parts; /* Total number of key parts in extended keys */ uint max_key_length, max_unique_length; uint uniques; /* Number of UNIQUE index */ uint db_create_options; /* Create options from database */ uint db_options_in_use; /* Options in use */ uint db_record_offset; /* if HA_REC_IN_SEQ */ uint rowid_field_offset; /* Field_nr +1 to rowid field */ /* Primary key index number, used in TABLE::key_info[] */ uint primary_key; uint next_number_index; /* autoincrement key number */ uint next_number_key_offset; /* autoinc keypart offset in a key */ uint next_number_keypart; /* autoinc keypart number in a key */ enum open_frm_error error; /* error from open_table_def() */ uint open_errno; /* error from open_table_def() */ uint column_bitmap_size; uchar frm_version; enum enum_v_keys { NOT_INITIALIZED=0, NO_V_KEYS, V_KEYS }; enum_v_keys check_set_initialized; bool use_ext_keys; /* Extended keys can be used */ bool null_field_first; bool system; /* Set if system table (one record) */ bool not_usable_by_query_cache; bool online_backup; /* Set if on-line backup supported */ /* This is used by log tables, for tables that have their own internal binary logging or for tables that doesn't support statement or row logging */ bool no_replicate; bool crashed; bool is_view; bool can_cmp_whole_record; /* This is set for temporary tables where CREATE was binary logged */ bool table_creation_was_logged; bool non_determinstic_insert; bool has_update_default_function; bool can_do_row_logging; /* 1 if table supports RBR */ bool long_unique_table; /* 1 if frm version cannot be updated as part of upgrade */ bool keep_original_mysql_version; ulonglong table_map_id; /* for row-based replication */ /* Things that are incompatible between the stored version and the current version. This is a set of HA_CREATE... bits that can be used to modify create_info->used_fields for ALTER TABLE. */ ulong incompatible_version; /** For shares representing views File_parser object with view definition read from .FRM file. */ const File_parser *view_def; /* For sequence tables, the current sequence state */ SEQUENCE *sequence; #ifdef WITH_PARTITION_STORAGE_ENGINE /* filled in when reading from frm */ bool auto_partitioned; char *partition_info_str; uint partition_info_str_len; uint partition_info_buffer_size; plugin_ref default_part_plugin; #endif /** System versioning and application-time periods support. */ struct period_info_t { field_index_t start_fieldno; field_index_t end_fieldno; Lex_ident name; Lex_ident constr_name; uint unique_keys; Field *start_field(TABLE_SHARE *s) const { return s->field[start_fieldno]; } Field *end_field(TABLE_SHARE *s) const { return s->field[end_fieldno]; } }; vers_kind_t versioned; period_info_t vers; period_info_t period; bool init_period_from_extra2(period_info_t *period, const uchar *data, const uchar *end); Field *vers_start_field() { DBUG_ASSERT(versioned); return field[vers.start_fieldno]; } Field *vers_end_field() { DBUG_ASSERT(versioned); return field[vers.end_fieldno]; } Field *period_start_field() const { DBUG_ASSERT(period.name); return field[period.start_fieldno]; } Field *period_end_field() const { DBUG_ASSERT(period.name); return field[period.end_fieldno]; } /** Cache the checked structure of this table. The pointer data is used to describe the structure that a instance of the table must have. Each element of the array specifies a field that must exist on the table. The pointer is cached in order to perform the check only once -- when the table is loaded from the disk. */ const TABLE_FIELD_DEF *table_field_def_cache; /** Main handler's share */ Handler_share *ha_share; /** Instrumentation for this table share. */ PSI_table_share *m_psi; inline void reset() { bzero((void*)this, sizeof(*this)); } /* Set share's table cache key and update its db and table name appropriately. SYNOPSIS set_table_cache_key() key_buff Buffer with already built table cache key to be referenced from share. key_length Key length. NOTES Since 'key_buff' buffer will be referenced from share it should has same life-time as share itself. This method automatically ensures that TABLE_SHARE::table_name/db have appropriate values by using table cache key as their source. */ void set_table_cache_key(char *key_buff, uint key_length) { table_cache_key.str= key_buff; table_cache_key.length= key_length; /* Let us use the fact that the key is "db/0/table_name/0" + optional part for temporary tables. */ db.str= table_cache_key.str; db.length= strlen(db.str); table_name.str= db.str + db.length + 1; table_name.length= strlen(table_name.str); } /* Set share's table cache key and update its db and table name appropriately. SYNOPSIS set_table_cache_key() key_buff Buffer to be used as storage for table cache key (should be at least key_length bytes). key Value for table cache key. key_length Key length. NOTE Since 'key_buff' buffer will be used as storage for table cache key it should has same life-time as share itself. */ void set_table_cache_key(char *key_buff, const char *key, uint key_length) { memcpy(key_buff, key, key_length); set_table_cache_key(key_buff, key_length); } inline bool require_write_privileges() { return (table_category == TABLE_CATEGORY_LOG); } inline ulonglong get_table_def_version() { return table_map_id; } /** Convert unrelated members of TABLE_SHARE to one enum representing its type. @todo perhaps we need to have a member instead of a function. */ enum enum_table_ref_type get_table_ref_type() const { if (is_view) return TABLE_REF_VIEW; switch (tmp_table) { case NO_TMP_TABLE: return TABLE_REF_BASE_TABLE; case SYSTEM_TMP_TABLE: return TABLE_REF_I_S_TABLE; default: return TABLE_REF_TMP_TABLE; } } /** Return a table metadata version. * for base tables and views, we return table_map_id. It is assigned from a global counter incremented for each new table loaded into the table definition cache (TDC). * for temporary tables it's table_map_id again. But for temporary tables table_map_id is assigned from thd->query_id. The latter is assigned from a thread local counter incremented for every new SQL statement. Since temporary tables are thread-local, each temporary table gets a unique id. * for everything else (e.g. information schema tables), the version id is zero. This choice of version id is a large compromise to have a working prepared statement validation in 5.1. In future version ids will be persistent, as described in WL#4180. Let's try to explain why and how this limited solution allows to validate prepared statements. Firstly, sets (in mathematical sense) of version numbers never intersect for different table types. Therefore, version id of a temporary table is never compared with a version id of a view, and vice versa. Secondly, for base tables and views, we know that each DDL flushes the respective share from the TDC. This ensures that whenever a table is altered or dropped and recreated, it gets a new version id. Unfortunately, since elements of the TDC are also flushed on LRU basis, this choice of version ids leads to false positives. E.g. when the TDC size is too small, we may have a SELECT * FROM INFORMATION_SCHEMA.TABLES flush all its elements, which in turn will lead to a validation error and a subsequent reprepare of all prepared statements. This is considered acceptable, since as long as prepared statements are automatically reprepared, spurious invalidation is only a performance hit. Besides, no better simple solution exists. For temporary tables, using thd->query_id ensures that if a temporary table was altered or recreated, a new version id is assigned. This suits validation needs very well and will perhaps never change. Metadata of information schema tables never changes. Thus we can safely assume 0 for a good enough version id. Finally, by taking into account table type, we always track that a change has taken place when a view is replaced with a base table, a base table is replaced with a temporary table and so on. @sa TABLE_LIST::is_the_same_definition() */ ulonglong get_table_ref_version() const { return (tmp_table == SYSTEM_TMP_TABLE) ? 0 : table_map_id; } bool is_optimizer_tmp_table() { return tmp_table == INTERNAL_TMP_TABLE && !db.length && table_name.length; } bool visit_subgraph(Wait_for_flush *waiting_ticket, MDL_wait_for_graph_visitor *gvisitor); bool wait_for_old_version(THD *thd, struct timespec *abstime, uint deadlock_weight); /** Release resources and free memory occupied by the table share. */ void destroy(); void set_use_ext_keys_flag(bool fl) { use_ext_keys= fl; } uint actual_n_key_parts(THD *thd); LEX_CUSTRING *frm_image; ///< only during CREATE TABLE (@sa ha_create_table) /* populates TABLE_SHARE from the table description in the binary frm image. if 'write' is true, this frm image is also written into a corresponding frm file, that serves as a persistent metadata cache to avoid discovering the table over and over again */ int init_from_binary_frm_image(THD *thd, bool write, const uchar *frm_image, size_t frm_length, const uchar *par_image=0, size_t par_length=0); /* populates TABLE_SHARE from the table description, specified as the complete CREATE TABLE sql statement. if 'write' is true, this frm image is also written into a corresponding frm file, that serves as a persistent metadata cache to avoid discovering the table over and over again */ int init_from_sql_statement_string(THD *thd, bool write, const char *sql, size_t sql_length); /* writes the frm image to an frm file, corresponding to this table */ bool write_frm_image(const uchar *frm_image, size_t frm_length); bool write_par_image(const uchar *par_image, size_t par_length); /* Only used by S3 */ bool write_frm_image(void) { return frm_image ? write_frm_image(frm_image->str, frm_image->length) : 0; } /* returns an frm image for this table. the memory is allocated and must be freed later */ bool read_frm_image(const uchar **frm_image, size_t *frm_length); /* frees the memory allocated in read_frm_image */ void free_frm_image(const uchar *frm); void set_overlapped_keys(); void set_ignored_indexes(); key_map usable_indexes(THD *thd); bool old_long_hash_function() const { return mysql_version < 100428 || (mysql_version >= 100500 && mysql_version < 100519) || (mysql_version >= 100600 && mysql_version < 100612) || (mysql_version >= 100700 && mysql_version < 100708) || (mysql_version >= 100800 && mysql_version < 100807) || (mysql_version >= 100900 && mysql_version < 100905) || (mysql_version >= 101000 && mysql_version < 101003) || (mysql_version >= 101100 && mysql_version < 101102); } Item_func_hash *make_long_hash_func(THD *thd, MEM_ROOT *mem_root, List *field_list) const; void update_engine_independent_stats(TABLE_STATISTICS_CB *stat); bool histograms_exists(); }; /* not NULL, but cannot be dereferenced */ #define UNUSABLE_TABLE_SHARE ((TABLE_SHARE*)1) /** Class is used as a BLOB field value storage for intermediate GROUP_CONCAT results. Used only for GROUP_CONCAT with DISTINCT or ORDER BY options. */ class Blob_mem_storage: public Sql_alloc { private: MEM_ROOT storage; /** Sign that some values were cut during saving into the storage. */ bool truncated_value; public: Blob_mem_storage() :truncated_value(false) { init_alloc_root(key_memory_blob_mem_storage, &storage, MAX_FIELD_VARCHARLENGTH, 0, MYF(0)); } ~ Blob_mem_storage() { free_root(&storage, MYF(0)); } void reset() { free_root(&storage, MYF(MY_MARK_BLOCKS_FREE)); truncated_value= false; } /** Fuction creates duplicate of 'from' string in 'storage' MEM_ROOT. @param from string to copy @param length string length @retval Pointer to the copied string. @retval 0 if an error occurred. */ char *store(const char *from, size_t length) { return (char*) memdup_root(&storage, from, length); } void set_truncated_value(bool is_truncated_value) { truncated_value= is_truncated_value; } bool is_truncated_value() { return truncated_value; } }; /* Information for one open table */ enum index_hint_type { INDEX_HINT_IGNORE, INDEX_HINT_USE, INDEX_HINT_FORCE }; struct st_cond_statistic; #define CHECK_ROW_FOR_NULLS_TO_REJECT (1 << 0) #define REJECT_ROW_DUE_TO_NULL_FIELDS (1 << 1) class SplM_opt_info; struct vers_select_conds_t; struct TABLE { TABLE() = default; /* Remove gcc warning */ TABLE_SHARE *s; handler *file; TABLE *next, *prev; private: /** Links for the list of all TABLE objects for this share. Declared as private to avoid direct manipulation with those objects. One should use methods of I_P_List template instead. */ TABLE *share_all_next, **share_all_prev; TABLE *global_free_next, **global_free_prev; friend struct All_share_tables; friend struct Table_cache_instance; public: uint32 instance; /** Table cache instance this TABLE is belonging to */ THD *in_use; /* Which thread uses this */ uchar *record[3]; /* Pointer to records */ uchar *write_row_record; /* Used as optimisation in THD::write_row */ uchar *insert_values; /* used by INSERT ... UPDATE */ /* Map of keys that can be used to retrieve all data from this table needed by the query without reading the row. */ key_map covering_keys, intersect_keys; /* A set of keys that can be used in the query that references this table. All indexes disabled on the table's TABLE_SHARE (see TABLE::s) will be subtracted from this set upon instantiation. Thus for any TABLE t it holds that t.keys_in_use_for_query is a subset of t.s.keys_in_use. Generally we must not introduce any new keys here (see setup_tables). The set is implemented as a bitmap. */ key_map keys_in_use_for_query; /* Map of keys that can be used to calculate GROUP BY without sorting */ key_map keys_in_use_for_group_by; /* Map of keys that can be used to calculate ORDER BY without sorting */ key_map keys_in_use_for_order_by; /* Map of keys dependent on some constraint */ key_map constraint_dependent_keys; KEY *key_info; /* data of keys in database */ Field **field; /* Pointer to fields */ Field **vfield; /* Pointer to virtual fields*/ Field **default_field; /* Fields with non-constant DEFAULT */ Field *next_number_field; /* Set if next_number is activated */ Field *found_next_number_field; /* Set on open */ Virtual_column_info **check_constraints; /* Table's triggers, 0 if there are no of them */ Table_triggers_list *triggers; TABLE_LIST *pos_in_table_list;/* Element referring to this table */ /* Position in thd->locked_table_list under LOCK TABLES */ TABLE_LIST *pos_in_locked_tables; /* Tables used in DEFAULT and CHECK CONSTRAINT (normally sequence tables) */ TABLE_LIST *internal_tables; /* Not-null for temporary tables only. Non-null values means this table is used to compute GROUP BY, it has a unique of GROUP BY columns. (set by create_tmp_table) */ ORDER *group; String alias; /* alias or table name */ uchar *null_flags; MY_BITMAP def_read_set, def_write_set, tmp_set; MY_BITMAP def_rpl_write_set; MY_BITMAP eq_join_set; /* used to mark equi-joined fields */ MY_BITMAP cond_set; /* used to mark fields from sargable conditions*/ /* Active column sets */ MY_BITMAP *read_set, *write_set, *rpl_write_set; /* On INSERT: fields that the user specified a value for */ MY_BITMAP has_value_set; /* The ID of the query that opened and is using this table. Has different meanings depending on the table type. Temporary tables: table->query_id is set to thd->query_id for the duration of a statement and is reset to 0 once it is closed by the same statement. A non-zero table->query_id means that a statement is using the table even if it's not the current statement (table is in use by some outer statement). Non-temporary tables: Under pre-locked or LOCK TABLES mode: query_id is set to thd->query_id for the duration of a statement and is reset to 0 once it is closed by the same statement. A non-zero query_id is used to control which tables in the list of pre-opened and locked tables are actually being used. */ query_id_t query_id; /* This structure is used for statistical data on the table that is collected by the function collect_statistics_for_table */ Table_statistics *collected_stats; /* The estimate of the number of records in the table used by optimizer */ ha_rows used_stat_records; key_map opt_range_keys; /* The following structure is filled for each key that has opt_range_keys.is_set(key) == TRUE */ struct OPT_RANGE { uint key_parts; uint ranges; ha_rows rows; double cost; /* If there is a range access by i-th index then the cost of index only access for it is stored in index_only_costs[i] */ double index_only_cost; } *opt_range; /* Bitmaps of key parts that =const for the duration of join execution. If we're in a subquery, then the constant may be different across subquery re-executions. */ key_part_map *const_key_parts; /* Estimate of number of records that satisfy SARGable part of the table condition, or table->file->records if no SARGable condition could be constructed. This value is used by join optimizer as an estimate of number of records that will pass the table condition (condition that depends on fields of this table and constants) */ ha_rows opt_range_condition_rows; double cond_selectivity; List *cond_selectivity_sampling_explain; table_map map; /* ID bit of table (1,2,4,8,16...) */ uint lock_position; /* Position in MYSQL_LOCK.table */ uint lock_data_start; /* Start pos. in MYSQL_LOCK.locks */ uint lock_count; /* Number of locks */ uint tablenr,used_fields; uint temp_pool_slot; /* Used by intern temp tables */ uint status; /* What's in record[0] */ uint db_stat; /* mode of file as in handler.h */ /* number of select if it is derived table */ uint derived_select_number; /* Possible values: - 0 by default - JOIN_TYPE_{LEFT|RIGHT} if the table is inner w.r.t an outer join operation - 1 if the SELECT has mixed_implicit_grouping=1. example: select max(col1), col2 from t1. In this case, the query produces one row with all columns having NULL values. Interpetation: If maybe_null!=0, all fields of the table are considered NULLable (and have NULL values when null_row=true) */ uint maybe_null; int current_lock; /* Type of lock on table */ bool copy_blobs; /* copy_blobs when storing */ /* Set if next_number_field is in the UPDATE fields of INSERT ... ON DUPLICATE KEY UPDATE. */ bool next_number_field_updated; /* If true, the current table row is considered to have all columns set to NULL, including columns declared as "not null" (see maybe_null). */ bool null_row; /* No rows that contain null values can be placed into this table. Currently this flag can be set to true only for a temporary table that used to store the result of materialization of a subquery. */ bool no_rows_with_nulls; /* This field can contain two bit flags: CHECK_ROW_FOR_NULLS_TO_REJECT REJECT_ROW_DUE_TO_NULL_FIELDS The first flag is set for the dynamic contexts where it is prohibited to write any null into the table. The second flag is set only if the first flag is set on. The informs the outer scope that there was an attept to write null into a field of the table in the context where it is prohibited. This flag should be set off as soon as the first flag is set on. Currently these flags are used only the tables tno_rows_with_nulls set to true. */ uint8 null_catch_flags; /* TODO: Each of the following flags take up 8 bits. They can just as easily be put into one single unsigned long and instead of taking up 18 bytes, it would take up 4. */ bool force_index; /** Flag set when the statement contains FORCE INDEX FOR ORDER BY See TABLE_LIST::process_index_hints(). */ bool force_index_order; /** Flag set when the statement contains FORCE INDEX FOR GROUP BY See TABLE_LIST::process_index_hints(). */ bool force_index_group; /* TRUE<=> this table was created with create_tmp_table(... distinct=TRUE..) call */ bool distinct; bool const_table,no_rows, used_for_duplicate_elimination; /** Forces DYNAMIC Aria row format for internal temporary tables. */ bool keep_row_order; bool no_keyread; /** If set, indicate that the table is not replicated by the server. */ bool locked_by_logger; bool locked_by_name; bool fulltext_searched; bool no_cache; /* To signal that the table is associated with a HANDLER statement */ bool open_by_handler; /* To indicate that a non-null value of the auto_increment field was provided by the user or retrieved from the current record. Used only in the MODE_NO_AUTO_VALUE_ON_ZERO mode. */ bool auto_increment_field_not_null; /* NOTE: alias_name_used is only a hint! It works only in need_correct_ident() condition. On other cases it is FALSE even if table_name is alias. E.g. in update t1 as x set a = 1 */ bool alias_name_used; /* true if table_name is alias */ bool get_fields_in_item_tree; /* Signal to fix_field */ List vcol_refix_list; private: bool m_needs_reopen; bool created; /* For tmp tables. TRUE <=> tmp table was actually created.*/ public: #ifdef HAVE_REPLICATION /* used in RBR Triggers */ bool master_had_triggers; #endif REGINFO reginfo; /* field connections */ MEM_ROOT mem_root; /* this is for temporary tables created inside Item_func_group_concat */ union { bool group_concat; /* used during create_tmp_table() */ Blob_mem_storage *blob_storage; /* used after create_tmp_table() */ }; GRANT_INFO grant; /* The arena which the items for expressions from the table definition are associated with. Currently only the items of the expressions for virtual columns are associated with this arena. TODO: To attach the partitioning expressions to this arena. */ Query_arena *expr_arena; #ifdef WITH_PARTITION_STORAGE_ENGINE partition_info *part_info; /* Partition related information */ /* If true, all partitions have been pruned away */ bool all_partitions_pruned_away; #endif uint max_keys; /* Size of allocated key_info array. */ bool stats_is_read; /* Persistent statistics is read for the table */ bool histograms_are_read; MDL_ticket *mdl_ticket; /* This is used only for potentially splittable materialized tables and it points to the info used by the optimizer to apply splitting optimization */ SplM_opt_info *spl_opt_info; key_map keys_usable_for_splitting; /* Conjunction of the predicates of the form IS NOT NULL(f) where f refers to a column of this TABLE such that they can be inferred from the condition of the WHERE clause or from some ON expression of the processed select and can be useful for range optimizer. */ Item *notnull_cond; TABLE_STATISTICS_CB *stats_cb; inline void reset() { bzero((void*)this, sizeof(*this)); } void init(THD *thd, TABLE_LIST *tl); bool fill_item_list(List *item_list) const; void reset_item_list(List *item_list, uint skip) const; void clear_column_bitmaps(void); void prepare_for_position(void); MY_BITMAP *prepare_for_keyread(uint index, MY_BITMAP *map); MY_BITMAP *prepare_for_keyread(uint index) { return prepare_for_keyread(index, &tmp_set); } void mark_index_columns(uint index, MY_BITMAP *bitmap); void mark_index_columns_no_reset(uint index, MY_BITMAP *bitmap); void mark_index_columns_for_read(uint index); void restore_column_maps_after_keyread(MY_BITMAP *backup); void mark_auto_increment_column(bool insert_fl); void mark_columns_needed_for_update(void); void mark_columns_needed_for_delete(void); void mark_columns_needed_for_insert(void); void mark_columns_per_binlog_row_image(void); inline bool mark_column_with_deps(Field *field); inline bool mark_virtual_column_with_deps(Field *field); inline void mark_virtual_column_deps(Field *field); bool mark_virtual_columns_for_write(bool insert_fl); bool check_virtual_columns_marked_for_read(); bool check_virtual_columns_marked_for_write(); void mark_default_fields_for_write(bool insert_fl); void mark_columns_used_by_virtual_fields(void); void mark_check_constraint_columns_for_read(void); int verify_constraints(bool ignore_failure); void free_engine_stats(); void update_engine_independent_stats(); inline void column_bitmaps_set(MY_BITMAP *read_set_arg) { read_set= read_set_arg; if (file) file->column_bitmaps_signal(); } inline void column_bitmaps_set(MY_BITMAP *read_set_arg, MY_BITMAP *write_set_arg) { read_set= read_set_arg; write_set= write_set_arg; if (file) file->column_bitmaps_signal(); } inline void column_bitmaps_set_no_signal(MY_BITMAP *read_set_arg, MY_BITMAP *write_set_arg) { read_set= read_set_arg; write_set= write_set_arg; } inline void use_all_columns() { column_bitmaps_set(&s->all_set, &s->all_set); } inline void use_all_stored_columns(); inline void default_column_bitmaps() { read_set= &def_read_set; write_set= &def_write_set; rpl_write_set= 0; } /** Should this instance of the table be reopened? */ inline bool needs_reopen() { return !db_stat || m_needs_reopen; } /* Mark that all current connection instances of the table should be reopen at end of statement */ void mark_table_for_reopen(); /* Should only be called from Locked_tables_list::mark_table_for_reopen() */ void internal_set_needs_reopen(bool value) { m_needs_reopen= value; } bool init_expr_arena(MEM_ROOT *mem_root); bool alloc_keys(uint key_count); bool check_tmp_key(uint key, uint key_parts, uint (*next_field_no) (uchar *), uchar *arg); bool add_tmp_key(uint key, uint key_parts, uint (*next_field_no) (uchar *), uchar *arg, bool unique); void create_key_part_by_field(KEY_PART_INFO *key_part_info, Field *field, uint fieldnr); void use_index(int key_to_save); void set_table_map(table_map map_arg, uint tablenr_arg) { map= map_arg; tablenr= tablenr_arg; } /// Return true if table is instantiated, and false otherwise. bool is_created() const { DBUG_ASSERT(!created || file != 0); return created; } /** Set the table as "created", and enable flags in storage engine that could not be enabled without an instantiated table. */ void set_created() { if (created) return; if (file->keyread_enabled()) file->extra(HA_EXTRA_KEYREAD); created= true; } void reset_created() { created= 0; } /* Returns TRUE if the table is filled at execution phase (and so, the optimizer must not do anything that depends on the contents of the table, like range analysis or constant table detection) */ bool is_filled_at_execution(); bool update_const_key_parts(COND *conds); void update_keypart_vcol_info(); inline void initialize_opt_range_structures(); my_ptrdiff_t default_values_offset() const { return (my_ptrdiff_t) (s->default_values - record[0]); } void move_fields(Field **ptr, const uchar *to, const uchar *from); void remember_blob_values(String *blob_storage); void restore_blob_values(String *blob_storage); uint actual_n_key_parts(KEY *keyinfo); ulong actual_key_flags(KEY *keyinfo); int update_virtual_field(Field *vf, bool ignore_warnings); int update_virtual_fields(handler *h, enum_vcol_update_mode update_mode); int update_default_fields(bool ignore_errors); void evaluate_update_default_function(); void reset_default_fields(); inline ha_rows stat_records() { return used_stat_records; } void prepare_triggers_for_insert_stmt_or_event(); bool prepare_triggers_for_delete_stmt_or_event(); bool prepare_triggers_for_update_stmt_or_event(); Field **field_to_fill(); bool validate_default_values_of_unset_fields(THD *thd) const; bool insert_all_rows_into_tmp_table(THD *thd, TABLE *tmp_table, TMP_TABLE_PARAM *tmp_table_param, bool with_cleanup); bool check_sequence_privileges(THD *thd); bool vcol_fix_expr(THD *thd); bool vcol_cleanup_expr(THD *thd); Field *find_field_by_name(LEX_CSTRING *str) const; bool export_structure(THD *thd, class Row_definition_list *defs); bool is_splittable() { return spl_opt_info != NULL; } void set_spl_opt_info(SplM_opt_info *spl_info); void deny_splitting(); double get_materialization_cost(); // Now used only if is_splittable()==true void add_splitting_info_for_key_field(struct KEY_FIELD *key_field); key_map with_impossible_ranges; /* Number of cost info elements for possible range filters */ uint range_rowid_filter_cost_info_elems; /* Pointer to the array of cost info elements for range filters */ Range_rowid_filter_cost_info *range_rowid_filter_cost_info; /* The array of pointers to cost info elements for range filters */ Range_rowid_filter_cost_info **range_rowid_filter_cost_info_ptr; void init_cost_info_for_usable_range_rowid_filters(THD *thd); void prune_range_rowid_filters(); void trace_range_rowid_filters(THD *thd) const; Range_rowid_filter_cost_info * best_range_rowid_filter_for_partial_join(uint access_key_no, double records, double access_cost_factor); /** System Versioning support */ bool vers_write; bool versioned() const { return s->versioned; } bool versioned(vers_kind_t type) const { DBUG_ASSERT(type); return s->versioned == type; } bool versioned_write() const { DBUG_ASSERT(versioned() || !vers_write); return versioned() ? vers_write : false; } bool versioned_write(vers_kind_t type) const { DBUG_ASSERT(type); DBUG_ASSERT(versioned() || !vers_write); return versioned(type) ? vers_write : false; } Field *vers_start_field() const { DBUG_ASSERT(s->versioned); return field[s->vers.start_fieldno]; } Field *vers_end_field() const { DBUG_ASSERT(s->versioned); return field[s->vers.end_fieldno]; } Field *period_start_field() const { DBUG_ASSERT(s->period.name); return field[s->period.start_fieldno]; } Field *period_end_field() const { DBUG_ASSERT(s->period.name); return field[s->period.end_fieldno]; } ulonglong vers_start_id() const; ulonglong vers_end_id() const; int update_generated_fields(); void period_prepare_autoinc(); int period_make_insert(Item *src, Field *dst); int insert_portion_of_time(THD *thd, const vers_select_conds_t &period_conds, ha_rows *rows_inserted); bool vers_check_update(List &items); static bool check_period_overlaps(const KEY &key, const uchar *lhs, const uchar *rhs); int delete_row(); /* Used in majority of DML (called from fill_record()) */ void vers_update_fields(); /* Used in DELETE, DUP REPLACE and insert history row */ void vers_update_end(); void find_constraint_correlated_indexes(); /** Number of additional fields used in versioned tables */ #define VERSIONING_FIELDS 2 }; /** Helper class which specifies which members of TABLE are used for participation in the list of used/unused TABLE objects for the share. */ struct TABLE_share { static inline TABLE **next_ptr(TABLE *l) { return &l->next; } static inline TABLE ***prev_ptr(TABLE *l) { return (TABLE ***) &l->prev; } }; struct All_share_tables { static inline TABLE **next_ptr(TABLE *l) { return &l->share_all_next; } static inline TABLE ***prev_ptr(TABLE *l) { return &l->share_all_prev; } }; typedef I_P_List All_share_tables_list; enum enum_schema_table_state { NOT_PROCESSED= 0, PROCESSED_BY_CREATE_SORT_INDEX, PROCESSED_BY_JOIN_EXEC }; enum enum_fk_option { FK_OPTION_UNDEF, FK_OPTION_RESTRICT, FK_OPTION_NO_ACTION, FK_OPTION_CASCADE, FK_OPTION_SET_NULL, FK_OPTION_SET_DEFAULT }; typedef struct st_foreign_key_info { LEX_CSTRING *foreign_id; LEX_CSTRING *foreign_db; LEX_CSTRING *foreign_table; LEX_CSTRING *referenced_db; LEX_CSTRING *referenced_table; enum_fk_option update_method; enum_fk_option delete_method; LEX_CSTRING *referenced_key_name; List foreign_fields; List referenced_fields; private: unsigned char *fields_nullable= nullptr; /** Get the number of fields exist in foreign key relationship */ unsigned get_n_fields() const noexcept { unsigned n_fields= foreign_fields.elements; if (n_fields == 0) n_fields= referenced_fields.elements; return n_fields; } /** Assign nullable field for referenced and foreign fields based on number of fields. This nullable fields should be allocated by engine for passing the foreign key information @param thd thread to allocate the memory @param num_fields number of fields */ void assign_nullable(THD *thd, unsigned num_fields) noexcept { fields_nullable= (unsigned char *)thd_calloc(thd, my_bits_in_bytes(2 * num_fields)); } public: /** Set nullable bit for the field in the given field @param referenced set null bit for referenced column @param field field number @param n_fields number of fields */ void set_nullable(THD *thd, bool referenced, unsigned field, unsigned n_fields) noexcept { if (!fields_nullable) assign_nullable(thd, n_fields); DBUG_ASSERT(fields_nullable); DBUG_ASSERT(field < n_fields); size_t bit= size_t{field} + referenced * n_fields; #if defined __GNUC__ && !defined __clang__ && __GNUC__ < 6 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wconversion" #endif fields_nullable[bit / 8]|= static_cast(1 << (bit % 8)); #if defined __GNUC__ && !defined __clang__ && __GNUC__ < 6 # pragma GCC diagnostic pop #endif } /** Check whether the given field_no in foreign key field or referenced key field @param referenced check referenced field nullable value @param field field number @return true if the field is nullable or false if it is not */ bool is_nullable(bool referenced, unsigned field) const noexcept { if (!fields_nullable) return false; unsigned n_field= get_n_fields(); DBUG_ASSERT(field < n_field); size_t bit= size_t{field} + referenced * n_field; return fields_nullable[bit / 8] & (1U << (bit % 8)); } } FOREIGN_KEY_INFO; LEX_CSTRING *fk_option_name(enum_fk_option opt); static inline bool fk_modifies_child(enum_fk_option opt) { return opt >= FK_OPTION_CASCADE; } class IS_table_read_plan; /* Types of derived tables. The ending part is a bitmap of phases that are applicable to a derived table of the type. */ #define DTYPE_ALGORITHM_UNDEFINED 0U #define DTYPE_VIEW 1U #define DTYPE_TABLE 2U #define DTYPE_MERGE 4U #define DTYPE_MATERIALIZE 8U #define DTYPE_MULTITABLE 16U #define DTYPE_MASK (DTYPE_VIEW|DTYPE_TABLE|DTYPE_MULTITABLE) /* Phases of derived tables/views handling, see sql_derived.cc Values are used as parts of a bitmap attached to derived table types. */ #define DT_INIT 1U #define DT_PREPARE 2U #define DT_OPTIMIZE 4U #define DT_MERGE 8U #define DT_MERGE_FOR_INSERT 16U #define DT_CREATE 32U #define DT_FILL 64U #define DT_REINIT 128U #define DT_PHASES 8U /* Phases that are applicable to all derived tables. */ #define DT_COMMON (DT_INIT + DT_PREPARE + DT_REINIT + DT_OPTIMIZE) /* Phases that are applicable only to materialized derived tables. */ #define DT_MATERIALIZE (DT_CREATE + DT_FILL) #define DT_PHASES_MERGE (DT_COMMON | DT_MERGE | DT_MERGE_FOR_INSERT) #define DT_PHASES_MATERIALIZE (DT_COMMON | DT_MATERIALIZE) #define VIEW_ALGORITHM_UNDEFINED 0 /* Special value for ALTER VIEW: inherit original algorithm. */ #define VIEW_ALGORITHM_INHERIT DTYPE_VIEW #define VIEW_ALGORITHM_MERGE (DTYPE_VIEW | DTYPE_MERGE) #define VIEW_ALGORITHM_TMPTABLE (DTYPE_VIEW | DTYPE_MATERIALIZE) /* View algorithm values as stored in the FRM. Values differ from in-memory representation for backward compatibility. */ #define VIEW_ALGORITHM_UNDEFINED_FRM 0U #define VIEW_ALGORITHM_MERGE_FRM 1U #define VIEW_ALGORITHM_TMPTABLE_FRM 2U #define JOIN_TYPE_LEFT 1U #define JOIN_TYPE_RIGHT 2U #define JOIN_TYPE_OUTER 4U /* Marker that this is an outer join */ /* view WITH CHECK OPTION parameter options */ #define VIEW_CHECK_NONE 0 #define VIEW_CHECK_LOCAL 1 #define VIEW_CHECK_CASCADED 2 /* result of view WITH CHECK OPTION parameter check */ #define VIEW_CHECK_OK 0 #define VIEW_CHECK_ERROR 1 #define VIEW_CHECK_SKIP 2 /** The threshold size a blob field buffer before it is freed */ #define MAX_TDC_BLOB_SIZE 65536 /** number of bytes used by field positional indexes in frm */ constexpr uint frm_fieldno_size= 2; /** number of bytes used by key position number in frm */ constexpr uint frm_keyno_size= 2; static inline field_index_t read_frm_fieldno(const uchar *data) { return uint2korr(data); } static inline void store_frm_fieldno(uchar *data, field_index_t fieldno) { int2store(data, fieldno); } static inline uint16 read_frm_keyno(const uchar *data) { return uint2korr(data); } static inline void store_frm_keyno(uchar *data, uint16 keyno) { int2store(data, keyno); } static inline size_t extra2_str_size(size_t len) { return (len > 255 ? 3 : 1) + len; } class select_unit; class TMP_TABLE_PARAM; Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, LEX_CSTRING *name); struct Field_translator { Item *item; LEX_CSTRING name; }; /* Column reference of a NATURAL/USING join. Since column references in joins can be both from views and stored tables, may point to either a Field (for tables), or a Field_translator (for views). */ class Natural_join_column: public Sql_alloc { public: Field_translator *view_field; /* Column reference of merge view. */ Item_field *table_field; /* Column reference of table or temp view. */ TABLE_LIST *table_ref; /* Original base table/view reference. */ /* True if a common join column of two NATURAL/USING join operands. Notice that when we have a hierarchy of nested NATURAL/USING joins, a column can be common at some level of nesting but it may not be common at higher levels of nesting. Thus this flag may change depending on at which level we are looking at some column. */ bool is_common; public: Natural_join_column(Field_translator *field_param, TABLE_LIST *tab); Natural_join_column(Item_field *field_param, TABLE_LIST *tab); LEX_CSTRING *name(); Item *create_item(THD *thd); Field *field(); const char *safe_table_name(); const char *safe_db_name(); GRANT_INFO *grant(); }; /** Type of table which can be open for an element of table list. */ enum enum_open_type { OT_TEMPORARY_OR_BASE= 0, OT_TEMPORARY_ONLY, OT_BASE_ONLY }; class SJ_MATERIALIZATION_INFO; class Index_hint; class Item_in_subselect; /* trivial class, for %union in sql_yacc.yy */ struct vers_history_point_t { vers_kind_t unit; Item *item; }; class Vers_history_point : public vers_history_point_t { void fix_item(); public: Vers_history_point() { empty(); } Vers_history_point(vers_kind_t unit_arg, Item *item_arg) { unit= unit_arg; item= item_arg; fix_item(); } Vers_history_point(vers_history_point_t p) { unit= p.unit; item= p.item; fix_item(); } void empty() { unit= VERS_TIMESTAMP; item= NULL; } void print(String *str, enum_query_type, const char *prefix, size_t plen) const; bool check_unit(THD *thd); bool eq(const vers_history_point_t &point) const; }; struct vers_select_conds_t { vers_system_time_t type; vers_system_time_t orig_type; bool used:1; bool delete_history:1; Vers_history_point start; Vers_history_point end; Lex_ident name; Item_field *field_start; Item_field *field_end; const TABLE_SHARE::period_info_t *period; void empty() { type= SYSTEM_TIME_UNSPECIFIED; orig_type= SYSTEM_TIME_UNSPECIFIED; used= false; delete_history= false; start.empty(); end.empty(); } void init(vers_system_time_t _type, Vers_history_point _start= Vers_history_point(), Vers_history_point _end= Vers_history_point(), Lex_ident _name= "SYSTEM_TIME") { type= _type; orig_type= _type; used= false; delete_history= (type == SYSTEM_TIME_HISTORY || type == SYSTEM_TIME_BEFORE); start= _start; end= _end; name= _name; } void set_all() { type= SYSTEM_TIME_ALL; name= "SYSTEM_TIME"; } void print(String *str, enum_query_type query_type) const; bool init_from_sysvar(THD *thd); bool is_set() const { return type != SYSTEM_TIME_UNSPECIFIED; } bool check_units(THD *thd); bool was_set() const { return orig_type != SYSTEM_TIME_UNSPECIFIED; } bool need_setup() const { return type != SYSTEM_TIME_UNSPECIFIED && type != SYSTEM_TIME_ALL; } bool eq(const vers_select_conds_t &conds) const; }; /* Table reference in the FROM clause. These table references can be of several types that correspond to different SQL elements. Below we list all types of TABLE_LISTs with the necessary conditions to determine when a TABLE_LIST instance belongs to a certain type. 1) table (TABLE_LIST::view == NULL) - base table (TABLE_LIST::derived == NULL) - FROM-clause subquery - TABLE_LIST::table is a temp table (TABLE_LIST::derived != NULL) - information schema table (TABLE_LIST::schema_table != NULL) NOTICE: for schema tables TABLE_LIST::field_translation may be != NULL 2) view (TABLE_LIST::view != NULL) - merge (TABLE_LIST::effective_algorithm == VIEW_ALGORITHM_MERGE) also (TABLE_LIST::field_translation != NULL) - tmptable (TABLE_LIST::effective_algorithm == VIEW_ALGORITHM_TMPTABLE) also (TABLE_LIST::field_translation == NULL) 2.5) TODO: Add derived tables description here 3) nested table reference (TABLE_LIST::nested_join != NULL) - table sequence - e.g. (t1, t2, t3) TODO: how to distinguish from a JOIN? - general JOIN TODO: how to distinguish from a table sequence? - NATURAL JOIN (TABLE_LIST::natural_join != NULL) - JOIN ... USING (TABLE_LIST::join_using_fields != NULL) - semi-join nest (sj_on_expr!= NULL && sj_subq_pred!=NULL) 4) jtbm semi-join (jtbm_subselect != NULL) */ /** last_leaf_for_name_resolutioning support. */ struct LEX; class Index_hint; /* @struct TABLE_CHAIN @brief Subchain of global chain of table references The structure contains a pointer to the address of the next_global pointer to the first TABLE_LIST objectof the subchain and the address of the next_global pointer to the element right after the last TABLE_LIST object of the subchain. For an empty subchain both pointers have the same value. */ struct TABLE_CHAIN { TABLE_CHAIN() = default; TABLE_LIST **start_pos; TABLE_LIST ** end_pos; void set_start_pos(TABLE_LIST **pos) { start_pos= pos; } void set_end_pos(TABLE_LIST **pos) { end_pos= pos; } }; class Table_ident; struct TABLE_LIST { TABLE_LIST(THD *thd, LEX_CSTRING db_str, bool fqtn, LEX_CSTRING alias_str, bool has_alias_ptr, Table_ident *table_ident, thr_lock_type lock_t, enum_mdl_type mdl_t, ulong table_opts, bool info_schema, st_select_lex *sel, List *index_hints_ptr, LEX_STRING *option_ptr); TABLE_LIST() = default; /* Remove gcc warning */ enum prelocking_types { PRELOCK_NONE, PRELOCK_ROUTINE, PRELOCK_FK }; /** Prepare TABLE_LIST that consists of one table instance to use in open_and_lock_tables */ inline void reset() { bzero((void*)this, sizeof(*this)); } inline void init_one_table(const LEX_CSTRING *db_arg, const LEX_CSTRING *table_name_arg, const LEX_CSTRING *alias_arg, enum thr_lock_type lock_type_arg) { enum enum_mdl_type mdl_type; if (lock_type_arg >= TL_FIRST_WRITE) mdl_type= MDL_SHARED_WRITE; else if (lock_type_arg == TL_READ_NO_INSERT) mdl_type= MDL_SHARED_NO_WRITE; else mdl_type= MDL_SHARED_READ; reset(); DBUG_ASSERT(!db_arg->str || strlen(db_arg->str) == db_arg->length); DBUG_ASSERT(!table_name_arg->str || strlen(table_name_arg->str) == table_name_arg->length); DBUG_ASSERT(!alias_arg || strlen(alias_arg->str) == alias_arg->length); db= *db_arg; table_name= *table_name_arg; alias= (alias_arg ? *alias_arg : *table_name_arg); lock_type= lock_type_arg; updating= lock_type >= TL_FIRST_WRITE; MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, db.str, table_name.str, mdl_type, MDL_TRANSACTION); } TABLE_LIST(TABLE *table_arg, thr_lock_type lock_type) { DBUG_ASSERT(table_arg->s); init_one_table(&table_arg->s->db, &table_arg->s->table_name, NULL, lock_type); table= table_arg; vers_conditions.name= table->s->vers.name; } inline void init_one_table_for_prelocking(const LEX_CSTRING *db_arg, const LEX_CSTRING *table_name_arg, const LEX_CSTRING *alias_arg, enum thr_lock_type lock_type_arg, prelocking_types prelocking_type, TABLE_LIST *belong_to_view_arg, uint8 trg_event_map_arg, TABLE_LIST ***last_ptr, my_bool insert_data) { init_one_table(db_arg, table_name_arg, alias_arg, lock_type_arg); cacheable_table= 1; prelocking_placeholder= prelocking_type; open_type= (prelocking_type == PRELOCK_ROUTINE ? OT_TEMPORARY_OR_BASE : OT_BASE_ONLY); belong_to_view= belong_to_view_arg; trg_event_map= trg_event_map_arg; /* MDL is enough for read-only FK checks, we don't need the table */ if (prelocking_type == PRELOCK_FK && lock_type < TL_FIRST_WRITE) open_strategy= OPEN_STUB; **last_ptr= this; prev_global= *last_ptr; *last_ptr= &next_global; for_insert_data= insert_data; } /* List of tables local to a subquery (used by SQL_I_List). Considers views as leaves (unlike 'next_leaf' below). Created at parse time in st_select_lex::add_table_to_list() -> table_list.link_in_list(). */ TABLE_LIST *next_local; /* link in a global list of all queries tables */ TABLE_LIST *next_global, **prev_global; LEX_CSTRING db; LEX_CSTRING table_name; LEX_CSTRING schema_table_name; LEX_CSTRING alias; const char *option; /* Used by cache index */ Item *on_expr; /* Used with outer join */ Name_resolution_context *on_context; /* For ON expressions */ Table_function_json_table *table_function; /* If it's the table function. */ Item *sj_on_expr; /* (Valid only for semi-join nests) Bitmap of tables that are within the semi-join (this is different from bitmap of all nest's children because tables that were pulled out of the semi-join nest remain listed as nest's children). */ table_map sj_inner_tables; /* Number of IN-compared expressions */ uint sj_in_exprs; /* If this is a non-jtbm semi-join nest: corresponding subselect predicate */ Item_in_subselect *sj_subq_pred; table_map original_subq_pred_used_tables; /* If this is a jtbm semi-join object: corresponding subselect predicate */ Item_in_subselect *jtbm_subselect; /* TODO: check if this can be joined with tablenr_exec */ uint jtbm_table_no; SJ_MATERIALIZATION_INFO *sj_mat_info; /* The structure of ON expression presented in the member above can be changed during certain optimizations. This member contains a snapshot of AND-OR structure of the ON expression made after permanent transformations of the parse tree, and is used to restore ON clause before every reexecution of a prepared statement or stored procedure. */ Item *prep_on_expr; COND_EQUAL *cond_equal; /* Used with outer join */ /* During parsing - left operand of NATURAL/USING join where 'this' is the right operand. After parsing (this->natural_join == this) iff 'this' represents a NATURAL or USING join operation. Thus after parsing 'this' is a NATURAL/USING join iff (natural_join != NULL). */ TABLE_LIST *natural_join; /* True if 'this' represents a nested join that is a NATURAL JOIN. For one of the operands of 'this', the member 'natural_join' points to the other operand of 'this'. */ bool is_natural_join; /* Field names in a USING clause for JOIN ... USING. */ List *join_using_fields; /* Explicitly store the result columns of either a NATURAL/USING join or an operand of such a join. */ List *join_columns; /* TRUE if join_columns contains all columns of this table reference. */ bool is_join_columns_complete; /* List of nodes in a nested join tree, that should be considered as leaves with respect to name resolution. The leaves are: views, top-most nodes representing NATURAL/USING joins, subqueries, and base tables. All of these TABLE_LIST instances contain a materialized list of columns. The list is local to a subquery. */ TABLE_LIST *next_name_resolution_table; /* Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */ List *index_hints; TABLE *table; /* opened table */ ulonglong table_id; /* table id (from binlog) for opened table */ /* select_result for derived table to pass it from table creation to table filling procedure */ select_unit *derived_result; /* Stub used for materialized derived tables. */ table_map map; /* ID bit of table (1,2,4,8,16...) */ table_map get_map() { return jtbm_subselect? table_map(1) << jtbm_table_no : table->map; } uint get_tablenr() { return jtbm_subselect? jtbm_table_no : table->tablenr; } void set_tablenr(uint new_tablenr) { if (jtbm_subselect) { jtbm_table_no= new_tablenr; } if (table) { table->tablenr= new_tablenr; table->map= table_map(1) << new_tablenr; } } /* Reference from aux_tables to local list entry of main select of multi-delete statement: delete t1 from t2,t1 where t1.a<'B' and t2.b=t1.b; here it will be reference of first occurrence of t1 to second (as you can see this lists can't be merged) */ TABLE_LIST *correspondent_table; /** @brief Normally, this field is non-null for anonymous derived tables only. @details This field is set to non-null for - Anonymous derived tables, In this case it points to the SELECT_LEX_UNIT representing the derived table. E.g. for a query @verbatim SELECT * FROM (SELECT a FROM t1) b @endverbatim For the @c TABLE_LIST representing the derived table @c b, @c derived points to the SELECT_LEX_UNIT representing the result of the query within parenteses. - Views. This is set for views with @verbatim ALGORITHM = TEMPTABLE @endverbatim by mysql_make_view(). @note Inside views, a subquery in the @c FROM clause is not allowed. @note Do not use this field to separate views/base tables/anonymous derived tables. Use TABLE_LIST::is_anonymous_derived_table(). */ st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ With_element *with; /* With element defining this table (if any) */ /* Bitmap of the defining with element */ table_map with_internal_reference_map; TABLE_LIST * next_with_rec_ref; bool is_derived_with_recursive_reference; bool block_handle_derived; /* The interface employed to materialize the table by a foreign engine */ derived_handler *dt_handler; /* The text of the query specifying the derived table */ LEX_CSTRING derived_spec; /* The object used to organize execution of the query that specifies the derived table by a foreign engine */ Pushdown_derived *pushdown_derived; ST_SCHEMA_TABLE *schema_table; /* Information_schema table */ st_select_lex *schema_select_lex; /* True when the view field translation table is used to convert schema table fields for backwards compatibility with SHOW command. */ bool schema_table_reformed; TMP_TABLE_PARAM *schema_table_param; /* link to select_lex where this table was used */ st_select_lex *select_lex; LEX *view; /* link on VIEW lex for merging */ Field_translator *field_translation; /* array of VIEW fields */ /* pointer to element after last one in translation table above */ Field_translator *field_translation_end; bool field_translation_updated; /* List (based on next_local) of underlying tables of this view. I.e. it does not include the tables of subqueries used in the view. Is set only for merged views. */ TABLE_LIST *merge_underlying_list; /* - 0 for base tables - in case of the view it is the list of all (not only underlying tables but also used in subquery ones) tables of the view. */ List *view_tables; /* most upper view this table belongs to */ TABLE_LIST *belong_to_view; /* A merged derived table this table belongs to */ TABLE_LIST *belong_to_derived; /* The view directly referencing this table (non-zero only for merged underlying tables of a view). */ TABLE_LIST *referencing_view; table_map view_used_tables; table_map map_exec; /* TODO: check if this can be joined with jtbm_table_no */ uint tablenr_exec; uint maybe_null_exec; /* Ptr to parent MERGE table list item. See top comment in ha_myisammrg.cc */ TABLE_LIST *parent_l; /* Security context (non-zero only for tables which belong to view with SQL SECURITY DEFINER) */ Security_context *security_ctx; uchar tabledef_version_buf[MY_UUID_SIZE > MICROSECOND_TIMESTAMP_BUFFER_SIZE-1 ? MY_UUID_SIZE + 1 : MICROSECOND_TIMESTAMP_BUFFER_SIZE]; LEX_CUSTRING tabledef_version; /* This view security context (non-zero only for views with SQL SECURITY DEFINER) */ Security_context *view_sctx; bool allowed_show; Item *where; /* VIEW WHERE clause condition */ Item *check_option; /* WITH CHECK OPTION condition */ LEX_STRING select_stmt; /* text of (CREATE/SELECT) statement */ LEX_CSTRING md5; /* md5 of query text */ LEX_CSTRING source; /* source of CREATE VIEW */ LEX_CSTRING view_db; /* saved view database */ LEX_CSTRING view_name; /* saved view name */ LEX_STRING hr_timestamp; /* time stamp of last operation */ LEX_USER definer; /* definer of view */ ulonglong file_version; /* version of file's field set */ ulonglong mariadb_version; /* version of server on creation */ ulonglong updatable_view; /* VIEW can be updated */ /** @brief The declared algorithm, if this is a view. @details One of - VIEW_ALGORITHM_UNDEFINED - VIEW_ALGORITHM_TMPTABLE - VIEW_ALGORITHM_MERGE @to do Replace with an enum */ ulonglong algorithm; ulonglong view_suid; /* view is suid (TRUE dy default) */ ulonglong with_check; /* WITH CHECK OPTION */ /* effective value of WITH CHECK OPTION (differ for temporary table algorithm) */ uint8 effective_with_check; /** @brief The view algorithm that is actually used, if this is a view. @details One of - VIEW_ALGORITHM_UNDEFINED - VIEW_ALGORITHM_TMPTABLE - VIEW_ALGORITHM_MERGE @to do Replace with an enum */ uint8 derived_type; GRANT_INFO grant; /* data need by some engines in query cache*/ ulonglong engine_data; /* call back function for asking handler about caching in query cache */ qc_engine_callback callback_func; thr_lock_type lock_type; /* Two fields below are set during parsing this table reference in the cases when the table reference can be potentially a reference to a CTE table. In this cases the fact that the reference is a reference to a CTE or not will be ascertained at the very end of parsing of the query when referencies to CTE are resolved. For references to CTE and to derived tables no mdl requests are needed while for other table references they are. If a request is possibly postponed the info that allows to issue this request must be saved in 'mdl_type' and 'table_options'. */ enum_mdl_type mdl_type; ulong table_options; uint outer_join; /* Which join type */ uint shared; /* Used in multi-upd */ bool updatable; /* VIEW/TABLE can be updated now */ bool straight; /* optimize with prev table */ bool updating; /* for replicate-do/ignore table */ bool force_index; /* prefer index over table scan */ bool ignore_leaves; /* preload only non-leaf nodes */ bool crashed; /* Table was found crashed */ bool skip_locked; /* Skip locked in view defination */ table_map dep_tables; /* tables the table depends on */ table_map on_expr_dep_tables; /* tables on expression depends on */ struct st_nested_join *nested_join; /* if the element is a nested join */ TABLE_LIST *embedding; /* nested join containing the table */ List *join_list;/* join list the table belongs to */ bool lifted; /* set to true when the table is moved to the upper level at the parsing stage */ bool cacheable_table; /* stop PS caching */ /* used in multi-upd/views privilege check */ bool table_in_first_from_clause; /** Specifies which kind of table should be open for this element of table list. */ enum enum_open_type open_type; /* TRUE if this merged view contain auto_increment field */ bool contain_auto_increment; bool compact_view_format; /* Use compact format for SHOW CREATE VIEW */ /* view where processed */ bool where_processed; /* TRUE <=> VIEW CHECK OPTION expression has been processed */ bool check_option_processed; /* TABLE_TYPE_UNKNOWN if any type is acceptable */ Table_type required_type; handlerton *db_type; /* table_type for handler */ char timestamp_buffer[MICROSECOND_TIMESTAMP_BUFFER_SIZE]; /* This TABLE_LIST object is just placeholder for prelocking, it will be used for implicit LOCK TABLES only and won't be used in real statement. */ prelocking_types prelocking_placeholder; /** Indicates that if TABLE_LIST object corresponds to the table/view which requires special handling. */ enum enum_open_strategy { /* Normal open. */ OPEN_NORMAL= 0, /* Associate a table share only if the the table exists. */ OPEN_IF_EXISTS, /* Don't associate a table share. */ OPEN_STUB } open_strategy; /** TRUE if an alias for this table was specified in the SQL. */ bool is_alias; /** TRUE if the table is referred to in the statement using a fully qualified name (.). */ bool is_fqtn; /* TRUE <=> derived table should be filled right after optimization. */ bool fill_me; /* TRUE <=> view/DT is merged. */ /* TODO: replace with derived_type */ bool merged; bool merged_for_insert; bool sequence; /* Part of NEXTVAL/CURVAL/LASTVAL */ /* Items created by create_view_field and collected to change them in case of materialization of the view/derived table */ List used_items; /* Sublist (tail) of persistent used_items */ List persistent_used_items; /* View creation context. */ View_creation_ctx *view_creation_ctx; /* Attributes to save/load view creation context in/from frm-file. Ther are required only to be able to use existing parser to load view-definition file. As soon as the parser parsed the file, view creation context is initialized and the attributes become redundant. These attributes MUST NOT be used for any purposes but the parsing. */ LEX_CSTRING view_client_cs_name; LEX_CSTRING view_connection_cl_name; /* View definition (SELECT-statement) in the UTF-form. */ LEX_CSTRING view_body_utf8; /* End of view definition context. */ /** Indicates what triggers we need to pre-load for this TABLE_LIST when opening an associated TABLE. This is filled after the parsed tree is created. slave_fk_event_map is filled on the slave side with bitmaps value representing row-based event operation to help find and prelock possible FK constrain-related child tables. */ uint8 trg_event_map, slave_fk_event_map; /* TRUE <=> this table is a const one and was optimized away. */ bool optimized_away; /** TRUE <=> already materialized. Valid only for materialized derived tables/views. */ bool materialized; /* I_S: Flags to open_table (e.g. OPEN_TABLE_ONLY or OPEN_VIEW_ONLY) */ uint i_s_requested_object; bool prohibit_cond_pushdown; /* I_S: how to read the tables (SKIP_OPEN_TABLE/OPEN_FRM_ONLY/OPEN_FULL_TABLE) */ uint table_open_method; /* I_S: where the schema table was filled (this is a hack. The code should be able to figure out whether reading from I_S should be done by create_sort_index() or by JOIN::exec.) */ enum enum_schema_table_state schema_table_state; /* Something like a "query plan" for reading INFORMATION_SCHEMA table */ IS_table_read_plan *is_table_read_plan; MDL_request mdl_request; #ifdef WITH_PARTITION_STORAGE_ENGINE /* List to carry partition names from PARTITION (...) clause in statement */ List *partition_names; #endif /* WITH_PARTITION_STORAGE_ENGINE */ void calc_md5(char *buffer); int view_check_option(THD *thd, bool ignore_failure); bool create_field_translation(THD *thd); bool setup_underlying(THD *thd); void cleanup_items(); bool placeholder() { return derived || view || schema_table || !table || table_function; } void print(THD *thd, table_map eliminated_tables, String *str, enum_query_type query_type); void print_leaf_tables(THD *thd, String *str, enum_query_type query_type); bool check_single_table(TABLE_LIST **table, table_map map, TABLE_LIST *view); bool set_insert_values(MEM_ROOT *mem_root); void replace_view_error_with_generic(THD *thd); TABLE_LIST *find_underlying_table(TABLE *table); TABLE_LIST *first_leaf_for_name_resolution(); TABLE_LIST *last_leaf_for_name_resolution(); /* System Versioning */ vers_select_conds_t vers_conditions; vers_select_conds_t period_conditions; bool has_period() const { return period_conditions.is_set(); } my_bool for_insert_data; /** @brief Find the bottom in the chain of embedded table VIEWs. @detail This is used for single-table UPDATE/DELETE when they are modifying a single-table VIEW. */ TABLE_LIST *find_table_for_update() { TABLE_LIST *tbl= this; while(!tbl->is_multitable() && tbl->single_table_updatable() && tbl->merge_underlying_list) { tbl= tbl->merge_underlying_list; } return tbl; } TABLE *get_real_join_table(); bool is_leaf_for_name_resolution(); inline TABLE_LIST *top_table() { return belong_to_view ? belong_to_view : this; } inline bool prepare_check_option(THD *thd) { bool res= FALSE; if (effective_with_check) res= prep_check_option(thd, effective_with_check); return res; } inline bool prepare_where(THD *thd, Item **conds, bool no_where_clause) { if (!view || is_merged_derived()) return prep_where(thd, conds, no_where_clause); return FALSE; } void register_want_access(privilege_t want_access); bool prepare_security(THD *thd); #ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *find_view_security_context(THD *thd); bool prepare_view_security_context(THD *thd, bool upgrade_check); #endif /* Cleanup for re-execution in a prepared statement or a stored procedure. */ void reinit_before_use(THD *thd); Item_subselect *containing_subselect(); /* Compiles the tagged hints list and fills up TABLE::keys_in_use_for_query, TABLE::keys_in_use_for_group_by, TABLE::keys_in_use_for_order_by, TABLE::force_index and TABLE::covering_keys. */ bool process_index_hints(TABLE *table); bool is_the_same_definition(THD *thd, TABLE_SHARE *s); /** Record the value of metadata version of the corresponding table definition cache element in this parse tree node. @sa check_and_update_table_version() */ inline void set_table_ref_id(TABLE_SHARE *s) { set_table_ref_id(s->get_table_ref_type(), s->get_table_ref_version()); } inline void set_table_ref_id(enum_table_ref_type table_ref_type_arg, ulonglong table_ref_version_arg) { m_table_ref_type= table_ref_type_arg; m_table_ref_version= table_ref_version_arg; } void set_table_id(TABLE_SHARE *s) { set_table_ref_id(s); set_tabledef_version(s); } void set_tabledef_version(TABLE_SHARE *s) { if (!tabledef_version.length && s->tabledef_version.length) { DBUG_ASSERT(s->tabledef_version.length < sizeof(tabledef_version_buf)); tabledef_version.str= tabledef_version_buf; memcpy(tabledef_version_buf, s->tabledef_version.str, (tabledef_version.length= s->tabledef_version.length)); // safety tabledef_version_buf[tabledef_version.length]= 0; } } /* Set of functions returning/setting state of a derived table/view. */ bool is_non_derived() const { return (!derived_type); } bool is_view_or_derived() const { return derived_type; } bool is_view() const { return (derived_type & DTYPE_VIEW); } bool is_derived() const { return (derived_type & DTYPE_TABLE); } bool is_with_table(); bool is_recursive_with_table(); bool is_with_table_recursive_reference(); void register_as_derived_with_rec_ref(With_element *rec_elem); bool is_nonrecursive_derived_with_rec_ref(); bool fill_recursive(THD *thd); inline void set_view() { derived_type= DTYPE_VIEW; } inline void set_derived() { derived_type= DTYPE_TABLE; } bool is_merged_derived() const { return (derived_type & DTYPE_MERGE); } inline void set_merged_derived() { DBUG_ENTER("set_merged_derived"); DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", (alias.str ? alias.str : ""), get_unit())); derived_type= static_cast((derived_type & DTYPE_MASK) | DTYPE_MERGE); set_check_merged(); DBUG_VOID_RETURN; } bool is_materialized_derived() const { return (derived_type & DTYPE_MATERIALIZE); } void set_materialized_derived() { DBUG_ENTER("set_materialized_derived"); DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", (alias.str ? alias.str : ""), get_unit())); derived_type= static_cast((derived_type & (derived ? DTYPE_MASK : DTYPE_VIEW)) | DTYPE_MATERIALIZE); set_check_materialized(); DBUG_VOID_RETURN; } bool is_multitable() const { return (derived_type & DTYPE_MULTITABLE); } inline void set_multitable() { derived_type|= DTYPE_MULTITABLE; } bool set_as_with_table(THD *thd, With_element *with_elem); void reset_const_table(); bool handle_derived(LEX *lex, uint phases); /** @brief True if this TABLE_LIST represents an anonymous derived table, i.e. the result of a subquery. */ bool is_anonymous_derived_table() const { return derived && !view; } /** @brief Returns the name of the database that the referenced table belongs to. */ const LEX_CSTRING get_db_name() const { return view != NULL ? view_db : db; } /** @brief Returns the name of the table that this TABLE_LIST represents. @details The unqualified table name or view name for a table or view, respectively. */ const LEX_CSTRING get_table_name() const { return view != NULL ? view_name : table_name; } bool is_active_sjm(); bool is_sjm_scan_table(); bool is_jtbm() { return MY_TEST(jtbm_subselect != NULL); } st_select_lex_unit *get_unit(); st_select_lex *get_single_select(); void wrap_into_nested_join(List &join_list); bool init_derived(THD *thd, bool init_view); int fetch_number_of_rows(); bool change_refs_to_fields(); bool single_table_updatable(); bool is_inner_table_of_outer_join() { for (TABLE_LIST *tbl= this; tbl; tbl= tbl->embedding) { if (tbl->outer_join) return true; } return false; } void set_lock_type(THD* thd, enum thr_lock_type lock); derived_handler *find_derived_handler(THD *thd); TABLE_LIST *get_first_table(); void remove_join_columns() { if (join_columns) { join_columns->empty(); join_columns= NULL; is_join_columns_complete= FALSE; } } inline void set_view_def_version(LEX_STRING *version) { m_table_ref_type= TABLE_REF_VIEW; tabledef_version.str= (const uchar *) version->str; tabledef_version.length= version->length; } private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); void set_check_materialized(); #ifndef DBUG_OFF void set_check_merged(); #else inline void set_check_merged() {} #endif /** See comments for set_table_ref_id() */ enum enum_table_ref_type m_table_ref_type; /** See comments for set_table_ref_id() */ ulonglong m_table_ref_version; }; #define ERROR_TABLE ((TABLE_LIST*) 0x1) class Item; /* Iterator over the fields of a generic table reference. */ class Field_iterator: public Sql_alloc { public: Field_iterator() = default; /* Remove gcc warning */ virtual ~Field_iterator() = default; virtual void set(TABLE_LIST *)= 0; virtual void next()= 0; virtual bool end_of_fields()= 0; /* Return 1 at end of list */ virtual LEX_CSTRING *name()= 0; virtual Item *create_item(THD *)= 0; virtual Field *field()= 0; }; /* Iterator over the fields of a base table, view with temporary table, or subquery. */ class Field_iterator_table: public Field_iterator { Field **ptr; public: Field_iterator_table() :ptr(0) {} void set(TABLE_LIST *table) override { ptr= table->table->field; } void set_table(TABLE *table) { ptr= table->field; } void next() override { ptr++; } bool end_of_fields() override { return *ptr == 0; } LEX_CSTRING *name() override; Item *create_item(THD *thd) override; Field *field() override { return *ptr; } }; /* Iterator over the fields of a merge view. */ class Field_iterator_view: public Field_iterator { Field_translator *ptr, *array_end; TABLE_LIST *view; public: Field_iterator_view() :ptr(0), array_end(0) {} void set(TABLE_LIST *table) override; void next() override { ptr++; } bool end_of_fields() override { return ptr == array_end; } LEX_CSTRING *name() override; Item *create_item(THD *thd) override; Item **item_ptr() {return &ptr->item; } Field *field() override { return 0; } inline Item *item() { return ptr->item; } Field_translator *field_translator() { return ptr; } }; /* Field_iterator interface to the list of materialized fields of a NATURAL/USING join. */ class Field_iterator_natural_join: public Field_iterator { List_iterator_fast column_ref_it; Natural_join_column *cur_column_ref; public: Field_iterator_natural_join() :cur_column_ref(NULL) {} ~Field_iterator_natural_join() = default; void set(TABLE_LIST *table) override; void next() override; bool end_of_fields() override { return !cur_column_ref; } LEX_CSTRING *name() override { return cur_column_ref->name(); } Item *create_item(THD *thd) override { return cur_column_ref->create_item(thd); } Field *field() override { return cur_column_ref->field(); } Natural_join_column *column_ref() { return cur_column_ref; } }; /* Generic iterator over the fields of an arbitrary table reference. DESCRIPTION This class unifies the various ways of iterating over the columns of a table reference depending on the type of SQL entity it represents. If such an entity represents a nested table reference, this iterator encapsulates the iteration over the columns of the members of the table reference. IMPLEMENTATION The implementation assumes that all underlying NATURAL/USING table references already contain their result columns and are linked into the list TABLE_LIST::next_name_resolution_table. */ class Field_iterator_table_ref: public Field_iterator { TABLE_LIST *table_ref, *first_leaf, *last_leaf; Field_iterator_table table_field_it; Field_iterator_view view_field_it; Field_iterator_natural_join natural_join_it; Field_iterator *field_it; void set_field_iterator(); public: Field_iterator_table_ref() :field_it(NULL) {} void set(TABLE_LIST *table) override; void next() override; bool end_of_fields() override { return (table_ref == last_leaf && field_it->end_of_fields()); } LEX_CSTRING *name() override { return field_it->name(); } const char *get_table_name(); const char *get_db_name(); GRANT_INFO *grant(); Item *create_item(THD *thd) override { return field_it->create_item(thd); } Field *field() override { return field_it->field(); } Natural_join_column *get_or_create_column_ref(THD *thd, TABLE_LIST *parent_table_ref); Natural_join_column *get_natural_column_ref(); }; #define JOIN_OP_NEST 1 #define REBALANCED_NEST 2 typedef struct st_nested_join { List join_list; /* list of elements in the nested join */ /* Currently the valid values for nest type are: JOIN_OP_NEST - for nest created for JOIN operation used as an operand in a join expression, contains 2 elements; JOIN_OP_NEST | REBALANCED_NEST - nest created after tree re-balancing in st_select_lex::add_cross_joined_table(), contains 1 element; 0 - for all other nests. Examples: 1. SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a; Here the nest created for LEFT JOIN at first has nest_type==JOIN_OP_NEST. After re-balancing in st_select_lex::add_cross_joined_table() this nest has nest_type==JOIN_OP_NEST | REBALANCED_NEST. The nest for JOIN created in st_select_lex::add_cross_joined_table() has nest_type== JOIN_OP_NEST. 2. SELECT * FROM t1 JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) Here the nest created for LEFT JOIN has nest_type==0, because it's not an operand in a join expression. The nest created for JOIN has nest_type set to JOIN_OP_NEST. */ uint nest_type; /* Bitmap of tables within this nested join (including those embedded within its children), including tables removed by table elimination. */ table_map used_tables; table_map not_null_tables; /* tables that rejects nulls */ /** Used for pointing out the first table in the plan being covered by this join nest. It is used exclusively within make_outerjoin_info(). */ struct st_join_table *first_nested; /* Used to count tables in the nested join in 2 isolated places: 1. In make_outerjoin_info(). 2. check_interleaving_with_nj/restore_prev_nj_state (these are called by the join optimizer. Before each use the counters are zeroed by reset_nj_counters. */ uint counter; /* Number of elements in join_list that participate in the join plan choice: - Base tables that were not removed by table elimination - Join nests that were not removed by mark_join_nest_as_const */ uint n_tables; nested_join_map nj_map; /* Bit used to identify this nested join*/ /* (Valid only for semi-join nests) Bitmap of tables outside the semi-join that are used within the semi-join's ON condition. */ table_map sj_depends_on; /* Outer non-trivially correlated tables */ table_map sj_corr_tables; List sj_outer_expr_list; /** True if this join nest node is completely covered by the query execution plan. This means two things. 1. All tables on its @c join_list are covered by the plan. 2. All child join nest nodes are fully covered. */ bool is_fully_covered() const { return n_tables == counter; } } NESTED_JOIN; typedef struct st_changed_table_list { struct st_changed_table_list *next; char *key; size_t key_length; } CHANGED_TABLE_LIST; typedef struct st_open_table_list{ struct st_open_table_list *next; char *db,*table; uint32 in_use,locked; } OPEN_TABLE_LIST; static inline MY_BITMAP *tmp_use_all_columns(TABLE *table, MY_BITMAP **bitmap) { MY_BITMAP *old= *bitmap; *bitmap= &table->s->all_set; return old; } static inline void tmp_restore_column_map(MY_BITMAP **bitmap, MY_BITMAP *old) { *bitmap= old; } /* The following is only needed for debugging */ static inline MY_BITMAP *dbug_tmp_use_all_columns(TABLE *table, MY_BITMAP **bitmap) { #ifdef DBUG_ASSERT_EXISTS return tmp_use_all_columns(table, bitmap); #else return 0; #endif } static inline void dbug_tmp_restore_column_map(MY_BITMAP **bitmap, MY_BITMAP *old) { #ifdef DBUG_ASSERT_EXISTS tmp_restore_column_map(bitmap, old); #endif } /* Variant of the above : handle both read and write sets. Provide for the possiblity of the read set being the same as the write set */ static inline void dbug_tmp_use_all_columns(TABLE *table, MY_BITMAP **save, MY_BITMAP **read_set, MY_BITMAP **write_set) { #ifdef DBUG_ASSERT_EXISTS save[0]= *read_set; save[1]= *write_set; (void) tmp_use_all_columns(table, read_set); (void) tmp_use_all_columns(table, write_set); #endif } static inline void dbug_tmp_restore_column_maps(MY_BITMAP **read_set, MY_BITMAP **write_set, MY_BITMAP **old) { #ifdef DBUG_ASSERT_EXISTS tmp_restore_column_map(read_set, old[0]); tmp_restore_column_map(write_set, old[1]); #endif } bool ok_for_lower_case_names(const char *names); enum get_table_share_flags { GTS_TABLE = 1, GTS_VIEW = 2, GTS_NOLOCK = 4, GTS_USE_DISCOVERY = 8, GTS_FORCE_DISCOVERY = 16 }; size_t max_row_length(TABLE *table, MY_BITMAP const *cols, const uchar *data); void init_mdl_requests(TABLE_LIST *table_list); enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, const LEX_CSTRING *alias, uint db_stat, uint prgflag, uint ha_open_flags, TABLE *outparam, bool is_create_table, List *partitions_to_open= NULL); bool copy_keys_from_share(TABLE *outparam, MEM_ROOT *root); bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table, bool *error_reported, vcol_init_mode expr); TABLE_SHARE *alloc_table_share(const char *db, const char *table_name, const char *key, uint key_length); void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key, uint key_length, const char *table_name, const char *path); void free_table_share(TABLE_SHARE *share); enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags = GTS_TABLE); void open_table_error(TABLE_SHARE *share, enum open_frm_error error, int db_errno); void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form); bool check_db_name(LEX_STRING *db); bool check_column_name(const char *name); bool check_period_name(const char *name); bool check_table_name(const char *name, size_t length, bool check_for_path_chars); int rename_file_ext(const char * from,const char * to,const char * ext); char *get_field(MEM_ROOT *mem, Field *field); bool get_field(MEM_ROOT *mem, Field *field, class String *res); bool validate_comment_length(THD *thd, LEX_CSTRING *comment, size_t max_len, uint err_code, const char *name); int closefrm(TABLE *table); void free_blobs(TABLE *table); void free_field_buffers_larger_than(TABLE *table, uint32 size); ulong get_form_pos(File file, uchar *head, TYPELIB *save_names); void append_unescaped(String *res, const char *pos, size_t length); void prepare_frm_header(THD *thd, uint reclength, uchar *fileinfo, HA_CREATE_INFO *create_info, uint keys, KEY *key_info); const char *fn_frm_ext(const char *name); /* Check that the integer is in the internal */ static inline int set_zone(int nr,int min_zone,int max_zone) { if (nr <= min_zone) return min_zone; if (nr >= max_zone) return max_zone; return nr; } /* performance schema */ extern LEX_CSTRING PERFORMANCE_SCHEMA_DB_NAME; extern LEX_CSTRING GENERAL_LOG_NAME; extern LEX_CSTRING SLOW_LOG_NAME; extern LEX_CSTRING TRANSACTION_REG_NAME; /* information schema */ extern LEX_CSTRING INFORMATION_SCHEMA_NAME; extern Lex_ident_db MYSQL_SCHEMA_NAME; /* table names */ extern LEX_CSTRING MYSQL_PROC_NAME; inline bool is_infoschema_db(const LEX_CSTRING *name) { return lex_string_eq(&INFORMATION_SCHEMA_NAME, name); } inline bool is_perfschema_db(const LEX_CSTRING *name) { return lex_string_eq(&PERFORMANCE_SCHEMA_DB_NAME, name); } inline void mark_as_null_row(TABLE *table) { table->null_row=1; table->status|=STATUS_NULL_ROW; if (table->s->null_bytes) bfill(table->null_flags,table->s->null_bytes,255); } /* Restore table to state before mark_as_null_row() call. This assumes that the caller has restored table->null_flags, as is done in unclear_tables(). */ inline void unmark_as_null_row(TABLE *table) { table->null_row= 0; table->status&= ~STATUS_NULL_ROW; } bool is_simple_order(ORDER *order); class Open_tables_backup; /** Transaction Registry Table (TRT) This table holds transaction IDs, their corresponding times and other transaction-related data which is used for transaction order resolution. When versioned table marks its records lifetime with transaction IDs, TRT is used to get their actual timestamps. */ class TR_table: public TABLE_LIST { THD *thd; Open_tables_backup *open_tables_backup; public: enum field_id_t { FLD_TRX_ID= 0, FLD_COMMIT_ID, FLD_BEGIN_TS, FLD_COMMIT_TS, FLD_ISO_LEVEL, FIELD_COUNT }; enum enabled {NO, MAYBE, YES}; static enum enabled use_transaction_registry; /** @param[in,out] Thread handle @param[in] Current transaction is read-write. */ TR_table(THD *_thd, bool rw= false); /** Opens a transaction_registry table. @retval true on error, false otherwise. */ bool open(); ~TR_table(); /** @retval current thd */ THD *get_thd() const { return thd; } /** Stores value to internal transaction_registry TABLE object. @param[in] field number in a TABLE @param[in] value to store */ void store(uint field_id, ulonglong val); /** Stores value to internal transaction_registry TABLE object. @param[in] field number in a TABLE @param[in] value to store */ void store(uint field_id, timeval ts); /** Update the transaction_registry right before commit. @param start_id transaction identifier at start @param end_id transaction identifier at commit @retval false on success @retval true on error (the transaction must be rolled back) */ bool update(ulonglong start_id, ulonglong end_id); // return true if found; false if not found or error bool query(ulonglong trx_id); /** Gets a row from transaction_registry with the closest commit_timestamp to first argument. We can search for a value which a lesser or greater than first argument. Also loads a row into an internal TABLE object. @param[in] timestamp @param[in] true if we search for a lesser timestamp, false if greater @retval true if exists, false it not exists or an error occurred */ bool query(MYSQL_TIME &commit_time, bool backwards); /** Checks whether transaction1 sees transaction0. @param[out] true if transaction1 sees transaction0, undefined on error and when transaction1=transaction0 and false otherwise @param[in] transaction_id of transaction1 @param[in] transaction_id of transaction0 @param[in] commit time of transaction1 or 0 if we want it to be queried @param[in] isolation level (from handler.h) of transaction1 @param[in] commit time of transaction0 or 0 if we want it to be queried @retval true on error, false otherwise */ bool query_sees(bool &result, ulonglong trx_id1, ulonglong trx_id0, ulonglong commit_id1= 0, enum_tx_isolation iso_level1= ISO_READ_UNCOMMITTED, ulonglong commit_id0= 0); /** @retval transaction isolation level of a row from internal TABLE object. */ enum_tx_isolation iso_level() const; /** Stores transactioin isolation level to internal TABLE object. */ void store_iso_level(enum_tx_isolation iso_level) { DBUG_ASSERT(iso_level <= ISO_SERIALIZABLE); store(FLD_ISO_LEVEL, iso_level + 1); } /** Writes a message to MariaDB log about incorrect transaction_registry schema. @param[in] a message explained what's incorrect in schema */ void warn_schema_incorrect(const char *reason); /** Checks whether transaction_registry table has a correct schema. @retval true if schema is incorrect and false otherwise */ bool check(bool error); TABLE * operator-> () const { return table; } Field * operator[] (uint field_id) const { DBUG_ASSERT(field_id < FIELD_COUNT); return table->field[field_id]; } operator bool () const { return table; } bool operator== (const TABLE_LIST &subj) const { return (!cmp(&db, &subj.db) && !cmp(&table_name, &subj.table_name)); } bool operator!= (const TABLE_LIST &subj) const { return !(*this == subj); } }; #endif /* MYSQL_CLIENT */ #endif /* TABLE_INCLUDED */ server/private/rpl_gtid.h000064400000032563151031265050011510 0ustar00/* Copyright (c) 2013, Kristian Nielsen and MariaDB Services Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef RPL_GTID_H #define RPL_GTID_H #include "hash.h" #include "queues.h" #include /* Definitions for MariaDB global transaction ID (GTID). */ extern const LEX_CSTRING rpl_gtid_slave_state_table_name; class String; #define PARAM_GTID(G) G.domain_id, G.server_id, G.seq_no #define GTID_MAX_STR_LENGTH (10+1+10+1+20) struct rpl_gtid { uint32 domain_id; uint32 server_id; uint64 seq_no; }; inline bool operator==(const rpl_gtid& lhs, const rpl_gtid& rhs) { return lhs.domain_id == rhs.domain_id && lhs.server_id == rhs.server_id && lhs.seq_no == rhs.seq_no; }; enum enum_gtid_skip_type { GTID_SKIP_NOT, GTID_SKIP_STANDALONE, GTID_SKIP_TRANSACTION }; /* Structure to keep track of threads waiting in MASTER_GTID_WAIT(). Since replication is (mostly) single-threaded, we want to minimise the performance impact on that from MASTER_GTID_WAIT(). To achieve this, we are careful to keep the common lock between replication threads and MASTER_GTID_WAIT threads held for as short as possible. We keep only a single thread waiting to be notified by the replication threads; this thread then handles all the (potentially heavy) lifting of dealing with all current waiting threads. */ struct gtid_waiting { /* Elements in the hash, basically a priority queue for each domain. */ struct hash_element { QUEUE queue; uint32 domain_id; }; /* A priority queue to handle waiters in one domain in seq_no order. */ struct queue_element { uint64 wait_seq_no; THD *thd; int queue_idx; /* do_small_wait is true if we have responsibility for ensuring that there is a small waiter. */ bool do_small_wait; /* The flag `done' is set when the wait is completed (either due to reaching the position waited for, or due to timeout or kill). The queue_element is in the queue if and only if `done' is true. */ bool done; }; mysql_mutex_t LOCK_gtid_waiting; HASH hash; void init(); void destroy(); hash_element *get_entry(uint32 domain_id); int wait_for_pos(THD *thd, String *gtid_str, longlong timeout_us); void promote_new_waiter(gtid_waiting::hash_element *he); int wait_for_gtid(THD *thd, rpl_gtid *wait_gtid, struct timespec *wait_until); void process_wait_hash(uint64 wakeup_seq_no, gtid_waiting::hash_element *he); int register_in_wait_queue(THD *thd, rpl_gtid *wait_gtid, hash_element *he, queue_element *elem); void remove_from_wait_queue(hash_element *he, queue_element *elem); }; class Relay_log_info; struct rpl_group_info; class Gtid_list_log_event; /* Replication slave state. For every independent replication stream (identified by domain_id), this remembers the last gtid applied on the slave within this domain. Since events are always committed in-order within a single domain, this is sufficient to maintain the state of the replication slave. */ struct rpl_slave_state { /* Elements in the list of GTIDs kept for each domain_id. */ struct list_element { struct list_element *next; uint64 sub_id; uint32 domain_id; uint32 server_id; uint64 seq_no; /* hton of mysql.gtid_slave_pos* table used to record this GTID. Can be NULL if the gtid table failed to load (eg. missing mysql.gtid_slave_pos table following an upgrade). */ void *hton; }; /* Elements in the HASH that hold the state for one domain_id. */ struct element { struct list_element *list; uint32 domain_id; /* Highest seq_no seen so far in this domain. */ uint64 highest_seq_no; /* If this is non-NULL, then it is the waiter responsible for the small wait in MASTER_GTID_WAIT(). */ gtid_waiting::queue_element *gtid_waiter; /* If gtid_waiter is non-NULL, then this is the seq_no that its MASTER_GTID_WAIT() is waiting on. When we reach this seq_no, we need to signal the waiter on COND_wait_gtid. */ uint64 min_wait_seq_no; mysql_cond_t COND_wait_gtid; /* For --gtid-ignore-duplicates. The Relay_log_info that currently owns this domain, and the number of worker threads that are active in it. The idea is that only one of multiple master connections is allowed to actively apply events for a given domain. Other connections must either discard the events (if the seq_no in GTID shows they have already been applied), or wait to see if the current owner will apply it. */ const Relay_log_info *owner_rli; uint32 owner_count; mysql_cond_t COND_gtid_ignore_duplicates; list_element *grab_list() { list_element *l= list; list= NULL; return l; } void add(list_element *l) { l->next= list; list= l; } }; /* Descriptor for mysql.gtid_slave_posXXX table in specific engine. */ enum gtid_pos_table_state { GTID_POS_AUTO_CREATE, GTID_POS_CREATE_REQUESTED, GTID_POS_CREATE_IN_PROGRESS, GTID_POS_AVAILABLE }; struct gtid_pos_table { struct gtid_pos_table *next; /* Use a void * here, rather than handlerton *, to make explicit that we are not using the value to access any functionality in the engine. It is just used as an opaque value to identify which engine we are using for each GTID row. */ void *table_hton; LEX_CSTRING table_name; uint8 state; }; /* Mapping from domain_id to its element. */ HASH hash; /* GTIDs added since last purge of old mysql.gtid_slave_pos rows. */ uint32 pending_gtid_count; /* Mutex protecting access to the state. */ mysql_mutex_t LOCK_slave_state; /* Auxiliary buffer to sort gtid list. */ DYNAMIC_ARRAY gtid_sort_array; uint64 last_sub_id; /* List of tables available for durably storing the slave GTID position. Accesses to this table is protected by LOCK_slave_state. However for efficiency, there is also a provision for read access to it from a running slave without lock. An element can be added at the head of a list by storing the new gtid_pos_tables pointer atomically with release semantics, to ensure that the next pointer of the new element is visible to readers of the new list. Other changes (like deleting or replacing elements) must happen only while all SQL driver threads are stopped. LOCK_slave_state must be held in any case. The list can be read without lock by an SQL driver thread or worker thread by reading the gtid_pos_tables pointer atomically with acquire semantics, to ensure that it will see the correct next pointer of a new head element. */ std::atomic gtid_pos_tables; /* The default entry in gtid_pos_tables, mysql.gtid_slave_pos. */ std::atomic default_gtid_pos_table; bool loaded; rpl_slave_state(); ~rpl_slave_state(); void truncate_hash(); ulong count() const { return hash.records; } int update(uint32 domain_id, uint32 server_id, uint64 sub_id, uint64 seq_no, void *hton, rpl_group_info *rgi); int update_nolock(uint32 domain_id, uint32 server_id, uint64 sub_id, uint64 seq_no, void *hton, rpl_group_info *rgi); int truncate_state_table(THD *thd); void select_gtid_pos_table(THD *thd, LEX_CSTRING *out_tablename); int record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, bool in_transaction, bool in_statement, void **out_hton); list_element *gtid_grab_pending_delete_list(); LEX_CSTRING *select_gtid_pos_table(void *hton); void gtid_delete_pending(THD *thd, rpl_slave_state::list_element **list_ptr); uint64 next_sub_id(uint32 domain_id); int iterate(int (*cb)(rpl_gtid *, void *), void *data, rpl_gtid *extra_gtids, uint32 num_extra, bool sort); int tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra); bool domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid); int load(THD *thd, const char *state_from_master, size_t len, bool reset, bool in_statement); bool is_empty(); element *get_element(uint32 domain_id); int put_back_list(list_element *list); void update_state_hash(uint64 sub_id, rpl_gtid *gtid, void *hton, rpl_group_info *rgi); int record_and_update_gtid(THD *thd, struct rpl_group_info *rgi); int check_duplicate_gtid(rpl_gtid *gtid, rpl_group_info *rgi); void release_domain_owner(rpl_group_info *rgi); void set_gtid_pos_tables_list(gtid_pos_table *new_list, gtid_pos_table *default_entry); void add_gtid_pos_table(gtid_pos_table *entry); struct gtid_pos_table *alloc_gtid_pos_table(LEX_CSTRING *table_name, void *hton, rpl_slave_state::gtid_pos_table_state state); void free_gtid_pos_tables(struct gtid_pos_table *list); }; /* Binlog state. This keeps the last GTID written to the binlog for every distinct (domain_id, server_id) pair. This will be logged at the start of the next binlog file as a Gtid_list_log_event; this way, it is easy to find the binlog file containing a given GTID, by simply scanning backwards from the newest one until a lower seq_no is found in the Gtid_list_log_event at the start of a binlog for the given domain_id and server_id. We also remember the last logged GTID for every domain_id. This is used to know where to start when a master is changed to a slave. As a side effect, it also allows to skip a hash lookup in the very common case of logging a new GTID with same server id as last GTID. */ struct rpl_binlog_state { struct element { uint32 domain_id; HASH hash; /* Containing all server_id for one domain_id */ /* The most recent entry in the hash. */ rpl_gtid *last_gtid; /* Counter to allocate next seq_no for this domain. */ uint64 seq_no_counter; int update_element(const rpl_gtid *gtid); }; /* Mapping from domain_id to collection of elements. */ HASH hash; /* Mutex protecting access to the state. */ mysql_mutex_t LOCK_binlog_state; my_bool initialized; /* Auxiliary buffer to sort gtid list. */ DYNAMIC_ARRAY gtid_sort_array; rpl_binlog_state() :initialized(0) {} ~rpl_binlog_state(); void init(); void reset_nolock(); void reset(); void free(); bool load(struct rpl_gtid *list, uint32 count); bool load(rpl_slave_state *slave_pos); int update_nolock(const struct rpl_gtid *gtid, bool strict); int update(const struct rpl_gtid *gtid, bool strict); int update_with_next_gtid(uint32 domain_id, uint32 server_id, rpl_gtid *gtid); int alloc_element_nolock(const rpl_gtid *gtid); bool check_strict_sequence(uint32 domain_id, uint32 server_id, uint64 seq_no, bool no_error= false); int bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no); int write_to_iocache(IO_CACHE *dest); int read_from_iocache(IO_CACHE *src); uint32 count(); int get_gtid_list(rpl_gtid *gtid_list, uint32 list_size); int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size); bool append_pos(String *str); bool append_state(String *str); rpl_gtid *find_nolock(uint32 domain_id, uint32 server_id); rpl_gtid *find(uint32 domain_id, uint32 server_id); rpl_gtid *find_most_recent(uint32 domain_id); const char* drop_domain(DYNAMIC_ARRAY *ids, Gtid_list_log_event *glev, char*); }; /* Represent the GTID state that a slave connection to a master requests the master to start sending binlog events from. */ struct slave_connection_state { struct entry { rpl_gtid gtid; uint32 flags; }; /* Bits for 'flags' */ enum start_flags { START_OWN_SLAVE_POS= 0x1, START_ON_EMPTY_DOMAIN= 0x2 }; /* Mapping from domain_id to the entry with GTID requested for that domain. */ HASH hash; /* Auxiliary buffer to sort gtid list. */ DYNAMIC_ARRAY gtid_sort_array; slave_connection_state(); ~slave_connection_state(); void reset() { my_hash_reset(&hash); } int load(const char *slave_request, size_t len); int load(const rpl_gtid *gtid_list, uint32 count); int load(rpl_slave_state *state, rpl_gtid *extra_gtids, uint32 num_extra); rpl_gtid *find(uint32 domain_id); entry *find_entry(uint32 domain_id); int update(const rpl_gtid *in_gtid); void remove(const rpl_gtid *gtid); void remove_if_present(const rpl_gtid *in_gtid); ulong count() const { return hash.records; } int to_string(String *out_str); int append_to_string(String *out_str); int get_gtid_list(rpl_gtid *gtid_list, uint32 list_size); bool is_pos_reached(); }; extern bool rpl_slave_state_tostring_helper(String *dest, const rpl_gtid *gtid, bool *first); extern int gtid_check_rpl_slave_state_table(TABLE *table); extern rpl_gtid *gtid_parse_string_to_list(const char *p, size_t len, uint32 *out_len); #endif /* RPL_GTID_H */ server/private/my_stacktrace.h000064400000006217151031265050012532 0ustar00/* Copyright (c) 2001, 2011, Oracle and/or its affiliates. Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_stacktrace_h_ #define _my_stacktrace_h_ #ifdef TARGET_OS_LINUX #if defined (__x86_64__) || defined (__i386__) || \ (defined(__alpha__) && defined(__GNUC__)) #define HAVE_STACKTRACE 1 #endif #elif defined(_WIN32) || defined(HAVE_PRINTSTACK) #define HAVE_STACKTRACE 1 #endif #if HAVE_BACKTRACE && (HAVE_BACKTRACE_SYMBOLS || HAVE_BACKTRACE_SYMBOLS_FD) #undef HAVE_STACKTRACE #define HAVE_STACKTRACE 1 #endif #define HAVE_WRITE_CORE #if HAVE_BACKTRACE && HAVE_BACKTRACE_SYMBOLS && HAVE_ABI_CXA_DEMANGLE && \ HAVE_WEAK_SYMBOL #define BACKTRACE_DEMANGLE 1 #endif C_MODE_START #if defined(HAVE_STACKTRACE) || defined(HAVE_BACKTRACE) void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack, my_bool silent); int my_safe_print_str(const char* val, size_t max_len); void my_write_core(int sig); # if BACKTRACE_DEMANGLE char *my_demangle(const char *mangled_name, int *status); # endif /* BACKTRACE_DEMANGLE */ # ifdef _WIN32 # define my_setup_stacktrace() void my_set_exception_pointers(EXCEPTION_POINTERS *ep); # else void my_setup_stacktrace(void); # endif /* _WIN32 */ #else # define my_setup_stacktrace() #endif /* ! (defined(HAVE_STACKTRACE) || defined(HAVE_BACKTRACE)) */ #ifndef _WIN32 #define MY_ADDR_RESOLVE_FORK #endif #if defined(HAVE_BFD_H) || defined(MY_ADDR_RESOLVE_FORK) #define HAVE_MY_ADDR_RESOLVE 1 #endif typedef struct { const char *file; const char *func; uint line; } my_addr_loc; #ifdef HAVE_MY_ADDR_RESOLVE int my_addr_resolve(void *ptr, my_addr_loc *loc); const char *my_addr_resolve_init(); #else #define my_addr_resolve_init() (0) #define my_addr_resolve(A,B) (1) #endif #ifdef HAVE_WRITE_CORE void my_write_core(int sig); #endif /** A (very) limited version of snprintf, which writes the result to STDERR. @sa my_safe_snprintf Implemented with simplicity, and async-signal-safety in mind. @note Has an internal buffer capacity of 512 bytes, which should suffice for our signal handling routines. */ size_t my_safe_printf_stderr(const char* fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); /** Writes up to count bytes from buffer to STDERR. Implemented with simplicity, and async-signal-safety in mind. @param buf Buffer containing data to be written. @param count Number of bytes to write. @returns Number of bytes written. */ size_t my_write_stderr(const void *buf, size_t count); C_MODE_END #endif /* _my_stacktrace_h_ */ server/private/sql_lex.h000064400000521004151031265050011344 0ustar00/* Copyright (c) 2000, 2019, Oracle and/or its affiliates. Copyright (c) 2010, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @defgroup Semantic_Analysis Semantic Analysis */ #ifndef SQL_LEX_INCLUDED #define SQL_LEX_INCLUDED #include "violite.h" /* SSL_type */ #include "sql_trigger.h" #include "thr_lock.h" /* thr_lock_type, TL_UNLOCK */ #include "mem_root_array.h" #include "grant.h" #include "sql_cmd.h" #include "sql_alter.h" // Alter_info #include "sql_window.h" #include "sql_trigger.h" #include "sp.h" // enum enum_sp_type #include "sql_tvc.h" #include "item.h" #include "sql_limit.h" // Select_limit_counters #include "json_table.h" // Json_table_column #include "sql_schema.h" #include "table.h" /* Used for flags of nesting constructs */ #define SELECT_NESTING_MAP_SIZE 64 typedef Bitmap nesting_map; /* YACC and LEX Definitions */ /** A string with metadata. Usually points to a string in the client character set, but unlike Lex_ident_cli_st (see below) it does not necessarily point to a query fragment. It can also point to memory of other kinds (e.g. an additional THD allocated memory buffer not overlapping with the current query text). We'll add more flags here eventually, to know if the string has, e.g.: - multi-byte characters - bad byte sequences - backslash escapes: 'a\nb' and reuse the original query fragments instead of making the string copy too early, in Lex_input_stream::get_text(). This will allow to avoid unnecessary copying, as well as create more optimal Item types in sql_yacc.yy */ struct Lex_string_with_metadata_st: public LEX_CSTRING { private: bool m_is_8bit; // True if the string has 8bit characters char m_quote; // Quote character, or 0 if not quoted public: void set_8bit(bool is_8bit) { m_is_8bit= is_8bit; } void set_metadata(bool is_8bit, char quote) { m_is_8bit= is_8bit; m_quote= quote; } void set(const char *s, size_t len, bool is_8bit, char quote) { str= s; length= len; set_metadata(is_8bit, quote); } void set(const LEX_CSTRING *s, bool is_8bit, char quote) { ((LEX_CSTRING &)*this)= *s; set_metadata(is_8bit, quote); } bool is_8bit() const { return m_is_8bit; } bool is_quoted() const { return m_quote != '\0'; } char quote() const { return m_quote; } // Get string repertoire by the 8-bit flag and the character set my_repertoire_t repertoire(CHARSET_INFO *cs) const { return !m_is_8bit && my_charset_is_ascii_based(cs) ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30; } // Get string repertoire by the 8-bit flag, for ASCII-based character sets my_repertoire_t repertoire() const { return !m_is_8bit ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30; } }; /* Used to store identifiers in the client character set. Points to a query fragment. */ struct Lex_ident_cli_st: public Lex_string_with_metadata_st { public: void set_keyword(const char *s, size_t len) { set(s, len, false, '\0'); } void set_ident(const char *s, size_t len, bool is_8bit) { set(s, len, is_8bit, '\0'); } void set_ident_quoted(const char *s, size_t len, bool is_8bit, char quote) { set(s, len, is_8bit, quote); } void set_unquoted(const LEX_CSTRING *s, bool is_8bit) { set(s, is_8bit, '\0'); } const char *pos() const { return str - is_quoted(); } const char *end() const { return str + length + is_quoted(); } }; class Lex_ident_cli: public Lex_ident_cli_st { public: Lex_ident_cli(const LEX_CSTRING *s, bool is_8bit) { set_unquoted(s, is_8bit); } Lex_ident_cli(const char *s, size_t len) { set_ident(s, len, false); } }; struct Lex_ident_sys_st: public LEX_CSTRING { public: static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return alloc_root(mem_root, size); } static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} bool copy_ident_cli(THD *thd, const Lex_ident_cli_st *str); bool copy_keyword(THD *thd, const Lex_ident_cli_st *str); bool copy_sys(THD *thd, const LEX_CSTRING *str); bool convert(THD *thd, const LEX_CSTRING *str, CHARSET_INFO *cs); bool copy_or_convert(THD *thd, const Lex_ident_cli_st *str, CHARSET_INFO *cs); bool is_null() const { return str == NULL; } bool to_size_number(ulonglong *to) const; void set_valid_utf8(const LEX_CSTRING *name) { DBUG_ASSERT(Well_formed_prefix(system_charset_info, name->str, name->length).length() == name->length); str= name->str ; length= name->length; } }; class Lex_ident_sys: public Lex_ident_sys_st { public: Lex_ident_sys(THD *thd, const Lex_ident_cli_st *str) { if (copy_ident_cli(thd, str)) ((LEX_CSTRING &) *this)= null_clex_str; } Lex_ident_sys() { ((LEX_CSTRING &) *this)= null_clex_str; } Lex_ident_sys(const char *name, size_t length) { LEX_CSTRING tmp= {name, length}; set_valid_utf8(&tmp); } Lex_ident_sys(THD *thd, const LEX_CSTRING *str) { set_valid_utf8(str); } Lex_ident_sys & operator=(const Lex_ident_sys_st &name) { Lex_ident_sys_st::operator=(name); return *this; } }; struct Lex_column_list_privilege_st { List *m_columns; privilege_t m_privilege; }; class Lex_column_list_privilege: public Lex_column_list_privilege_st { public: Lex_column_list_privilege(List *columns, privilege_t privilege) { m_columns= columns; m_privilege= privilege; } }; /** ORDER BY ... LIMIT parameters; */ class Lex_order_limit_lock: public Sql_alloc { public: SQL_I_List *order_list; /* ORDER clause */ Lex_select_lock lock; Lex_select_limit limit; Lex_order_limit_lock() :order_list(NULL) {} bool set_to(st_select_lex *sel); }; enum sub_select_type { UNSPECIFIED_TYPE, /* following 3 enums should be as they are*/ UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE, OLAP_TYPE }; enum set_op_type { UNSPECIFIED, UNION_DISTINCT, UNION_ALL, EXCEPT_DISTINCT, EXCEPT_ALL, INTERSECT_DISTINCT, INTERSECT_ALL }; inline int cmp_unit_op(enum sub_select_type op1, enum sub_select_type op2) { DBUG_ASSERT(op1 >= UNION_TYPE && op1 <= EXCEPT_TYPE); DBUG_ASSERT(op2 >= UNION_TYPE && op2 <= EXCEPT_TYPE); return (op1 == INTERSECT_TYPE ? 1 : 0) - (op2 == INTERSECT_TYPE ? 1 : 0); } enum unit_common_op {OP_MIX, OP_UNION, OP_INTERSECT, OP_EXCEPT}; enum enum_view_suid { VIEW_SUID_INVOKER= 0, VIEW_SUID_DEFINER= 1, VIEW_SUID_DEFAULT= 2 }; enum plsql_cursor_attr_t { PLSQL_CURSOR_ATTR_ISOPEN, PLSQL_CURSOR_ATTR_FOUND, PLSQL_CURSOR_ATTR_NOTFOUND, PLSQL_CURSOR_ATTR_ROWCOUNT }; enum enum_sp_suid_behaviour { SP_IS_DEFAULT_SUID= 0, SP_IS_NOT_SUID, SP_IS_SUID }; enum enum_sp_aggregate_type { DEFAULT_AGGREGATE= 0, NOT_AGGREGATE, GROUP_AGGREGATE }; /* These may not be declared yet */ class Table_ident; class sql_exchange; class LEX_COLUMN; class sp_head; class sp_name; class sp_instr; class sp_pcontext; class sp_variable; class sp_expr_lex; class sp_assignment_lex; class st_alter_tablespace; class partition_info; class Event_parse_data; class set_var_base; class sys_var; class Item_func_match; class File_parser; class Key_part_spec; class Item_window_func; struct sql_digest_state; class With_clause; class my_var; class select_handler; class Pushdown_select; #define ALLOC_ROOT_SET 1024 #ifdef MYSQL_SERVER /* There are 8 different type of table access so there is no more than combinations 2^8 = 256: . STMT_READS_TRANS_TABLE . STMT_READS_NON_TRANS_TABLE . STMT_READS_TEMP_TRANS_TABLE . STMT_READS_TEMP_NON_TRANS_TABLE . STMT_WRITES_TRANS_TABLE . STMT_WRITES_NON_TRANS_TABLE . STMT_WRITES_TEMP_TRANS_TABLE . STMT_WRITES_TEMP_NON_TRANS_TABLE The unsafe conditions for each combination is represented within a byte and stores the status of the option --binlog-direct-non-trans-updates, whether the trx-cache is empty or not, and whether the isolation level is lower than ISO_REPEATABLE_READ: . option (OFF/ON) . trx-cache (empty/not empty) . isolation (>= ISO_REPEATABLE_READ / < ISO_REPEATABLE_READ) bits 0 : . OFF, . empty, . >= ISO_REPEATABLE_READ bits 1 : . OFF, . empty, . < ISO_REPEATABLE_READ bits 2 : . OFF, . not empty, . >= ISO_REPEATABLE_READ bits 3 : . OFF, . not empty, . < ISO_REPEATABLE_READ bits 4 : . ON, . empty, . >= ISO_REPEATABLE_READ bits 5 : . ON, . empty, . < ISO_REPEATABLE_READ bits 6 : . ON, . not empty, . >= ISO_REPEATABLE_READ bits 7 : . ON, . not empty, . < ISO_REPEATABLE_READ */ extern uint binlog_unsafe_map[256]; /* Initializes the array with unsafe combinations and its respective conditions. */ void binlog_unsafe_map_init(); #endif #ifdef MYSQL_SERVER /* The following hack is needed because yy_*.cc do not define YYSTYPE before including this file */ #ifdef MYSQL_YACC #define LEX_YYSTYPE void * #else #include "lex_symbol.h" #ifdef MYSQL_LEX #include "item_func.h" /* Cast_target used in yy_mariadb.hh */ #include "sql_get_diagnostics.h" /* Types used in yy_mariadb.hh */ #include "sp_pcontext.h" #include "yy_mariadb.hh" #define LEX_YYSTYPE YYSTYPE * #else #define LEX_YYSTYPE void * #endif #endif #endif // describe/explain types #define DESCRIBE_NORMAL 1 #define DESCRIBE_EXTENDED 2 /* This is not within #ifdef because we want "EXPLAIN PARTITIONS ..." to produce additional "partitions" column even if partitioning is not compiled in. */ #define DESCRIBE_PARTITIONS 4 #define DESCRIBE_EXTENDED2 8 #ifdef MYSQL_SERVER extern const LEX_STRING empty_lex_str; extern const LEX_CSTRING empty_clex_str; extern const LEX_CSTRING star_clex_str; extern const LEX_CSTRING param_clex_str; enum enum_sp_data_access { SP_DEFAULT_ACCESS= 0, SP_CONTAINS_SQL, SP_NO_SQL, SP_READS_SQL_DATA, SP_MODIFIES_SQL_DATA }; const LEX_CSTRING sp_data_access_name[]= { { STRING_WITH_LEN("") }, { STRING_WITH_LEN("CONTAINS SQL") }, { STRING_WITH_LEN("NO SQL") }, { STRING_WITH_LEN("READS SQL DATA") }, { STRING_WITH_LEN("MODIFIES SQL DATA") } }; #define DERIVED_SUBQUERY 1 #define DERIVED_VIEW 2 #define DERIVED_WITH 4 enum enum_view_create_mode { VIEW_CREATE_NEW, // check that there are not such VIEW/table VIEW_ALTER, // check that VIEW .frm with such name exists VIEW_CREATE_OR_REPLACE // check only that there are not such table }; class Create_view_info: public Sql_alloc { public: LEX_CSTRING select; // The SELECT statement of CREATE VIEW enum enum_view_create_mode mode; uint16 algorithm; uint8 check; enum enum_view_suid suid; Create_view_info(enum_view_create_mode mode_arg, uint16 algorithm_arg, enum_view_suid suid_arg) :select(null_clex_str), mode(mode_arg), algorithm(algorithm_arg), check(VIEW_CHECK_NONE), suid(suid_arg) { } }; enum enum_drop_mode { DROP_DEFAULT, // mode is not specified DROP_CASCADE, // CASCADE option DROP_RESTRICT // RESTRICT option }; /* Options to add_table_to_list() */ #define TL_OPTION_UPDATING 1 #define TL_OPTION_FORCE_INDEX 2 #define TL_OPTION_IGNORE_LEAVES 4 #define TL_OPTION_ALIAS 8 #define TL_OPTION_SEQUENCE 16 #define TL_OPTION_TABLE_FUNCTION 32 typedef List List_item; typedef Mem_root_array Group_list_ptrs; /* SERVERS CACHE CHANGES */ typedef struct st_lex_server_options { long port; LEX_CSTRING server_name, host, db, username, password, scheme, socket, owner; void reset(LEX_CSTRING name) { server_name= name; host= db= username= password= scheme= socket= owner= null_clex_str; port= -1; } } LEX_SERVER_OPTIONS; /** Structure to hold parameters for CHANGE MASTER, START SLAVE, and STOP SLAVE. Remark: this should not be confused with Master_info (and perhaps would better be renamed to st_lex_replication_info). Some fields, e.g., delay, are saved in Relay_log_info, not in Master_info. */ struct LEX_MASTER_INFO { DYNAMIC_ARRAY repl_ignore_server_ids; DYNAMIC_ARRAY repl_do_domain_ids; DYNAMIC_ARRAY repl_ignore_domain_ids; const char *host, *user, *password, *log_file_name; const char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher; const char *ssl_crl, *ssl_crlpath; const char *relay_log_name; LEX_CSTRING connection_name; /* Value in START SLAVE UNTIL master_gtid_pos=xxx */ LEX_CSTRING gtid_pos_str; ulonglong pos; ulong relay_log_pos; ulong server_id; uint port, connect_retry; float heartbeat_period; int sql_delay; /* Enum is used for making it possible to detect if the user changed variable or if it should be left at old value */ enum {LEX_MI_UNCHANGED= 0, LEX_MI_DISABLE, LEX_MI_ENABLE} ssl, ssl_verify_server_cert, heartbeat_opt, repl_ignore_server_ids_opt, repl_do_domain_ids_opt, repl_ignore_domain_ids_opt; enum { LEX_GTID_UNCHANGED, LEX_GTID_NO, LEX_GTID_CURRENT_POS, LEX_GTID_SLAVE_POS } use_gtid_opt; void init() { bzero(this, sizeof(*this)); my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_ignore_server_ids, sizeof(::server_id), 0, 16, MYF(0)); my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_do_domain_ids, sizeof(ulong), 0, 16, MYF(0)); my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_ignore_domain_ids, sizeof(ulong), 0, 16, MYF(0)); sql_delay= -1; } void reset(bool is_change_master) { if (unlikely(is_change_master)) { delete_dynamic(&repl_ignore_server_ids); /* Free all the array elements. */ delete_dynamic(&repl_do_domain_ids); delete_dynamic(&repl_ignore_domain_ids); } host= user= password= log_file_name= ssl_key= ssl_cert= ssl_ca= ssl_capath= ssl_cipher= ssl_crl= ssl_crlpath= relay_log_name= NULL; pos= relay_log_pos= server_id= port= connect_retry= 0; heartbeat_period= 0; ssl= ssl_verify_server_cert= heartbeat_opt= repl_ignore_server_ids_opt= repl_do_domain_ids_opt= repl_ignore_domain_ids_opt= LEX_MI_UNCHANGED; gtid_pos_str= null_clex_str; use_gtid_opt= LEX_GTID_UNCHANGED; sql_delay= -1; } }; typedef struct st_lex_reset_slave { bool all; } LEX_RESET_SLAVE; enum olap_type { UNSPECIFIED_OLAP_TYPE, CUBE_TYPE, ROLLUP_TYPE }; /* String names used to print a statement with index hints. Keep in sync with index_hint_type. */ extern const char * index_hint_type_name[]; typedef uchar index_clause_map; /* Bits in index_clause_map : one for each possible FOR clause in USE/FORCE/IGNORE INDEX index hint specification */ #define INDEX_HINT_MASK_JOIN (1) #define INDEX_HINT_MASK_GROUP (1 << 1) #define INDEX_HINT_MASK_ORDER (1 << 2) #define INDEX_HINT_MASK_ALL (INDEX_HINT_MASK_JOIN | INDEX_HINT_MASK_GROUP | \ INDEX_HINT_MASK_ORDER) class select_result_sink; /* Single element of an USE/FORCE/IGNORE INDEX list specified as a SQL hint */ class Index_hint : public Sql_alloc { public: /* The type of the hint : USE/FORCE/IGNORE */ enum index_hint_type type; /* Where the hit applies to. A bitmask of INDEX_HINT_MASK_ values */ index_clause_map clause; /* The index name. Empty (str=NULL) name represents an empty list USE INDEX () clause */ LEX_CSTRING key_name; Index_hint (enum index_hint_type type_arg, index_clause_map clause_arg, const char *str, size_t length) : type(type_arg), clause(clause_arg) { key_name.str= str; key_name.length= length; } void print(THD *thd, String *str); }; /* The state of the lex parsing for selects master and slaves are pointers to select_lex. master is pointer to upper level node. slave is pointer to lower level node select_lex is a SELECT without union unit is container of either - One SELECT - UNION of selects select_lex and unit are both inherited form st_select_lex_node neighbors are two select_lex or units on the same level All select describing structures linked with following pointers: - list of neighbors (next/prev) (prev of first element point to slave pointer of upper structure) - For select this is a list of UNION's (or one element list) - For units this is a list of sub queries for the upper level select - pointer to master (master), which is If this is a unit - pointer to outer select_lex If this is a select_lex - pointer to outer unit structure for select - pointer to slave (slave), which is either: If this is a unit: - first SELECT that belong to this unit If this is a select_lex - first unit that belong to this SELECT (subquries or derived tables) - list of all select_lex (link_next/link_prev) This is to be used for things like derived tables creation, where we go through this list and create the derived tables. If unit contain several selects (UNION now, INTERSECT etc later) then it have special select_lex called fake_select_lex. It used for storing global parameters (like ORDER BY, LIMIT) and executing union. Subqueries used in global ORDER BY clause will be attached to this fake_select_lex, which will allow them correctly resolve fields of 'upper' UNION and outer selects. For example for following query: select * from table1 where table1.field IN (select * from table1_1_1 union select * from table1_1_2) union select * from table2 where table2.field=(select (select f1 from table2_1_1_1_1 where table2_1_1_1_1.f2=table2_1_1.f3) from table2_1_1 where table2_1_1.f1=table2.f2) union select * from table3; we will have following structure: select1: (select * from table1 ...) select2: (select * from table2 ...) select3: (select * from table3) select1.1.1: (select * from table1_1_1) ... main unit fake0 select1 select2 select3 |^^ |^ s||| ||master l||| |+---------------------------------+ a||| +---------------------------------+| v|||master slave || e||+-------------------------+ || V| neighbor | V| unit1.1<+==================>unit1.2 unit2.1 fake1.1 select1.1.1 select 1.1.2 select1.2.1 select2.1.1 |^ || V| unit2.1.1.1 select2.1.1.1.1 relation in main unit will be following: (bigger picture for: main unit fake0 select1 select2 select3 in the above picture) main unit |^^^^|fake_select_lex |||||+--------------------------------------------+ ||||+--------------------------------------------+| |||+------------------------------+ || ||+--------------+ | || slave||master | | || V| neighbor | neighbor | master|V select1<========>select2<========>select3 fake0 list of all select_lex will be following (as it will be constructed by parser): select1->select2->select3->select2.1.1->select 2.1.2->select2.1.1.1.1-+ | +---------------------------------------------------------------------+ | +->select1.1.1->select1.1.2 */ /* Base class for st_select_lex (SELECT_LEX) & st_select_lex_unit (SELECT_LEX_UNIT) */ struct LEX; class st_select_lex; class st_select_lex_unit; class st_select_lex_node { protected: st_select_lex_node *next, **prev, /* neighbor list */ *master, *slave, /* vertical links */ *link_next, **link_prev; /* list of whole SELECT_LEX */ enum sub_select_type linkage; void init_query_common(); public: ulonglong options; uint8 uncacheable; bool distinct:1; bool no_table_names_allowed:1; /* used for global order by */ /* result of this query can't be cached, bit field, can be : UNCACHEABLE_DEPENDENT_GENERATED UNCACHEABLE_DEPENDENT_INJECTED UNCACHEABLE_RAND UNCACHEABLE_SIDEEFFECT UNCACHEABLE_EXPLAIN UNCACHEABLE_PREPARE */ bool is_linkage_set() const { return linkage == UNION_TYPE || linkage == INTERSECT_TYPE || linkage == EXCEPT_TYPE; } enum sub_select_type get_linkage() { return linkage; } static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return (void*) alloc_root(mem_root, (uint) size); } static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} // Ensures that at least all members used during cleanup() are initialized. st_select_lex_node() : next(NULL), prev(NULL), master(NULL), slave(NULL), link_next(NULL), link_prev(NULL), linkage(UNSPECIFIED_TYPE) { } inline st_select_lex_node* get_master() { return master; } void include_down(st_select_lex_node *upper); void attach_single(st_select_lex_node *slave_arg); void include_neighbour(st_select_lex_node *before); void link_chain_down(st_select_lex_node *first); void link_neighbour(st_select_lex_node *neighbour) { DBUG_ASSERT(next == NULL); DBUG_ASSERT(neighbour != NULL); next= neighbour; neighbour->prev= &next; } void cut_next() { next= NULL; } void include_standalone(st_select_lex_node *sel, st_select_lex_node **ref); void include_global(st_select_lex_node **plink); void exclude(); void exclude_from_tree(); void exclude_from_global() { if (!link_prev) return; if (((*link_prev)= link_next)) link_next->link_prev= link_prev; link_next= NULL; link_prev= NULL; } void substitute_in_tree(st_select_lex_node *subst); void set_slave(st_select_lex_node *slave_arg) { slave= slave_arg; } void move_node(st_select_lex_node *where_to_move) { if (where_to_move == this) return; if (next) next->prev= prev; *prev= next; *where_to_move->prev= this; next= where_to_move; } st_select_lex_node *insert_chain_before(st_select_lex_node **ptr_pos_to_insert, st_select_lex_node *end_chain_node); void move_as_slave(st_select_lex_node *new_master); void set_linkage(enum sub_select_type l) { DBUG_ENTER("st_select_lex_node::set_linkage"); DBUG_PRINT("info", ("node: %p linkage: %d->%d", this, linkage, l)); linkage= l; DBUG_VOID_RETURN; } /* This method created for reiniting LEX in mysql_admin_table() and can be used only if you are going remove all SELECT_LEX & units except belonger to LEX (LEX::unit & LEX::select, for other purposes there are SELECT_LEX_UNIT::exclude_level & SELECT_LEX_UNIT::exclude_tree. It is also used in parsing to detach builtin select. */ void cut_subtree() { slave= 0; } friend class st_select_lex_unit; friend bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel); friend bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, bool open_view_no_parse); friend class st_select_lex; private: void fast_exclude(); }; typedef class st_select_lex_node SELECT_LEX_NODE; /* SELECT_LEX_UNIT - unit of selects (UNION, INTERSECT, ...) group SELECT_LEXs */ class THD; class select_result; class JOIN; class select_unit; class Procedure; class Explain_query; void delete_explain_query(LEX *lex); void create_explain_query(LEX *lex, MEM_ROOT *mem_root); void create_explain_query_if_not_exists(LEX *lex, MEM_ROOT *mem_root); bool print_explain_for_slow_log(LEX *lex, THD *thd, String *str); class st_select_lex_unit: public st_select_lex_node { protected: TABLE_LIST result_table_list; select_unit *union_result; ulonglong found_rows_for_union; bool prepare_join(THD *thd, SELECT_LEX *sl, select_result *result, ulonglong additional_options, bool is_union_select); bool join_union_type_handlers(THD *thd, class Type_holder *holders, uint count); bool join_union_type_attributes(THD *thd, class Type_holder *holders, uint count); public: bool join_union_item_types(THD *thd, List &types, uint count); // Ensures that at least all members used during cleanup() are initialized. st_select_lex_unit() : union_result(NULL), table(NULL), result(NULL), fake_select_lex(NULL), last_procedure(NULL),cleaned(false), bag_set_op_optimized(false), have_except_all_or_intersect_all(false) { } TABLE *table; /* temporary table using for appending UNION results */ select_result *result; st_select_lex *pre_last_parse; /* Node on which we should return current_select pointer after parsing subquery */ st_select_lex *return_to; /* LIMIT clause runtime counters */ Select_limit_counters lim; /* not NULL if unit used in subselect, point to subselect item */ Item_subselect *item; /* TABLE_LIST representing this union in the embedding select. Used for derived tables/views handling. */ TABLE_LIST *derived; /* With clause attached to this unit (if any) */ With_clause *with_clause; /* With element where this unit is used as the specification (if any) */ With_element *with_element; /* The unit used as a CTE specification from which this unit is cloned */ st_select_lex_unit *cloned_from; /* thread handler */ THD *thd; /* SELECT_LEX for hidden SELECT in union which process global ORDER BY and LIMIT */ st_select_lex *fake_select_lex; /** SELECT_LEX that stores LIMIT and OFFSET for UNION ALL when noq fake_select_lex is used. */ st_select_lex *saved_fake_select_lex; /* pointer to the last node before last subsequence of UNION ALL */ st_select_lex *union_distinct; Procedure *last_procedure; /* Pointer to procedure, if such exists */ // list of fields which points to temporary table for union List item_list; /* list of types of items inside union (used for union & derived tables) Item_type_holders from which this list consist may have pointers to Field, pointers is valid only after preparing SELECTS of this unit and before any SELECT of this unit execution */ List types; bool prepared:1; // prepare phase already performed for UNION (unit) bool optimized:1; // optimize phase already performed for UNION (unit) bool optimized_2:1; bool executed:1; // already executed bool cleaned:1; bool bag_set_op_optimized:1; bool optimize_started:1; bool have_except_all_or_intersect_all:1; /** TRUE if the unit contained TVC at the top level that has been wrapped into SELECT: VALUES (v1) ... (vn) => SELECT * FROM (VALUES (v1) ... (vn)) as tvc */ bool with_wrapped_tvc:1; bool is_view:1; bool describe:1; /* union exec() called for EXPLAIN */ bool columns_are_renamed:1; protected: /* This is bool, not bit, as it's used and set in many places */ bool saved_error; public: /** Pointer to 'last' select, or pointer to select where we stored global parameters for union. If this is a union of multiple selects, the parser puts the global parameters in fake_select_lex. If the union doesn't use a temporary table, st_select_lex_unit::prepare() nulls out fake_select_lex, but saves a copy in saved_fake_select_lex in order to preserve the global parameters. If it is not a union, first_select() is the last select. @return select containing the global parameters */ inline st_select_lex *global_parameters() { if (fake_select_lex != NULL) return fake_select_lex; else if (saved_fake_select_lex != NULL) return saved_fake_select_lex; return first_select(); }; void init_query(); st_select_lex* outer_select(); const st_select_lex* first_select() const { return reinterpret_cast(slave); } st_select_lex* first_select() { return reinterpret_cast(slave); } void set_with_clause(With_clause *with_cl); st_select_lex_unit* next_unit() { return reinterpret_cast(next); } st_select_lex* return_after_parsing() { return return_to; } void exclude_level(); // void exclude_tree(); // it is not used for long time bool is_excluded() { return prev == NULL; } /* UNION methods */ bool prepare(TABLE_LIST *derived_arg, select_result *sel_result, ulonglong additional_options); bool optimize(); void optimize_bag_operation(bool is_outer_distinct); bool exec(); bool exec_recursive(); bool cleanup(); inline void unclean() { cleaned= 0; } void reinit_exec_mechanism(); void print(String *str, enum_query_type query_type); bool add_fake_select_lex(THD *thd); void init_prepare_fake_select_lex(THD *thd, bool first_execution); inline bool is_prepared() { return prepared; } bool change_result(select_result_interceptor *result, select_result_interceptor *old_result); void set_limit(st_select_lex *values); void set_thd(THD *thd_arg) { thd= thd_arg; } inline bool is_unit_op (); bool union_needs_tmp_table(); void set_unique_exclude(); bool check_distinct_in_union(); friend struct LEX; friend int subselect_union_engine::exec(); List *get_column_types(bool for_cursor); select_unit *get_union_result() { return union_result; } int save_union_explain(Explain_query *output); int save_union_explain_part2(Explain_query *output); unit_common_op common_op(); bool explainable() const; void reset_distinct(); void fix_distinct(); void register_select_chain(SELECT_LEX *first_sel); bool set_nest_level(int new_nest_level); bool check_parameters(SELECT_LEX *main_select); bool set_lock_to_the_last_select(Lex_select_lock l); void print_lock_from_the_last_select(String *str); bool can_be_merged(); friend class st_select_lex; }; typedef class st_select_lex_unit SELECT_LEX_UNIT; typedef Bounds_checked_array Ref_ptr_array; /** Structure which consists of the field and the item that corresponds to this field. */ class Field_pair :public Sql_alloc { public: Field *field; Item *corresponding_item; Field_pair(Field *fld, Item *item) :field(fld), corresponding_item(item) {} }; Field_pair *get_corresponding_field_pair(Item *item, List pair_list); Field_pair *find_matching_field_pair(Item *item, List pair_list); #define TOUCHED_SEL_COND 1/* WHERE/HAVING/ON should be reinited before use */ #define TOUCHED_SEL_DERIVED (1<<1)/* derived should be reinited before use */ #define UNIT_NEST_FL 1 /* SELECT_LEX - store information of parsed SELECT statment */ class st_select_lex: public st_select_lex_node { public: /* Currently the field first_nested is used only by parser. It containa either a reference to the first select of the nest of selects to which 'this' belongs to, or in the case of priority jump it contains a reference to the select to which the priority nest has to be attached to. If there is no priority jump then the first select of the nest contains the reference to itself in first_nested. Example: select1 union select2 intersect select Here we have a priority jump at select2. So select2->first_nested points to select1, while select3->first_nested points to select2 and select1->first_nested points to select1. */ Name_resolution_context context; LEX_CSTRING db; /* Point to the LEX in which it was created, used in view subquery detection. TODO: make also st_select_lex::parent_stmt_lex (see LEX::stmt_lex) and use st_select_lex::parent_lex & st_select_lex::parent_stmt_lex instead of global (from THD) references where it is possible. */ LEX *parent_lex; st_select_lex *first_nested; Item *where, *having; /* WHERE & HAVING clauses */ Item *prep_where; /* saved WHERE clause for prepared statement processing */ Item *prep_having;/* saved HAVING clause for prepared statement processing */ Item *cond_pushed_into_where; /* condition pushed into WHERE */ Item *cond_pushed_into_having; /* condition pushed into HAVING */ /* nest_levels are local to the query or VIEW, and that view merge procedure does not re-calculate them. So we also have to remember unit against which we count levels. */ SELECT_LEX_UNIT *nest_level_base; Item_sum *inner_sum_func_list; /* list of sum func in nested selects */ /* This is a copy of the original JOIN USING list that comes from the parser. The parser : 1. Sets the natural_join of the second TABLE_LIST in the join and the st_select_lex::prev_join_using. 2. Makes a parent TABLE_LIST and sets its is_natural_join/ join_using_fields members. 3. Uses the wrapper TABLE_LIST as a table in the upper level. We cannot assign directly to join_using_fields in the parser because at stage (1.) the parent TABLE_LIST is not constructed yet and the assignment will override the JOIN USING fields of the lower level joins on the right. */ List *prev_join_using; JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */ TABLE_LIST *embedding; /* table embedding to the above list */ table_value_constr *tvc; /* The interface employed to execute the select query by a foreign engine */ select_handler *select_h; /* The object used to organize execution of the query by a foreign engine */ select_handler *pushdown_select; List *join_list; /* list for the currently parsed join */ st_select_lex *merged_into; /* select which this select is merged into */ /* (not 0 only for views/derived tables) */ const char *type; /* type of select for EXPLAIN */ /* List of references to fields referenced from inner selects */ List inner_refs_list; List attach_to_conds; /* Saved values of the WHERE and HAVING clauses*/ Item::cond_result cond_value, having_value; /* Usually it is pointer to ftfunc_list_alloc, but in union used to create fake select_lex for calling mysql_select under results of union */ List *ftfunc_list; List ftfunc_list_alloc; /* The list of items to which MIN/MAX optimizations of opt_sum_query() have been applied. Used to rollback those optimizations if it's needed. */ List min_max_opt_list; List top_join_list; /* join list of the top level */ List sj_nests; /* Semi-join nests within this join */ /* Beginning of the list of leaves in a FROM clause, where the leaves inlcude all base tables including view tables. The tables are connected by TABLE_LIST::next_leaf, so leaf_tables points to the left-most leaf. List of all base tables local to a subquery including all view tables. Unlike 'next_local', this in this list views are *not* leaves. Created in setup_tables() -> make_leaves_list(). */ /* Subqueries that will need to be converted to semi-join nests, including those converted to jtbm nests. The list is emptied when conversion is done. */ List sj_subselects; /* List of IN-predicates in this st_select_lex that can be transformed into IN-subselect defined with TVC. */ List in_funcs; /** Flag to guard against double initialization of leaf tables list */ bool leaf_tables_saved; List leaf_tables; List leaf_tables_exec; List leaf_tables_prep; /* current index hint kind. used in filling up index_hints */ enum index_hint_type current_index_hint_type; /* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */ SQL_I_List table_list; /* GROUP BY clause. This list may be mutated during optimization (by remove_const()), so for prepared statements, we keep a copy of the ORDER.next pointers in group_list_ptrs, and re-establish the original list before each execution. */ SQL_I_List group_list; SQL_I_List save_group_list; Group_list_ptrs *group_list_ptrs; List item_list; /* list of fields & expressions */ List pre_fix; /* above list before fix_fields */ List fix_after_optimize; SQL_I_List order_list; /* ORDER clause */ SQL_I_List save_order_list; SQL_I_List gorder_list; Lex_select_limit limit_params; /* LIMIT clause parameters */ /* Structure to store fields that are used in the GROUP BY of this select */ List grouping_tmp_fields; List udf_list; /* udf function calls stack */ List *index_hints; /* list of USE/FORCE/IGNORE INDEX */ /* This list is used to restore the names of items from item_list after each execution of the statement. */ List *orig_names_of_item_list_elems; List save_many_values; List *save_insert_list; bool is_item_list_lookup:1; /* Needed to correctly generate 'PRIMARY' or 'SIMPLE' for select_type column of EXPLAIN */ bool have_merged_subqueries:1; bool is_set_query_expr_tail:1; bool with_sum_func:1; /* sum function indicator */ bool with_rownum:1; /* rownum() function indicator */ bool braces:1; /* SELECT ... UNION (SELECT ... ) <- this braces */ bool automatic_brackets:1; /* dummy select for INTERSECT precedence */ /* TRUE when having fix field called in processing of this SELECT */ bool having_fix_field:1; /* TRUE when fix field is called for a new condition pushed into the HAVING clause of this SELECT */ bool having_fix_field_for_pushed_cond:1; /* there are subquery in HAVING clause => we can't close tables before query processing end even if we use temporary table */ bool subquery_in_having:1; /* TRUE <=> this SELECT is correlated w.r.t. some ancestor select */ bool with_all_modifier:1; /* used for selects in union */ bool is_correlated:1; bool first_natural_join_processing:1; bool first_cond_optimization:1; /** The purpose of this flag is to run initialization phase for rownum only once. This flag is set on at st_select_lex::init_query and reset to the value false after the method optimize_rownum() has been called from the method JOIN::optimize_inner. */ bool first_rownum_optimization:1; /* do not wrap view fields with Item_ref */ bool no_wrap_view_item:1; /* exclude this select from check of unique_table() */ bool exclude_from_table_unique_test:1; bool in_tvc:1; bool skip_locked:1; bool m_non_agg_field_used:1; bool m_agg_func_used:1; bool m_custom_agg_func_used:1; /* the select is "service-select" and can not have tables */ bool is_service_select:1; /// Array of pointers to top elements of all_fields list Ref_ptr_array ref_pointer_array; ulong table_join_options; /* number of items in select_list and HAVING clause used to get number bigger then can be number of entries that will be added to all item list during split_sum_func */ uint select_n_having_items; uint cond_count; /* number of sargable Items in where/having/on */ uint between_count; /* number of between predicates in where/having/on */ uint max_equal_elems; /* max number of elements in multiple equalities */ /* Number of fields used in select list or where clause of current select and all inner subselects. */ uint select_n_where_fields; /* Total number of elements in group by and order by lists */ uint order_group_num; /* reserved for exists 2 in */ uint select_n_reserved; /* it counts the number of bit fields in the SELECT list. These are used when DISTINCT is converted to a GROUP BY involving BIT fields. */ uint hidden_bit_fields; /* Number of fields used in the definition of all the windows functions. This includes: 1) Fields in the arguments 2) Fields in the PARTITION BY clause 3) Fields in the ORDER BY clause */ /* Number of current derived table made with TVC during the transformation of IN-predicate into IN-subquery for this st_select_lex. */ uint curr_tvc_name; /* true <=> select has been created a TVC wrapper */ bool is_tvc_wrapper; uint fields_in_window_functions; uint insert_tables; enum_parsing_place parsing_place; /* where we are parsing expression */ enum_parsing_place save_parsing_place; enum_parsing_place context_analysis_place; /* where we are in prepare */ enum leaf_list_state {UNINIT, READY, SAVED}; enum leaf_list_state prep_leaf_list_state; enum olap_type olap; /* SELECT [FOR UPDATE/LOCK IN SHARE MODE] [SKIP LOCKED] */ enum select_lock_type {NONE, IN_SHARE_MODE, FOR_UPDATE}; enum select_lock_type select_lock; uint in_sum_expr; uint select_number; /* number of select (used for EXPLAIN) */ uint with_wild; /* item list contain '*' ; Counter */ /* Number of Item_sum-derived objects in this SELECT */ uint n_sum_items; /* Number of Item_sum-derived objects in children and descendant SELECTs */ uint n_child_sum_items; uint versioned_tables; /* For versioning */ int nest_level; /* nesting level of select */ /* index in the select list of the expression currently being fixed */ int cur_pos_in_select_list; /* This array is used to note whether we have any candidates for expression caching in the corresponding clauses */ bool expr_cache_may_be_used[PARSING_PLACE_SIZE]; uint8 nest_flags; /* This variable is required to ensure proper work of subqueries and stored procedures. Generally, one should use the states of Query_arena to determine if it's a statement prepare or first execution of a stored procedure. However, in case when there was an error during the first execution of a stored procedure, the SP body is not expelled from the SP cache. Therefore, a deeply nested subquery might be left unoptimized. So we need this per-subquery variable to inidicate the optimization/execution state of every subquery. Prepared statements work OK in that regard, as in case of an error during prepare the PS is not created. */ uint8 changed_elements; // see TOUCHED_SEL_* /** The set of those tables whose fields are referenced in the select list of this select level. */ table_map select_list_tables; /* Set to 1 if any field in field list has ROWNUM() */ bool rownum_in_field_list; /* namp of nesting SELECT visibility (for aggregate functions check) */ nesting_map name_visibility_map; table_map with_dep; index_clause_map current_index_hint_clause; /* it is for correct printing SELECT options */ thr_lock_type lock_type; /** System Versioning */ int vers_setup_conds(THD *thd, TABLE_LIST *tables); /* push new Item_field into item_list */ bool vers_push_field(THD *thd, TABLE_LIST *table, const LEX_CSTRING field_name); int period_setup_conds(THD *thd, TABLE_LIST *table); void init_query(); void init_select(); st_select_lex_unit* master_unit() { return (st_select_lex_unit*) master; } inline void set_master_unit(st_select_lex_unit *master_unit) { master= (st_select_lex_node *)master_unit; } void set_master(st_select_lex *master_arg) { master= master_arg; } st_select_lex_unit* first_inner_unit() { return (st_select_lex_unit*) slave; } st_select_lex* outer_select(); bool is_query_topmost(THD *thd); st_select_lex* next_select() { return (st_select_lex*) next; } st_select_lex* next_select_in_list() { return (st_select_lex*) link_next; } st_select_lex_node** next_select_in_list_addr() { return &link_next; } st_select_lex* return_after_parsing() { return master_unit()->return_after_parsing(); } inline bool is_subquery_function() { return master_unit()->item != 0; } bool mark_as_dependent(THD *thd, st_select_lex *last, Item_ident *dependency); void set_braces(bool value) { braces= value; } bool inc_in_sum_expr(); uint get_in_sum_expr(); bool add_item_to_list(THD *thd, Item *item); bool add_group_to_list(THD *thd, Item *item, bool asc); bool add_ftfunc_to_list(THD *thd, Item_func_match *func); bool add_order_to_list(THD *thd, Item *item, bool asc); bool add_gorder_to_list(THD *thd, Item *item, bool asc); TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table, LEX_CSTRING *alias, ulong table_options, thr_lock_type flags= TL_UNLOCK, enum_mdl_type mdl_type= MDL_SHARED_READ, List *hints= 0, List *partition_names= 0, LEX_STRING *option= 0); TABLE_LIST* get_table_list(); bool init_nested_join(THD *thd); TABLE_LIST *end_nested_join(THD *thd); TABLE_LIST *nest_last_join(THD *thd); void add_joined_table(TABLE_LIST *table); bool add_cross_joined_table(TABLE_LIST *left_op, TABLE_LIST *right_op, bool straight_fl); TABLE_LIST *convert_right_join(); List* get_item_list(); bool save_item_list_names(THD *thd); void restore_item_list_names(); ulong get_table_join_options(); void set_lock_for_tables(thr_lock_type lock_type, bool for_update, bool skip_locks); /* This method created for reiniting LEX in mysql_admin_table() and can be used only if you are going remove all SELECT_LEX & units except belonger to LEX (LEX::unit & LEX::select, for other purposes there are SELECT_LEX_UNIT::exclude_level & SELECT_LEX_UNIT::exclude_tree */ void cut_subtree() { slave= 0; } bool test_limit(); /** Get offset for LIMIT. Evaluate offset item if necessary. @return Number of rows to skip. */ ha_rows get_offset(); /** Get limit. Evaluate limit item if necessary. @return Limit of rows in result. */ ha_rows get_limit(); friend struct LEX; st_select_lex() : group_list_ptrs(NULL), braces(0), automatic_brackets(0), n_sum_items(0), n_child_sum_items(0) {} void make_empty_select() { init_query(); init_select(); } bool setup_ref_array(THD *thd, uint order_group_num); uint get_cardinality_of_ref_ptrs_slice(uint order_group_num_arg); void print(THD *thd, String *str, enum_query_type query_type); void print_lock_type(String *str); void print_item_list(THD *thd, String *str, enum_query_type query_type); void print_set_clause(THD *thd, String *str, enum_query_type query_type); void print_on_duplicate_key_clause(THD *thd, String *str, enum_query_type query_type); static void print_order(String *str, ORDER *order, enum_query_type query_type); void print_limit(THD *thd, String *str, enum_query_type query_type); void fix_prepare_information(THD *thd, Item **conds, Item **having_conds); /* Destroy the used execution plan (JOIN) of this subtree (this SELECT_LEX and all nested SELECT_LEXes and SELECT_LEX_UNITs). */ bool cleanup(); /* Recursively cleanup the join of this select lex and of all nested select lexes. */ void cleanup_all_joins(bool full); void set_index_hint_type(enum index_hint_type type, index_clause_map clause); /* Add a index hint to the tagged list of hints. The type and clause of the hint will be the current ones (set by set_index_hint()) */ bool add_index_hint (THD *thd, const char *str, size_t length); /* make a list to hold index hints */ void alloc_index_hints (THD *thd); /* read and clear the index hints */ List* pop_index_hints(void) { List *hints= index_hints; index_hints= NULL; return hints; } inline void clear_index_hints(void) { index_hints= NULL; } bool is_part_of_union() { return master_unit()->is_unit_op(); } bool is_top_level_node() { return (select_number == 1) && !is_part_of_union(); } bool optimize_unflattened_subqueries(bool const_only); /* Set the EXPLAIN type for this subquery. */ void set_explain_type(bool on_the_fly); bool handle_derived(LEX *lex, uint phases); void append_table_to_list(TABLE_LIST *TABLE_LIST::*link, TABLE_LIST *table); bool get_free_table_map(table_map *map, uint *tablenr); void replace_leaf_table(TABLE_LIST *table, List &tbl_list); void remap_tables(TABLE_LIST *derived, table_map map, uint tablenr, st_select_lex *parent_lex); bool merge_subquery(THD *thd, TABLE_LIST *derived, st_select_lex *subq_lex, uint tablenr, table_map map); inline bool is_mergeable() { return (next_select() == 0 && group_list.elements == 0 && having == 0 && with_sum_func == 0 && with_rownum == 0 && table_list.elements >= 1 && !(options & SELECT_DISTINCT) && limit_params.select_limit == 0); } void mark_as_belong_to_derived(TABLE_LIST *derived); void increase_derived_records(ha_rows records); void update_used_tables(); void update_correlated_cache(); void mark_const_derived(bool empty); bool save_leaf_tables(THD *thd); bool save_prep_leaf_tables(THD *thd); void set_unique_exclude(); bool is_merged_child_of(st_select_lex *ancestor); /* For MODE_ONLY_FULL_GROUP_BY we need to maintain two flags: - Non-aggregated fields are used in this select. - Aggregate functions are used in this select. In MODE_ONLY_FULL_GROUP_BY only one of these may be true. */ bool non_agg_field_used() const { return m_non_agg_field_used; } bool agg_func_used() const { return m_agg_func_used; } bool custom_agg_func_used() const { return m_custom_agg_func_used; } void set_non_agg_field_used(bool val) { m_non_agg_field_used= val; } void set_agg_func_used(bool val) { m_agg_func_used= val; } void set_custom_agg_func_used(bool val) { m_custom_agg_func_used= val; } inline void set_with_clause(With_clause *with_clause); With_clause *get_with_clause() { return master_unit()->with_clause; } With_element *get_with_element() { return master_unit()->cloned_from ? master_unit()->cloned_from->with_element : master_unit()->with_element; } With_element *find_table_def_in_with_clauses(TABLE_LIST *table, st_select_lex_unit * excl_spec); bool check_unrestricted_recursive(bool only_standard_compliant); bool check_subqueries_with_recursive_references(); void collect_grouping_fields_for_derived(THD *thd, ORDER *grouping_list); bool collect_grouping_fields(THD *thd); bool collect_fields_equal_to_grouping(THD *thd); void check_cond_extraction_for_grouping_fields(THD *thd, Item *cond); Item *build_cond_for_grouping_fields(THD *thd, Item *cond, bool no_to_clones); List window_specs; bool is_win_spec_list_built; void prepare_add_window_spec(THD *thd); bool add_window_def(THD *thd, LEX_CSTRING *win_name, LEX_CSTRING *win_ref, SQL_I_List win_partition_list, SQL_I_List win_order_list, Window_frame *win_frame); bool add_window_spec(THD *thd, LEX_CSTRING *win_ref, SQL_I_List win_partition_list, SQL_I_List win_order_list, Window_frame *win_frame); List window_funcs; bool add_window_func(Item_window_func *win_func); bool have_window_funcs() const { return (window_funcs.elements !=0); } ORDER *find_common_window_func_partition_fields(THD *thd); bool cond_pushdown_is_allowed() const { return !olap && !limit_params.explicit_limit && !tvc && !with_rownum; } bool build_pushable_cond_for_having_pushdown(THD *thd, Item *cond); void pushdown_cond_into_where_clause(THD *thd, Item *extracted_cond, Item **remaining_cond, Item_transformer transformer, uchar *arg); Item *pushdown_from_having_into_where(THD *thd, Item *having); select_handler *find_select_handler(THD *thd); bool is_set_op() { return linkage == UNION_TYPE || linkage == EXCEPT_TYPE || linkage == INTERSECT_TYPE; } inline void add_where_field(st_select_lex *sel) { DBUG_ASSERT(this != sel); select_n_where_fields+= sel->select_n_where_fields; } inline void set_linkage_and_distinct(enum sub_select_type l, bool d) { DBUG_ENTER("SELECT_LEX::set_linkage_and_distinct"); DBUG_PRINT("info", ("select: %p distinct %d", this, d)); set_linkage(l); DBUG_ASSERT(l == UNION_TYPE || l == INTERSECT_TYPE || l == EXCEPT_TYPE); if (d && master_unit() && master_unit()->union_distinct != this) master_unit()->union_distinct= this; distinct= d; with_all_modifier= !distinct; DBUG_VOID_RETURN; } bool set_nest_level(int new_nest_level); bool check_parameters(SELECT_LEX *main_select); void mark_select() { DBUG_ENTER("st_select_lex::mark_select()"); DBUG_PRINT("info", ("Select #%d", select_number)); DBUG_VOID_RETURN; } void register_unit(SELECT_LEX_UNIT *unit, Name_resolution_context *outer_context); SELECT_LEX_UNIT *attach_selects_chain(SELECT_LEX *sel, Name_resolution_context *context); void add_statistics(SELECT_LEX_UNIT *unit); bool make_unique_derived_name(THD *thd, LEX_CSTRING *alias); void lex_start(LEX *plex); bool is_unit_nest() { return (nest_flags & UNIT_NEST_FL); } void mark_as_unit_nest() { nest_flags= UNIT_NEST_FL; } TABLE_LIST *find_table(THD *thd, const LEX_CSTRING *db_name, const LEX_CSTRING *table_name); }; typedef class st_select_lex SELECT_LEX; inline bool st_select_lex_unit::is_unit_op () { if (!first_select()->next_select()) { if (first_select()->tvc) return 1; else return 0; } enum sub_select_type linkage= first_select()->next_select()->linkage; return linkage == UNION_TYPE || linkage == INTERSECT_TYPE || linkage == EXCEPT_TYPE; } struct st_sp_chistics { LEX_CSTRING comment; enum enum_sp_suid_behaviour suid; bool detistic; enum enum_sp_data_access daccess; enum enum_sp_aggregate_type agg_type; void init() { bzero(this, sizeof(*this)); } void set(const st_sp_chistics &other) { *this= other; } bool read_from_mysql_proc_row(THD *thd, TABLE *table); }; class Sp_chistics: public st_sp_chistics { public: Sp_chistics() { init(); } }; struct st_trg_chistics: public st_trg_execution_order { enum trg_action_time_type action_time; enum trg_event_type event; const char *ordering_clause_begin; const char *ordering_clause_end; }; enum xa_option_words {XA_NONE, XA_JOIN, XA_RESUME, XA_ONE_PHASE, XA_SUSPEND, XA_FOR_MIGRATE}; class Sroutine_hash_entry; /* Class representing list of all tables used by statement and other information which is necessary for opening and locking its tables, like SQL command for this statement. Also contains information about stored functions used by statement since during its execution we may have to add all tables used by its stored functions/triggers to this list in order to pre-open and lock them. Also used by LEX::reset_n_backup/restore_backup_query_tables_list() methods to save and restore this information. */ class Query_tables_list { public: /** SQL command for this statement. Part of this class since the process of opening and locking tables for the statement needs this information to determine correct type of lock for some of the tables. */ enum_sql_command sql_command; /* Global list of all tables used by this statement */ TABLE_LIST *query_tables; /* Pointer to next_global member of last element in the previous list. */ TABLE_LIST **query_tables_last; /* If non-0 then indicates that query requires prelocking and points to next_global member of last own element in query table list (i.e. last table which was not added to it as part of preparation to prelocking). 0 - indicates that this query does not need prelocking. */ TABLE_LIST **query_tables_own_last; /* Set of stored routines called by statement. (Note that we use lazy-initialization for this hash). */ enum { START_SROUTINES_HASH_SIZE= 16 }; HASH sroutines; /* List linking elements of 'sroutines' set. Allows you to add new elements to this set as you iterate through the list of existing elements. 'sroutines_list_own_last' is pointer to ::next member of last element of this list which represents routine which is explicitly used by query. 'sroutines_list_own_elements' number of explicitly used routines. We use these two members for restoring of 'sroutines_list' to the state in which it was right after query parsing. */ SQL_I_List sroutines_list; Sroutine_hash_entry **sroutines_list_own_last; uint sroutines_list_own_elements; /* These constructor and destructor serve for creation/destruction of Query_tables_list instances which are used as backup storage. */ Query_tables_list() = default; ~Query_tables_list() = default; /* Initializes (or resets) Query_tables_list object for "real" use. */ void reset_query_tables_list(bool init); void destroy_query_tables_list(); void set_query_tables_list(Query_tables_list *state) { *this= *state; } /* Direct addition to the list of query tables. If you are using this function, you must ensure that the table object, in particular table->db member, is initialized. */ void add_to_query_tables(TABLE_LIST *table) { *(table->prev_global= query_tables_last)= table; query_tables_last= &table->next_global; } bool requires_prelocking() { return MY_TEST(query_tables_own_last); } void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last) { query_tables_own_last= tables_own_last; } /* Return pointer to first not-own table in query-tables or 0 */ TABLE_LIST* first_not_own_table() { return ( query_tables_own_last ? *query_tables_own_last : 0); } void chop_off_not_own_tables() { if (query_tables_own_last) { *query_tables_own_last= 0; query_tables_last= query_tables_own_last; query_tables_own_last= 0; } } /** Return a pointer to the last element in query table list. */ TABLE_LIST *last_table() { /* Don't use offsetof() macro in order to avoid warnings. */ return query_tables ? (TABLE_LIST*) ((char*) query_tables_last - ((char*) &(query_tables->next_global) - (char*) query_tables)) : 0; } /** Enumeration listing of all types of unsafe statement. @note The order of elements of this enumeration type must correspond to the order of the elements of the @c explanations array defined in the body of @c THD::issue_unsafe_warnings. */ enum enum_binlog_stmt_unsafe { /** SELECT..LIMIT is unsafe because the set of rows returned cannot be predicted. */ BINLOG_STMT_UNSAFE_LIMIT= 0, /** INSERT DELAYED is unsafe because the time when rows are inserted cannot be predicted. */ BINLOG_STMT_UNSAFE_INSERT_DELAYED, /** Access to log tables is unsafe because slave and master probably log different things. */ BINLOG_STMT_UNSAFE_SYSTEM_TABLE, /** Inserting into an autoincrement column in a stored routine is unsafe. Even with just one autoincrement column, if the routine is invoked more than once slave is not guaranteed to execute the statement graph same way as the master. And since it's impossible to estimate how many times a routine can be invoked at the query pre-execution phase (see lock_tables), the statement is marked pessimistically unsafe. */ BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS, /** Using a UDF (user-defined function) is unsafe. */ BINLOG_STMT_UNSAFE_UDF, /** Using most system variables is unsafe, because slave may run with different options than master. */ BINLOG_STMT_UNSAFE_SYSTEM_VARIABLE, /** Using some functions is unsafe (e.g., UUID). */ BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION, /** Mixing transactional and non-transactional statements are unsafe if non-transactional reads or writes are occur after transactional reads or writes inside a transaction. */ BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS, /** Mixing self-logging and non-self-logging engines in a statement is unsafe. */ BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE, /** Statements that read from both transactional and non-transactional tables and write to any of them are unsafe. */ BINLOG_STMT_UNSAFE_MIXED_STATEMENT, /** INSERT...IGNORE SELECT is unsafe because which rows are ignored depends on the order that rows are retrieved by SELECT. This order cannot be predicted and may differ on master and the slave. */ BINLOG_STMT_UNSAFE_INSERT_IGNORE_SELECT, /** INSERT...SELECT...UPDATE is unsafe because which rows are updated depends on the order that rows are retrieved by SELECT. This order cannot be predicted and may differ on master and the slave. */ BINLOG_STMT_UNSAFE_INSERT_SELECT_UPDATE, /** Query that writes to a table with auto_inc column after selecting from other tables are unsafe as the order in which the rows are retrieved by select may differ on master and slave. */ BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT, /** INSERT...REPLACE SELECT is unsafe because which rows are replaced depends on the order that rows are retrieved by SELECT. This order cannot be predicted and may differ on master and the slave. */ BINLOG_STMT_UNSAFE_REPLACE_SELECT, /** CREATE TABLE... IGNORE... SELECT is unsafe because which rows are ignored depends on the order that rows are retrieved by SELECT. This order cannot be predicted and may differ on master and the slave. */ BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT, /** CREATE TABLE...REPLACE... SELECT is unsafe because which rows are replaced depends on the order that rows are retrieved from SELECT. This order cannot be predicted and may differ on master and the slave */ BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT, /** CREATE TABLE...SELECT on a table with auto-increment column is unsafe because which rows are replaced depends on the order that rows are retrieved from SELECT. This order cannot be predicted and may differ on master and the slave */ BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC, /** UPDATE...IGNORE is unsafe because which rows are ignored depends on the order that rows are updated. This order cannot be predicted and may differ on master and the slave. */ BINLOG_STMT_UNSAFE_UPDATE_IGNORE, /** INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEYS is unsafe. */ BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS, /** INSERT into auto-inc field which is not the first part of composed primary key. */ BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST, /** Autoincrement lock mode is incompatible with STATEMENT binlog format. */ BINLOG_STMT_UNSAFE_AUTOINC_LOCK_MODE, /** INSERT .. SELECT ... SKIP LOCKED is unlikely to have the same rows locked on the replica. primary key. */ BINLOG_STMT_UNSAFE_SKIP_LOCKED, /* The last element of this enumeration type. */ BINLOG_STMT_UNSAFE_COUNT }; /** This has all flags from 0 (inclusive) to BINLOG_STMT_FLAG_COUNT (exclusive) set. */ static const uint32 BINLOG_STMT_UNSAFE_ALL_FLAGS= ((1U << BINLOG_STMT_UNSAFE_COUNT) - 1); /** Maps elements of enum_binlog_stmt_unsafe to error codes. */ static const int binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT]; /** Determine if this statement is marked as unsafe. @retval 0 if the statement is not marked as unsafe. @retval nonzero if the statement is marked as unsafe. */ inline bool is_stmt_unsafe() const { return get_stmt_unsafe_flags() != 0; } inline bool is_stmt_unsafe(enum_binlog_stmt_unsafe unsafe) { return binlog_stmt_flags & (1 << unsafe); } /** Flag the current (top-level) statement as unsafe. The flag will be reset after the statement has finished. @param unsafe_type The type of unsafety: one of the @c BINLOG_STMT_FLAG_UNSAFE_* flags in @c enum_binlog_stmt_flag. */ inline void set_stmt_unsafe(enum_binlog_stmt_unsafe unsafe_type) { DBUG_ENTER("set_stmt_unsafe"); DBUG_ASSERT(unsafe_type >= 0 && unsafe_type < BINLOG_STMT_UNSAFE_COUNT); binlog_stmt_flags|= (1U << unsafe_type); DBUG_VOID_RETURN; } /** Set the bits of binlog_stmt_flags determining the type of unsafeness of the current statement. No existing bits will be cleared, but new bits may be set. @param flags A binary combination of zero or more bits, (1<= ISO_REPEATABLE_READ */ /** Sets the type of table that is about to be accessed while executing a statement. @param accessed_table Enumeration type that defines the type of table, e.g. temporary, transactional, non-transactional. */ inline void set_stmt_accessed_table(enum_stmt_accessed_table accessed_table) { DBUG_ENTER("LEX::set_stmt_accessed_table"); DBUG_ASSERT(accessed_table >= 0 && accessed_table < STMT_ACCESS_TABLE_COUNT); stmt_accessed_table_flag |= (1U << accessed_table); DBUG_VOID_RETURN; } /** Checks if a type of table is about to be accessed while executing a statement. @param accessed_table Enumeration type that defines the type of table, e.g. temporary, transactional, non-transactional. @return @retval TRUE if the type of the table is about to be accessed @retval FALSE otherwise */ inline bool stmt_accessed_table(enum_stmt_accessed_table accessed_table) { DBUG_ENTER("LEX::stmt_accessed_table"); DBUG_ASSERT(accessed_table >= 0 && accessed_table < STMT_ACCESS_TABLE_COUNT); DBUG_RETURN((stmt_accessed_table_flag & (1U << accessed_table)) != 0); } /** Checks either a trans/non trans temporary table is being accessed while executing a statement. @return @retval TRUE if a temporary table is being accessed @retval FALSE otherwise */ inline bool stmt_accessed_temp_table() { DBUG_ENTER("THD::stmt_accessed_temp_table"); DBUG_RETURN(stmt_accessed_non_trans_temp_table() || stmt_accessed_trans_temp_table()); } /** Checks if a temporary transactional table is being accessed while executing a statement. @return @retval TRUE if a temporary transactional table is being accessed @retval FALSE otherwise */ inline bool stmt_accessed_trans_temp_table() { DBUG_ENTER("THD::stmt_accessed_trans_temp_table"); DBUG_RETURN((stmt_accessed_table_flag & ((1U << STMT_READS_TEMP_TRANS_TABLE) | (1U << STMT_WRITES_TEMP_TRANS_TABLE))) != 0); } inline bool stmt_writes_to_non_temp_table() { DBUG_ENTER("THD::stmt_writes_to_non_temp_table"); DBUG_RETURN((stmt_accessed_table_flag & ((1U << STMT_WRITES_TRANS_TABLE) | (1U << STMT_WRITES_NON_TRANS_TABLE)))); } /** Checks if a temporary non-transactional table is about to be accessed while executing a statement. @return @retval TRUE if a temporary non-transactional table is about to be accessed @retval FALSE otherwise */ inline bool stmt_accessed_non_trans_temp_table() { DBUG_ENTER("THD::stmt_accessed_non_trans_temp_table"); DBUG_RETURN((stmt_accessed_table_flag & ((1U << STMT_READS_TEMP_NON_TRANS_TABLE) | (1U << STMT_WRITES_TEMP_NON_TRANS_TABLE))) != 0); } /* Checks if a mixed statement is unsafe. @param in_multi_stmt_transaction_mode defines if there is an on-going multi-transactional statement. @param binlog_direct defines if --binlog-direct-non-trans-updates is active. @param trx_cache_is_not_empty defines if the trx-cache is empty or not. @param trx_isolation defines the isolation level. @return @retval TRUE if the mixed statement is unsafe @retval FALSE otherwise */ inline bool is_mixed_stmt_unsafe(bool in_multi_stmt_transaction_mode, bool binlog_direct, bool trx_cache_is_not_empty, uint tx_isolation) { bool unsafe= FALSE; if (in_multi_stmt_transaction_mode) { uint condition= (binlog_direct ? BINLOG_DIRECT_ON : BINLOG_DIRECT_OFF) & (trx_cache_is_not_empty ? TRX_CACHE_NOT_EMPTY : TRX_CACHE_EMPTY) & (tx_isolation >= ISO_REPEATABLE_READ ? IL_GTE_REPEATABLE : IL_LT_REPEATABLE); unsafe= (binlog_unsafe_map[stmt_accessed_table_flag] & condition); #if !defined(DBUG_OFF) DBUG_PRINT("LEX::is_mixed_stmt_unsafe", ("RESULT %02X %02X %02X", condition, binlog_unsafe_map[stmt_accessed_table_flag], (binlog_unsafe_map[stmt_accessed_table_flag] & condition))); int type_in= 0; for (; type_in < STMT_ACCESS_TABLE_COUNT; type_in++) { if (stmt_accessed_table((enum_stmt_accessed_table) type_in)) DBUG_PRINT("LEX::is_mixed_stmt_unsafe", ("ACCESSED %s ", stmt_accessed_table_string((enum_stmt_accessed_table) type_in))); } #endif } if (stmt_accessed_table(STMT_WRITES_NON_TRANS_TABLE) && stmt_accessed_table(STMT_READS_TRANS_TABLE) && tx_isolation < ISO_REPEATABLE_READ) unsafe= TRUE; else if (stmt_accessed_table(STMT_WRITES_TEMP_NON_TRANS_TABLE) && stmt_accessed_table(STMT_READS_TRANS_TABLE) && tx_isolation < ISO_REPEATABLE_READ) unsafe= TRUE; return(unsafe); } /** true if the parsed tree contains references to stored procedures or functions, false otherwise */ bool uses_stored_routines() const { return sroutines_list.elements != 0; } private: /** Enumeration listing special types of statements. Currently, the only possible type is ROW_INJECTION. */ enum enum_binlog_stmt_type { /** The statement is a row injection (i.e., either a BINLOG statement or a row event executed by the slave SQL thread). */ BINLOG_STMT_TYPE_ROW_INJECTION = BINLOG_STMT_UNSAFE_COUNT, /** The last element of this enumeration type. */ BINLOG_STMT_TYPE_COUNT }; /** Bit field indicating the type of statement. There are two groups of bits: - The low BINLOG_STMT_UNSAFE_COUNT bits indicate the types of unsafeness that the current statement has. - The next BINLOG_STMT_TYPE_COUNT-BINLOG_STMT_TYPE_COUNT bits indicate if the statement is of some special type. This must be a member of LEX, not of THD: each stored procedure needs to remember its unsafeness state between calls and each stored procedure has its own LEX object (but no own THD object). */ uint32 binlog_stmt_flags; /** Bit field that determines the type of tables that are about to be be accessed while executing a statement. */ uint32 stmt_accessed_table_flag; }; /* st_parsing_options contains the flags for constructions that are allowed in the current statement. */ struct st_parsing_options { bool allows_variable; bool lookup_keywords_after_qualifier; st_parsing_options() { reset(); } void reset(); }; /** The state of the lexical parser, when parsing comments. */ enum enum_comment_state { /** Not parsing comments. */ NO_COMMENT, /** Parsing comments that need to be preserved. Typically, these are user comments '/' '*' ... '*' '/'. */ PRESERVE_COMMENT, /** Parsing comments that need to be discarded. Typically, these are special comments '/' '*' '!' ... '*' '/', or '/' '*' '!' 'M' 'M' 'm' 'm' 'm' ... '*' '/', where the comment markers should not be expanded. */ DISCARD_COMMENT }; /** @brief This class represents the character input stream consumed during lexical analysis. In addition to consuming the input stream, this class performs some comment pre processing, by filtering out out of bound special text from the query input stream. Two buffers, with pointers inside each buffers, are maintained in parallel. The 'raw' buffer is the original query text, which may contain out-of-bound comments. The 'cpp' (for comments pre processor) is the pre-processed buffer that contains only the query text that should be seen once out-of-bound data is removed. */ class Lex_input_stream { size_t unescape(CHARSET_INFO *cs, char *to, const char *str, const char *end, int sep); my_charset_conv_wc_mb get_escape_func(THD *thd, my_wc_t sep) const; public: Lex_input_stream() = default; ~Lex_input_stream() = default; /** Object initializer. Must be called before usage. @retval FALSE OK @retval TRUE Error */ bool init(THD *thd, char *buff, size_t length); void reset(char *buff, size_t length); /** The main method to scan the next token, with token contraction processing for LALR(2) resolution, e.g. translate "WITH" followed by "ROLLUP" to a single token WITH_ROLLUP_SYM. */ int lex_token(union YYSTYPE *yylval, THD *thd); void reduce_digest_token(uint token_left, uint token_right); private: enum Ident_mode { GENERAL_KEYWORD_OR_FUNC_LPAREN, QUALIFIED_SPECIAL_FUNC_LPAREN }; int scan_ident_common(THD *thd, Lex_ident_cli_st *str, Ident_mode mode); /** Set the echo mode. When echo is true, characters parsed from the raw input stream are preserved. When false, characters parsed are silently ignored. @param echo the echo mode. */ void set_echo(bool echo) { m_echo= echo; } void save_in_comment_state() { m_echo_saved= m_echo; in_comment_saved= in_comment; } void restore_in_comment_state() { m_echo= m_echo_saved; in_comment= in_comment_saved; } /** Skip binary from the input stream. @param n number of bytes to accept. */ void skip_binary(int n) { if (m_echo) { memcpy(m_cpp_ptr, m_ptr, n); m_cpp_ptr += n; } m_ptr += n; } /** Get a character, and advance in the stream. @return the next character to parse. */ unsigned char yyGet() { char c= *m_ptr++; if (m_echo) *m_cpp_ptr++ = c; return c; } /** Get the last character accepted. @return the last character accepted. */ unsigned char yyGetLast() const { return m_ptr[-1]; } /** Look at the next character to parse, but do not accept it. */ unsigned char yyPeek() const { return m_ptr[0]; } /** Look ahead at some character to parse. @param n offset of the character to look up */ unsigned char yyPeekn(int n) const { return m_ptr[n]; } /** Cancel the effect of the last yyGet() or yySkip(). Note that the echo mode should not change between calls to yyGet / yySkip and yyUnget. The caller is responsible for ensuring that. */ void yyUnget() { m_ptr--; if (m_echo) m_cpp_ptr--; } /** Accept a character, by advancing the input stream. */ void yySkip() { if (m_echo) *m_cpp_ptr++ = *m_ptr++; else m_ptr++; } /** Accept multiple characters at once. @param n the number of characters to accept. */ void yySkipn(int n) { if (m_echo) { memcpy(m_cpp_ptr, m_ptr, n); m_cpp_ptr += n; } m_ptr += n; } /** Puts a character back into the stream, canceling the effect of the last yyGet() or yySkip(). Note that the echo mode should not change between calls to unput, get, or skip from the stream. */ char *yyUnput(char ch) { *--m_ptr= ch; if (m_echo) m_cpp_ptr--; return m_ptr; } /** End of file indicator for the query text to parse. @param n number of characters expected @return true if there are less than n characters to parse */ bool eof(int n) const { return ((m_ptr + n) >= m_end_of_query); } /** Mark the stream position as the start of a new token. */ void start_token() { m_tok_start_prev= m_tok_start; m_tok_start= m_ptr; m_tok_end= m_ptr; m_cpp_tok_start_prev= m_cpp_tok_start; m_cpp_tok_start= m_cpp_ptr; m_cpp_tok_end= m_cpp_ptr; } /** Adjust the starting position of the current token. This is used to compensate for starting whitespace. */ void restart_token() { m_tok_start= m_ptr; m_cpp_tok_start= m_cpp_ptr; } /** Get the maximum length of the utf8-body buffer. The utf8 body can grow because of the character set conversion and escaping. */ size_t get_body_utf8_maximum_length(THD *thd) const; /** Get the length of the current token, in the raw buffer. */ uint yyLength() const { /* The assumption is that the lexical analyser is always 1 character ahead, which the -1 account for. */ DBUG_ASSERT(m_ptr > m_tok_start); return (uint) ((m_ptr - m_tok_start) - 1); } /** Test if a lookahead token was already scanned by lex_token(), for LALR(2) resolution. */ bool has_lookahead() const { return lookahead_token >= 0; } public: /** End of file indicator for the query text to parse. @return true if there are no more characters to parse */ bool eof() const { return (m_ptr >= m_end_of_query); } /** Get the raw query buffer. */ const char *get_buf() const { return m_buf; } /** Get the pre-processed query buffer. */ const char *get_cpp_buf() const { return m_cpp_buf; } /** Get the end of the raw query buffer. */ const char *get_end_of_query() const { return m_end_of_query; } /** Get the token start position, in the raw buffer. */ const char *get_tok_start() const { return has_lookahead() ? m_tok_start_prev : m_tok_start; } void set_cpp_tok_start(const char *pos) { m_cpp_tok_start= pos; } /** Get the token end position, in the raw buffer. */ const char *get_tok_end() const { return m_tok_end; } /** Get the current stream pointer, in the raw buffer. */ const char *get_ptr() const { return m_ptr; } /** Get the token start position, in the pre-processed buffer. */ const char *get_cpp_tok_start() const { return has_lookahead() ? m_cpp_tok_start_prev : m_cpp_tok_start; } /** Get the token end position, in the pre-processed buffer. */ const char *get_cpp_tok_end() const { return m_cpp_tok_end; } /** Get the token end position in the pre-processed buffer, with trailing spaces removed. */ const char *get_cpp_tok_end_rtrim() const { const char *p; for (p= m_cpp_tok_end; p > m_cpp_buf && my_isspace(system_charset_info, p[-1]); p--) { } return p; } /** Get the current stream pointer, in the pre-processed buffer. */ const char *get_cpp_ptr() const { return m_cpp_ptr; } /** Get the current stream pointer, in the pre-processed buffer, with traling spaces removed. */ const char *get_cpp_ptr_rtrim() const { const char *p; for (p= m_cpp_ptr; p > m_cpp_buf && my_isspace(system_charset_info, p[-1]); p--) { } return p; } /** Get the utf8-body string. */ LEX_CSTRING body_utf8() const { return LEX_CSTRING({m_body_utf8, (size_t) (m_body_utf8_ptr - m_body_utf8)}); } void body_utf8_start(THD *thd, const char *begin_ptr); void body_utf8_append(const char *ptr); void body_utf8_append(const char *ptr, const char *end_ptr); void body_utf8_append_ident(THD *thd, const Lex_string_with_metadata_st *txt, const char *end_ptr); void body_utf8_append_escape(THD *thd, const LEX_CSTRING *txt, CHARSET_INFO *txt_cs, const char *end_ptr, my_wc_t sep); private: /** LALR(2) resolution, look ahead token. Value of the next token to return, if any, or -1, if no token was parsed in advance. Note: 0 is a legal token, and represents YYEOF. */ int lookahead_token; /** LALR(2) resolution, value of the look ahead token.*/ LEX_YYSTYPE lookahead_yylval; bool get_text(Lex_string_with_metadata_st *to, uint sep, int pre_skip, int post_skip); void add_digest_token(uint token, LEX_YYSTYPE yylval); bool consume_comment(int remaining_recursions_permitted); int lex_one_token(union YYSTYPE *yylval, THD *thd); int find_keyword(Lex_ident_cli_st *str, uint len, bool function) const; int find_keyword_qualified_special_func(Lex_ident_cli_st *str, uint len) const; LEX_CSTRING get_token(uint skip, uint length); int scan_ident_start(THD *thd, Lex_ident_cli_st *str); int scan_ident_middle(THD *thd, Lex_ident_cli_st *str, CHARSET_INFO **cs, my_lex_states *); int scan_ident_delimited(THD *thd, Lex_ident_cli_st *str, uchar quote_char); bool get_7bit_or_8bit_ident(THD *thd, uchar *last_char); /** Current thread. */ THD *m_thd; /** Pointer to the current position in the raw input stream. */ char *m_ptr; /** Starting position of the last token parsed, in the raw buffer. */ const char *m_tok_start; /** Ending position of the previous token parsed, in the raw buffer. */ const char *m_tok_end; /** End of the query text in the input stream, in the raw buffer. */ const char *m_end_of_query; /** Starting position of the previous token parsed, in the raw buffer. */ const char *m_tok_start_prev; /** Begining of the query text in the input stream, in the raw buffer. */ const char *m_buf; /** Length of the raw buffer. */ size_t m_buf_length; /** Echo the parsed stream to the pre-processed buffer. */ bool m_echo:1; bool m_echo_saved:1; /** Pre-processed buffer. */ char *m_cpp_buf; /** Pointer to the current position in the pre-processed input stream. */ char *m_cpp_ptr; /** Starting position of the last token parsed, in the pre-processed buffer. */ const char *m_cpp_tok_start; /** Starting position of the previous token parsed, in the pre-procedded buffer. */ const char *m_cpp_tok_start_prev; /** Ending position of the previous token parsed, in the pre-processed buffer. */ const char *m_cpp_tok_end; /** UTF8-body buffer created during parsing. */ char *m_body_utf8; /** Pointer to the current position in the UTF8-body buffer. */ char *m_body_utf8_ptr; /** Position in the pre-processed buffer. The query from m_cpp_buf to m_cpp_utf_processed_ptr is converted to UTF8-body. */ const char *m_cpp_utf8_processed_ptr; public: /** Current state of the lexical analyser. */ enum my_lex_states next_state; /** Position of ';' in the stream, to delimit multiple queries. This delimiter is in the raw buffer. */ const char *found_semicolon; /** SQL_MODE = IGNORE_SPACE. */ bool ignore_space:1; /** TRUE if we're parsing a prepared statement: in this mode we should allow placeholders. */ bool stmt_prepare_mode:1; /** TRUE if we should allow multi-statements. */ bool multi_statements:1; /** Current line number. */ uint yylineno; /** Current statement digest instrumentation. */ sql_digest_state* m_digest; private: /** State of the lexical analyser for comments. */ enum_comment_state in_comment; enum_comment_state in_comment_saved; /** Starting position of the TEXT_STRING or IDENT in the pre-processed buffer. NOTE: this member must be used within MYSQLlex() function only. */ const char *m_cpp_text_start; /** Ending position of the TEXT_STRING or IDENT in the pre-processed buffer. NOTE: this member must be used within MYSQLlex() function only. */ const char *m_cpp_text_end; /** Character set specified by the character-set-introducer. NOTE: this member must be used within MYSQLlex() function only. */ CHARSET_INFO *m_underscore_cs; }; /** Abstract representation of a statement. This class is an interface between the parser and the runtime. The parser builds the appropriate sub classes of Sql_statement to represent a SQL statement in the parsed tree. The execute() method in the sub classes contain the runtime implementation. Note that this interface is used for SQL statement recently implemented, the code for older statements tend to load the LEX structure with more attributes instead. The recommended way to implement new statements is to sub-class Sql_statement, as this improves code modularity (see the 'big switch' in dispatch_command()), and decrease the total size of the LEX structure (therefore saving memory in stored programs). */ class Sql_statement : public Sql_alloc { public: /** Execute this SQL statement. @param thd the current thread. @return 0 on success. */ virtual bool execute(THD *thd) = 0; protected: /** Constructor. @param lex the LEX structure that represents parts of this statement. */ Sql_statement(LEX *lex) : m_lex(lex) {} /** Destructor. */ virtual ~Sql_statement() { /* Sql_statement objects are allocated in thd->mem_root. In MySQL, the C++ destructor is never called, the underlying MEM_ROOT is simply destroyed instead. Do not rely on the destructor for any cleanup. */ DBUG_ASSERT(FALSE); } protected: /** The legacy LEX structure for this statement. The LEX structure contains the existing properties of the parsed tree. TODO: with time, attributes from LEX should move to sub classes of Sql_statement, so that the parser only builds Sql_statement objects with the minimum set of attributes, instead of a LEX structure that contains the collection of every possible attribute. */ LEX *m_lex; }; class Delete_plan; class SQL_SELECT; class Explain_query; class Explain_update; class Explain_delete; /* Query plan of a single-table UPDATE. (This is actually a plan for single-table DELETE also) */ class Update_plan { protected: bool impossible_where; bool no_partitions; public: /* Allocate things there */ MEM_ROOT *mem_root; TABLE *table; SQL_SELECT *select; uint index; ha_rows scanned_rows; /* Top-level select_lex. Most of its fields are not used, we need it only to get to the subqueries. */ SELECT_LEX *select_lex; key_map possible_keys; bool using_filesort; bool using_io_buffer; /* Set this plan to be a plan to do nothing because of impossible WHERE */ void set_impossible_where() { impossible_where= true; } void set_no_partitions() { no_partitions= true; } Explain_update* save_explain_update_data(THD *thd, MEM_ROOT *mem_root); protected: bool save_explain_data_intern(THD *thd, MEM_ROOT *mem_root, Explain_update *eu, bool is_analyze); public: virtual ~Update_plan() = default; Update_plan(MEM_ROOT *mem_root_arg) : impossible_where(false), no_partitions(false), mem_root(mem_root_arg), using_filesort(false), using_io_buffer(false) {} }; /* Query plan of a single-table DELETE */ class Delete_plan : public Update_plan { bool deleting_all_rows; public: /* Construction functions */ Delete_plan(MEM_ROOT *mem_root_arg) : Update_plan(mem_root_arg), deleting_all_rows(false) {} /* Set this query plan to be a plan to make a call to h->delete_all_rows() */ void set_delete_all_rows(ha_rows rows_arg) { deleting_all_rows= true; scanned_rows= rows_arg; } void cancel_delete_all_rows() { deleting_all_rows= false; } Explain_delete* save_explain_delete_data(THD *thd, MEM_ROOT *mem_root); }; enum account_lock_type { ACCOUNTLOCK_UNSPECIFIED= 0, ACCOUNTLOCK_LOCKED, ACCOUNTLOCK_UNLOCKED }; enum password_exp_type { PASSWORD_EXPIRE_UNSPECIFIED= 0, PASSWORD_EXPIRE_NOW, PASSWORD_EXPIRE_NEVER, PASSWORD_EXPIRE_DEFAULT, PASSWORD_EXPIRE_INTERVAL }; struct Account_options: public USER_RESOURCES { Account_options() = default; void reset() { bzero(this, sizeof(*this)); ssl_type= SSL_TYPE_NOT_SPECIFIED; } enum SSL_type ssl_type; // defined in violite.h LEX_CSTRING x509_subject, x509_issuer, ssl_cipher; account_lock_type account_locked; password_exp_type password_expire; longlong num_expiration_days; }; class Query_arena_memroot; /* The state of the lex parsing. This is saved in the THD struct */ class Lex_prepared_stmt { Lex_ident_sys m_name; // Statement name (in all queries) Item *m_code; // PREPARE or EXECUTE IMMEDIATE source expression List m_params; // List of parameters for EXECUTE [IMMEDIATE] public: Lex_prepared_stmt() :m_code(NULL) { } const Lex_ident_sys &name() const { return m_name; } uint param_count() const { return m_params.elements; } List ¶ms() { return m_params; } void set(const Lex_ident_sys_st &ident, Item *code, List *params) { DBUG_ASSERT(m_params.elements == 0); m_name= ident; m_code= code; if (params) m_params= *params; } bool params_fix_fields(THD *thd) { // Fix Items in the EXECUTE..USING list List_iterator_fast param_it(m_params); while (Item *param= param_it++) { if (param->fix_fields_if_needed_for_scalar(thd, 0)) return true; } return false; } bool get_dynamic_sql_string(THD *thd, LEX_CSTRING *dst, String *buffer); void lex_start() { m_params.empty(); } }; class Lex_grant_object_name: public Grant_object_name, public Sql_alloc { public: Lex_grant_object_name(Table_ident *table_ident) :Grant_object_name(table_ident) { } Lex_grant_object_name(const LEX_CSTRING &db, Type type) :Grant_object_name(db, type) { } }; class Lex_grant_privilege: public Grant_privilege, public Sql_alloc { public: Lex_grant_privilege() {} Lex_grant_privilege(privilege_t grant, bool all_privileges= false) :Grant_privilege(grant, all_privileges) { } }; struct LEX: public Query_tables_list { SELECT_LEX_UNIT unit; /* most upper unit */ SELECT_LEX *first_select_lex() { return unit.first_select(); } const SELECT_LEX *first_select_lex() const { return unit.first_select(); } private: SELECT_LEX builtin_select; public: /* current SELECT_LEX in parsing */ SELECT_LEX *current_select; /* list of all SELECT_LEX */ SELECT_LEX *all_selects_list; /* current with clause in parsing if any, otherwise 0*/ With_clause *curr_with_clause; /* pointer to the first with clause in the current statement */ With_clause *with_clauses_list; /* (*with_clauses_list_last_next) contains a pointer to the last with clause in the current statement */ With_clause **with_clauses_list_last_next; /* When a copy of a with element is parsed this is set to the offset of the with element in the input string, otherwise it's set to 0 */ my_ptrdiff_t clone_spec_offset; Create_view_info *create_view; /* Query Plan Footprint of a currently running select */ Explain_query *explain; // type information CHARSET_INFO *charset; /* LEX which represents current statement (conventional, SP or PS) For example during view parsing THD::lex will point to the views LEX and lex::stmt_lex will point to LEX of the statement where the view will be included Currently it is used to have always correct select numbering inside statement (LEX::current_select_number) without storing and restoring a global counter which was THD::select_number. TODO: make some unified statement representation (now SP has different) to store such data like LEX::current_select_number. */ LEX *stmt_lex; LEX_CSTRING name; const char *help_arg; const char *backup_dir; /* For RESTORE/BACKUP */ const char* to_log; /* For PURGE MASTER LOGS TO */ String *wild; /* Wildcard in SHOW {something} LIKE 'wild'*/ sql_exchange *exchange; select_result *result; /** @c the two may also hold BINLOG arguments: either comment holds a base64-char string or both represent the BINLOG fragment user variables. */ LEX_CSTRING comment, ident; LEX_USER *grant_user; XID *xid; THD *thd; /* maintain a list of used plugins for this LEX */ DYNAMIC_ARRAY plugins; plugin_ref plugins_static_buffer[INITIAL_LEX_PLUGIN_LIST_SIZE]; /** SELECT of CREATE VIEW statement */ LEX_STRING create_view_select; /** Start of 'ON table', in trigger statements. */ const char* raw_trg_on_table_name_begin; /** End of 'ON table', in trigger statements. */ const char* raw_trg_on_table_name_end; /* Partition info structure filled in by PARTITION BY parse part */ partition_info *part_info; /* The definer of the object being created (view, trigger, stored routine). I.e. the value of DEFINER clause. */ LEX_USER *definer; /* Used in ALTER/CREATE user to store account locking options */ Account_options account_options; Table_type table_type; /* Used for SHOW CREATE */ List ref_list; List users_list; List *insert_list= nullptr,field_list,value_list,update_list; List many_values; List var_list; List stmt_var_list; //SET_STATEMENT values List old_var_list; // SET STATEMENT old values private: Query_arena_memroot *arena_for_set_stmt; MEM_ROOT *mem_root_for_set_stmt; bool sp_block_finalize(THD *thd, const Lex_spblock_st spblock, class sp_label **splabel); bool sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive); bool sp_exit_block(THD *thd, sp_label *lab); bool sp_exit_block(THD *thd, sp_label *lab, Item *when); bool sp_continue_loop(THD *thd, sp_label *lab); bool sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop); bool sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop); /* Check if Item_field and Item_ref are allowed in the current statement. @retval false OK (fields are allowed) @retval true ERROR (fields are not allowed). Error is raised. */ bool check_expr_allows_fields_or_error(THD *thd, const char *name) const; protected: bool sp_continue_loop(THD *thd, sp_label *lab, Item *when); public: void parse_error(uint err_number= ER_SYNTAX_ERROR); inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;} bool set_arena_for_set_stmt(Query_arena *backup); void reset_arena_for_set_stmt(Query_arena *backup); void free_arena_for_set_stmt(); void print(String *str, enum_query_type qtype); List set_var_list; // in-query assignment list List param_list; List view_list; // view list (list of field names in view) List *column_list; // list of column names (in ANALYZE) List *index_list; // list of index names (in ANALYZE) /* A stack of name resolution contexts for the query. This stack is used at parse time to set local name resolution contexts for various parts of a query. For example, in a JOIN ... ON (some_condition) clause the Items in 'some_condition' must be resolved only against the operands of the the join, and not against the whole clause. Similarly, Items in subqueries should be resolved against the subqueries (and outer queries). The stack is used in the following way: when the parser detects that all Items in some clause need a local context, it creates a new context and pushes it on the stack. All newly created Items always store the top-most context in the stack. Once the parser leaves the clause that required a local context, the parser pops the top-most context. */ List context_stack; SELECT_LEX *select_stack[MAX_SELECT_NESTING + 1]; uint select_stack_top; /* Usually this is set to 0, but for INSERT/REPLACE SELECT it is set to 1. When parsing such statements the pointer to the most outer select is placed into the second element of select_stack rather than into the first. */ uint select_stack_outer_barrier; SQL_I_List proc_list; SQL_I_List auxiliary_table_list, save_list; Column_definition *last_field; Table_function_json_table *json_table; Item_sum *in_sum_func; udf_func udf; HA_CHECK_OPT check_opt; // check/repair options Table_specification_st create_info; Key *last_key; LEX_MASTER_INFO mi; // used by CHANGE MASTER LEX_SERVER_OPTIONS server_options; LEX_CSTRING relay_log_connection_name; LEX_RESET_SLAVE reset_slave_info; ulonglong type; ulong next_binlog_file_number; /* The following is used by KILL */ killed_state kill_signal; killed_type kill_type; uint current_select_number; // valid for statment LEX (not view) /* The following bool variables should not be bit fields as they are not reset for every query */ bool autocommit; // Often used, better as bool bool sp_lex_in_use; // Keep track on lex usage in SPs for error handling /* Bit fields, reset for every query */ bool is_shutdown_wait_for_slaves:1; bool selects_allow_procedure:1; /* A special command "PARSE_VCOL_EXPR" is defined for the parser to translate a defining expression of a virtual column into an Item object. The following flag is used to prevent other applications to use this command. */ bool parse_vcol_expr:1; bool analyze_stmt:1; /* TRUE<=> this is "ANALYZE $stmt" */ bool explain_json:1; /* true <=> The parsed fragment requires resolution of references to CTE at the end of parsing. This name resolution process involves searching for possible dependencies between CTE defined in the parsed fragment and detecting possible recursive references. The flag is set to true if the fragment contains CTE definitions. */ bool with_cte_resolution:1; /* true <=> only resolution of references to CTE are required in the parsed fragment, no checking of dependencies between CTE is required. This flag is used only when parsing clones of CTE specifications. */ bool only_cte_resolution:1; bool local_file:1; bool check_exists:1; bool verbose:1, no_write_to_binlog:1; bool safe_to_cache_query:1; bool ignore:1; bool next_is_main:1; // use "main" SELECT_LEX for nrxt allocation; bool next_is_down:1; // use "main" SELECT_LEX for nrxt allocation; /* field_list was created for view and should be removed before PS/SP rexecuton */ bool empty_field_list_on_rset:1; /** During name resolution search only in the table list given by Name_resolution_context::first_name_resolution_table and Name_resolution_context::last_name_resolution_table (see Item_field::fix_fields()). */ bool use_only_table_context:1; bool escape_used:1; bool default_used:1; /* using default() function */ bool with_rownum:1; /* Using rownum() function */ bool is_lex_started:1; /* If lex_start() did run. For debugging. */ /* This variable is used in post-parse stage to declare that sum-functions, or functions which have sense only if GROUP BY is present, are allowed. For example in a query SELECT ... FROM ...WHERE MIN(i) == 1 GROUP BY ... HAVING MIN(i) > 2 MIN(i) in the WHERE clause is not allowed in the opposite to MIN(i) in the HAVING clause. Due to possible nesting of select construct the variable can contain 0 or 1 for each nest level. */ nesting_map allow_sum_func; Sql_cmd *m_sql_cmd; /* Usually `expr` rule of yacc is quite reused but some commands better not support subqueries which comes standard with this rule, like KILL, HA_READ, CREATE/ALTER EVENT etc. Set this to a non-NULL clause name to get an error. */ const char *clause_that_disallows_subselect; enum enum_duplicates duplicates; enum enum_tx_isolation tx_isolation; enum enum_ha_read_modes ha_read_mode; union { enum ha_rkey_function ha_rkey_mode; enum xa_option_words xa_opt; bool with_admin_option; // GRANT role bool with_persistent_for_clause; // uses PERSISTENT FOR clause (in ANALYZE) }; enum enum_var_type option_type; enum enum_drop_mode drop_mode; enum backup_stages backup_stage; enum Foreign_key::fk_match_opt fk_match_option; enum_fk_option fk_update_opt; enum_fk_option fk_delete_opt; enum enum_yes_no_unknown tx_chain, tx_release; st_parsing_options parsing_options; /* In sql_cache we store SQL_CACHE flag as specified by user to be able to restore SELECT statement from internal structures. */ enum e_sql_cache { SQL_CACHE_UNSPECIFIED, SQL_NO_CACHE, SQL_CACHE }; e_sql_cache sql_cache; uint slave_thd_opt, start_transaction_opt; uint profile_query_id; uint profile_options; int nest_level; /* In LEX representing update which were transformed to multi-update stores total number of tables. For LEX representing multi-delete holds number of tables from which we will delete records. */ uint table_count_update; uint8 describe; /* A flag that indicates what kinds of derived tables are present in the query (0 if no derived tables, otherwise a combination of flags DERIVED_SUBQUERY and DERIVED_VIEW). */ uint8 derived_tables; uint8 context_analysis_only; uint8 lex_options; // see OPTION_LEX_* Alter_info alter_info; Lex_prepared_stmt prepared_stmt; /* For CREATE TABLE statement last element of table list which is not part of SELECT or LIKE part (i.e. either element for table we are creating or last of tables referenced by foreign keys). */ TABLE_LIST *create_last_non_select_table; sp_head *sphead; sp_name *spname; sp_pcontext *spcont; st_sp_chistics sp_chistics; Event_parse_data *event_parse_data; /* Characterstics of trigger being created */ st_trg_chistics trg_chistics; /* List of all items (Item_trigger_field objects) representing fields in old/new version of row in trigger. We use this list for checking whenever all such fields are valid at trigger creation time and for binding these fields to TABLE object at table open (altough for latter pointer to table being opened is probably enough). */ SQL_I_List trg_table_fields; /* stmt_definition_begin is intended to point to the next word after DEFINER-clause in the following statements: - CREATE TRIGGER (points to "TRIGGER"); - CREATE PROCEDURE (points to "PROCEDURE"); - CREATE FUNCTION (points to "FUNCTION" or "AGGREGATE"); - CREATE EVENT (points to "EVENT") This pointer is required to add possibly omitted DEFINER-clause to the DDL-statement before dumping it to the binlog. keyword_delayed_begin_offset is the offset to the beginning of the DELAYED keyword in INSERT DELAYED statement. keyword_delayed_end_offset is the offset to the character right after the DELAYED keyword. */ union { const char *stmt_definition_begin; uint keyword_delayed_begin_offset; }; union { const char *stmt_definition_end; uint keyword_delayed_end_offset; }; /** Collects create options for KEY */ engine_option_value *option_list; /** Helper pointer to the end of the list when parsing options for LEX::create_info.option_list (for table) LEX::last_field->option_list (for fields) LEX::option_list (for indexes) */ engine_option_value *option_list_last; /* Reference to a struct that contains information in various commands to add/create/drop/change table spaces. */ st_alter_tablespace *alter_tablespace_info; /* The set of those tables whose fields are referenced in all subqueries of the query. TODO: possibly this it is incorrect to have used tables in LEX because with subquery, it is not clear what does the field mean. To fix this we should aggregate used tables information for selected expressions into the select_lex. */ table_map used_tables; /** Maximum number of rows and/or keys examined by the query, both read, changed or written. This is the argument of LIMIT ROWS EXAMINED. The limit is represented by two variables - the Item is needed because in case of parameters we have to delay its evaluation until execution. Once evaluated, its value is stored in examined_rows_limit_cnt. */ Item *limit_rows_examined; ulonglong limit_rows_examined_cnt; /** Holds a set of domain_ids for deletion at FLUSH..DELETE_DOMAIN_ID */ DYNAMIC_ARRAY delete_gtid_domain; static const ulong initial_gtid_domain_buffer_size= 16; uint32 gtid_domain_static_buffer[initial_gtid_domain_buffer_size]; inline void set_limit_rows_examined() { if (limit_rows_examined) limit_rows_examined_cnt= limit_rows_examined->val_uint(); else limit_rows_examined_cnt= ULONGLONG_MAX; } LEX_CSTRING *win_ref; Window_frame *win_frame; Window_frame_bound *frame_top_bound; Window_frame_bound *frame_bottom_bound; Window_spec *win_spec; Item *upd_del_where; /* System Versioning */ vers_select_conds_t vers_conditions; vers_select_conds_t period_conditions; inline void free_set_stmt_mem_root() { DBUG_ASSERT(!is_arena_for_set_stmt()); if (mem_root_for_set_stmt) { free_root(mem_root_for_set_stmt, MYF(0)); delete mem_root_for_set_stmt; mem_root_for_set_stmt= 0; } } LEX(); virtual ~LEX() { free_set_stmt_mem_root(); destroy_query_tables_list(); plugin_unlock_list(NULL, (plugin_ref *)plugins.buffer, plugins.elements); delete_dynamic(&plugins); } virtual class Query_arena *query_arena() { DBUG_ASSERT(0); return NULL; } void start(THD *thd); inline bool is_ps_or_view_context_analysis() { return (context_analysis_only & (CONTEXT_ANALYSIS_ONLY_PREPARE | CONTEXT_ANALYSIS_ONLY_VCOL_EXPR | CONTEXT_ANALYSIS_ONLY_VIEW)); } inline bool is_view_context_analysis() { return (context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW); } /** Mark all queries in this lex structure as uncacheable for the cause given @param cause the reason queries are to be marked as uncacheable Note, any cause is sufficient for st_select_lex_unit::can_be_merged() to disallow query merges. */ inline void uncacheable(uint8 cause) { safe_to_cache_query= 0; if (current_select) // initialisation SP variables has no SELECT { /* There are no sense to mark select_lex and union fields of LEX, but we should merk all subselects as uncacheable from current till most upper */ SELECT_LEX *sl; SELECT_LEX_UNIT *un; for (sl= current_select, un= sl->master_unit(); un && un != &unit; sl= sl->outer_select(), un= (sl ? sl->master_unit() : NULL)) { sl->uncacheable|= cause; un->uncacheable|= cause; } if (sl) sl->uncacheable|= cause; } if (first_select_lex()) first_select_lex()->uncacheable|= cause; } void set_trg_event_type_for_tables(); TABLE_LIST *unlink_first_table(bool *link_to_local); void link_first_table_back(TABLE_LIST *first, bool link_to_local); void first_lists_tables_same(); void fix_first_select_number(); bool can_be_merged(); bool can_use_merged(); bool can_not_use_merged(); bool only_view_structure(); bool need_correct_ident(); uint8 get_effective_with_check(TABLE_LIST *view); /* Is this update command where 'WHITH CHECK OPTION' clause is important SYNOPSIS LEX::which_check_option_applicable() RETURN TRUE have to take 'WHITH CHECK OPTION' clause into account FALSE 'WHITH CHECK OPTION' clause do not need */ inline bool which_check_option_applicable() { switch (sql_command) { case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: case SQLCOM_DELETE: case SQLCOM_DELETE_MULTI: case SQLCOM_INSERT: case SQLCOM_INSERT_SELECT: case SQLCOM_REPLACE: case SQLCOM_REPLACE_SELECT: case SQLCOM_LOAD: return TRUE; default: return FALSE; } } void cleanup_after_one_table_open(); bool push_context(Name_resolution_context *context); Name_resolution_context *pop_context(); SELECT_LEX *select_stack_head() { if (likely(select_stack_top)) return select_stack[select_stack_top - 1]; return NULL; } bool push_select(SELECT_LEX *select_lex) { DBUG_ENTER("LEX::push_select"); DBUG_PRINT("info", ("Top Select was %p (%d) depth: %u pushed: %p (%d)", select_stack_head(), select_stack_top, (select_stack_top ? select_stack_head()->select_number : 0), select_lex, select_lex->select_number)); if (unlikely(select_stack_top > MAX_SELECT_NESTING)) { my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0)); DBUG_RETURN(TRUE); } if (push_context(&select_lex->context)) DBUG_RETURN(TRUE); select_stack[select_stack_top++]= select_lex; current_select= select_lex; DBUG_RETURN(FALSE); } SELECT_LEX *pop_select() { DBUG_ENTER("LEX::pop_select"); SELECT_LEX *select_lex; if (likely(select_stack_top)) select_lex= select_stack[--select_stack_top]; else select_lex= 0; DBUG_PRINT("info", ("Top Select is %p (%d) depth: %u poped: %p (%d)", select_stack_head(), select_stack_top, (select_stack_top ? select_stack_head()->select_number : 0), select_lex, (select_lex ? select_lex->select_number : 0))); DBUG_ASSERT(select_lex); pop_context(); if (unlikely(!select_stack_top)) { current_select= &builtin_select; DBUG_PRINT("info", ("Top Select is empty -> sel builtin: %p service: %u", current_select, builtin_select.is_service_select)); builtin_select.is_service_select= false; } else current_select= select_stack[select_stack_top - 1]; DBUG_RETURN(select_lex); } SELECT_LEX *current_select_or_default() { return current_select ? current_select : &builtin_select; } bool copy_db_to(LEX_CSTRING *to); void inc_select_stack_outer_barrier() { select_stack_outer_barrier++; } SELECT_LEX *parser_current_outer_select() { return select_stack_top - 1 == select_stack_outer_barrier ? 0 : select_stack[select_stack_top - 2]; } Name_resolution_context *current_context() { return context_stack.head(); } /* Restore the LEX and THD in case of a parse error. */ static void cleanup_lex_after_parse_error(THD *thd); void reset_n_backup_query_tables_list(Query_tables_list *backup); void restore_backup_query_tables_list(Query_tables_list *backup); bool table_or_sp_used(); bool is_partition_management() const; bool part_values_current(THD *thd); bool part_values_history(THD *thd); /** @brief check if the statement is a single-level join @return result of the check @retval TRUE The statement doesn't contain subqueries, unions and stored procedure calls. @retval FALSE There are subqueries, UNIONs or stored procedure calls. */ bool is_single_level_stmt() { /* This check exploits the fact that the last added to all_select_list is on its top. So select_lex (as the first added) will be at the tail of the list. */ if (first_select_lex() == all_selects_list && !sroutines.records) { return TRUE; } return FALSE; } bool save_prep_leaf_tables(); int print_explain(select_result_sink *output, uint8 explain_flags, bool is_analyze, bool *printed_anything); bool restore_set_statement_var(); void init_last_field(Column_definition *field, const LEX_CSTRING *name, const CHARSET_INFO *cs); bool last_field_generated_always_as_row_start_or_end(Lex_ident *p, const char *type, uint flags); bool last_field_generated_always_as_row_start(); bool last_field_generated_always_as_row_end(); bool set_bincmp(CHARSET_INFO *cs, bool bin); bool new_sp_instr_stmt(THD *, const LEX_CSTRING &prefix, const LEX_CSTRING &suffix); bool sp_proc_stmt_statement_finalize_buf(THD *, const LEX_CSTRING &qbuf); bool sp_proc_stmt_statement_finalize(THD *, bool no_lookahead); sp_variable *sp_param_init(LEX_CSTRING *name); bool sp_param_fill_definition(sp_variable *spvar, const Lex_field_type_st &def); bool sf_return_fill_definition(const Lex_field_type_st &def); int case_stmt_action_then(); bool setup_select_in_parentheses(); bool set_trigger_new_row(const LEX_CSTRING *name, Item *val); bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2, Item *val); bool set_system_variable(enum_var_type var_type, sys_var *var, const Lex_ident_sys_st *base_name, Item *val); bool set_system_variable(enum_var_type var_type, const Lex_ident_sys_st *name, Item *val); bool set_system_variable(THD *thd, enum_var_type var_type, const Lex_ident_sys_st *name1, const Lex_ident_sys_st *name2, Item *val); bool set_default_system_variable(enum_var_type var_type, const Lex_ident_sys_st *name, Item *val); bool set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val); void set_stmt_init(); sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name); sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name1, const LEX_CSTRING *name2); sp_name *make_sp_name_package_routine(THD *thd, const LEX_CSTRING *name); sp_head *make_sp_head(THD *thd, const sp_name *name, const Sp_handler *sph, enum_sp_aggregate_type agg_type); sp_head *make_sp_head_no_recursive(THD *thd, const sp_name *name, const Sp_handler *sph, enum_sp_aggregate_type agg_type); bool sp_body_finalize_routine(THD *); bool sp_body_finalize_trigger(THD *); bool sp_body_finalize_event(THD *); bool sp_body_finalize_function(THD *); bool sp_body_finalize_procedure(THD *); bool sp_body_finalize_procedure_standalone(THD *, const sp_name *end_name); sp_package *create_package_start(THD *thd, enum_sql_command command, const Sp_handler *sph, const sp_name *name, DDL_options_st options); bool create_package_finalize(THD *thd, const sp_name *name, const sp_name *name2, const char *cpp_body_end); bool call_statement_start(THD *thd, sp_name *name); bool call_statement_start(THD *thd, const Lex_ident_sys_st *name); bool call_statement_start(THD *thd, const Lex_ident_sys_st *name1, const Lex_ident_sys_st *name2); bool call_statement_start(THD *thd, const Lex_ident_sys_st *db, const Lex_ident_sys_st *pkg, const Lex_ident_sys_st *proc); sp_variable *find_variable(const LEX_CSTRING *name, sp_pcontext **ctx, const Sp_rcontext_handler **rh) const; sp_variable *find_variable(const LEX_CSTRING *name, const Sp_rcontext_handler **rh) const { sp_pcontext *not_used_ctx; return find_variable(name, ¬_used_ctx, rh); } bool set_variable(const Lex_ident_sys_st *name, Item *item); bool set_variable(const Lex_ident_sys_st *name1, const Lex_ident_sys_st *name2, Item *item); void sp_variable_declarations_init(THD *thd, int nvars); bool sp_variable_declarations_finalize(THD *thd, int nvars, const Column_definition *cdef, Item *def); bool sp_variable_declarations_set_default(THD *thd, int nvars, Item *def); bool sp_variable_declarations_row_finalize(THD *thd, int nvars, Row_definition_list *row, Item *def); bool sp_variable_declarations_with_ref_finalize(THD *thd, int nvars, Qualified_column_ident *col, Item *def); bool sp_variable_declarations_rowtype_finalize(THD *thd, int nvars, Qualified_column_ident *, Item *def); bool sp_variable_declarations_cursor_rowtype_finalize(THD *thd, int nvars, uint offset, Item *def); bool sp_variable_declarations_table_rowtype_finalize(THD *thd, int nvars, const LEX_CSTRING &db, const LEX_CSTRING &table, Item *def); bool sp_variable_declarations_column_type_finalize(THD *thd, int nvars, Qualified_column_ident *ref, Item *def); bool sp_variable_declarations_vartype_finalize(THD *thd, int nvars, const LEX_CSTRING &name, Item *def); bool sp_variable_declarations_copy_type_finalize(THD *thd, int nvars, const Column_definition &ref, Row_definition_list *fields, Item *def); LEX_USER *current_user_for_set_password(THD *thd); bool sp_create_set_password_instr(THD *thd, LEX_USER *user, USER_AUTH *auth, bool no_lookahead); bool sp_create_set_password_instr(THD *thd, USER_AUTH *auth, bool no_lookahead) { LEX_USER *user; return !(user= current_user_for_set_password(thd)) || sp_create_set_password_instr(thd, user, auth, no_lookahead); } bool sp_handler_declaration_init(THD *thd, int type); bool sp_handler_declaration_finalize(THD *thd, int type); bool sp_declare_cursor(THD *thd, const LEX_CSTRING *name, class sp_lex_cursor *cursor_stmt, sp_pcontext *param_ctx, bool add_cpush_instr); bool sp_open_cursor(THD *thd, const LEX_CSTRING *name, List *parameters); Item_splocal *create_item_for_sp_var(const Lex_ident_cli_st *name, sp_variable *spvar); Item *create_item_qualified_asterisk(THD *thd, const Lex_ident_sys_st *name); Item *create_item_qualified_asterisk(THD *thd, const Lex_ident_sys_st *a, const Lex_ident_sys_st *b); Item *create_item_qualified_asterisk(THD *thd, const Lex_ident_cli_st *cname) { Lex_ident_sys name(thd, cname); if (name.is_null()) return NULL; // EOM return create_item_qualified_asterisk(thd, &name); } Item *create_item_qualified_asterisk(THD *thd, const Lex_ident_cli_st *ca, const Lex_ident_cli_st *cb) { Lex_ident_sys a(thd, ca), b(thd, cb); if (a.is_null() || b.is_null()) return NULL; // EOM return create_item_qualified_asterisk(thd, &a, &b); } Item *create_item_ident_field(THD *thd, const Lex_ident_sys_st &db, const Lex_ident_sys_st &table, const Lex_ident_sys_st &name); Item *create_item_ident_nosp(THD *thd, Lex_ident_sys_st *name) { return create_item_ident_field(thd, Lex_ident_sys(), Lex_ident_sys(), *name); } Item *create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, const char *start, const char *end); Item *create_item_ident(THD *thd, Lex_ident_cli_st *cname) { Lex_ident_sys name(thd, cname); if (name.is_null()) return NULL; // EOM return sphead ? create_item_ident_sp(thd, &name, cname->pos(), cname->end()) : create_item_ident_nosp(thd, &name); } /* Create an Item corresponding to a qualified name: a.b when the parser is out of an SP context. @param THD - THD, for mem_root @param a - the first name @param b - the second name @retval - a pointer to a created item, or NULL on error. Possible Item types that can be created: - Item_trigger_field - Item_field - Item_ref */ Item *create_item_ident_nospvar(THD *thd, const Lex_ident_sys_st *a, const Lex_ident_sys_st *b); /* Create an Item corresponding to a ROW field valiable: var.field @param THD - THD, for mem_root @param rh [OUT] - the rcontext handler (local vs package variables) @param var - the ROW variable name @param field - the ROW variable field name @param spvar - the variable that was previously found by name using "var_name". @param start - position in the query (for binary log) @param end - end in the query (for binary log) */ Item_splocal *create_item_spvar_row_field(THD *thd, const Sp_rcontext_handler *rh, const Lex_ident_sys *var, const Lex_ident_sys *field, sp_variable *spvar, const char *start, const char *end); /* Create an item from its qualified name. Depending on context, it can be either a ROW variable field, or trigger, table field, table field reference. See comments to create_item_spvar_row_field() and create_item_ident_nospvar(). @param thd - THD, for mem_root @param a - the first name @param b - the second name @retval - NULL on error, or a pointer to a new Item. */ Item *create_item_ident(THD *thd, const Lex_ident_cli_st *a, const Lex_ident_cli_st *b); /* Create an item from its qualified name. Depending on context, it can be a table field, a table field reference, or a sequence NEXTVAL and CURRVAL. @param thd - THD, for mem_root @param a - the first name @param b - the second name @param c - the third name @retval - NULL on error, or a pointer to a new Item. */ Item *create_item_ident(THD *thd, const Lex_ident_sys_st *a, const Lex_ident_sys_st *b, const Lex_ident_sys_st *c); Item *create_item_ident(THD *thd, const Lex_ident_cli_st *ca, const Lex_ident_cli_st *cb, const Lex_ident_cli_st *cc) { Lex_ident_sys b(thd, cb), c(thd, cc); if (b.is_null() || c.is_null()) return NULL; if (ca->pos() == cb->pos()) // SELECT .t1.col1 { DBUG_ASSERT(ca->length == 0); Lex_ident_sys none; return create_item_ident(thd, &none, &b, &c); } Lex_ident_sys a(thd, ca); return a.is_null() ? NULL : create_item_ident(thd, &a, &b, &c); } /* Create an item for "NEXT VALUE FOR sequence_name" */ Item *create_item_func_nextval(THD *thd, Table_ident *ident); Item *create_item_func_nextval(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *name); /* Create an item for "PREVIOUS VALUE FOR sequence_name" */ Item *create_item_func_lastval(THD *thd, Table_ident *ident); Item *create_item_func_lastval(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *name); /* Create an item for "SETVAL(sequence_name, value [, is_used [, round]]) */ Item *create_item_func_setval(THD *thd, Table_ident *ident, longlong value, ulonglong round, bool is_used); /* Create an item for a name in LIMIT clause: LIMIT var @param THD - THD, for mem_root @param var_name - the variable name @retval - a new Item corresponding to the SP variable, or NULL on error (non in SP, unknown variable, wrong data type). */ Item *create_item_limit(THD *thd, const Lex_ident_cli_st *var_name); /* Create an item for a qualified name in LIMIT clause: LIMIT var.field @param THD - THD, for mem_root @param var_name - the variable name @param field_name - the variable field name @param start - start in the query (for binary log) @param end - end in the query (for binary log) @retval - a new Item corresponding to the SP variable, or NULL on error (non in SP, unknown variable, unknown ROW field, wrong data type). */ Item *create_item_limit(THD *thd, const Lex_ident_cli_st *var_name, const Lex_ident_cli_st *field_name); Item *create_item_query_expression(THD *thd, st_select_lex_unit *unit); Item *make_item_func_sysdate(THD *thd, uint fsp); static const Schema * find_func_schema_by_name_or_error(const Lex_ident_sys &schema_name, const Lex_ident_sys &func_name); Item *make_item_func_replace(THD *thd, const Lex_ident_cli_st &schema_name, const Lex_ident_cli_st &func_name, Item *org, Item *find, Item *replace); Item *make_item_func_replace(THD *thd, const Lex_ident_cli_st &schema_name, const Lex_ident_cli_st &func_name, List *args); Item *make_item_func_substr(THD *thd, const Lex_ident_cli_st &schema_name, const Lex_ident_cli_st &func_name, const Lex_substring_spec_st &spec); Item *make_item_func_substr(THD *thd, const Lex_ident_cli_st &schema_name, const Lex_ident_cli_st &func_name, List *args); Item *make_item_func_trim(THD *thd, const Lex_ident_cli_st &schema_name, const Lex_ident_cli_st &func_name, const Lex_trim_st &spec); Item *make_item_func_trim(THD *thd, const Lex_ident_cli_st &schema_name, const Lex_ident_cli_st &func_name, List *args); Item *make_item_func_call_generic(THD *thd, const Lex_ident_cli_st *db, const Lex_ident_cli_st *name, List *args); Item *make_item_func_call_generic(THD *thd, const Lex_ident_sys &db, const Lex_ident_sys &name, List *args); Item *make_item_func_call_generic(THD *thd, Lex_ident_cli_st *db, Lex_ident_cli_st *pkg, Lex_ident_cli_st *name, List *args); Item *make_item_func_call_native_or_parse_error(THD *thd, Lex_ident_cli_st &name, List *args); my_var *create_outvar(THD *thd, const LEX_CSTRING *name); /* Create a my_var instance for a ROW field variable that was used as an OUT SP parameter: CALL p1(var.field); @param THD - THD, for mem_root @param var_name - the variable name @param field_name - the variable field name */ my_var *create_outvar(THD *thd, const LEX_CSTRING *var_name, const LEX_CSTRING *field_name); bool is_trigger_new_or_old_reference(const LEX_CSTRING *name) const; Item *create_and_link_Item_trigger_field(THD *thd, const LEX_CSTRING *name, bool new_row); // For syntax with colon, e.g. :NEW.a or :OLD.a Item *make_item_colon_ident_ident(THD *thd, const Lex_ident_cli_st *a, const Lex_ident_cli_st *b); // PLSQL: cursor%ISOPEN etc Item *make_item_plsql_cursor_attr(THD *thd, const LEX_CSTRING *name, plsql_cursor_attr_t attr); // For "SELECT @@var", "SELECT @@var.field" Item *make_item_sysvar(THD *thd, enum_var_type type, const LEX_CSTRING *name) { return make_item_sysvar(thd, type, name, &null_clex_str); } Item *make_item_sysvar(THD *thd, enum_var_type type, const LEX_CSTRING *name, const LEX_CSTRING *component); void sp_block_init(THD *thd, const LEX_CSTRING *label); void sp_block_init(THD *thd) { // Unlabeled blocks get an empty label sp_block_init(thd, &empty_clex_str); } bool sp_block_finalize(THD *thd, const Lex_spblock_st spblock) { class sp_label *tmp; return sp_block_finalize(thd, spblock, &tmp); } bool sp_block_finalize(THD *thd) { return sp_block_finalize(thd, Lex_spblock()); } bool sp_block_finalize(THD *thd, const Lex_spblock_st spblock, const LEX_CSTRING *end_label); bool sp_block_finalize(THD *thd, const LEX_CSTRING *end_label) { return sp_block_finalize(thd, Lex_spblock(), end_label); } bool sp_declarations_join(Lex_spblock_st *res, const Lex_spblock_st b1, const Lex_spblock_st b2) const { if ((b2.vars || b2.conds) && (b1.curs || b1.hndlrs)) { my_error(ER_SP_VARCOND_AFTER_CURSHNDLR, MYF(0)); return true; } if (b2.curs && b1.hndlrs) { my_error(ER_SP_CURSOR_AFTER_HANDLER, MYF(0)); return true; } res->join(b1, b2); return false; } bool sp_block_with_exceptions_finalize_declarations(THD *thd); bool sp_block_with_exceptions_finalize_executable_section(THD *thd, uint executable_section_ip); bool sp_block_with_exceptions_finalize_exceptions(THD *thd, uint executable_section_ip, uint exception_count); bool sp_block_with_exceptions_add_empty(THD *thd); bool sp_exit_statement(THD *thd, Item *when); bool sp_exit_statement(THD *thd, const LEX_CSTRING *label_name, Item *item); bool sp_leave_statement(THD *thd, const LEX_CSTRING *label_name); bool sp_goto_statement(THD *thd, const LEX_CSTRING *label_name); bool sp_continue_statement(THD *thd); bool sp_continue_statement(THD *thd, const LEX_CSTRING *label_name); bool sp_iterate_statement(THD *thd, const LEX_CSTRING *label_name); bool maybe_start_compound_statement(THD *thd); bool sp_push_loop_label(THD *thd, const LEX_CSTRING *label_name); bool sp_push_loop_empty_label(THD *thd); bool sp_pop_loop_label(THD *thd, const LEX_CSTRING *label_name); void sp_pop_loop_empty_label(THD *thd); bool sp_while_loop_expression(THD *thd, Item *expr); bool sp_while_loop_finalize(THD *thd); bool sp_if_after_statements(THD *thd); bool sp_push_goto_label(THD *thd, const LEX_CSTRING *label_name); Item_param *add_placeholder(THD *thd, const LEX_CSTRING *name, const char *start, const char *end); /* Integer range FOR LOOP methods */ sp_variable *sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name, Item *value); sp_variable *sp_add_for_loop_target_bound(THD *thd, Item *value) { LEX_CSTRING name= { STRING_WITH_LEN("[target_bound]") }; return sp_add_for_loop_variable(thd, &name, value); } bool sp_for_loop_intrange_declarations(THD *thd, Lex_for_loop_st *loop, const LEX_CSTRING *index, const Lex_for_loop_bounds_st &bounds); bool sp_for_loop_intrange_condition_test(THD *thd, const Lex_for_loop_st &loop); bool sp_for_loop_intrange_iterate(THD *thd, const Lex_for_loop_st &loop); /* Cursor FOR LOOP methods */ bool sp_for_loop_cursor_declarations(THD *thd, Lex_for_loop_st *loop, const LEX_CSTRING *index, const Lex_for_loop_bounds_st &bounds); sp_variable *sp_add_for_loop_cursor_variable(THD *thd, const LEX_CSTRING *name, const class sp_pcursor *cur, uint coffset, sp_assignment_lex *param_lex, Item_args *parameters); bool sp_for_loop_implicit_cursor_statement(THD *thd, Lex_for_loop_bounds_st *bounds, sp_lex_cursor *cur); bool sp_for_loop_cursor_condition_test(THD *thd, const Lex_for_loop_st &loop); bool sp_for_loop_cursor_iterate(THD *thd, const Lex_for_loop_st &); /* Generic FOR LOOP methods*/ /* Generate FOR loop declarations and initialize "loop" from "index" and "bounds". @param [IN] thd - current THD, for mem_root and error reporting @param [OUT] loop - the loop generated SP variables are stored here, together with additional loop characteristics. @param [IN] index - the loop index variable name @param [IN] bounds - the loop bounds (in sp_assignment_lex format) and additional loop characteristics, as created by the sp_for_loop_bounds rule. @retval true - on error @retval false - on success This methods adds declarations: - An explicit integer or cursor%ROWTYPE "index" variable - An implicit integer upper bound variable, in case of integer range loops - A CURSOR, in case of an implicit CURSOR loops The generated variables are stored into "loop". Additional loop characteristics are copied from "bounds" to "loop". */ bool sp_for_loop_declarations(THD *thd, Lex_for_loop_st *loop, const LEX_CSTRING *index, const Lex_for_loop_bounds_st &bounds) { return bounds.is_for_loop_cursor() ? sp_for_loop_cursor_declarations(thd, loop, index, bounds) : sp_for_loop_intrange_declarations(thd, loop, index, bounds); } /* Generate a conditional jump instruction to leave the loop, using a proper condition depending on the loop type: - Item_func_le -- integer range loops - Item_func_ge -- integer range reverse loops - Item_func_cursor_found -- cursor loops */ bool sp_for_loop_condition_test(THD *thd, const Lex_for_loop_st &loop) { return loop.is_for_loop_cursor() ? sp_for_loop_cursor_condition_test(thd, loop) : sp_for_loop_intrange_condition_test(thd, loop); } /* Generate "increment" instructions followed by a jump to the condition test in the beginnig of the loop. "Increment" depends on the loop type and can be: - index:= index + 1; -- integer range loops - index:= index - 1; -- integer range reverse loops - FETCH cursor INTO index; -- cursor loops */ bool sp_for_loop_finalize(THD *thd, const Lex_for_loop_st &loop) { if (loop.is_for_loop_cursor() ? sp_for_loop_cursor_iterate(thd, loop) : sp_for_loop_intrange_iterate(thd, loop)) return true; // Generate a jump to the beginning of the loop return sp_while_loop_finalize(thd); } bool sp_for_loop_outer_block_finalize(THD *thd, const Lex_for_loop_st &loop); /* Make an Item when an identifier is found in the FOR loop bounds: FOR rec IN cursor FOR rec IN var1 .. var2 FOR rec IN row1.field1 .. xxx */ Item *create_item_for_loop_bound(THD *thd, const LEX_CSTRING *a, const LEX_CSTRING *b, const LEX_CSTRING *c); /* End of FOR LOOP methods */ bool add_signal_statement(THD *thd, const class sp_condition_value *value); bool add_resignal_statement(THD *thd, const class sp_condition_value *value); // Check if "KEY IF NOT EXISTS name" used outside of ALTER context bool check_add_key(DDL_options_st ddl) { if (ddl.if_not_exists() && sql_command != SQLCOM_ALTER_TABLE) { parse_error(); return true; } return false; } // Add a key as a part of CREATE TABLE or ALTER TABLE bool add_key(Key::Keytype key_type, const LEX_CSTRING *key_name, ha_key_alg algorithm, DDL_options_st ddl) { if (check_add_key(ddl) || !(last_key= new Key(key_type, key_name, algorithm, false, ddl))) return true; alter_info.key_list.push_back(last_key); return false; } // Add a key for a CREATE INDEX statement bool add_create_index(Key::Keytype key_type, const LEX_CSTRING *key_name, ha_key_alg algorithm, DDL_options_st ddl) { if (check_create_options(ddl) || !(last_key= new Key(key_type, key_name, algorithm, false, ddl))) return true; alter_info.key_list.push_back(last_key); return false; } bool add_create_index_prepare(Table_ident *table) { sql_command= SQLCOM_CREATE_INDEX; if (!current_select->add_table_to_list(thd, table, NULL, TL_OPTION_UPDATING, TL_READ_NO_INSERT, MDL_SHARED_UPGRADABLE)) return true; alter_info.reset(); alter_info.flags= ALTER_ADD_INDEX; option_list= NULL; return false; } /* Add an UNIQUE or PRIMARY key which is a part of a column definition: CREATE TABLE t1 (a INT PRIMARY KEY); */ void add_key_to_list(LEX_CSTRING *field_name, enum Key::Keytype type, bool check_exists); // Add a constraint as a part of CREATE TABLE or ALTER TABLE bool add_constraint(const LEX_CSTRING &name, Virtual_column_info *constr, bool if_not_exists) { constr->name= name; constr->if_not_exists= if_not_exists; alter_info.check_constraint_list.push_back(constr); return false; } bool add_alter_list(LEX_CSTRING par_name, Virtual_column_info *expr, bool par_exists); bool add_alter_list(LEX_CSTRING name, LEX_CSTRING new_name, bool exists); void set_command(enum_sql_command command, DDL_options_st options) { sql_command= command; create_info.set(options); } void set_command(enum_sql_command command, uint scope, DDL_options_st options) { set_command(command, options); create_info.options|= scope; // HA_LEX_CREATE_TMP_TABLE or 0 } bool check_create_options(DDL_options_st options) { if (options.or_replace() && options.if_not_exists()) { my_error(ER_WRONG_USAGE, MYF(0), "OR REPLACE", "IF NOT EXISTS"); return true; } return false; } bool set_create_options_with_check(DDL_options_st options) { create_info.set(options); return check_create_options(create_info); } bool add_create_options_with_check(DDL_options_st options) { create_info.add(options); return check_create_options(create_info); } bool sp_add_cfetch(THD *thd, const LEX_CSTRING *name); bool sp_add_agg_cfetch(); bool set_command_with_check(enum_sql_command command, uint scope, DDL_options_st options) { set_command(command, scope, options); return check_create_options(options); } bool set_command_with_check(enum_sql_command command, DDL_options_st options) { set_command(command, options); return check_create_options(options); } /* DROP shares lex->create_info to store TEMPORARY and IF EXISTS options to save on extra initialization in lex_start(). Add some wrappers, to avoid direct use of lex->create_info in the caller code processing DROP statements (which might look confusing). */ bool tmp_table() const { return create_info.tmp_table(); } bool if_exists() const { return create_info.if_exists(); } /* Run specified phases for derived tables/views in the given list @param table_list - list of derived tables/view to handle @param phase - phases to process tables/views through @details This method runs phases specified by the 'phases' on derived tables/views found in the 'table_list' with help of the TABLE_LIST::handle_derived function. 'this' is passed as an argument to the TABLE_LIST::handle_derived. @return false - ok @return true - error */ bool handle_list_of_derived(TABLE_LIST *table_list, uint phases) { for (TABLE_LIST *tl= table_list; tl; tl= tl->next_local) { if (tl->is_view_or_derived() && tl->handle_derived(this, phases)) return true; } return false; } bool create_like() const { DBUG_ASSERT(!create_info.like() || !first_select_lex()->item_list.elements); return create_info.like(); } bool create_select() const { DBUG_ASSERT(!create_info.like() || !first_select_lex()->item_list.elements); return first_select_lex()->item_list.elements; } bool create_simple() const { return !create_like() && !create_select(); } SELECT_LEX *exclude_last_select(); SELECT_LEX *exclude_not_first_select(SELECT_LEX *exclude); void check_automatic_up(enum sub_select_type type); bool create_or_alter_view_finalize(THD *thd, Table_ident *table_ident); bool add_alter_view(THD *thd, uint16 algorithm, enum_view_suid suid, Table_ident *table_ident); bool add_create_view(THD *thd, DDL_options_st ddl, uint16 algorithm, enum_view_suid suid, Table_ident *table_ident); bool add_grant_command(THD *thd, const List &columns); bool stmt_grant_table(THD *thd, Grant_privilege *grant, const Lex_grant_object_name &ident, privilege_t grant_option); bool stmt_revoke_table(THD *thd, Grant_privilege *grant, const Lex_grant_object_name &ident); bool stmt_grant_sp(THD *thd, Grant_privilege *grant, const Lex_grant_object_name &ident, const Sp_handler &sph, privilege_t grant_option); bool stmt_revoke_sp(THD *thd, Grant_privilege *grant, const Lex_grant_object_name &ident, const Sp_handler &sph); bool stmt_grant_proxy(THD *thd, LEX_USER *user, privilege_t grant_option); bool stmt_revoke_proxy(THD *thd, LEX_USER *user); Vers_parse_info &vers_get_info() { return create_info.vers_info; } /* The list of history-generating DML commands */ bool vers_history_generating() const { switch (sql_command) { case SQLCOM_DELETE: return !vers_conditions.delete_history; case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: case SQLCOM_DELETE_MULTI: case SQLCOM_REPLACE: case SQLCOM_REPLACE_SELECT: return true; case SQLCOM_INSERT: case SQLCOM_INSERT_SELECT: return duplicates == DUP_UPDATE; case SQLCOM_LOAD: return duplicates == DUP_REPLACE; default: /* Row injections (i.e. row binlog events and BINLOG statements) should generate history. */ return is_stmt_row_injection(); } } int add_period(Lex_ident name, Lex_ident_sys_st start, Lex_ident_sys_st end) { if (check_period_name(name.str)) { my_error(ER_WRONG_COLUMN_NAME, MYF(0), name.str); return 1; } if (lex_string_cmp(system_charset_info, &start, &end) == 0) { my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), start.str); return 1; } Table_period_info &info= create_info.period_info; if (check_exists && info.name.streq(name)) return 0; if (info.is_set()) { my_error(ER_MORE_THAN_ONE_PERIOD, MYF(0)); return 1; } info.set_period(start, end); info.name= name; info.constr= new Virtual_column_info(); info.constr->expr= lt_creator.create(thd, create_item_ident_nosp(thd, &start), create_item_ident_nosp(thd, &end)); add_constraint(null_clex_str, info.constr, false); return 0; } sp_package *get_sp_package() const; /** Check if the select is a simple select (not an union). @retval 0 ok @retval 1 error ; In this case the error messege is sent to the client */ bool check_simple_select(const LEX_CSTRING *option) { if (current_select != &builtin_select) { char command[80]; strmake(command, option->str, MY_MIN(option->length, sizeof(command)-1)); my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command); return true; } return false; } SELECT_LEX_UNIT *alloc_unit(); SELECT_LEX *alloc_select(bool is_select); SELECT_LEX_UNIT *create_unit(SELECT_LEX*); SELECT_LEX *wrap_unit_into_derived(SELECT_LEX_UNIT *unit); SELECT_LEX *wrap_select_chain_into_derived(SELECT_LEX *sel); void init_select() { current_select->init_select(); wild= 0; exchange= 0; } bool main_select_push(bool service= false); bool insert_select_hack(SELECT_LEX *sel); SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest); bool set_main_unit(st_select_lex_unit *u) { unit.options= u->options; unit.uncacheable= u->uncacheable; unit.register_select_chain(u->first_select()); unit.first_select()->options|= builtin_select.options; unit.fake_select_lex= u->fake_select_lex; unit.union_distinct= u->union_distinct; unit.set_with_clause(u->with_clause); builtin_select.exclude_from_global(); return false; } bool check_main_unit_semantics(); SELECT_LEX_UNIT *parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2, enum sub_select_type unit_type, bool distinct); SELECT_LEX_UNIT *parsed_select_expr_cont(SELECT_LEX_UNIT *unit, SELECT_LEX *s2, enum sub_select_type unit_type, bool distinct, bool oracle); bool parsed_multi_operand_query_expression_body(SELECT_LEX_UNIT *unit); SELECT_LEX_UNIT *add_tail_to_query_expression_body(SELECT_LEX_UNIT *unit, Lex_order_limit_lock *l); SELECT_LEX_UNIT * add_tail_to_query_expression_body_ext_parens(SELECT_LEX_UNIT *unit, Lex_order_limit_lock *l); SELECT_LEX_UNIT *parsed_body_ext_parens_primary(SELECT_LEX_UNIT *unit, SELECT_LEX *primary, enum sub_select_type unit_type, bool distinct); SELECT_LEX_UNIT * add_primary_to_query_expression_body(SELECT_LEX_UNIT *unit, SELECT_LEX *sel, enum sub_select_type unit_type, bool distinct, bool oracle); SELECT_LEX_UNIT * add_primary_to_query_expression_body(SELECT_LEX_UNIT *unit, SELECT_LEX *sel, enum sub_select_type unit_type, bool distinct); SELECT_LEX_UNIT * add_primary_to_query_expression_body_ext_parens( SELECT_LEX_UNIT *unit, SELECT_LEX *sel, enum sub_select_type unit_type, bool distinct); SELECT_LEX *parsed_subselect(SELECT_LEX_UNIT *unit); bool parsed_insert_select(SELECT_LEX *firs_select); void save_values_list_state(); void restore_values_list_state(); bool parsed_TVC_start(); SELECT_LEX *parsed_TVC_end(); TABLE_LIST *parsed_derived_table(SELECT_LEX_UNIT *unit, int for_system_time, LEX_CSTRING *alias); bool parsed_create_view(SELECT_LEX_UNIT *unit, int check); bool select_finalize(st_select_lex_unit *expr); bool select_finalize(st_select_lex_unit *expr, Lex_select_lock l); void relink_hack(st_select_lex *select_lex); bool stmt_install_plugin(const DDL_options_st &opt, const Lex_ident_sys_st &name, const LEX_CSTRING &soname); void stmt_install_plugin(const LEX_CSTRING &soname); bool stmt_uninstall_plugin_by_name(const DDL_options_st &opt, const Lex_ident_sys_st &name); bool stmt_uninstall_plugin_by_soname(const DDL_options_st &opt, const LEX_CSTRING &soname); bool stmt_prepare_validate(const char *stmt_type); bool stmt_prepare(const Lex_ident_sys_st &ident, Item *code); bool stmt_execute(const Lex_ident_sys_st &ident, List *params); bool stmt_execute_immediate(Item *code, List *params); void stmt_deallocate_prepare(const Lex_ident_sys_st &ident); bool stmt_alter_table_exchange_partition(Table_ident *table); void stmt_purge_to(const LEX_CSTRING &to); bool stmt_purge_before(Item *item); SELECT_LEX *returning() { return &builtin_select; } bool has_returning() { return !builtin_select.item_list.is_empty(); } private: bool stmt_create_routine_start(const DDL_options_st &options) { create_info.set(options); return main_select_push() || check_create_options(options); } public: bool stmt_create_function_start(const DDL_options_st &options) { sql_command= SQLCOM_CREATE_SPFUNCTION; return stmt_create_routine_start(options); } bool stmt_create_procedure_start(const DDL_options_st &options) { sql_command= SQLCOM_CREATE_PROCEDURE; return stmt_create_routine_start(options); } void stmt_create_routine_finalize() { pop_select(); // main select } bool stmt_create_stored_function_start(const DDL_options_st &options, enum_sp_aggregate_type, const sp_name *name); bool stmt_create_stored_function_finalize_standalone(const sp_name *end_name); bool stmt_create_udf_function(const DDL_options_st &options, enum_sp_aggregate_type agg_type, const Lex_ident_sys_st &name, Item_result return_type, const LEX_CSTRING &soname); bool stmt_drop_function(const DDL_options_st &options, const Lex_ident_sys_st &db, const Lex_ident_sys_st &name); bool stmt_drop_function(const DDL_options_st &options, const Lex_ident_sys_st &name); bool stmt_drop_procedure(const DDL_options_st &options, sp_name *name); bool stmt_alter_function_start(sp_name *name); bool stmt_alter_procedure_start(sp_name *name); sp_condition_value *stmt_signal_value(const Lex_ident_sys_st &ident); Spvar_definition *row_field_name(THD *thd, const Lex_ident_sys_st &name); bool set_field_type_udt(Lex_field_type_st *type, const LEX_CSTRING &name, const Lex_length_and_dec_st &attr); bool set_cast_type_udt(Lex_cast_type_st *type, const LEX_CSTRING &name); bool map_data_type(const Lex_ident_sys_st &schema, Lex_field_type_st *type) const; void mark_first_table_as_inserting(); bool fields_are_impossible() { // no select or it is last select with no tables (service select) return !select_stack_head() || (select_stack_top == 1 && select_stack[0]->is_service_select); } bool add_table_foreign_key(const LEX_CSTRING *name, const LEX_CSTRING *constraint_name, Table_ident *table_name, DDL_options ddl_options); bool add_column_foreign_key(const LEX_CSTRING *name, const LEX_CSTRING *constraint_name, Table_ident *ref_table_name, DDL_options ddl_options); bool check_dependencies_in_with_clauses(); bool check_cte_dependencies_and_resolve_references(); bool resolve_references_to_cte(TABLE_LIST *tables, TABLE_LIST **tables_last, st_select_lex_unit *excl_spec); /** Turn on the SELECT_DESCRIBE flag for every SELECT_LEX involved into the statement being processed in case the statement is EXPLAIN UPDATE/DELETE. @param lex current LEX */ void promote_select_describe_flag_if_needed() { if (describe) builtin_select.options |= SELECT_DESCRIBE; } }; /** Set_signal_information is a container used in the parsed tree to represent the collection of assignments to condition items in the SIGNAL and RESIGNAL statements. */ class Set_signal_information { public: /** Empty default constructor, use clear() */ Set_signal_information() = default; /** Copy constructor. */ Set_signal_information(const Set_signal_information& set); /** Destructor. */ ~Set_signal_information() = default; /** Clear all items. */ void clear(); /** For each condition item assignment, m_item[] contains the parsed tree that represents the expression assigned, if any. m_item[] is an array indexed by Diag_condition_item_name. */ Item *m_item[LAST_DIAG_SET_PROPERTY+1]; }; /** The internal state of the syntax parser. This object is only available during parsing, and is private to the syntax parser implementation (sql_yacc.yy). */ class Yacc_state { public: Yacc_state() : yacc_yyss(NULL), yacc_yyvs(NULL) { reset(); } void reset() { if (yacc_yyss != NULL) { my_free(yacc_yyss); yacc_yyss = NULL; } if (yacc_yyvs != NULL) { my_free(yacc_yyvs); yacc_yyvs = NULL; } m_set_signal_info.clear(); m_lock_type= TL_READ_DEFAULT; m_mdl_type= MDL_SHARED_READ; } ~Yacc_state(); /** Reset part of the state which needs resetting before parsing substatement. */ void reset_before_substatement() { m_lock_type= TL_READ_DEFAULT; m_mdl_type= MDL_SHARED_READ; } /** Bison internal state stack, yyss, when dynamically allocated using my_yyoverflow(). */ uchar *yacc_yyss; /** Bison internal semantic value stack, yyvs, when dynamically allocated using my_yyoverflow(). */ uchar *yacc_yyvs; /** Fragments of parsed tree, used during the parsing of SIGNAL and RESIGNAL. */ Set_signal_information m_set_signal_info; /** Type of lock to be used for tables being added to the statement's table list in table_factor, table_alias_ref, single_multi and table_wild_one rules. Statements which use these rules but require lock type different from one specified by this member have to override it by using st_select_lex::set_lock_for_tables() method. The default value of this member is TL_READ_DEFAULT. The only two cases in which we change it are: - When parsing SELECT HIGH_PRIORITY. - Rule for DELETE. In which we use this member to pass information about type of lock from delete to single_multi part of rule. We should try to avoid introducing new use cases as we would like to get rid of this member eventually. */ thr_lock_type m_lock_type; /** The type of requested metadata lock for tables added to the statement table list. */ enum_mdl_type m_mdl_type; /* TODO: move more attributes from the LEX structure here. */ }; /** Internal state of the parser. The complete state consist of: - state data used during lexical parsing, - state data used during syntactic parsing. */ class Parser_state { public: Parser_state() : m_yacc() {} /** Object initializer. Must be called before usage. @retval FALSE OK @retval TRUE Error */ bool init(THD *thd, char *buff, size_t length) { return m_lip.init(thd, buff, length); } ~Parser_state() = default; Lex_input_stream m_lip; Yacc_state m_yacc; /** Current performance digest instrumentation. */ PSI_digest_locker* m_digest_psi; void reset(char *found_semicolon, unsigned int length) { m_lip.reset(found_semicolon, length); m_yacc.reset(); } }; extern sql_digest_state * digest_add_token(sql_digest_state *state, uint token, LEX_YYSTYPE yylval); extern sql_digest_state * digest_reduce_token(sql_digest_state *state, uint token_left, uint token_right); struct st_lex_local: public LEX, public Sql_alloc { }; /** An st_lex_local extension with automatic initialization for SP purposes. Used to parse sub-expressions and SP sub-statements. This class is reused for: 1. sp_head::reset_lex() based constructs - SP variable assignments (e.g. SET x=10;) - FOR loop conditions and index variable increments - Cursor statements - SP statements - SP function RETURN statements - CASE statements - REPEAT..UNTIL expressions - WHILE expressions - EXIT..WHEN and CONTINUE..WHEN statements 2. sp_assignment_lex based constructs: - CURSOR parameter assignments */ class sp_lex_local: public st_lex_local { public: sp_lex_local(THD *thd, const LEX *oldlex) { /* Reset most stuff. */ start(thd); /* Keep the parent SP stuff */ sphead= oldlex->sphead; spcont= oldlex->spcont; /* Keep the parent trigger stuff too */ trg_chistics= oldlex->trg_chistics; trg_table_fields.empty(); sp_lex_in_use= false; } }; class sp_lex_set_var: public sp_lex_local { public: sp_lex_set_var(THD *thd, const LEX *oldlex) :sp_lex_local(thd, oldlex) { // Set new LEX as if we at start of set rule init_select(); sql_command= SQLCOM_SET_OPTION; var_list.empty(); autocommit= 0; option_type= oldlex->option_type; // Inherit from the outer lex } }; class sp_expr_lex: public sp_lex_local { Item *m_item; // The expression public: sp_expr_lex(THD *thd, LEX *oldlex) :sp_lex_local(thd, oldlex), m_item(NULL) { } void set_item(Item *item) { m_item= item; } Item *get_item() const { return m_item; } bool sp_continue_when_statement(THD *thd); bool sp_continue_when_statement(THD *thd, const LEX_CSTRING *label_name); int case_stmt_action_expr(); int case_stmt_action_when(bool simple); bool sp_while_loop_expression(THD *thd) { return LEX::sp_while_loop_expression(thd, get_item()); } bool sp_repeat_loop_finalize(THD *thd); bool sp_if_expr(THD *thd); }; /** An assignment specific LEX, which additionally has an Item (an expression) and an associated with the Item free_list, which is usually freed after the expression is calculated. Note, consider changing some of sp_lex_local to sp_assignment_lex, as the latter allows to use a simpler grammar in sql_yacc.yy (IMO). If the expression is simple (e.g. does not have function calls), then m_item and m_free_list point to the same Item. If the expressions is complex (e.g. have function calls), then m_item points to the leftmost Item, while m_free_list points to the rightmost item. For example: f1(COALESCE(f2(10), f2(20))) - m_item points to Item_func_sp for f1 (the leftmost Item) - m_free_list points to Item_int for 20 (the rightmost Item) Note, we could avoid storing m_item at all, as we can always reach the leftmost item from the rightmost item by iterating through m_free_list. But with a separate m_item the code should be faster. */ class sp_assignment_lex: public sp_lex_local { Item *m_item; // The expression Item *m_free_list; // The associated free_list (sub-expressions) public: sp_assignment_lex(THD *thd, LEX *oldlex) :sp_lex_local(thd, oldlex), m_item(NULL), m_free_list(NULL) { } void set_item_and_free_list(Item *item, Item *free_list) { m_item= item; m_free_list= free_list; } Item *get_item() const { return m_item; } Item *get_free_list() const { return m_free_list; } }; extern void lex_init(void); extern void lex_free(void); extern void lex_start(THD *thd); extern void lex_end(LEX *lex); extern void lex_end_nops(LEX *lex); extern void lex_unlock_plugins(LEX *lex); void end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex); int init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex); extern int MYSQLlex(union YYSTYPE *yylval, THD *thd); extern int ORAlex(union YYSTYPE *yylval, THD *thd); inline void trim_whitespace(CHARSET_INFO *cs, LEX_CSTRING *str, size_t * prefix_length = 0) { *str= Lex_cstring(*str).trim_whitespace(cs, prefix_length); } extern bool is_lex_native_function(const LEX_CSTRING *name); extern bool is_native_function(THD *thd, const LEX_CSTRING *name); extern bool is_native_function_with_warn(THD *thd, const LEX_CSTRING *name); /** @} (End of group Semantic_Analysis) */ void my_missing_function_error(const LEX_CSTRING &token, const char *name); bool is_keyword(const char *name, uint len); int set_statement_var_if_exists(THD *thd, const char *var_name, size_t var_name_length, ulonglong value); Virtual_column_info *add_virtual_expression(THD *thd, Item *expr); Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, Item *expr); bool sp_create_assignment_lex(THD *thd, const char *pos); bool sp_create_assignment_instr(THD *thd, bool no_lookahead, bool need_set_keyword= true); void mark_or_conds_to_avoid_pushdown(Item *cond); #endif /* MYSQL_SERVER */ #endif /* SQL_LEX_INCLUDED */ server/private/wsrep_binlog.h000064400000006561151031265050012375 0ustar00/* Copyright (C) 2013 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA. */ #ifndef WSREP_BINLOG_H #define WSREP_BINLOG_H #include "my_global.h" #include "sql_class.h" // THD, IO_CACHE #define HEAP_PAGE_SIZE 65536 /* 64K */ #define WSREP_MAX_WS_SIZE 2147483647 /* 2GB */ /* Write the contents of a cache to a memory buffer. This function quite the same as MYSQL_BIN_LOG::write_cache(), with the exception that here we write in buffer instead of log file. */ int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len); /* Write the contents of a cache to wsrep provider. This function quite the same as MYSQL_BIN_LOG::write_cache(), with the exception that here we write in buffer instead of log file. @param len total amount of data written @return wsrep error status */ int wsrep_write_cache(THD* thd, IO_CACHE* cache, size_t* len); /* Dump replication buffer to disk */ void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len); /* Dump replication buffer along with header to a file */ void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf, size_t buf_len); /** Write a skip event into binlog. @param thd Thread object pointer @return Zero in case of success, non-zero on failure. */ int wsrep_write_skip_event(THD* thd); /* Write dummy event into binlog in place of unused GTID. The binlog write is done in thd context. */ int wsrep_write_dummy_event_low(THD *thd, const char *msg); /* Write dummy event to binlog in place of unused GTID and commit. The binlog write and commit are done in temporary thd context, the original thd state is not altered. */ int wsrep_write_dummy_event(THD* thd, const char *msg); void wsrep_register_binlog_handler(THD *thd, bool trx); /** Return true if committing THD will write to binlog during commit. This is the case for: - Local THD, binlog is open - Replaying THD, binlog is open - Applier THD, log-slave-updates is enabled */ bool wsrep_commit_will_write_binlog(THD *thd); /** Register THD for group commit. The wsrep_trx must be in committing state, i.e. the call must be done after wsrep_before_commit() but before commit order is released. This call will release commit order critical section if it is determined that the commit will go through binlog group commit. */ void wsrep_register_for_group_commit(THD *thd); /** Deregister THD from group commit. The wsrep_trx must be in committing state, as for wsrep_register_for_group_commit() above. This call must be used only for THDs which will not go through binlog group commit. */ void wsrep_unregister_from_group_commit(THD *thd); #endif /* WSREP_BINLOG_H */ server/private/item_strfunc.h000064400000215061151031265050012402 0ustar00#ifndef ITEM_STRFUNC_INCLUDED #define ITEM_STRFUNC_INCLUDED /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. Copyright (c) 2009, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file defines all string functions */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif extern size_t username_char_length; class Item_str_func :public Item_func { protected: /** Sets the result value of the function an empty string, using the current character set. No memory is allocated. @retval A pointer to the str_value member. */ virtual String *make_empty_result(String *str) { /* Reset string length to an empty string. We don't use str_value.set() as we don't want to free and potentially have to reallocate the buffer for each call. */ if (!str->is_alloced()) str->set("", 0, collation.collation); /* Avoid null ptrs */ else { str->length(0); /* Reuse allocated area */ str->set_charset(collation.collation); } return str; } public: Item_str_func(THD *thd): Item_func(thd) { decimals=NOT_FIXED_DEC; } Item_str_func(THD *thd, Item *a): Item_func(thd, a) {decimals=NOT_FIXED_DEC; } Item_str_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b) { decimals=NOT_FIXED_DEC; } Item_str_func(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b, c) { decimals=NOT_FIXED_DEC; } Item_str_func(THD *thd, Item *a, Item *b, Item *c, Item *d): Item_func(thd, a, b, c, d) { decimals=NOT_FIXED_DEC; } Item_str_func(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e): Item_func(thd, a, b, c, d, e) { decimals=NOT_FIXED_DEC; } Item_str_func(THD *thd, List &list): Item_func(thd, list) { decimals=NOT_FIXED_DEC; } longlong val_int() override; double val_real() override; my_decimal *val_decimal(my_decimal *) override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_string(thd, ltime, fuzzydate); } const Type_handler *type_handler() const override { return string_type_handler(); } void left_right_max_length(); bool fix_fields(THD *thd, Item **ref) override; }; /* Functions that return values with ASCII repertoire */ class Item_str_ascii_func :public Item_str_func { String ascii_buf; public: Item_str_ascii_func(THD *thd): Item_str_func(thd) {} Item_str_ascii_func(THD *thd, Item *a): Item_str_func(thd, a) {} Item_str_ascii_func(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} Item_str_ascii_func(THD *thd, Item *a, Item *b, Item *c): Item_str_func(thd, a, b, c) {} String *val_str(String *str) override { return val_str_from_val_str_ascii(str, &ascii_buf); } String *val_str_ascii(String *) override= 0; }; /** Functions that return a checksum or a hash of the argument, or somehow else encode or decode the argument, returning an ASCII-repertoire string. */ class Item_str_ascii_checksum_func: public Item_str_ascii_func { public: Item_str_ascii_checksum_func(THD *thd, Item *a) :Item_str_ascii_func(thd, a) { } Item_str_ascii_checksum_func(THD *thd, Item *a, Item *b) :Item_str_ascii_func(thd, a, b) { } bool eq(const Item *item, bool binary_cmp) const override { // Always use binary argument comparison: MD5('x') != MD5('X') return Item_func::eq(item, true); } }; /** Functions that return a checksum or a hash of the argument, or somehow else encode or decode the argument, returning a binary string. */ class Item_str_binary_checksum_func: public Item_str_func { public: Item_str_binary_checksum_func(THD *thd, Item *a) :Item_str_func(thd, a) { } Item_str_binary_checksum_func(THD *thd, Item *a, Item *b) :Item_str_func(thd, a, b) { } bool eq(const Item *item, bool binary_cmp) const override { /* Always use binary argument comparison: FROM_BASE64('test') != FROM_BASE64('TEST') */ return Item_func::eq(item, true); } }; class Item_func_md5 :public Item_str_ascii_checksum_func { public: Item_func_md5(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {} String *val_str_ascii(String *) override; bool fix_length_and_dec() override { fix_length_and_charset(32, default_charset()); return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("md5") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_sha :public Item_str_ascii_checksum_func { public: Item_func_sha(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {} String *val_str_ascii(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("sha") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_sha2 :public Item_str_ascii_checksum_func { public: Item_func_sha2(THD *thd, Item *a, Item *b) :Item_str_ascii_checksum_func(thd, a, b) {} String *val_str_ascii(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("sha2") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_to_base64 :public Item_str_ascii_checksum_func { String tmp_value; public: Item_func_to_base64(THD *thd, Item *a) :Item_str_ascii_checksum_func(thd, a) {} String *val_str_ascii(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("to_base64") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_from_base64 :public Item_str_binary_checksum_func { String tmp_value; public: Item_func_from_base64(THD *thd, Item *a) :Item_str_binary_checksum_func(thd, a) { } String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("from_base64") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #include class Item_aes_crypt :public Item_str_binary_checksum_func { enum { AES_KEY_LENGTH = 128 }; void create_key(String *user_key, uchar* key); protected: int what; String tmp_value; public: Item_aes_crypt(THD *thd, Item *a, Item *b) :Item_str_binary_checksum_func(thd, a, b) {} String *val_str(String *) override; }; class Item_func_aes_encrypt :public Item_aes_crypt { public: Item_func_aes_encrypt(THD *thd, Item *a, Item *b) :Item_aes_crypt(thd, a, b) {} bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("aes_encrypt") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_aes_decrypt :public Item_aes_crypt { public: Item_func_aes_decrypt(THD *thd, Item *a, Item *b): Item_aes_crypt(thd, a, b) {} bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("aes_decrypt") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_concat :public Item_str_func { protected: String tmp_value; /* Append a non-NULL value to the result. @param [IN] thd - The current thread. @param [IN/OUT] res - The current val_str() return value. @param [IN] app - The value to be appended. @retval - false on success, true on error */ bool append_value(THD *thd, String *res, const String *app); bool realloc_result(String *str, uint length) const; public: Item_func_concat(THD *thd, List &list): Item_str_func(thd, list) {} Item_func_concat(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} const Schema *schema() const override { return &mariadb_schema; } void print(String *str, enum_query_type query_type) override { print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("concat") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* This class handles the || operator in sql_mode=ORACLE. Unlike the traditional MariaDB concat(), it treats NULL arguments as ''. */ class Item_func_concat_operator_oracle :public Item_func_concat { public: Item_func_concat_operator_oracle(THD *thd, List &list) :Item_func_concat(thd, list) { } Item_func_concat_operator_oracle(THD *thd, Item *a, Item *b) :Item_func_concat(thd, a, b) { } String *val_str(String *) override; const Schema *schema() const override { return &oracle_schema_ref; } void print(String *str, enum_query_type query_type) override { if (query_type & QT_FOR_FRM) { // 10.3 downgrade compatibility for FRM str->append(STRING_WITH_LEN("concat_operator_oracle")); } else print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_decode_histogram :public Item_str_func { public: Item_func_decode_histogram(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} String *val_str(String *) override; bool fix_length_and_dec() override { collation.set(system_charset_info); max_length= MAX_BLOB_WIDTH; set_maybe_null(); return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("decode_histogram") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_concat_ws :public Item_str_func { String tmp_value; public: Item_func_concat_ws(THD *thd, List &list): Item_str_func(thd, list) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("concat_ws") }; return name; } table_map not_null_tables() const override { return 0; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_reverse :public Item_str_func { String tmp_value; public: Item_func_reverse(THD *thd, Item *a): Item_str_func(thd, a) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("reverse") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_replace :public Item_str_func { String tmp_value,tmp_value2; protected: String *val_str_internal(String *str, bool null_to_empty); public: Item_func_replace(THD *thd, Item *org, Item *find, Item *replace): Item_str_func(thd, org, find, replace) {} String *val_str(String *to) override { return val_str_internal(to, false); }; bool fix_length_and_dec() override; const Schema *schema() const override { return &mariadb_schema; } void print(String *str, enum_query_type query_type) override { print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("replace") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_replace_oracle :public Item_func_replace { String tmp_emtpystr; public: Item_func_replace_oracle(THD *thd, Item *org, Item *find, Item *replace): Item_func_replace(thd, org, find, replace) {} String *val_str(String *to) override { return val_str_internal(to, true); }; const Schema *schema() const override { return &oracle_schema_ref; } void print(String *str, enum_query_type query_type) override { if (query_type & QT_FOR_FRM) { // 10.3 downgrade compatibility for FRM str->append(STRING_WITH_LEN("replace_oracle")); } else print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_regexp_replace :public Item_str_func { Regexp_processor_pcre re; bool append_replacement(String *str, const LEX_CSTRING *source, const LEX_CSTRING *replace); protected: String *val_str_internal(String *str, bool null_to_empty); public: Item_func_regexp_replace(THD *thd, Item *a, Item *b, Item *c): Item_str_func(thd, a, b, c) {} const Schema *schema() const override { return &mariadb_schema; } void print(String *str, enum_query_type query_type) override { print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } void cleanup() override { DBUG_ENTER("Item_func_regexp_replace::cleanup"); Item_str_func::cleanup(); re.cleanup(); DBUG_VOID_RETURN; } String *val_str(String *str) override { return val_str_internal(str, false); } bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("regexp_replace") }; return name; } Item *do_get_copy(THD *thd) const override { return 0;} }; class Item_func_regexp_replace_oracle: public Item_func_regexp_replace { public: Item_func_regexp_replace_oracle(THD *thd, Item *a, Item *b, Item *c) :Item_func_regexp_replace(thd, a, b, c) {} const Schema *schema() const override { return &oracle_schema_ref; } bool fix_length_and_dec() override { bool rc= Item_func_regexp_replace::fix_length_and_dec(); set_maybe_null(); // Empty result is converted to NULL return rc; } String *val_str(String *str) override { return val_str_internal(str, true); } }; class Item_func_regexp_substr :public Item_str_func { Regexp_processor_pcre re; public: Item_func_regexp_substr(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} void cleanup() override { DBUG_ENTER("Item_func_regexp_substr::cleanup"); Item_str_func::cleanup(); re.cleanup(); DBUG_VOID_RETURN; } String *val_str(String *str) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("regexp_substr") }; return name; } Item *do_get_copy(THD *thd) const override { return 0; } }; class Item_func_insert :public Item_str_func { String tmp_value; public: Item_func_insert(THD *thd, Item *org, Item *start, Item *length, Item *new_str): Item_str_func(thd, org, start, length, new_str) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("insert") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_str_conv :public Item_str_func { protected: uint multiply; my_charset_conv_case converter; String tmp_value; public: Item_str_conv(THD *thd, Item *item): Item_str_func(thd, item) {} String *val_str(String *) override; }; class Item_func_lcase :public Item_str_conv { public: Item_func_lcase(THD *thd, Item *item): Item_str_conv(thd, item) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("lcase") }; return name; } bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_ucase :public Item_str_conv { public: Item_func_ucase(THD *thd, Item *item): Item_str_conv(thd, item) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("ucase") }; return name; } bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_left :public Item_str_func { String tmp_value; public: Item_func_left(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} bool hash_not_null(Hasher *hasher) override; String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("left") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_right :public Item_str_func { String tmp_value; public: Item_func_right(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("right") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_substr :public Item_str_func { String tmp_value; protected: virtual longlong get_position() { return args[1]->val_int(); } public: Item_func_substr(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} Item_func_substr(THD *thd, Item *a, Item *b, Item *c): Item_str_func(thd, a, b, c) {} Item_func_substr(THD *thd, List &list) :Item_str_func(thd, list) {} String *val_str(String *) override; bool fix_length_and_dec() override; const Schema *schema() const override { return &mariadb_schema; } void print(String *str, enum_query_type query_type) override { print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("substr") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_substr_oracle :public Item_func_substr { protected: longlong get_position() override { longlong pos= args[1]->val_int(); return pos == 0 ? 1 : pos; } String *make_empty_result(String *str) override { null_value= 1; return NULL; } public: Item_func_substr_oracle(THD *thd, Item *a, Item *b): Item_func_substr(thd, a, b) {} Item_func_substr_oracle(THD *thd, Item *a, Item *b, Item *c): Item_func_substr(thd, a, b, c) {} Item_func_substr_oracle(THD *thd, List &list) :Item_func_substr(thd, list) {} bool fix_length_and_dec() override { bool res= Item_func_substr::fix_length_and_dec(); set_maybe_null(); return res; } const Schema *schema() const override { return &oracle_schema_ref; } void print(String *str, enum_query_type query_type) override { if (query_type & QT_FOR_FRM) { // 10.3 downgrade compatibility for FRM str->append(STRING_WITH_LEN("substr_oracle")); } else print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_substr_index :public Item_str_func { String tmp_value; public: Item_func_substr_index(THD *thd, Item *a,Item *b,Item *c): Item_str_func(thd, a, b, c) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("substring_index") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_trim :public Item_str_func { protected: String tmp_value; String remove; String *trimmed_value(String *res, uint32 offset, uint32 length) { if (length == 0) return make_empty_result(&tmp_value); tmp_value.set(*res, offset, length); /* Make sure to return correct charset and collation: TRIM(0x000000 FROM _ucs2 0x0061) should set charset to "binary" rather than to "ucs2". */ tmp_value.set_charset(collation.collation); return &tmp_value; } String *non_trimmed_value(String *res) { return trimmed_value(res, 0, res->length()); } public: Item_func_trim(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} Item_func_trim(THD *thd, Item *a): Item_str_func(thd, a) {} Sql_mode_dependency value_depends_on_sql_mode() const override; String *val_str(String *) override; bool fix_length_and_dec() override; const Schema *schema() const override { return &mariadb_schema; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("trim") }; return name; } void print(String *str, enum_query_type query_type) override; virtual LEX_CSTRING mode_name() const { return { "both", 4}; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_trim_oracle :public Item_func_trim { protected: String *make_empty_result(String *str) override { null_value= 1; return NULL; } public: Item_func_trim_oracle(THD *thd, Item *a, Item *b): Item_func_trim(thd, a, b) {} Item_func_trim_oracle(THD *thd, Item *a): Item_func_trim(thd, a) {} const Schema *schema() const override { return &oracle_schema_ref; } bool fix_length_and_dec() override { bool res= Item_func_trim::fix_length_and_dec(); set_maybe_null(); return res; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_ltrim :public Item_func_trim { public: Item_func_ltrim(THD *thd, Item *a, Item *b): Item_func_trim(thd, a, b) {} Item_func_ltrim(THD *thd, Item *a): Item_func_trim(thd, a) {} Sql_mode_dependency value_depends_on_sql_mode() const override { return Item_func::value_depends_on_sql_mode(); } String *val_str(String *) override; const Schema *schema() const override { return &mariadb_schema; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("ltrim") }; return name; } LEX_CSTRING mode_name() const override { return { STRING_WITH_LEN("leading") }; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_ltrim_oracle :public Item_func_ltrim { protected: String *make_empty_result(String *str) override { null_value= 1; return NULL; } public: Item_func_ltrim_oracle(THD *thd, Item *a, Item *b): Item_func_ltrim(thd, a, b) {} Item_func_ltrim_oracle(THD *thd, Item *a): Item_func_ltrim(thd, a) {} const Schema *schema() const override { return &oracle_schema_ref; } bool fix_length_and_dec() override { bool res= Item_func_ltrim::fix_length_and_dec(); set_maybe_null(); return res; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_rtrim :public Item_func_trim { public: Item_func_rtrim(THD *thd, Item *a, Item *b): Item_func_trim(thd, a, b) {} Item_func_rtrim(THD *thd, Item *a): Item_func_trim(thd, a) {} String *val_str(String *) override; const Schema *schema() const override { return &mariadb_schema; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("rtrim") }; return name; } LEX_CSTRING mode_name() const override { return { STRING_WITH_LEN("trailing") }; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_rtrim_oracle :public Item_func_rtrim { protected: String *make_empty_result(String *str) override { null_value= 1; return NULL; } public: Item_func_rtrim_oracle(THD *thd, Item *a, Item *b): Item_func_rtrim(thd, a, b) {} Item_func_rtrim_oracle(THD *thd, Item *a): Item_func_rtrim(thd, a) {} const Schema *schema() const override { return &oracle_schema_ref; } bool fix_length_and_dec() override { bool res= Item_func_rtrim::fix_length_and_dec(); set_maybe_null(); return res; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* Item_func_password -- new (4.1.1) PASSWORD() function implementation. Returns strcat('*', octet2hex(sha1(sha1(password)))). '*' stands for new password format, sha1(sha1(password) is so-called hash_stage2 value. Length of returned string is always 41 byte. To find out how entire authentication procedure works, see comments in password.c. */ class Item_func_password :public Item_str_ascii_checksum_func { public: enum PW_Alg {OLD, NEW}; private: char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; enum PW_Alg alg; bool deflt; public: Item_func_password(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a), alg(NEW), deflt(1) {} Item_func_password(THD *thd, Item *a, PW_Alg al): Item_str_ascii_checksum_func(thd, a), alg(al), deflt(0) {} String *val_str_ascii(String *str) override; bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override { fix_length_and_charset((alg == 1 ? SCRAMBLED_PASSWORD_CHAR_LENGTH : SCRAMBLED_PASSWORD_CHAR_LENGTH_323), default_charset()); return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING password_normal= {STRING_WITH_LEN("password") }; static LEX_CSTRING password_old= {STRING_WITH_LEN("old_password") }; return (deflt || alg == 1) ? password_normal : password_old; } static char *alloc(THD *thd, const char *password, size_t pass_len, enum PW_Alg al); Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_des_encrypt :public Item_str_binary_checksum_func { String tmp_value,tmp_arg; public: Item_func_des_encrypt(THD *thd, Item *a) :Item_str_binary_checksum_func(thd, a) {} Item_func_des_encrypt(THD *thd, Item *a, Item *b) :Item_str_binary_checksum_func(thd, a, b) {} String *val_str(String *) override; bool fix_length_and_dec() override { set_maybe_null(); /* 9 = MAX ((8- (arg_len % 8)) + 1) */ max_length = args[0]->max_length + 9; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("des_encrypt") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_des_decrypt :public Item_str_binary_checksum_func { String tmp_value; public: Item_func_des_decrypt(THD *thd, Item *a) :Item_str_binary_checksum_func(thd, a) {} Item_func_des_decrypt(THD *thd, Item *a, Item *b) :Item_str_binary_checksum_func(thd, a, b) {} String *val_str(String *) override; bool fix_length_and_dec() override { set_maybe_null(); /* 9 = MAX ((8- (arg_len % 8)) + 1) */ max_length= args[0]->max_length; if (max_length >= 9U) max_length-= 9U; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("des_decrypt") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /** QQ: Item_func_encrypt should derive from Item_str_ascii_checksum_func. However, it should be fixed to handle UCS2, UTF16, UTF32 properly first, as the underlying crypt() call expects a null-terminated input string. */ class Item_func_encrypt :public Item_str_binary_checksum_func { String tmp_value; /* Encapsulate common constructor actions */ void constructor_helper() { collation.set(&my_charset_bin); } public: Item_func_encrypt(THD *thd, Item *a): Item_str_binary_checksum_func(thd, a) { constructor_helper(); } Item_func_encrypt(THD *thd, Item *a, Item *b) :Item_str_binary_checksum_func(thd, a, b) { constructor_helper(); } String *val_str(String *) override; bool fix_length_and_dec() override { set_maybe_null(); max_length = 13; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("encrypt") }; return name; } bool check_vcol_func_processor(void *arg) override { return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #include "sql_crypt.h" class Item_func_encode :public Item_str_binary_checksum_func { private: /** Whether the PRNG has already been seeded. */ bool seeded; protected: SQL_CRYPT sql_crypt; public: Item_func_encode(THD *thd, Item *a, Item *seed_arg): Item_str_binary_checksum_func(thd, a, seed_arg) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("encode") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } protected: virtual void crypto_transform(String *); private: /** Provide a seed for the PRNG sequence. */ bool seed(); }; class Item_func_decode :public Item_func_encode { public: Item_func_decode(THD *thd, Item *a, Item *seed_arg): Item_func_encode(thd, a, seed_arg) {} const Schema *schema() const override { return &mariadb_schema; } void print(String *str, enum_query_type query_type) override { print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("decode") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } protected: void crypto_transform(String *) override; }; class Item_func_sysconst :public Item_str_func { public: Item_func_sysconst(THD *thd): Item_str_func(thd) { collation.set(system_charset_info,DERIVATION_SYSCONST); } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; /* Used to create correct Item name in new converted item in safe_charset_converter, return string representation of this function call */ virtual const char *fully_qualified_func_name() const = 0; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(fully_qualified_func_name(), arg, VCOL_SESSION_FUNC); } bool const_item() const override; }; class Item_func_database :public Item_func_sysconst { public: Item_func_database(THD *thd): Item_func_sysconst(thd) {} String *val_str(String *) override; bool fix_length_and_dec() override { max_length= NAME_CHAR_LEN * system_charset_info->mbmaxlen; set_maybe_null(); return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("database") }; return name; } const char *fully_qualified_func_name() const override { return "database()"; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_sqlerrm :public Item_func_sysconst { public: Item_func_sqlerrm(THD *thd): Item_func_sysconst(thd) {} String *val_str(String *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("SQLERRM") }; return name; } const char *fully_qualified_func_name() const override { return "SQLERRM"; } void print(String *str, enum_query_type query_type) override { str->append(func_name_cstring()); } bool fix_length_and_dec() override { max_length= 512 * system_charset_info->mbmaxlen; null_value= false; base_flags&= ~item_base_t::MAYBE_NULL; return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_user :public Item_func_sysconst { protected: bool init (const char *user, const char *host); public: Item_func_user(THD *thd): Item_func_sysconst(thd) { str_value.set("", 0, system_charset_info); } String *val_str(String *) override { DBUG_ASSERT(fixed()); return (null_value ? 0 : &str_value); } bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override { max_length= (uint32) (username_char_length + HOSTNAME_LENGTH + 1) * SYSTEM_CHARSET_MBMAXLEN; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("user") }; return name; } const char *fully_qualified_func_name() const override { return "user()"; } int save_in_field(Field *field, bool no_conversions) override { return save_str_value_in_field(field, &str_value); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_current_user :public Item_func_user { Name_resolution_context *context; public: Item_func_current_user(THD *thd, Name_resolution_context *context_arg): Item_func_user(thd), context(context_arg) {} bool fix_fields(THD *thd, Item **ref) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("current_user") }; return name; } const char *fully_qualified_func_name() const override { return "current_user()"; } bool check_vcol_func_processor(void *arg) override { context= 0; return mark_unsupported_function(fully_qualified_func_name(), arg, VCOL_SESSION_FUNC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_current_role :public Item_func_sysconst { Name_resolution_context *context; public: Item_func_current_role(THD *thd, Name_resolution_context *context_arg): Item_func_sysconst(thd), context(context_arg) {} bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override { max_length= (uint32) username_char_length * SYSTEM_CHARSET_MBMAXLEN; return FALSE; } int save_in_field(Field *field, bool no_conversions) override { return save_str_value_in_field(field, &str_value); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("current_role") }; return name; } const char *fully_qualified_func_name() const override { return "current_role()"; } String *val_str(String *) override { DBUG_ASSERT(fixed()); return null_value ? NULL : &str_value; } bool check_vcol_func_processor(void *arg) override { context= 0; return mark_unsupported_function(fully_qualified_func_name(), arg, VCOL_SESSION_FUNC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_soundex :public Item_str_func { String tmp_value; public: Item_func_soundex(THD *thd, Item *a): Item_str_func(thd, a) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("soundex") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_elt :public Item_str_func { public: Item_func_elt(THD *thd, List &list): Item_str_func(thd, list) {} double val_real() override; longlong val_int() override; String *val_str(String *str) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("elt") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_make_set :public Item_str_func { String tmp_str; public: Item_func_make_set(THD *thd, List &list): Item_str_func(thd, list) {} String *val_str(String *str) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("make_set") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_format :public Item_str_ascii_func { const MY_LOCALE *locale; public: Item_func_format(THD *thd, Item *org, Item *dec): Item_str_ascii_func(thd, org, dec) {} Item_func_format(THD *thd, Item *org, Item *dec, Item *lang): Item_str_ascii_func(thd, org, dec, lang) {} String *val_str_ascii(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("format") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_char :public Item_str_func { public: Item_func_char(THD *thd, List &list): Item_str_func(thd, list) { collation.set(&my_charset_bin); } Item_func_char(THD *thd, List &list, CHARSET_INFO *cs): Item_str_func(thd, list) { collation.set(cs); } Item_func_char(THD *thd, Item *arg1, CHARSET_INFO *cs): Item_str_func(thd, arg1) { collation.set(cs); } String *val_str(String *) override; void append_char(String * str, int32 num); bool fix_length_and_dec() override { max_length= arg_count * 4; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("char") }; return name; } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_chr :public Item_func_char { public: Item_func_chr(THD *thd, Item *arg1, CHARSET_INFO *cs): Item_func_char(thd, arg1, cs) {} String *val_str(String *) override; bool fix_length_and_dec() override { max_length= 4; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("chr") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_repeat :public Item_str_func { String tmp_value; public: Item_func_repeat(THD *thd, Item *arg1, Item *arg2): Item_str_func(thd, arg1, arg2) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("repeat") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_space :public Item_str_func { public: Item_func_space(THD *thd, Item *arg1): Item_str_func(thd, arg1) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("space") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_binlog_gtid_pos :public Item_str_func { public: Item_func_binlog_gtid_pos(THD *thd, Item *arg1, Item *arg2): Item_str_func(thd, arg1, arg2) {} String *val_str(String *) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("binlog_gtid_pos") }; return name; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_pad: public Item_str_func { protected: String tmp_value, pad_str; public: Item_func_pad(THD *thd, Item *arg1, Item *arg2, Item *arg3): Item_str_func(thd, arg1, arg2, arg3) {} Item_func_pad(THD *thd, Item *arg1, Item *arg2): Item_str_func(thd, arg1, arg2) {} Item_func_pad(THD *thd, List &list): Item_str_func(thd,list) {} bool fix_length_and_dec() override; }; class Item_func_rpad :public Item_func_pad { public: Item_func_rpad(THD *thd, Item *arg1, Item *arg2, Item *arg3): Item_func_pad(thd, arg1, arg2, arg3) {} Item_func_rpad(THD *thd, Item *arg1, Item *arg2): Item_func_pad(thd, arg1, arg2) {} Item_func_rpad(THD *thd, List &list): Item_func_pad(thd,list) {} String *val_str(String *) override; const Schema *schema() const override { return &mariadb_schema; } void print(String *str, enum_query_type query_type) override { print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("rpad") }; return name; } Sql_mode_dependency value_depends_on_sql_mode() const override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_rpad_oracle :public Item_func_rpad { String *make_empty_result(String *str) override { null_value= 1; return NULL; } public: Item_func_rpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3): Item_func_rpad(thd, arg1, arg2, arg3) {} Item_func_rpad_oracle(THD *thd, Item *arg1, Item *arg2): Item_func_rpad(thd, arg1, arg2) {} Item_func_rpad_oracle(THD *thd, List &list): Item_func_rpad(thd,list) {} bool fix_length_and_dec() override { bool res= Item_func_rpad::fix_length_and_dec(); set_maybe_null(); return res; } const Schema *schema() const override { return &oracle_schema_ref; } void print(String *str, enum_query_type query_type) override { if (query_type & QT_FOR_FRM) { // 10.3 downgrade compatibility for FRM str->append(STRING_WITH_LEN("rpad_oracle")); } else print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_lpad :public Item_func_pad { public: Item_func_lpad(THD *thd, Item *arg1, Item *arg2, Item *arg3): Item_func_pad(thd, arg1, arg2, arg3) {} Item_func_lpad(THD *thd, Item *arg1, Item *arg2): Item_func_pad(thd, arg1, arg2) {} Item_func_lpad(THD *thd, List &list): Item_func_pad(thd,list) {} String *val_str(String *) override; const Schema *schema() const override { return &mariadb_schema; } void print(String *str, enum_query_type query_type) override { print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("lpad") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_lpad_oracle :public Item_func_lpad { String *make_empty_result(String *str) override { null_value= 1; return NULL; } public: Item_func_lpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3): Item_func_lpad(thd, arg1, arg2, arg3) {} Item_func_lpad_oracle(THD *thd, Item *arg1, Item *arg2): Item_func_lpad(thd, arg1, arg2) {} Item_func_lpad_oracle(THD *thd, List &list): Item_func_lpad(thd,list) {} bool fix_length_and_dec() override { bool res= Item_func_lpad::fix_length_and_dec(); set_maybe_null(); return res; } const Schema *schema() const override { return &oracle_schema_ref; } void print(String *str, enum_query_type query_type) override { if (query_type & QT_FOR_FRM) { // 10.3 downgrade compatibility for FRM str->append(STRING_WITH_LEN("lpad_oracle")); } else print_sql_mode_qualified_name(str, query_type); print_args_parenthesized(str, query_type); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_conv :public Item_str_func { public: Item_func_conv(THD *thd, Item *a, Item *b, Item *c): Item_str_func(thd, a, b, c) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("conv") }; return name; } String *val_str(String *) override; bool fix_length_and_dec() override { collation.set(default_charset()); fix_char_length(65); set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_hex :public Item_str_ascii_checksum_func { protected: String tmp_value; /* Calling arg[0]->type_handler() can be expensive on every row. It's a virtual method, and in case if args[0] is a complex Item, its type_handler() can call more virtual methods. So let's cache it during fix_length_and_dec(). */ const Type_handler *m_arg0_type_handler; public: Item_func_hex(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a), m_arg0_type_handler(NULL) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("hex") }; return name; } String *val_str_ascii_from_val_int(String *str); String *val_str_ascii_from_val_real(String *str); String *val_str_ascii_from_val_str(String *str); String *val_str_ascii(String *str) override { DBUG_ASSERT(fixed()); return m_arg0_type_handler->Item_func_hex_val_str_ascii(this, str); } bool fix_length_and_dec() override { m_arg0_type_handler= args[0]->type_handler(); collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); decimals=0; /* Reserve space for 16 characters for signed numeric data types: hex(-1) -> 'FFFFFFFFFFFFFFFF'. For unsigned numeric types, HEX() can create too large columns. This should be eventually fixed to create minimum possible columns. */ const Type_handler_numeric *tn= dynamic_cast(m_arg0_type_handler); size_t char_length= (tn && !(tn->flags() & UNSIGNED_FLAG)) ? (size_t) 16 : (size_t) args[0]->max_length * 2; fix_char_length(char_length); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_unhex :public Item_str_func { String tmp_value; public: Item_func_unhex(THD *thd, Item *a): Item_str_func(thd, a) { /* there can be bad hex strings */ set_maybe_null(); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("unhex") }; return name; } String *val_str(String *) override; bool fix_length_and_dec() override { collation.set(&my_charset_bin); decimals=0; max_length=(1+args[0]->max_length)/2; return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #ifndef DBUG_OFF class Item_func_like_range :public Item_str_func { protected: String min_str; String max_str; const bool is_min; public: Item_func_like_range(THD *thd, Item *a, Item *b, bool is_min_arg): Item_str_func(thd, a, b), is_min(is_min_arg) { set_maybe_null(); } String *val_str(String *) override; bool fix_length_and_dec() override { collation.set(args[0]->collation); decimals=0; max_length= MAX_BLOB_WIDTH; return FALSE; } }; class Item_func_like_range_min :public Item_func_like_range { public: Item_func_like_range_min(THD *thd, Item *a, Item *b): Item_func_like_range(thd, a, b, true) { } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("like_range_min") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_like_range_max :public Item_func_like_range { public: Item_func_like_range_max(THD *thd, Item *a, Item *b): Item_func_like_range(thd, a, b, false) { } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("like_range_max") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #endif class Item_func_binary :public Item_str_func { public: Item_func_binary(THD *thd, Item *a): Item_str_func(thd, a) {} String *val_str(String *a) override { DBUG_ASSERT(fixed()); String *tmp=args[0]->val_str(a); null_value=args[0]->null_value; if (tmp) tmp->set_charset(&my_charset_bin); return tmp; } bool fix_length_and_dec() override { collation.set(&my_charset_bin); max_length=args[0]->max_length; return FALSE; } void print(String *str, enum_query_type query_type) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("cast_as_binary") }; return name; } bool need_parentheses_in_default() override { return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_load_file :public Item_str_func { String tmp_value; public: Item_load_file(THD *thd, Item *a): Item_str_func(thd, a) {} String *val_str(String *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("load_file") }; return name; } bool fix_length_and_dec() override { collation.set(&my_charset_bin, DERIVATION_COERCIBLE); set_maybe_null(); max_length=MAX_BLOB_WIDTH; return FALSE; } bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_export_set: public Item_str_func { public: Item_func_export_set(THD *thd, Item *a, Item *b, Item* c): Item_str_func(thd, a, b, c) {} Item_func_export_set(THD *thd, Item *a, Item *b, Item* c, Item* d): Item_str_func(thd, a, b, c, d) {} Item_func_export_set(THD *thd, Item *a, Item *b, Item* c, Item* d, Item* e): Item_str_func(thd, a, b, c, d, e) {} String *val_str(String *str) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("export_set") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_quote :public Item_str_func { String tmp_value; public: Item_func_quote(THD *thd, Item *a): Item_str_func(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("quote") }; return name; } String *val_str(String *) override; bool fix_length_and_dec() override { collation.set(args[0]->collation); ulonglong max_result_length= (ulonglong) args[0]->max_length * 2 + 2 * collation.collation->mbmaxlen; // NULL argument is returned as a string "NULL" without quotes if (args[0]->maybe_null()) set_if_bigger(max_result_length, 4 * collation.collation->mbmaxlen); max_length= (uint32) MY_MIN(max_result_length, MAX_BLOB_WIDTH); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_conv_charset :public Item_str_func { bool use_cached_value; String tmp_value; public: bool safe; Item_func_conv_charset(THD *thd, Item *a, CHARSET_INFO *cs): Item_str_func(thd, a) { collation.set(cs, DERIVATION_IMPLICIT); use_cached_value= 0; safe= 0; } Item_func_conv_charset(THD *thd, Item *a, CHARSET_INFO *cs, bool cache_if_const): Item_str_func(thd, a) { collation.set(cs, DERIVATION_IMPLICIT); if (cache_if_const && args[0]->can_eval_in_optimize()) { uint errors= 0; String tmp, *str= args[0]->val_str(&tmp); if (!str || str_value.copy(str->ptr(), str->length(), str->charset(), cs, &errors)) null_value= 1; use_cached_value= 1; str_value.mark_as_const(); safe= (errors == 0); } else { use_cached_value= 0; /* Conversion from and to "binary" is safe. Conversion to Unicode is safe. Conversion from an expression with the ASCII repertoire to any character set that can store characters U+0000..U+007F is safe: - All supported multibyte character sets can store U+0000..U+007F - All supported 7bit character sets can store U+0000..U+007F except those marked with MY_CS_NONASCII (e.g. swe7). Other kind of conversions are potentially lossy. */ safe= (args[0]->collation.collation == &my_charset_bin || cs == &my_charset_bin || (cs->state & MY_CS_UNICODE) || (args[0]->collation.repertoire == MY_REPERTOIRE_ASCII && (cs->mbmaxlen > 1 || !(cs->state & MY_CS_NONASCII)))); } } String *val_str(String *) override; longlong val_int() override { if (args[0]->result_type() == STRING_RESULT) return Item_str_func::val_int(); longlong res= args[0]->val_int(); if ((null_value= args[0]->null_value)) return 0; return res; } double val_real() override { if (args[0]->result_type() == STRING_RESULT) return Item_str_func::val_real(); double res= args[0]->val_real(); if ((null_value= args[0]->null_value)) return 0; return res; } my_decimal *val_decimal(my_decimal *d) override { if (args[0]->result_type() == STRING_RESULT) return Item_str_func::val_decimal(d); my_decimal *res= args[0]->val_decimal(d); if ((null_value= args[0]->null_value)) return NULL; return res; } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { if (args[0]->result_type() == STRING_RESULT) return Item_str_func::get_date(thd, ltime, fuzzydate); bool res= args[0]->get_date(thd, ltime, fuzzydate); if ((null_value= args[0]->null_value)) return 1; return res; } bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("convert") }; return name; } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } int save_in_field(Field*, bool) override; }; class Item_func_set_collation :public Item_str_func { CHARSET_INFO *m_set_collation; public: Item_func_set_collation(THD *thd, Item *a, CHARSET_INFO *set_collation): Item_str_func(thd, a), m_set_collation(set_collation) {} String *val_str(String *) override; bool fix_length_and_dec() override; bool eq(const Item *item, bool binary_cmp) const override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("collate") }; return name; } enum precedence precedence() const override { return COLLATE_PRECEDENCE; } enum Functype functype() const override { return COLLATE_FUNC; } void print(String *str, enum_query_type query_type) override; Item_field *field_for_view_update() override { /* this function is transparent for view updating */ return args[0]->field_for_view_update(); } bool need_parentheses_in_default() override { return true; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_expr_str_metadata :public Item_str_func { public: Item_func_expr_str_metadata(THD *thd, Item *a): Item_str_func(thd, a) { } bool fix_length_and_dec() override { collation.set(system_charset_info); max_length= 64 * collation.collation->mbmaxlen; // should be enough base_flags&= ~item_base_t::MAYBE_NULL; return FALSE; }; table_map not_null_tables() const override { return 0; } Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { return this; } bool const_item() const override { return true; } }; class Item_func_charset :public Item_func_expr_str_metadata { LEX_CSTRING m_cached_charset_info; public: Item_func_charset(THD *thd, Item *a) :Item_func_expr_str_metadata(thd, a) { } String *val_str(String *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("charset") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } table_map used_tables() const override { return 0; } bool fix_length_and_dec() override { if (Item_func_expr_str_metadata::fix_length_and_dec()) return true; /* Since this is a const item which doesn't use tables (see used_tables()), we don't want to access the function arguments during execution. That's why we store the charset here during the preparation phase and only return it later at the execution phase */ DBUG_ASSERT(args[0]->fixed()); m_cached_charset_info.str= args[0]->charset_for_protocol()->cs_name.str; m_cached_charset_info.length= args[0]->charset_for_protocol()->cs_name.length; return false; } }; class Item_func_collation :public Item_func_expr_str_metadata { public: Item_func_collation(THD *thd, Item *a) :Item_func_expr_str_metadata(thd, a) {} String *val_str(String *) override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("collation") }; return name; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_weight_string :public Item_str_func { String tmp_value; uint weigth_flags; uint nweights; uint result_length; public: Item_func_weight_string(THD *thd, Item *a, uint result_length_arg, uint nweights_arg, uint flags_arg): Item_str_func(thd, a) { nweights= nweights_arg; weigth_flags= flags_arg; result_length= result_length_arg; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("weight_string") }; return name; } String *val_str(String *) override; bool fix_length_and_dec() override; bool eq(const Item *item, bool binary_cmp) const override { if (!Item_str_func::eq(item, binary_cmp)) return false; Item_func_weight_string *that= (Item_func_weight_string *)item; return this->weigth_flags == that->weigth_flags && this->nweights == that->nweights && this->result_length == that->result_length; } Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) override { return this; } void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_crc32 :public Item_long_func { bool check_arguments() const override { return args[0]->check_type_can_return_str(func_name_cstring()); } String value; public: Item_func_crc32(THD *thd, Item *a): Item_long_func(thd, a) { unsigned_flag= 1; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("crc32") }; return name; } bool fix_length_and_dec() override { max_length=10; return FALSE; } longlong val_int() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_uncompressed_length : public Item_long_func_length { String value; public: Item_func_uncompressed_length(THD *thd, Item *a) :Item_long_func_length(thd, a) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("uncompressed_length") }; return name; } bool fix_length_and_dec() override { max_length=10; set_maybe_null(); return FALSE; } longlong val_int() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #ifdef HAVE_COMPRESS #define ZLIB_DEPENDED_FUNCTION ; #else #define ZLIB_DEPENDED_FUNCTION { null_value=1; return 0; } #endif class Item_func_compress: public Item_str_binary_checksum_func { String tmp_value; public: Item_func_compress(THD *thd, Item *a) :Item_str_binary_checksum_func(thd, a) {} bool fix_length_and_dec() override { max_length= (args[0]->max_length * 120) / 100 + 12; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("compress") }; return name; } String *val_str(String *) override ZLIB_DEPENDED_FUNCTION Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_uncompress: public Item_str_binary_checksum_func { String tmp_value; public: Item_func_uncompress(THD *thd, Item *a) :Item_str_binary_checksum_func(thd, a) {} bool fix_length_and_dec() override { set_maybe_null(); max_length= MAX_BLOB_WIDTH; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("uncompress") }; return name; } String *val_str(String *) override ZLIB_DEPENDED_FUNCTION Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_uuid: public Item_str_func { /* Set if uuid should be returned without separators (Oracle sys_guid) */ bool without_separators; public: Item_func_uuid(THD *thd, bool without_separators_arg): Item_str_func(thd), without_separators(without_separators_arg) {} bool fix_length_and_dec() override { collation.set(DTCollation_numeric()); fix_char_length(without_separators ? MY_UUID_ORACLE_STRING_LENGTH : MY_UUID_STRING_LENGTH); return FALSE; } bool const_item() const override { return false; } table_map used_tables() const override { return RAND_TABLE_BIT; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING mariadb_name= {STRING_WITH_LEN("uuid") }; static LEX_CSTRING oracle_name= {STRING_WITH_LEN("sys_guid") }; return without_separators ? oracle_name : mariadb_name; } String *val_str(String *) override; bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(func_name(), "()", arg, VCOL_NON_DETERMINISTIC); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_dyncol_create: public Item_str_func { protected: DYNCALL_CREATE_DEF *defs; DYNAMIC_COLUMN_VALUE *vals; uint *keys_num; LEX_STRING *keys_str; bool names, force_names; bool prepare_arguments(THD *thd, bool force_names); void print_arguments(String *str, enum_query_type query_type); public: Item_func_dyncol_create(THD *thd, List &args, DYNCALL_CREATE_DEF *dfs); bool fix_fields(THD *thd, Item **ref) override; bool fix_length_and_dec() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("column_create") }; return name; } String *val_str(String *) override; void print(String *str, enum_query_type query_type) override; enum Functype functype() const override { return DYNCOL_FUNC; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_dyncol_add: public Item_func_dyncol_create { public: Item_func_dyncol_add(THD *thd, List &args_arg, DYNCALL_CREATE_DEF *dfs): Item_func_dyncol_create(thd, args_arg, dfs) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("column_add") }; return name; } String *val_str(String *) override; void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_dyncol_json: public Item_str_func { public: Item_func_dyncol_json(THD *thd, Item *str): Item_str_func(thd, str) {collation.set(DYNCOL_UTF);} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("column_json") }; return name; } String *val_str(String *) override; bool fix_length_and_dec() override { max_length= MAX_BLOB_WIDTH; set_maybe_null(); decimals= 0; return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* The following functions is always called from an Item_cast function */ class Item_dyncol_get: public Item_str_func { public: Item_dyncol_get(THD *thd, Item *str, Item *num): Item_str_func(thd, str, num) {} bool fix_length_and_dec() override { set_maybe_null(); max_length= MAX_BLOB_WIDTH; return FALSE; } /* Mark that collation can change between calls */ bool dynamic_result() override { return 1; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("column_get") }; return name; } String *val_str(String *) override; longlong val_int() override; longlong val_int_signed_typecast() override { unsigned_flag= false; // Mark that we want to have a signed value longlong value= val_int(); // val_int() can change unsigned_flag if (!null_value && unsigned_flag && value < 0) push_note_converted_to_negative_complement(current_thd); return value; } longlong val_int_unsigned_typecast() override { unsigned_flag= true; // Mark that we want to have an unsigned value longlong value= val_int(); // val_int() can change unsigned_flag if (!null_value && unsigned_flag == 0 && value < 0) push_note_converted_to_positive_complement(current_thd); return value; } double val_real() override; my_decimal *val_decimal(my_decimal *) override; bool get_dyn_value(THD *thd, DYNAMIC_COLUMN_VALUE *val, String *tmp); bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_dyncol_list: public Item_str_func { public: Item_func_dyncol_list(THD *thd, Item *str): Item_str_func(thd, str) {collation.set(DYNCOL_UTF);} bool fix_length_and_dec() override { set_maybe_null(); max_length= MAX_BLOB_WIDTH; return FALSE; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("column_list") }; return name; } String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; /* this is used by JOIN_TAB::keep_current_rowid and stores handler::position(). It has nothing to do with _rowid pseudo-column, that the parser supports. */ class Item_temptable_rowid :public Item_str_func { public: TABLE *table; Item_temptable_rowid(TABLE *table_arg); const Type_handler *type_handler() const override { return &type_handler_string; } Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table) { return create_table_field_from_handler(root, table); } String *val_str(String *str) override; enum Functype functype() const override { return TEMPTABLE_ROWID; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("") }; return name; } bool fix_length_and_dec() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #ifdef WITH_WSREP #include "wsrep_api.h" class Item_func_wsrep_last_written_gtid: public Item_str_ascii_func { String gtid_str; public: Item_func_wsrep_last_written_gtid(THD *thd): Item_str_ascii_func(thd) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("wsrep_last_written_gtid") }; return name; } String *val_str_ascii(String *) override; bool fix_length_and_dec() override { max_length= WSREP_GTID_STR_LEN; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_wsrep_last_seen_gtid: public Item_str_ascii_func { String gtid_str; public: Item_func_wsrep_last_seen_gtid(THD *thd): Item_str_ascii_func(thd) {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("wsrep_last_seen_gtid") }; return name; } String *val_str_ascii(String *) override; bool fix_length_and_dec() override { max_length= WSREP_GTID_STR_LEN; set_maybe_null(); return FALSE; } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; class Item_func_wsrep_sync_wait_upto: public Item_int_func { String value; public: Item_func_wsrep_sync_wait_upto(THD *thd, Item *a): Item_int_func(thd, a) {} Item_func_wsrep_sync_wait_upto(THD *thd, Item *a, Item* b): Item_int_func(thd, a, b) {} const Type_handler *type_handler() const override { return &type_handler_string; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("wsrep_sync_wait_upto_gtid") }; return name; } longlong val_int() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; #endif /* WITH_WSREP */ #endif /* ITEM_STRFUNC_INCLUDED */ server/private/sql_admin.h000064400000005543151031265050011651 0ustar00/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef SQL_TABLE_MAINTENANCE_H #define SQL_TABLE_MAINTENANCE_H /* Must be able to hold ALTER TABLE t PARTITION BY ... KEY ALGORITHM = 1 ... */ #define SQL_ADMIN_MSG_TEXT_SIZE (128 * 1024) bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list, const LEX_CSTRING *key_cache_name); bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list); int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache, KEY_CACHE *dst_cache); void fill_check_table_metadata_fields(THD *thd, List* fields); /** Sql_cmd_analyze_table represents the ANALYZE TABLE statement. */ class Sql_cmd_analyze_table : public Sql_cmd { public: /** Constructor, used to represent a ANALYZE TABLE statement. */ Sql_cmd_analyze_table() = default; ~Sql_cmd_analyze_table() = default; bool execute(THD *thd) override; enum_sql_command sql_command_code() const override { return SQLCOM_ANALYZE; } }; /** Sql_cmd_check_table represents the CHECK TABLE statement. */ class Sql_cmd_check_table : public Sql_cmd { public: /** Constructor, used to represent a CHECK TABLE statement. */ Sql_cmd_check_table() = default; ~Sql_cmd_check_table() = default; bool execute(THD *thd) override; enum_sql_command sql_command_code() const override { return SQLCOM_CHECK; } }; /** Sql_cmd_optimize_table represents the OPTIMIZE TABLE statement. */ class Sql_cmd_optimize_table : public Sql_cmd { public: /** Constructor, used to represent a OPTIMIZE TABLE statement. */ Sql_cmd_optimize_table() = default; ~Sql_cmd_optimize_table() = default; bool execute(THD *thd) override; enum_sql_command sql_command_code() const override { return SQLCOM_OPTIMIZE; } }; /** Sql_cmd_repair_table represents the REPAIR TABLE statement. */ class Sql_cmd_repair_table : public Sql_cmd { public: /** Constructor, used to represent a REPAIR TABLE statement. */ Sql_cmd_repair_table() = default; ~Sql_cmd_repair_table() = default; bool execute(THD *thd) override; enum_sql_command sql_command_code() const override { return SQLCOM_REPAIR; } }; #endif server/private/sql_mode.h000064400000015117151031265050011503 0ustar00#ifndef SQL_MODE_H_INCLUDED #define SQL_MODE_H_INCLUDED /* Copyright (c) 2019, MariaDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #include "sql_basic_types.h" /* class Sql_mode_dependency A combination of hard and soft dependency on sql_mode. Used to watch if a GENERATED ALWAYS AS expression guarantees consitent data written to its virtual column. A virtual column can appear in an index if: - the generation expression does not depend on any sql_mode flags, or - the generation expression has a soft dependency on an sql_mode flag, and the column knows how to handle this dependeny. A virtual column cannot appear in an index if: - its generation expression has a hard dependency - its generation expression has a soft dependency, but the column cannot handle it on store. An error is reported in such cases. How dependencies appear: - When a column return value depends on some sql_mode flag, its Item_field adds a corresponding bit to m_soft. For example, Item_field for a CHAR(N) column adds the PAD_CHAR_TO_FULL_LENGTH flag. - When an SQL function/operator return value depends on some sql_mode flag, it adds a corresponding bit to m_soft. For example, Item_func_minus adds the MODE_NO_UNSIGNED_SUBTRACTION in case of unsigned arguments. How dependency are processed (see examples below): - All SQL functions/operators bit-OR all hard dependencies from all arguments. - Some soft dependencies can be handled by the underlying Field on store, e.g. CHAR(N) can handle PAD_CHAR_TO_FULL_LENGTH. - Some soft dependencies can be handled by SQL functions and operators, e.g. RTRIM(expr) removes expr's soft dependency on PAD_CHAR_TO_FULL_LENGTH. If a function or operator handles a soft dependency on a certain sql_mode flag, it removes the corresponding bit from m_soft (see below). Note, m_hard is not touched in such cases. - When an expression with a soft dependency on a certain sql_mode flag goes as an argument to an SQL function/operator which cannot handle this flag, the dependency escalates from soft to hard (by moving the corresponding bit from m_soft to m_hard) and cannot be handled any more on the upper level, neither by a Field on store, nor by another SQL function/operator. There are four kinds of Items: 1. Items that generate a soft or hard dependency, e.g. - Item_field for CHAR(N) - generates soft/PAD_CHAR_TO_FULL_LENGTH - Item_func_minus - generates soft/NO_UNSIGNED_SUBTRACTION 2. Items that convert a soft dependency to a hard dependency. This happens e.g. when an Item_func instance gets a soft dependency from its arguments, and it does not know how to handle this dependency. Most Item_func descendants do this. 3. Items that remove soft dependencies, e.g.: - Item_func_rtrim - removes soft/PAD_CHAR_TO_FULL_LENGTH that came from args[0] (under certain conditions) - Item_func_rpad - removes soft/PAD_CJAR_TO_FULL_LENGTH that came from args[0] (under certain conditions) 4. Items that repeat soft dependency from its arguments to the caller. They are not implemented yet. But functions like Item_func_coalesce, Item_func_case, Item_func_case_abbreviation2 could do this. Examples: 1. CREATE OR REPLACE TABLE t1 (a CHAR(5), v CHAR(20) AS(a), KEY(v)); Here `v` has a soft dependency on `a`. The value of `a` depends on PAD_CHAR_TO_FULL_LENGTH, it can return: - 'a' - if PAD_CHAR_TO_FULL_LENGTH is disabled - 'a' followed by four spaces - if PAD_CHAR_TO_FULL_LENGTH is enabled But `v` will pad trailing spaces to the full length on store anyway. So Field_string handles this soft dependency on store. This combination of the virtial column data type and its generation expression is safe and provides consistent data in `v`, which is 'a' followed by four spaces, no matter what PAD_CHAR_TO_FULL_LENGTH is. 2. CREATE OR REPLACE TABLE t1 (a CHAR(5), v VARCHAR(20) AS(a), KEY(v)); Here `v` has a soft dependency on `a`. But Field_varstring does not pad spaces on store, so it cannot handle this dependency. This combination of the virtual column data type and its generation expression is not safe. An error is returned. 3. CREATE OR REPLACE TABLE t1 (a CHAR(5), v INT AS(LENGTH(a)), KEY(v)); Here `v` has a hard dependency on `a`, because the value of `a` is wrapped to the function LENGTH(). The value of `LENGTH(a)` depends on PAD_CHAR_TO_FULL_LENGTH, it can return: - 1 - if PAD_CHAR_TO_FULL_LENGTH is disabled - 4 - if PAD_CHAR_TO_FULL_LENGTH is enabled This combination cannot provide consistent data stored to `v`, therefore it's disallowed. */ class Sql_mode_dependency { sql_mode_t m_hard; sql_mode_t m_soft; public: Sql_mode_dependency() :m_hard(0), m_soft(0) { } Sql_mode_dependency(sql_mode_t hard, sql_mode_t soft) :m_hard(hard), m_soft(soft) { } sql_mode_t hard() const { return m_hard; } sql_mode_t soft() const { return m_soft; } operator bool () const { return m_hard > 0 || m_soft > 0; } Sql_mode_dependency operator|(const Sql_mode_dependency &other) const { return Sql_mode_dependency(m_hard | other.m_hard, m_soft | other.m_soft); } Sql_mode_dependency operator&(const Sql_mode_dependency &other) const { return Sql_mode_dependency(m_hard & other.m_hard, m_soft & other.m_soft); } Sql_mode_dependency &operator|=(const Sql_mode_dependency &other) { m_hard|= other.m_hard; m_soft|= other.m_soft; return *this; } Sql_mode_dependency &operator&=(const Sql_mode_dependency &other) { m_hard&= other.m_hard; m_soft&= other.m_soft; return *this; } Sql_mode_dependency &soft_to_hard() { m_hard|= m_soft; m_soft= 0; return *this; } void push_dependency_warnings(THD *thd) const; }; #endif // SQL_MODE_H_INCLUDED server/private/myisampack.h000064400000035121151031265050012033 0ustar00#ifndef MYISAMPACK_INCLUDED #define MYISAMPACK_INCLUDED /* Copyright (c) 2000-2002, 2004 MySQL AB, 2009 Sun Microsystems, Inc. Copyright (c) 2020, MariaDB Corporation. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Storing of values in high byte first order. integer keys and file pointers are stored with high byte first to get better compression */ /* these two are for uniformity */ #define mi_sint1korr(A) ((int8)(*A)) #define mi_uint1korr(A) ((uint8)(*A)) #define mi_sint2korr(A) ((int16) (((int16) (((const uchar*) (A))[1])) |\ ((int16) ((uint16) ((const uchar*) (A))[0]) << 8))) #define mi_sint3korr(A) ((int32) (((((const uchar*) (A))[0]) & 128) ? \ (((uint32) 255L << 24) | \ (((uint32) ((const uchar*) (A))[0]) << 16) |\ (((uint32) ((const uchar*) (A))[1]) << 8) | \ ((uint32) ((const uchar*) (A))[2])) : \ (((uint32) ((const uchar*) (A))[0]) << 16) |\ (((uint32) ((const uchar*) (A))[1]) << 8) | \ ((uint32) ((const uchar*) (A))[2]))) #define mi_sint4korr(A) ((int32) (((uint32) (((const uchar*) (A))[3])) |\ ((uint32) (((const uchar*) (A))[2]) << 8) |\ ((uint32) (((const uchar*) (A))[1]) << 16) |\ ((uint32) (((const uchar*) (A))[0]) << 24))) #define mi_sint8korr(A) ((longlong) mi_uint8korr(A)) #define mi_uint2korr(A) ((uint16) (((uint16) (((const uchar*) (A))[1])) |\ ((uint16) (((const uchar*) (A))[0]) << 8))) #define mi_uint3korr(A) ((uint32) (((uint32) (((const uchar*) (A))[2])) |\ (((uint32) (((const uchar*) (A))[1])) << 8) |\ (((uint32) (((const uchar*) (A))[0])) << 16))) #define mi_uint4korr(A) ((uint32) (((uint32) (((const uchar*) (A))[3])) |\ (((uint32) (((const uchar*) (A))[2])) << 8) |\ (((uint32) (((const uchar*) (A))[1])) << 16) |\ (((uint32) (((const uchar*) (A))[0])) << 24))) #ifndef HAVE_mi_uint5korr #define mi_uint5korr(A) ((ulonglong)(((uint32) (((const uchar*) (A))[4])) |\ (((uint32) (((const uchar*) (A))[3])) << 8) |\ (((uint32) (((const uchar*) (A))[2])) << 16) |\ (((uint32) (((const uchar*) (A))[1])) << 24)) |\ (((ulonglong) (((const uchar*) (A))[0])) << 32)) #endif /* HAVE_mi_uint5korr */ #ifndef HAVE_mi_uint6korr #define mi_uint6korr(A) ((ulonglong)(((uint32) (((const uchar*) (A))[5])) |\ (((uint32) (((const uchar*) (A))[4])) << 8) |\ (((uint32) (((const uchar*) (A))[3])) << 16) |\ (((uint32) (((const uchar*) (A))[2])) << 24)) |\ (((ulonglong) (((uint32) (((const uchar*) (A))[1])) |\ (((uint32) (((const uchar*) (A))[0]) << 8)))) <<\ 32)) #endif /* HAVE_mi_uint6korr */ #ifndef HAVE_mi_uint7korr #define mi_uint7korr(A) ((ulonglong)(((uint32) (((const uchar*) (A))[6])) |\ (((uint32) (((const uchar*) (A))[5])) << 8) |\ (((uint32) (((const uchar*) (A))[4])) << 16) |\ (((uint32) (((const uchar*) (A))[3])) << 24)) |\ (((ulonglong) (((uint32) (((const uchar*) (A))[2])) |\ (((uint32) (((const uchar*) (A))[1])) << 8) |\ (((uint32) (((const uchar*) (A))[0])) << 16))) <<\ 32)) #endif /* HAVE_mi_uint7korr */ #ifndef HAVE_mi_uint8korr #define mi_uint8korr(A) ((ulonglong)(((uint32) (((const uchar*) (A))[7])) |\ (((uint32) (((const uchar*) (A))[6])) << 8) |\ (((uint32) (((const uchar*) (A))[5])) << 16) |\ (((uint32) (((const uchar*) (A))[4])) << 24)) |\ (((ulonglong) (((uint32) (((const uchar*) (A))[3])) |\ (((uint32) (((const uchar*) (A))[2])) << 8) |\ (((uint32) (((const uchar*) (A))[1])) << 16) |\ (((uint32) (((const uchar*) (A))[0])) << 24))) <<\ 32)) #endif /* HAVE_mi_uint8korr */ /* This one is for uniformity */ #define mi_int1store(T,A) *((uchar*)(T))= (uchar) (A) #define mi_int2store(T,A) { uint def_temp= (uint) (A) ;\ ((uchar*) (T))[1]= (uchar) (def_temp);\ ((uchar*) (T))[0]= (uchar) (def_temp >> 8); } #define mi_int3store(T,A) { /*lint -save -e734 */\ ulong def_temp= (ulong) (A);\ ((uchar*) (T))[2]= (uchar) (def_temp);\ ((uchar*) (T))[1]= (uchar) (def_temp >> 8);\ ((uchar*) (T))[0]= (uchar) (def_temp >> 16);\ /*lint -restore */} #define mi_int4store(T,A) { ulong def_temp= (ulong) (A);\ ((uchar*) (T))[3]= (uchar) (def_temp);\ ((uchar*) (T))[2]= (uchar) (def_temp >> 8);\ ((uchar*) (T))[1]= (uchar) (def_temp >> 16);\ ((uchar*) (T))[0]= (uchar) (def_temp >> 24); } #define mi_int5store(T,A) { ulong def_temp= (ulong) (A),\ def_temp2= (ulong) ((A) >> 32);\ ((uchar*) (T))[4]= (uchar) (def_temp);\ ((uchar*) (T))[3]= (uchar) (def_temp >> 8);\ ((uchar*) (T))[2]= (uchar) (def_temp >> 16);\ ((uchar*) (T))[1]= (uchar) (def_temp >> 24);\ ((uchar*) (T))[0]= (uchar) (def_temp2); } #define mi_int6store(T,A) { ulong def_temp= (ulong) (A),\ def_temp2= (ulong) ((A) >> 32);\ ((uchar*) (T))[5]= (uchar) (def_temp);\ ((uchar*) (T))[4]= (uchar) (def_temp >> 8);\ ((uchar*) (T))[3]= (uchar) (def_temp >> 16);\ ((uchar*) (T))[2]= (uchar) (def_temp >> 24);\ ((uchar*) (T))[1]= (uchar) (def_temp2);\ ((uchar*) (T))[0]= (uchar) (def_temp2 >> 8); } #define mi_int7store(T,A) { ulong def_temp= (ulong) (A),\ def_temp2= (ulong) ((A) >> 32);\ ((uchar*) (T))[6]= (uchar) (def_temp);\ ((uchar*) (T))[5]= (uchar) (def_temp >> 8);\ ((uchar*) (T))[4]= (uchar) (def_temp >> 16);\ ((uchar*) (T))[3]= (uchar) (def_temp >> 24);\ ((uchar*) (T))[2]= (uchar) (def_temp2);\ ((uchar*) (T))[1]= (uchar) (def_temp2 >> 8);\ ((uchar*) (T))[0]= (uchar) (def_temp2 >> 16); } #define mi_int8store(T,A) { ulong def_temp3= (ulong) (A),\ def_temp4= (ulong) ((A) >> 32);\ mi_int4store((uchar*) (T) + 0, def_temp4);\ mi_int4store((uchar*) (T) + 4, def_temp3); } #ifdef WORDS_BIGENDIAN #define mi_float4store(T,A) { ((uchar*) (T))[0]= ((uchar*) &A)[0];\ ((uchar*) (T))[1]= ((uchar*) &A)[1];\ ((uchar*) (T))[2]= ((uchar*) &A)[2];\ ((uchar*) (T))[3]= ((uchar*) &A)[3]; } #define mi_float4get(V,M) { float def_temp;\ ((uchar*) &def_temp)[0]= ((const uchar*) (M))[0];\ ((uchar*) &def_temp)[1]= ((const uchar*) (M))[1]; \ ((uchar*) &def_temp)[2]= ((const uchar*) (M))[2];\ ((uchar*) &def_temp)[3]= ((const uchar*) (M))[3];\ (V)= def_temp; } #define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[0];\ ((uchar*) (T))[1]= ((const uchar*) &V)[1];\ ((uchar*) (T))[2]= ((const uchar*) &V)[2];\ ((uchar*) (T))[3]= ((const uchar*) &V)[3];\ ((uchar*) (T))[4]= ((const uchar*) &V)[4];\ ((uchar*) (T))[5]= ((const uchar*) &V)[5];\ ((uchar*) (T))[6]= ((const uchar*) &V)[6];\ ((uchar*) (T))[7]= ((const uchar*) &V)[7]; } #define mi_float8get(V,M) { double def_temp;\ ((uchar*) &def_temp)[0]= ((const uchar*) (M))[0];\ ((uchar*) &def_temp)[1]= ((const uchar*) (M))[1];\ ((uchar*) &def_temp)[2]= ((const uchar*) (M))[2];\ ((uchar*) &def_temp)[3]= ((const uchar*) (M))[3];\ ((uchar*) &def_temp)[4]= ((const uchar*) (M))[4];\ ((uchar*) &def_temp)[5]= ((const uchar*) (M))[5];\ ((uchar*) &def_temp)[6]= ((const uchar*) (M))[6];\ ((uchar*) &def_temp)[7]= ((const uchar*) (M))[7]; \ (V)= def_temp; } #else #define mi_float4store(T,A) { ((uchar*) (T))[0]= ((const uchar*) &A)[3];\ ((uchar*) (T))[1]= ((const uchar*) &A)[2];\ ((uchar*) (T))[2]= ((const uchar*) &A)[1];\ ((uchar*) (T))[3]= ((const uchar*) &A)[0]; } #define mi_float4get(V,M) { float def_temp;\ ((uchar*) &def_temp)[0]= ((const uchar*) (M))[3];\ ((uchar*) &def_temp)[1]= ((const uchar*) (M))[2];\ ((uchar*) &def_temp)[2]= ((const uchar*) (M))[1];\ ((uchar*) &def_temp)[3]= ((const uchar*) (M))[0];\ (V)= def_temp; } #if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) #define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[3];\ ((uchar*) (T))[1]= ((const uchar*) &V)[2];\ ((uchar*) (T))[2]= ((const uchar*) &V)[1];\ ((uchar*) (T))[3]= ((const uchar*) &V)[0];\ ((uchar*) (T))[4]= ((const uchar*) &V)[7];\ ((uchar*) (T))[5]= ((const uchar*) &V)[6];\ ((uchar*) (T))[6]= ((const uchar*) &V)[5];\ ((uchar*) (T))[7]= ((const uchar*) &V)[4];} #define mi_float8get(V,M) { double def_temp;\ ((uchar*) &def_temp)[0]= ((const uchar*) (M))[3];\ ((uchar*) &def_temp)[1]= ((const uchar*) (M))[2];\ ((uchar*) &def_temp)[2]= ((const uchar*) (M))[1];\ ((uchar*) &def_temp)[3]= ((const uchar*) (M))[0];\ ((uchar*) &def_temp)[4]= ((const uchar*) (M))[7];\ ((uchar*) &def_temp)[5]= ((const uchar*) (M))[6];\ ((uchar*) &def_temp)[6]= ((const uchar*) (M))[5];\ ((uchar*) &def_temp)[7]= ((const uchar*) (M))[4];\ (V)= def_temp; } #else #define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[7];\ ((uchar*) (T))[1]= ((const uchar*) &V)[6];\ ((uchar*) (T))[2]= ((const uchar*) &V)[5];\ ((uchar*) (T))[3]= ((const uchar*) &V)[4];\ ((uchar*) (T))[4]= ((const uchar*) &V)[3];\ ((uchar*) (T))[5]= ((const uchar*) &V)[2];\ ((uchar*) (T))[6]= ((const uchar*) &V)[1];\ ((uchar*) (T))[7]= ((const uchar*) &V)[0];} #define mi_float8get(V,M) { double def_temp;\ ((uchar*) &def_temp)[0]= ((const uchar*) (M))[7];\ ((uchar*) &def_temp)[1]= ((const uchar*) (M))[6];\ ((uchar*) &def_temp)[2]= ((const uchar*) (M))[5];\ ((uchar*) &def_temp)[3]= ((const uchar*) (M))[4];\ ((uchar*) &def_temp)[4]= ((const uchar*) (M))[3];\ ((uchar*) &def_temp)[5]= ((const uchar*) (M))[2];\ ((uchar*) &def_temp)[6]= ((const uchar*) (M))[1];\ ((uchar*) &def_temp)[7]= ((const uchar*) (M))[0];\ (V)= def_temp; } #endif /* __FLOAT_WORD_ORDER */ #endif /* WORDS_BIGENDIAN */ /* Fix to avoid warnings when sizeof(ha_rows) == sizeof(long) */ #ifdef BIG_TABLES #define mi_rowstore(T,A) mi_int8store(T, A) #define mi_rowkorr(T) mi_uint8korr(T) #else #define mi_rowstore(T,A) { mi_int4store(T, 0);\ mi_int4store(((uchar*) (T) + 4), A); } #define mi_rowkorr(T) mi_uint4korr((const uchar*) (T) + 4) #endif #if SIZEOF_OFF_T > 4 #define mi_sizestore(T,A) mi_int8store(T, A) #define mi_sizekorr(T) mi_uint8korr(T) #else #define mi_sizestore(T,A) { if ((A) == HA_OFFSET_ERROR)\ bfill((char*) (T), 8, 255);\ else { mi_int4store((T), 0);\ mi_int4store(((T) + 4), A); }} #define mi_sizekorr(T) mi_uint4korr((const uchar*) (T) + 4) #endif #endif /* MYISAMPACK_INCLUDED */ server/private/debug.h000064400000002322151031265050010760 0ustar00#ifndef DEBUG_INCLUDED #define DEBUG_INCLUDED /* Copyright (c) 2021, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file Declarations for debug_crash_here and other future mariadb server debug functionality. */ /* debug_crash_here() functionallity. See mysql_test/suite/atomic/create_table.test for an example of how it can be used */ #ifndef DBUG_OFF void debug_crash_here(const char *keyword); bool debug_simulate_error(const char *keyword, uint error); #else #define debug_crash_here(A) do { } while(0) #define debug_simulate_error(A, B) 0 #endif #endif /* DEBUG_INCLUDED */ server/private/my_libwrap.h000064400000002237151031265050012044 0ustar00#ifndef MY_LIBWRAP_INCLUDED #define MY_LIBWRAP_INCLUDED /* Copyright (c) 2000, 2006 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef HAVE_LIBWRAP #include #include #ifdef NEED_SYS_SYSLOG_H #include #endif /* NEED_SYS_SYSLOG_H */ extern void my_fromhost(struct request_info *req); extern int my_hosts_access(struct request_info *req); extern char *my_eval_client(struct request_info *req); #endif /* HAVE_LIBWRAP */ #endif /* MY_LIBWRAP_INCLUDED */ server/sslopt-longopts.h000064400000005137151031265050011416 0ustar00#ifndef SSLOPT_LONGOPTS_INCLUDED #define SSLOPT_LONGOPTS_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) {"ssl", 0, "Enable SSL for connection (automatically enabled with other flags).", &opt_use_ssl, &opt_use_ssl, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"ssl-ca", OPT_SSL_CA, "CA file in PEM format (check OpenSSL docs, implies --ssl).", &opt_ssl_ca, &opt_ssl_ca, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ssl-capath", OPT_SSL_CAPATH, "CA directory (check OpenSSL docs, implies --ssl).", &opt_ssl_capath, &opt_ssl_capath, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ssl-cert", OPT_SSL_CERT, "X509 cert in PEM format (implies --ssl).", &opt_ssl_cert, &opt_ssl_cert, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ssl-cipher", OPT_SSL_CIPHER, "SSL cipher to use (implies --ssl).", &opt_ssl_cipher, &opt_ssl_cipher, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ssl-key", OPT_SSL_KEY, "X509 key in PEM format (implies --ssl).", &opt_ssl_key, &opt_ssl_key, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ssl-crl", OPT_SSL_CRL, "Certificate revocation list (implies --ssl).", &opt_ssl_crl, &opt_ssl_crl, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ssl-crlpath", OPT_SSL_CRLPATH, "Certificate revocation list path (implies --ssl).", &opt_ssl_crlpath, &opt_ssl_crlpath, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"tls-version", 0, "TLS protocol version for secure connection.", &opt_tls_version, &opt_tls_version, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef MYSQL_CLIENT {"ssl-verify-server-cert", 0, "Verify server's \"Common Name\" in its cert against hostname used " "when connecting. This option is disabled by default.", &opt_ssl_verify_server_cert, &opt_ssl_verify_server_cert, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif #endif /* HAVE_OPENSSL */ #endif /* SSLOPT_LONGOPTS_INCLUDED */ server/mysql_version.h000064400000002405151031265050011134 0ustar00/* Copyright Abandoned 1996,1999 TCX DataKonsult AB & Monty Program KB & Detron HB, 1996, 1999-2004, 2007 MySQL AB. This file is public domain and comes with NO WARRANTY of any kind */ /* Version numbers for protocol & mysqld */ #ifndef _mysql_version_h #define _mysql_version_h #ifdef _CUSTOMCONFIG_ #include #else #define PROTOCOL_VERSION 10 #define MYSQL_SERVER_VERSION "10.6.23-MariaDB" #define MYSQL_BASE_VERSION "mysqld-10.6" #define MARIADB_BASE_VERSION "mariadb-10.6" #define MARIADBD_BASE_VERSION "mariadbd-10.6" #define MYSQL_SERVER_SUFFIX_DEF "" #define FRM_VER 6 #define MYSQL_VERSION_ID 100623 #define MARIADB_PORT 3306 #define MYSQL_PORT_DEFAULT 0 #define MARIADB_UNIX_ADDR "/var/lib/mysql/mysql.sock" #define MYSQL_CONFIG_NAME "my" #define MYSQL_COMPILATION_COMMENT "MariaDB Server" #define SERVER_MATURITY_LEVEL MariaDB_PLUGIN_MATURITY_STABLE #define MYSQL_PORT MARIADB_PORT #define MYSQL_UNIX_ADDR MARIADB_UNIX_ADDR #ifdef WITH_WSREP #define WSREP_PATCH_VERSION "wsrep_26.22" #endif /* mysqld compile time options */ #endif /* _CUSTOMCONFIG_ */ #ifndef LICENSE #define LICENSE GPL #endif /* LICENSE */ #endif /* _mysql_version_h */ server/byte_order_generic.h000064400000012172151031265050012056 0ustar00/* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Endianness-independent definitions for architectures other than the x86 architecture. */ #define sint2korr(A) (int16) (((int16) ((uchar) (A)[0])) |\ ((int16) ((int16) (A)[1]) << 8)) #define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ (((uint32) 255L << 24) | \ (((uint32) (uchar) (A)[2]) << 16) |\ (((uint32) (uchar) (A)[1]) << 8) | \ ((uint32) (uchar) (A)[0])) : \ (((uint32) (uchar) (A)[2]) << 16) |\ (((uint32) (uchar) (A)[1]) << 8) | \ ((uint32) (uchar) (A)[0]))) #define sint4korr(A) (int32) (((uint32) ((uchar) (A)[0])) |\ (((uint32) ((uchar) (A)[1]) << 8)) |\ (((uint32) ((uchar) (A)[2]) << 16)) |\ (((uint32) ((uchar) (A)[3]) << 24))) #define sint8korr(A) (longlong) uint8korr(A) #define uint2korr(A) (uint16) (((uint16) ((uchar) (A)[0])) |\ ((uint16) ((uchar) (A)[1]) << 8)) #define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) |\ (((uint32) ((uchar) (A)[1])) << 8) |\ (((uint32) ((uchar) (A)[2])) << 16)) #define uint4korr(A) (uint32) (((uint32) ((uchar) (A)[0])) |\ (((uint32) ((uchar) (A)[1])) << 8) |\ (((uint32) ((uchar) (A)[2])) << 16) |\ (((uint32) ((uchar) (A)[3])) << 24)) #define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) |\ (((uint32) ((uchar) (A)[1])) << 8) |\ (((uint32) ((uchar) (A)[2])) << 16) |\ (((uint32) ((uchar) (A)[3])) << 24)) |\ (((ulonglong) ((uchar) (A)[4])) << 32)) #define uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) | \ (((uint32) ((uchar) (A)[1])) << 8) | \ (((uint32) ((uchar) (A)[2])) << 16) | \ (((uint32) ((uchar) (A)[3])) << 24)) | \ (((ulonglong) ((uchar) (A)[4])) << 32) | \ (((ulonglong) ((uchar) (A)[5])) << 40)) #define uint8korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) |\ (((uint32) ((uchar) (A)[1])) << 8) |\ (((uint32) ((uchar) (A)[2])) << 16) |\ (((uint32) ((uchar) (A)[3])) << 24)) |\ (((ulonglong) (((uint32) ((uchar) (A)[4])) |\ (((uint32) ((uchar) (A)[5])) << 8) |\ (((uint32) ((uchar) (A)[6])) << 16) |\ (((uint32) ((uchar) (A)[7])) << 24))) <<\ 32)) #define int2store(T,A) do { uint def_temp= (uint) (A) ;\ *((uchar*) (T))= (uchar)(def_temp); \ *((uchar*) (T)+1)=(uchar)((def_temp >> 8)); \ } while(0) #define int3store(T,A) do { /*lint -save -e734 */\ *((uchar*)(T))=(uchar) ((A));\ *((uchar*) (T)+1)=(uchar) (((A) >> 8));\ *((uchar*)(T)+2)=(uchar) (((A) >> 16)); \ /*lint -restore */} while(0) #define 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 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) #define 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) #define int8store(T,A) do { uint def_temp= (uint) (A), \ def_temp2= (uint) ((A) >> 32); \ int4store((T),def_temp); \ int4store((T+4),def_temp2);\ } while(0) server/my_sys.h000064400000126311151031265050007550 0ustar00/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. Copyright (c) 2010, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_sys_h #define _my_sys_h #include #include C_MODE_START #include #include #include /* for CHARSET_INFO */ #include #include #include #include #include #include #define MY_INIT(name) { my_progname= name; my_init(); } /** Max length of an error message generated by mysys utilities. Some mysys functions produce error messages. These mostly go to stderr. This constant defines the size of the buffer used to format the message. It should be kept in sync with MYSQL_ERRMSG_SIZE, since sometimes mysys errors are stored in the server diagnostics area, and we would like to avoid unexpected truncation. */ #define MYSYS_ERRMSG_SIZE (512) #define MYSYS_STRERROR_SIZE (128) #define MY_FILE_ERROR ((size_t) -1) /* General bitmaps for my_func's */ #define MY_FFNF 1U /* Fatal if file not found */ #define MY_FNABP 2U /* Fatal if not all bytes read/written */ #define MY_NABP 4U /* Error if not all bytes read/written */ #define MY_FAE 8U /* Fatal if any error */ #define MY_WME 16U /* Write message on error */ #define MY_WAIT_IF_FULL 32U /* Wait and try again if disk full error */ #define MY_IGNORE_BADFD 32U /* my_sync(): ignore 'bad descriptor' errors */ #define MY_IGNORE_ENOENT 32U /* my_delete() ignores ENOENT (no such file) */ #define MY_ENCRYPT 64U /* Encrypt IO_CACHE temporary files */ #define MY_TEMPORARY 64U /* create_temp_file(): delete file at once */ #define MY_NOSYMLINKS 512U /* my_open(): don't follow symlinks */ #define MY_FULL_IO 512U /* my_read(): loop until I/O is complete */ #define MY_DONT_CHECK_FILESIZE 128U /* Option to init_io_cache() */ #define MY_LINK_WARNING 32U /* my_redel() gives warning if links */ #define MY_COPYTIME 64U /* my_redel() copies time */ #define MY_DELETE_OLD 256U /* my_create_with_symlink() */ #define MY_RESOLVE_LINK 128U /* my_realpath(); Only resolve links */ #define MY_HOLD_ORIGINAL_MODES 128U /* my_copy() holds to file modes */ #define MY_REDEL_MAKE_BACKUP 256U #define MY_SEEK_NOT_DONE 32U /* my_lock may have to do a seek */ #define MY_SHORT_WAIT 64U /* my_lock() don't wait if can't lock */ #define MY_FORCE_LOCK 128U /* use my_lock() even if disable_locking */ #define MY_NO_WAIT 256U /* my_lock() don't wait at all */ #define MY_NO_REGISTER 8196U /* my_open(), no malloc for file name */ /* If old_mode is UTF8_IS_UTF8MB3, then pass this flag. It mean utf8 is alias for utf8mb3. Otherwise utf8 is alias for utf8mb4. */ #define MY_UTF8_IS_UTF8MB3 1024U /* init_dynamic_array() has init buffer; Internal flag, not to be used by caller. */ #define MY_INIT_BUFFER_USED 256U #define MY_ZEROFILL 32U /* my_malloc(), fill array with zero */ #define MY_ALLOW_ZERO_PTR 64U /* my_realloc() ; zero ptr -> malloc */ #define MY_FREE_ON_ERROR 128U /* my_realloc() ; Free old ptr on error */ #define MY_DONT_OVERWRITE_FILE 2048U /* my_copy: Don't overwrite file */ #define MY_THREADSAFE 2048U /* my_seek(): lock fd mutex */ #define MY_SYNC 4096U /* my_copy(): sync dst file */ #define MY_SYNC_DIR 32768U /* my_create/delete/rename: sync directory */ #define MY_THREAD_SPECIFIC 0x10000U /* my_malloc(): thread specific */ /* Tree that should delete things automatically */ #define MY_TREE_WITH_DELETE 0x40000U #define MY_CHECK_ERROR 1U /* Params to my_end; Check open-close */ #define MY_GIVE_INFO 2U /* Give time info about process*/ #define MY_DONT_FREE_DBUG 4U /* Do not call DBUG_END() in my_end() */ #define ME_BELL 4U /* Ring bell then printing message */ #define ME_ERROR_LOG 64 /**< write the error message to error log */ #define ME_ERROR_LOG_ONLY 128 /**< write the error message to error log only */ #define ME_NOTE 1024 /**< not error but just info */ #define ME_WARNING 2048 /**< not error but just warning */ #define ME_FATAL 4096 /**< fatal statement error */ /* Bits in last argument to fn_format */ #define MY_REPLACE_DIR 1U /* replace dir in name with 'dir' */ #define MY_REPLACE_EXT 2U /* replace extension with 'ext' */ #define MY_UNPACK_FILENAME 4U /* Unpack name (~ -> home) */ #define MY_PACK_FILENAME 8U /* Pack name (home -> ~) */ #define MY_RESOLVE_SYMLINKS 16U /* Resolve all symbolic links */ #define MY_RETURN_REAL_PATH 32U /* return full path for file */ #define MY_SAFE_PATH 64U /* Return NULL if too long path */ #define MY_RELATIVE_PATH 128U /* name is relative to 'dir' */ #define MY_APPEND_EXT 256U /* add 'ext' as additional extension*/ /* My seek flags */ #define MY_SEEK_SET 0 #define MY_SEEK_CUR 1 #define MY_SEEK_END 2 /* Some constants */ #define MY_WAIT_FOR_USER_TO_FIX_PANIC 60 /* in seconds */ #define MY_WAIT_GIVE_USER_A_MESSAGE 10 /* Every 10 times of prev */ #define MIN_COMPRESS_LENGTH 50 /* Don't compress small bl. */ #define DFLT_INIT_HITS 3 /* root_alloc flags */ #define MY_KEEP_PREALLOC 1U #define MY_MARK_BLOCKS_FREE 2U /* move used to free list and reuse them */ /* Internal error numbers (for assembler functions) */ #define MY_ERRNO_EDOM 33 #define MY_ERRNO_ERANGE 34 /* Bits for get_date timeflag */ #define GETDATE_DATE_TIME 1U #define GETDATE_SHORT_DATE 2U #define GETDATE_HHMMSSTIME 4U #define GETDATE_GMT 8U #define GETDATE_FIXEDLENGTH 16U /* Extra length needed for filename if one calls my_create_backup_name */ #define MY_BACKUP_NAME_EXTRA_LENGTH 17 char *guess_malloc_library(); /* If we have our own safemalloc (for debugging) */ #if defined(SAFEMALLOC) void sf_report_leaked_memory(my_thread_id id); int sf_sanity(); extern my_thread_id (*sf_malloc_dbug_id)(void); #define SAFEMALLOC_REPORT_MEMORY(X) if (!sf_leaking_memory) sf_report_leaked_memory(X) #else #define SAFEMALLOC_REPORT_MEMORY(X) do {} while(0) #endif typedef void (*MALLOC_SIZE_CB) (long long size, my_bool is_thread_specific); extern void set_malloc_size_cb(MALLOC_SIZE_CB func); extern MALLOC_SIZE_CB update_malloc_size; /* defines when allocating data */ extern void *my_malloc(PSI_memory_key key, size_t size, myf MyFlags); extern void *my_multi_malloc(PSI_memory_key key, myf MyFlags, ...); extern void *my_multi_malloc_large(PSI_memory_key key, myf MyFlags, ...); extern void *my_realloc(PSI_memory_key key, void *ptr, size_t size, myf MyFlags); extern void my_free(void *ptr); extern void *my_memdup(PSI_memory_key key, const void *from,size_t length,myf MyFlags); extern char *my_strdup(PSI_memory_key key, const char *from,myf MyFlags); extern char *my_strndup(PSI_memory_key key, const char *from, size_t length, myf MyFlags); int my_init_large_pages(my_bool super_large_pages); uchar *my_large_malloc(size_t *size, myf my_flags); void my_large_free(void *ptr, size_t size); #ifdef _WIN32 extern BOOL my_obtain_privilege(LPCSTR lpPrivilege); #endif void my_init_atomic_write(void); #ifdef __linux__ my_bool my_test_if_atomic_write(File handle, int pagesize); my_bool my_test_if_thinly_provisioned(File handle); #else # define my_test_if_atomic_write(A, B) 0 # define my_test_if_thinly_provisioned(A) 0 #endif /* __linux__ */ extern my_bool my_may_have_atomic_write; #if defined(HAVE_ALLOCA) && !defined(HAVE_valgrind) #define my_alloca(SZ) alloca((size_t) (SZ)) #define my_afree(PTR) ((void)0) #define MAX_ALLOCA_SZ 4096 #define my_safe_alloca(size) (((size) <= MAX_ALLOCA_SZ) ? \ my_alloca(size) : \ my_malloc(PSI_NOT_INSTRUMENTED, (size), MYF(MY_THREAD_SPECIFIC|MY_WME))) #define my_safe_afree(ptr, size) \ do { if ((size) > MAX_ALLOCA_SZ) my_free(ptr); } while(0) #else #define my_alloca(SZ) my_malloc(PSI_NOT_INSTRUMENTED, SZ,MYF(MY_FAE)) #define my_afree(PTR) my_free(PTR) #define my_safe_alloca(size) my_alloca(size) #define my_safe_afree(ptr, size) my_afree(ptr) #endif /* HAVE_ALLOCA */ #ifndef errno /* did we already get it? */ #ifdef HAVE_ERRNO_AS_DEFINE #include /* errno is a define */ #else extern int errno; /* declare errno */ #endif #endif /* #ifndef errno */ extern char *home_dir; /* Home directory for user */ extern MYSQL_PLUGIN_IMPORT char *mysql_data_home; extern const char *my_progname; /* program-name (printed in errors) */ extern const char *my_progname_short; /* like above but without directory */ extern char curr_dir[]; /* Current directory for user */ extern void (*error_handler_hook)(uint my_err, const char *str,myf MyFlags); extern void (*fatal_error_handler_hook)(uint my_err, const char *str, myf MyFlags); extern uint my_file_limit; extern ulonglong my_thread_stack_size; extern int sf_leaking_memory; /* set to 1 to disable memleak detection */ extern void (*proc_info_hook)(void *, const PSI_stage_info *, PSI_stage_info *, const char *, const char *, const unsigned int); /* charsets */ #define MY_ALL_CHARSETS_SIZE 2048 extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *default_charset_info; extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *all_charsets[MY_ALL_CHARSETS_SIZE]; extern struct charset_info_st compiled_charsets[]; /* Collation properties and use statistics */ extern my_bool my_collation_is_known_id(uint id); extern ulonglong my_collation_statistics_get_use_count(uint id); extern const char *my_collation_get_tailoring(uint id); /* statistics */ extern ulong my_stream_opened, my_tmp_file_created; extern ulong my_file_total_opened; extern ulong my_sync_count; extern uint mysys_usage_id; extern int32 my_file_opened; extern my_bool my_init_done, my_thr_key_mysys_exists; extern my_bool my_assert; extern my_bool my_assert_on_error; extern myf my_global_flags; /* Set to MY_WME for more error messages */ /* Point to current my_message() */ extern void (*my_sigtstp_cleanup)(void), /* Executed before jump to shell */ (*my_sigtstp_restart)(void); /* Executed when coming from shell */ extern MYSQL_PLUGIN_IMPORT mode_t my_umask; /* Default creation mask */ extern mode_t my_umask_dir; extern int my_recived_signals, /* Signals we have got */ my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */ my_dont_interrupt; /* call remember_intr when set */ #ifdef _WIN32 extern SECURITY_ATTRIBUTES my_dir_security_attributes; LPSECURITY_ATTRIBUTES my_win_file_secattr(); #endif extern MYSQL_PLUGIN_IMPORT my_bool my_use_symdir; extern ulong my_default_record_cache_size; extern MYSQL_PLUGIN_IMPORT my_bool my_disable_locking; extern my_bool my_disable_async_io, my_disable_flush_key_blocks, my_disable_symlinks; extern my_bool my_disable_sync, my_disable_copystat_in_redel; extern char wild_many,wild_one,wild_prefix; extern const char *charsets_dir; enum cache_type { TYPE_NOT_SET= 0, READ_CACHE, WRITE_CACHE, SEQ_READ_APPEND /* sequential read or append */, READ_FIFO, READ_NET}; enum flush_type { FLUSH_KEEP, /* flush block and keep it in the cache */ FLUSH_RELEASE, /* flush block and remove it from the cache */ FLUSH_IGNORE_CHANGED, /* remove block from the cache */ /* As my_disable_flush_pagecache_blocks is always 0, the following option is strictly equivalent to FLUSH_KEEP */ FLUSH_FORCE_WRITE, /** @brief like FLUSH_KEEP but return immediately if file is already being flushed (even partially) by another thread; only for page cache, forbidden for key cache. */ FLUSH_KEEP_LAZY }; typedef struct st_record_cache /* Used when caching records */ { File file; int rc_seek,error,inited; uint rc_length,read_length,reclength; my_off_t rc_record_pos,end_of_file; uchar *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos; enum cache_type type; } RECORD_CACHE; enum file_type { UNOPEN = 0, FILE_BY_OPEN, FILE_BY_CREATE, STREAM_BY_FOPEN, STREAM_BY_FDOPEN, FILE_BY_O_TMPFILE, FILE_BY_MKSTEMP, FILE_BY_DUP }; struct st_my_file_info { char *name; #ifdef _WIN32 HANDLE fhandle; /* win32 file handle */ int oflag; /* open flags, e.g O_APPEND */ #endif enum file_type type; }; extern struct st_my_file_info *my_file_info; /* Free function pointer */ typedef void (*FREE_FUNC)(void *); typedef struct st_dynamic_array { uchar *buffer; uint elements,max_element; uint alloc_increment; uint size_of_element; PSI_memory_key m_psi_key; myf malloc_flags; } DYNAMIC_ARRAY; typedef struct st_my_tmpdir { DYNAMIC_ARRAY full_list; char **list; uint cur, max; mysql_mutex_t mutex; } MY_TMPDIR; typedef struct st_dynamic_string { char *str; size_t length,max_length,alloc_increment; } DYNAMIC_STRING; struct st_io_cache; typedef struct st_io_cache_share { mysql_mutex_t mutex; /* To sync on reads into buffer. */ mysql_cond_t cond; /* To wait for signals. */ mysql_cond_t cond_writer; /* For a synchronized writer. */ /* Offset in file corresponding to the first byte of buffer. */ my_off_t pos_in_file; /* If a synchronized write cache is the source of the data. */ struct st_io_cache *source_cache; uchar *buffer; /* The read buffer. */ uchar *read_end; /* Behind last valid byte of buffer. */ int running_threads; /* threads not in lock. */ int total_threads; /* threads sharing the cache. */ int error; /* Last error. */ #ifdef NOT_YET_IMPLEMENTED /* whether the structure should be free'd */ my_bool alloced; #endif } IO_CACHE_SHARE; typedef struct st_io_cache /* Used when caching files */ { /* Offset in file corresponding to the first byte of uchar* buffer. */ my_off_t pos_in_file; /* The offset of end of file for READ_CACHE and WRITE_CACHE. For SEQ_READ_APPEND it the maximum of the actual end of file and the position represented by read_end. */ my_off_t end_of_file; /* Points to current read position in the buffer */ uchar *read_pos; /* the non-inclusive boundary in the buffer for the currently valid read */ uchar *read_end; uchar *buffer; /* The read buffer */ /* Used in ASYNC_IO */ uchar *request_pos; /* Only used in WRITE caches and in SEQ_READ_APPEND to buffer writes */ uchar *write_buffer; /* Only used in SEQ_READ_APPEND, and points to the current read position in the write buffer. Note that reads in SEQ_READ_APPEND caches can happen from both read buffer (uchar* buffer) and write buffer (uchar* write_buffer). */ uchar *append_read_pos; /* Points to current write position in the write buffer */ uchar *write_pos; /* The non-inclusive boundary of the valid write area */ uchar *write_end; /* The lock is for append buffer used in SEQ_READ_APPEND cache need mutex copying from append buffer to read buffer. */ mysql_mutex_t append_buffer_lock; /* The following is used when several threads are reading the same file in parallel. They are synchronized on disk accesses reading the cached part of the file asynchronously. It should be set to NULL to disable the feature. Only READ_CACHE mode is supported. */ IO_CACHE_SHARE *share; /* A caller will use my_b_read() macro to read from the cache if the data is already in cache, it will be simply copied with memcpy() and internal variables will be accordingly updated with no functions invoked. However, if the data is not fully in the cache, my_b_read() will call read_function to fetch the data. read_function must never be invoked directly. */ int (*read_function)(struct st_io_cache *,uchar *,size_t); /* Same idea as in the case of read_function, except my_b_write() needs to be replaced with my_b_append() for a SEQ_READ_APPEND cache */ int (*write_function)(struct st_io_cache *,const uchar *,size_t); /* Specifies the type of the cache. Depending on the type of the cache certain operations might not be available and yield unpredicatable results. Details to be documented later */ enum cache_type type; /* Counts the number of times, when we were forced to use disk. We use it to increase the binlog_cache_disk_use and binlog_stmt_cache_disk_use status variables. */ ulong disk_writes; char *file_name; /* if used with 'open_cached_file' */ const char *dir; char prefix[3]; File file; /* file descriptor */ struct st_io_cache *next_file_user; /* seek_not_done is set by my_b_seek() to inform the upcoming read/write operation that a seek needs to be preformed prior to the actual I/O error is 0 if the cache operation was successful, -1 if there was a "hard" error, and the actual number of I/O-ed bytes if the read/write was partial. */ int seek_not_done,error; /* length of the buffer used for storing un-encrypted data */ size_t buffer_length; /* read_length is the same as buffer_length except when we use async io */ size_t read_length; myf myflags; /* Flags used to my_read/my_write */ /* alloced_buffer is set to the size of the buffer allocated for the IO_CACHE. Includes the overhead(storing key to encrypt and decrypt) for encryption. Set to 0 if nothing is allocated. Currently READ_NET is the only one that will use a buffer allocated somewhere else */ size_t alloced_buffer; } IO_CACHE; typedef void (*my_error_reporter)(enum loglevel level, const char *format, ...) ATTRIBUTE_FORMAT_FPTR(printf, 2, 3); extern my_error_reporter my_charset_error_reporter; extern PSI_file_key key_file_io_cache; /* inline functions for mf_iocache */ extern int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock); extern int _my_b_get(IO_CACHE *info); extern int _my_b_read(IO_CACHE *info,uchar *Buffer,size_t Count); extern int _my_b_write(IO_CACHE *info,const uchar *Buffer,size_t Count); /* Test if buffer is inited */ static inline void my_b_clear(IO_CACHE *info) { info->buffer= 0; } static inline int my_b_inited(IO_CACHE *info) { return MY_TEST(info->buffer); } #define my_b_EOF INT_MIN static inline int my_b_read(IO_CACHE *info, uchar *Buffer, size_t Count) { if (info->read_pos + Count <= info->read_end) { memcpy(Buffer, info->read_pos, Count); info->read_pos+= Count; return 0; } return _my_b_read(info, Buffer, Count); } static inline int my_b_write(IO_CACHE *info, const uchar *Buffer, size_t Count) { MEM_CHECK_DEFINED(Buffer, Count); if (info->write_pos + Count <= info->write_end) { if (Count) { memcpy(info->write_pos, Buffer, Count); info->write_pos+= Count; } return 0; } return _my_b_write(info, Buffer, Count); } static inline int my_b_get(IO_CACHE *info) { if (info->read_pos != info->read_end) { info->read_pos++; return info->read_pos[-1]; } return _my_b_get(info); } static inline my_bool my_b_write_byte(IO_CACHE *info, uchar chr) { MEM_CHECK_DEFINED(&chr, 1); if (info->write_pos >= info->write_end) if (my_b_flush_io_cache(info, 1)) return 1; *info->write_pos++= chr; return 0; } /** Fill buffer of the cache. @note It assumes that you have already used all characters in the CACHE, independent of the read_pos value! @returns 0 On error or EOF (info->error = -1 on error) # Number of characters */ static inline size_t my_b_fill(IO_CACHE *info) { info->read_pos= info->read_end; return _my_b_read(info,0,0) ? 0 : (size_t) (info->read_end - info->read_pos); } static inline my_off_t my_b_tell(const IO_CACHE *info) { if (info->type == WRITE_CACHE) { return info->pos_in_file + (my_off_t)(info->write_pos - info->request_pos); } return info->pos_in_file + (my_off_t) (info->read_pos - info->request_pos); } static inline my_off_t my_b_write_tell(const IO_CACHE *info) { return info->pos_in_file + (my_off_t) (info->write_pos - info->write_buffer); } static inline uchar* my_b_get_buffer_start(const IO_CACHE *info) { return info->request_pos; } static inline size_t my_b_get_bytes_in_buffer(const IO_CACHE *info) { return (size_t) (info->read_end - info->request_pos); } static inline my_off_t my_b_get_pos_in_file(const IO_CACHE *info) { return info->pos_in_file; } static inline size_t my_b_bytes_in_cache(const IO_CACHE *info) { if (info->type == WRITE_CACHE) { return (size_t) (info->write_end - info->write_pos); } return (size_t) (info->read_end - info->read_pos); } int my_b_copy_to_file (IO_CACHE *cache, FILE *file, size_t count); int my_b_copy_all_to_file(IO_CACHE *cache, FILE *file); my_off_t my_b_append_tell(IO_CACHE* info); my_off_t my_b_safe_tell(IO_CACHE* info); /* picks the correct tell() */ int my_b_pread(IO_CACHE *info, uchar *Buffer, size_t Count, my_off_t pos); typedef uint32 ha_checksum; extern int (*mysys_test_invalid_symlink)(const char *filename); #include /* Prototypes for mysys and my_func functions */ extern int my_copy(const char *from,const char *to,myf MyFlags); extern int my_delete(const char *name,myf MyFlags); extern int my_rmtree(const char *name, myf Myflags); extern int my_getwd(char * buf,size_t size,myf MyFlags); extern int my_setwd(const char *dir,myf MyFlags); extern int my_lock(File fd,int op,my_off_t start, my_off_t length,myf MyFlags); extern void *my_once_alloc(size_t Size,myf MyFlags); extern void my_once_free(void); extern char *my_once_strdup(const char *src,myf myflags); extern void *my_once_memdup(const void *src, size_t len, myf myflags); extern File my_open(const char *FileName,int Flags,myf MyFlags); extern File my_register_filename(File fd, const char *FileName, enum file_type type_of_file, uint error_message_number, myf MyFlags); extern File my_create(const char *FileName, mode_t CreateFlags, int AccessFlags, myf MyFlags); extern int my_close(File Filedes,myf MyFlags); extern int my_mkdir(const char *dir, int Flags, myf MyFlags); extern int my_readlink(char *to, const char *filename, myf MyFlags); extern int my_is_symlink(const char *filename); extern int my_realpath(char *to, const char *filename, myf MyFlags); extern File my_create_with_symlink(const char *linkname, const char *filename, mode_t createflags, int access_flags, myf MyFlags); extern int my_rename_with_symlink(const char *from,const char *to,myf MyFlags); extern int my_symlink(const char *content, const char *linkname, myf MyFlags); extern int my_handler_delete_with_symlink(const char *filename, myf sync_dir); extern size_t my_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags); extern size_t my_pread(File Filedes,uchar *Buffer,size_t Count,my_off_t offset, myf MyFlags); extern int my_rename(const char *from,const char *to,myf MyFlags); extern my_off_t my_seek(File fd,my_off_t pos,int whence,myf MyFlags); extern my_off_t my_tell(File fd,myf MyFlags); extern size_t my_write(File Filedes,const uchar *Buffer,size_t Count, myf MyFlags); extern size_t my_pwrite(File Filedes,const uchar *Buffer,size_t Count, my_off_t offset,myf MyFlags); extern size_t my_fread(FILE *stream,uchar *Buffer,size_t Count,myf MyFlags); extern size_t my_fwrite(FILE *stream,const uchar *Buffer,size_t Count, myf MyFlags); extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,myf MyFlags); extern my_off_t my_ftell(FILE *stream,myf MyFlags); extern void (*my_sleep_for_space)(unsigned int seconds); extern int my_get_exepath(char *buf, size_t size, const char *argv0); /* implemented in my_memmem.c */ extern void *my_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); #ifdef _WIN32 extern int my_access(const char *path, int amode); #define my_check_user(A,B) (NULL) #define my_set_user(A,B,C) (0) #else #define my_access access struct passwd *my_check_user(const char *user, myf MyFlags); int my_set_user(const char *user, struct passwd *user_info, myf MyFlags); #endif extern int check_if_legal_filename(const char *path); extern int check_if_legal_tablename(const char *path); #ifdef _WIN32 extern my_bool is_filename_allowed(const char *name, size_t length, my_bool allow_current_dir); #else /* _WIN32 */ # define is_filename_allowed(name, length, allow_cwd) (TRUE) #endif /* _WIN32 */ #ifdef _WIN32 /* Windows-only functions (CRT equivalents)*/ extern HANDLE my_get_osfhandle(File fd); extern File my_win_handle2File(HANDLE hFile); extern void my_osmaperr(unsigned long last_error); #endif extern void init_glob_errs(void); extern const char** get_global_errmsgs(int nr); extern void wait_for_free_space(const char *filename, int errors); extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags); extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags); extern FILE *my_freopen(const char *path, const char *mode, FILE *stream); extern int my_fclose(FILE *fd,myf MyFlags); extern int my_vfprintf(FILE *stream, const char* format, va_list args); extern const char* my_strerror(char *buf, size_t len, int nr); extern int my_fprintf(FILE *stream, const char* format, ...); extern File my_fileno(FILE *fd); extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); extern int my_chmod(const char *name, mode_t mode, myf my_flags); extern const char *my_basename(const char *filename); extern void thr_set_sync_wait_callback(void (*before_sync)(void), void (*after_sync)(void)); extern int my_sync(File fd, myf my_flags); extern int my_sync_dir(const char *dir_name, myf my_flags); extern int my_sync_dir_by_file(const char *file_name, myf my_flags); extern const char *my_get_err_msg(uint nr); extern int my_error_register(const char** (*get_errmsgs) (int nr), uint first, uint last); extern my_bool my_error_unregister(uint first, uint last); extern void my_message(uint my_err, const char *str,myf MyFlags); extern void my_message_stderr(uint my_err, const char *str, myf MyFlags); extern my_bool my_init(void); extern void my_end(int infoflag); extern int my_redel(const char *from, const char *to, time_t backup_time_stamp, myf MyFlags); void my_create_backup_name(char *to, const char *from, time_t backup_time_stamp); extern int my_copystat(const char *from, const char *to, int MyFlags); extern char * my_filename(File fd); extern my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist); extern char *my_tmpdir(MY_TMPDIR *tmpdir); extern void free_tmpdir(MY_TMPDIR *tmpdir); extern void my_remember_signal(int signal_number,sig_handler (*func)(int)); extern size_t dirname_part(char * to,const char *name, size_t *to_res_length); extern size_t dirname_length(const char *name); #define base_name(A) (A+dirname_length(A)) extern int test_if_hard_path(const char *dir_name); extern my_bool has_path(const char *name); extern char *convert_dirname(char *to, const char *from, const char *from_end); extern void to_unix_path(char * name); extern char * fn_ext(const char *name); extern char * fn_ext2(const char *name); extern char * fn_same(char * toname,const char *name,int flag); extern char * fn_format(char * to,const char *name,const char *dir, const char *form, uint flag); extern size_t strlength(const char *str); extern void pack_dirname(char * to,const char *from); extern size_t normalize_dirname(char * to, const char *from); extern size_t unpack_dirname(char * to,const char *from); extern size_t cleanup_dirname(char * to,const char *from); extern size_t system_filename(char * to,const char *from); extern size_t unpack_filename(char * to,const char *from); extern char * intern_filename(char * to,const char *from); extern int pack_filename(char * to, const char *name, size_t max_length); extern char * my_path(char * to,const char *progname, const char *own_pathname_part); extern char * my_load_path(char * to, const char *path, const char *own_path_prefix); extern int wild_compare(const char *str,const char *wildstr, pbool str_is_pattern); extern my_bool array_append_string_unique(const char *str, const char **array, size_t size); extern void get_date(char * to,int timeflag,time_t use_time); extern void soundex(CHARSET_INFO *, char * out_pntr, char * in_pntr, pbool remove_garbage); extern int init_record_cache(RECORD_CACHE *info,size_t cachesize,File file, size_t reclength,enum cache_type type, pbool use_async_io); extern int read_cache_record(RECORD_CACHE *info,uchar *to); extern int end_record_cache(RECORD_CACHE *info); extern int write_cache_record(RECORD_CACHE *info,my_off_t filepos, const uchar *record,size_t length); extern int flush_write_cache(RECORD_CACHE *info); extern void handle_recived_signals(void); extern sig_handler my_set_alarm_variable(int signo); extern my_bool radixsort_is_appliccable(uint n_items, size_t size_of_element); extern void my_string_ptr_sort(uchar *base,uint items,size_t size); extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements, size_t size_of_element,uchar *buffer[]); extern qsort_t my_qsort(void *base_ptr, size_t total_elems, size_t size, qsort_cmp cmp); extern qsort_t my_qsort2(void *base_ptr, size_t total_elems, size_t size, qsort_cmp2 cmp, void *cmp_argument); extern qsort_cmp2 get_ptr_compare(size_t); void my_store_ptr(uchar *buff, size_t pack_length, my_off_t pos); my_off_t my_get_ptr(uchar *ptr, size_t pack_length); extern int init_io_cache(IO_CACHE *info,File file,size_t cachesize, enum cache_type type,my_off_t seek_offset, my_bool use_async_io, myf cache_myflags); extern int init_io_cache_ext(IO_CACHE *info, File file, size_t cachesize, enum cache_type type, my_off_t seek_offset, pbool use_async_io, myf cache_myflags, PSI_file_key file_key); extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type, my_off_t seek_offset, my_bool use_async_io, my_bool clear_cache); extern void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare, IO_CACHE *write_cache, uint num_threads); extern int init_slave_io_cache(IO_CACHE *master, IO_CACHE *slave); void end_slave_io_cache(IO_CACHE *cache); void seek_io_cache(IO_CACHE *cache, my_off_t needed_offset); extern void remove_io_thread(IO_CACHE *info); extern int my_b_append(IO_CACHE *info,const uchar *Buffer,size_t Count); extern int my_b_safe_write(IO_CACHE *info,const uchar *Buffer,size_t Count); extern int my_block_write(IO_CACHE *info, const uchar *Buffer, size_t Count, my_off_t pos); #define flush_io_cache(info) my_b_flush_io_cache((info),1) extern int end_io_cache(IO_CACHE *info); extern void my_b_seek(IO_CACHE *info,my_off_t pos); extern size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length); extern my_off_t my_b_filelength(IO_CACHE *info); extern my_bool my_b_write_backtick_quote(IO_CACHE *info, const char *str, size_t len); extern my_bool my_b_printf(IO_CACHE *info, const char* fmt, ...); extern size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list ap); extern my_bool open_cached_file(IO_CACHE *cache,const char *dir, const char *prefix, size_t cache_size, myf cache_myflags); extern my_bool real_open_cached_file(IO_CACHE *cache); extern void close_cached_file(IO_CACHE *cache); File create_temp_file(char *to, const char *dir, const char *pfx, int mode, myf MyFlags); #define my_init_dynamic_array(A,B,C,D,E,F) init_dynamic_array2(A,B,C,NULL,D,E,F) #define my_init_dynamic_array2(A,B,C,D,E,F,G) init_dynamic_array2(A,B,C,D,E,F,G) extern my_bool init_dynamic_array2(PSI_memory_key psi_key, DYNAMIC_ARRAY *array, uint element_size, void *init_buffer, uint init_alloc, uint alloc_increment, myf my_flags); extern my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void* element); extern void *alloc_dynamic(DYNAMIC_ARRAY *array); extern void *pop_dynamic(DYNAMIC_ARRAY*); extern my_bool set_dynamic(DYNAMIC_ARRAY *array, const void *element, uint array_index); extern my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements); extern void get_dynamic(DYNAMIC_ARRAY *array, void *element, uint array_index); extern void delete_dynamic(DYNAMIC_ARRAY *array); extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index); extern void delete_dynamic_with_callback(DYNAMIC_ARRAY *array, FREE_FUNC f); extern void freeze_size(DYNAMIC_ARRAY *array); extern int get_index_dynamic(DYNAMIC_ARRAY *array, void *element); #define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element) #define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index)) #define push_dynamic(A,B) insert_dynamic((A),(B)) #define reset_dynamic(array) ((array)->elements= 0) #define sort_dynamic(A,cmp) my_qsort((A)->buffer, (A)->elements, (A)->size_of_element, (cmp)) extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, size_t init_alloc,size_t alloc_increment); extern my_bool dynstr_append(DYNAMIC_STRING *str, const char *append); my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append, size_t length); extern my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, ...); extern my_bool dynstr_append_quoted(DYNAMIC_STRING *str, const char *append, size_t len, char quote); extern my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str); extern my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size); extern my_bool dynstr_trunc(DYNAMIC_STRING *str, size_t n); extern void dynstr_free(DYNAMIC_STRING *str); extern uint32 copy_and_convert_extended(char *to, uint32 to_length, CHARSET_INFO *to_cs, const char *from, uint32 from_length, CHARSET_INFO *from_cs, uint *errors); extern void dynstr_reassociate(DYNAMIC_STRING *str, char **res, size_t *length, size_t *alloc_length); extern uint32 copy_and_convert_extended(char *to, uint32 to_length, CHARSET_INFO *to_cs, const char *from, uint32 from_length, CHARSET_INFO *from_cs, uint *errors); #ifdef HAVE_MLOCK extern void *my_malloc_lock(size_t length,myf flags); extern void my_free_lock(void *ptr); #else #define my_malloc_lock(A,B) my_malloc(PSI_INSTRUMENT_ME, (A),(B)) #define my_free_lock(A) my_free((A)) #endif #define alloc_root_inited(A) ((A)->min_malloc != 0) #define ALLOC_ROOT_MIN_BLOCK_SIZE (MALLOC_OVERHEAD + sizeof(USED_MEM) + 8) #define DEFAULT_ROOT_BLOCK_SIZE 1024 #define clear_alloc_root(A) do { (A)->free= (A)->used= (A)->pre_alloc= 0; (A)->min_malloc=0;} while(0) extern void init_alloc_root(PSI_memory_key key, MEM_ROOT *mem_root, size_t block_size, size_t pre_alloc_size, myf my_flags); extern void *alloc_root(MEM_ROOT *mem_root, size_t Size); extern void *multi_alloc_root(MEM_ROOT *mem_root, ...); extern void free_root(MEM_ROOT *root, myf MyFLAGS); extern void move_root(MEM_ROOT *to, MEM_ROOT *from); extern void set_prealloc_root(MEM_ROOT *root, char *ptr); extern void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size, size_t prealloc_size); extern char *strdup_root(MEM_ROOT *root,const char *str); static inline char *safe_strdup_root(MEM_ROOT *root, const char *str) { return str ? strdup_root(root, str) : 0; } extern char *strmake_root(MEM_ROOT *root,const char *str,size_t len); extern void *memdup_root(MEM_ROOT *root,const void *str, size_t len); extern LEX_CSTRING safe_lexcstrdup_root(MEM_ROOT *root, const LEX_CSTRING str); extern my_bool my_compress(uchar *, size_t *, size_t *); extern my_bool my_uncompress(uchar *, size_t , size_t *); extern uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen); extern void *my_az_allocator(void *dummy, unsigned int items, unsigned int size); extern void my_az_free(void *dummy, void *address); extern int my_compress_buffer(uchar *dest, size_t *destLen, const uchar *source, size_t sourceLen); extern int packfrm(const uchar *, size_t, uchar **, size_t *); extern int unpackfrm(uchar **, size_t *, const uchar *); extern uint32 my_checksum(uint32, const void *, size_t); extern uint32 my_crc32c(uint32, const void *, size_t); extern const char *my_crc32c_implementation(); #ifdef DBUG_ASSERT_EXISTS extern void my_debug_put_break_here(void); #else #define my_debug_put_break_here() do {} while(0) #endif extern void my_sleep(ulong m_seconds); extern uint my_set_max_open_files(uint files); void my_free_open_file_info(void); extern my_bool my_gethwaddr(uchar *to); extern int my_getncpus(void); #define HRTIME_RESOLUTION 1000000ULL /* microseconds */ typedef struct {ulonglong val;} my_hrtime_t; void my_time_init(void); extern my_hrtime_t my_hrtime(void); #ifdef _WIN32 extern my_hrtime_t my_hrtime_coarse(); #else #define my_hrtime_coarse() my_hrtime() #endif extern ulonglong my_interval_timer(void); extern ulonglong my_getcputime(void); #define microsecond_interval_timer() (my_interval_timer()/1000) #define hrtime_to_time(X) ((time_t)((X).val/HRTIME_RESOLUTION)) #define hrtime_from_time(X) ((ulonglong)((X)*HRTIME_RESOLUTION)) #define hrtime_to_double(X) ((X).val/(double)HRTIME_RESOLUTION) #define hrtime_sec_part(X) ((ulong)((X).val % HRTIME_RESOLUTION)) #define my_time(X) hrtime_to_time(my_hrtime_coarse()) /** Make high resolution time from two parts. */ static inline my_hrtime_t make_hr_time(my_time_t time, ulong time_sec_part) { my_hrtime_t res= {((ulonglong) time)*1000000 + time_sec_part}; return res; } #if STACK_DIRECTION < 0 #define available_stack_size(CUR,END) (long) ((char*)(CUR) - (char*)(END)) #else #define available_stack_size(CUR,END) (long) ((char*)(END) - (char*)(CUR)) #endif #ifndef MAP_SYNC #define MAP_SYNC 0x80000 #endif #ifndef MAP_SHARED_VALIDATE #define MAP_SHARED_VALIDATE 0x03 #endif #ifdef HAVE_SYS_MMAN_H #ifndef MAP_NOSYNC #define MAP_NOSYNC 0 #endif #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 /* For irix and AIX */ #endif #ifdef HAVE_MMAP64 #define my_mmap(a,b,c,d,e,f) mmap64(a,b,c,d,e,f) #else #define my_mmap(a,b,c,d,e,f) mmap(a,b,c,d,e,f) #endif #define my_munmap(a,b) munmap((a),(b)) #else /* not a complete set of mmap() flags, but only those that necessary */ #define PROT_READ 1 #define PROT_WRITE 2 #define MAP_NORESERVE 0 #define MAP_SHARED 0x0001 #define MAP_PRIVATE 0x0002 #define MAP_NOSYNC 0x0800 #define MAP_FAILED ((void *)-1) #define MS_SYNC 0x0000 #define HAVE_MMAP void *my_mmap(void *, size_t, int, int, int, my_off_t); int my_munmap(void *, size_t); #endif #ifdef _WIN32 extern FILE* my_win_popen(const char*, const char*); extern int my_win_pclose(FILE*); #define my_popen(A,B) my_win_popen(A,B) #define my_pclose(A) my_win_pclose(A) #else #define my_popen(A,B) popen(A,B) #define my_pclose(A) pclose(A) #endif /* my_getpagesize */ #ifdef HAVE_GETPAGESIZE #define my_getpagesize() getpagesize() #else int my_getpagesize(void); #endif int my_msync(int, void *, size_t, int); #define MY_UUID_SIZE 16 #define MY_UUID_STRING_LENGTH (8+1+4+1+4+1+4+1+12) #define MY_UUID_ORACLE_STRING_LENGTH (8+4+4+4+12) void my_uuid_init(ulong seed1, ulong seed2); void my_uuid(uchar *guid); void my_uuid2str(const uchar *guid, char *s); void my_uuid2str_oracle(const uchar *guid, char *s); void my_uuid_end(void); const char *my_dlerror(const char *dlpath); /* character sets */ extern void my_charset_loader_init_mysys(MY_CHARSET_LOADER *loader); extern uint get_charset_number(const char *cs_name, uint cs_flags, myf flags); extern uint get_collation_number(const char *name,myf flags); extern const char *get_charset_name(uint cs_number); extern CHARSET_INFO *get_charset(uint cs_number, myf flags); extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); extern CHARSET_INFO *my_collation_get_by_name(MY_CHARSET_LOADER *loader, const char *name, myf flags); extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, uint cs_flags, myf my_flags); extern CHARSET_INFO *my_charset_get_by_name(MY_CHARSET_LOADER *loader, const char *name, uint cs_flags, myf my_flags); extern my_bool resolve_charset(const char *cs_name, CHARSET_INFO *default_cs, CHARSET_INFO **cs, myf flags); extern my_bool resolve_collation(const char *cl_name, CHARSET_INFO *default_cl, CHARSET_INFO **cl, myf my_flags); extern void free_charsets(void); extern char *get_charsets_dir(char *buf); static inline my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2) { return (cs1->cs_name.str == cs2->cs_name.str); } extern my_bool init_compiled_charsets(myf flags); extern void add_compiled_collation(struct charset_info_st *cs); extern void add_compiled_extra_collation(struct charset_info_st *cs); extern size_t escape_string_for_mysql(CHARSET_INFO *charset_info, char *to, size_t to_length, const char *from, size_t length, my_bool *overflow); extern char *my_get_tty_password(const char *opt_message); #ifdef _WIN32 #define BACKSLASH_MBTAIL /* File system character set */ extern CHARSET_INFO *fs_character_set(void); #endif extern const char *my_default_csname(void); extern size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info, char *to, size_t to_length, const char *from, size_t length, my_bool *overflow); extern void thd_increment_bytes_sent(void *thd, size_t length); extern void thd_increment_bytes_received(void *thd, size_t length); extern void thd_increment_net_big_packet_count(void *thd, size_t length); #ifdef _WIN32 /* implemented in my_conio.c */ char* my_cgets(char *string, size_t clen, size_t* plen); #endif #include #ifdef HAVE_PSI_INTERFACE extern MYSQL_PLUGIN_IMPORT struct PSI_bootstrap *PSI_hook; extern void set_psi_server(PSI *psi); void my_init_mysys_psi_keys(void); #endif struct st_mysql_file; extern struct st_mysql_file *mysql_stdin; C_MODE_END #endif /* _my_sys_h */ server/my_list.h000064400000002742151031265050007706 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _list_h_ #define _list_h_ #ifdef __cplusplus extern "C" { #endif typedef struct st_list { struct st_list *prev,*next; void *data; } LIST; typedef int (*list_walk_action)(void *,void *); extern LIST *list_add(LIST *root,LIST *element); extern LIST *list_delete(LIST *root,LIST *element); extern LIST *list_cons(void *data,LIST *root); extern LIST *list_reverse(LIST *root); extern void list_free(LIST *root,unsigned int free_data); extern unsigned int list_length(LIST *); extern int list_walk(LIST *,list_walk_action action,unsigned char * argument); #define list_rest(a) ((a)->next) #define list_push(a,b) (a)=list_cons((b),(a)) #define list_pop(A) {LIST *old=(A); (A)=list_delete(old,old); my_free(old); } #ifdef __cplusplus } #endif #endif server/my_cmp.h000064400000001622151031265050007506 0ustar00/* Copyright (c) 2024, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #pragma once #ifdef __cplusplus extern "C" { #endif typedef int (*qsort_cmp)(const void *, const void *); typedef int (*qsort_cmp2)(void *param, const void *a, const void *b); #ifdef __cplusplus } #endif server/mysql.h000064400000115460151031265050007375 0ustar00/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. Copyright (c) 2012, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* This file defines the client API to MySQL and also the ABI of the dynamically linked libmysqlclient. The ABI should never be changed in a released product of MySQL, thus you need to take great care when changing the file. In case the file is changed so the ABI is broken, you must also update the SHARED_LIB_MAJOR_VERSION in cmake/mysql_version.cmake */ #ifndef _mysql_h #define _mysql_h #ifdef _AIX /* large-file support will break without this */ #include #endif #ifdef __cplusplus extern "C" { #endif #ifndef MY_GLOBAL_INCLUDED /* If not standard header */ #ifndef MYSQL_ABI_CHECK #include #endif #ifndef MYSQL_PLUGIN_INCLUDED typedef char my_bool; #endif #if !defined(_WIN32) #define STDCALL #else #define STDCALL __stdcall #endif #ifndef my_socket_defined #if defined (_WIN64) #define my_socket unsigned long long #elif defined (_WIN32) #define my_socket unsigned int #else typedef int my_socket; #endif /* _WIN64 */ #endif /* my_socket_defined */ #endif /* MY_GLOBAL_INCLUDED */ #include "mariadb_capi_rename.h" #include "mysql_version.h" #include "mysql_com.h" #include "mysql_time.h" #include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */ extern unsigned int mariadb_deinitialize_ssl; extern unsigned int mysql_port; extern char *mysql_unix_port; #define CLIENT_NET_READ_TIMEOUT (365*24*3600) /* Timeout on read */ #define CLIENT_NET_WRITE_TIMEOUT (365*24*3600) /* Timeout on write */ #define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG) #define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG) #define IS_BLOB(n) ((n) & BLOB_FLAG) /** Returns true if the value is a number which does not need quotes for the sql_lex.cc parser to parse correctly. */ #define IS_NUM(t) (((t) <= MYSQL_TYPE_INT24 && (t) != MYSQL_TYPE_TIMESTAMP) || (t) == MYSQL_TYPE_YEAR || (t) == MYSQL_TYPE_NEWDECIMAL) #define IS_LONGDATA(t) ((t) >= MYSQL_TYPE_TINY_BLOB && (t) <= MYSQL_TYPE_STRING) typedef struct st_mysql_const_lex_string MARIADB_CONST_STRING; typedef struct st_mysql_field { char *name; /* Name of column */ char *org_name; /* Original column name, if an alias */ char *table; /* Table of column if column was a field */ char *org_table; /* Org table name, if table was an alias */ char *db; /* Database for table */ char *catalog; /* Catalog for table */ char *def; /* Default value (set by mysql_list_fields) */ unsigned long length; /* Width of column (create length) */ unsigned long max_length; /* Max width for selected set */ unsigned int name_length; unsigned int org_name_length; unsigned int table_length; unsigned int org_table_length; unsigned int db_length; unsigned int catalog_length; unsigned int def_length; unsigned int flags; /* Div flags */ unsigned int decimals; /* Number of decimals in field */ unsigned int charsetnr; /* Character set */ enum enum_field_types type; /* Type of field. See mysql_com.h for types */ void *extension; } MYSQL_FIELD; typedef char **MYSQL_ROW; /* return data as array of strings */ typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */ #ifndef MY_GLOBAL_INCLUDED #if defined(NO_CLIENT_LONG_LONG) typedef unsigned long my_ulonglong; #elif defined (_WIN32) typedef unsigned __int64 my_ulonglong; #else typedef unsigned long long my_ulonglong; #endif #endif #include "typelib.h" #define MYSQL_COUNT_ERROR (~(my_ulonglong) 0) /* backward compatibility define - to be removed eventually */ #define ER_WARN_DATA_TRUNCATED WARN_DATA_TRUNCATED #define WARN_PLUGIN_DELETE_BUILTIN ER_PLUGIN_DELETE_BUILTIN #define ER_FK_DUP_NAME ER_DUP_CONSTRAINT_NAME #define ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED #define ER_PRIMARY_KEY_BASED_ON_VIRTUAL_COLUMN ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN #define ER_WRONG_FK_OPTION_FOR_VIRTUAL_COLUMN ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN #define ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN #define ER_UNSUPPORTED_ENGINE_FOR_VIRTUAL_COLUMNS ER_UNSUPPORTED_ENGINE_FOR_GENERATED_COLUMNS #define ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT ER_QUERY_RESULT_INCOMPLETE typedef struct st_mysql_rows { struct st_mysql_rows *next; /* list of rows */ MYSQL_ROW data; unsigned long length; } MYSQL_ROWS; typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */ #include "my_alloc.h" typedef struct embedded_query_result EMBEDDED_QUERY_RESULT; typedef struct st_mysql_data { MYSQL_ROWS *data; struct embedded_query_result *embedded_info; MEM_ROOT alloc; my_ulonglong rows; unsigned int fields; /* extra info for embedded library */ void *extension; } MYSQL_DATA; enum mysql_option { MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE, MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE, MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT, MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, MYSQL_OPT_BIND, MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT, MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER, MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH, MYSQL_OPT_CONNECT_ATTR_RESET, MYSQL_OPT_CONNECT_ATTR_ADD, MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_SERVER_PUBLIC_KEY, MYSQL_ENABLE_CLEARTEXT_PLUGIN, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, /* MariaDB options */ MYSQL_PROGRESS_CALLBACK=5999, MYSQL_OPT_NONBLOCK, MYSQL_OPT_USE_THREAD_SPECIFIC_MEMORY }; /** @todo remove the "extension", move st_mysql_options completely out of mysql.h */ struct st_mysql_options_extention; struct st_mysql_options { unsigned int connect_timeout, read_timeout, write_timeout; unsigned int port, protocol; unsigned long client_flag; char *host,*user,*password,*unix_socket,*db; struct st_dynamic_array *init_commands; char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name; char *ssl_key; /* PEM key file */ char *ssl_cert; /* PEM cert file */ char *ssl_ca; /* PEM CA file */ char *ssl_capath; /* PEM directory of CA-s? */ char *ssl_cipher; /* cipher to use */ char *shared_memory_base_name; unsigned long max_allowed_packet; my_bool use_ssl; /* if to use SSL or not */ my_bool compress,named_pipe; my_bool use_thread_specific_memory; my_bool unused2; my_bool unused3; my_bool unused4; enum mysql_option methods_to_use; char *client_ip; /* Refuse client connecting to server if it uses old (pre-4.1.1) protocol */ my_bool secure_auth; /* 0 - never report, 1 - always report (default) */ my_bool report_data_truncation; /* function pointers for local infile support */ int (*local_infile_init)(void **, const char *, void *); int (*local_infile_read)(void *, char *, unsigned int); void (*local_infile_end)(void *); int (*local_infile_error)(void *, char *, unsigned int); void *local_infile_userdata; struct st_mysql_options_extention *extension; }; enum mysql_status { MYSQL_STATUS_READY, MYSQL_STATUS_GET_RESULT, MYSQL_STATUS_USE_RESULT, MYSQL_STATUS_STATEMENT_GET_RESULT }; enum mysql_protocol_type { MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET, MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY }; typedef struct character_set { unsigned int number; /* character set number */ unsigned int state; /* character set state */ const char *csname; /* collation name */ const char *name; /* character set name */ const char *comment; /* comment */ const char *dir; /* character set directory */ unsigned int mbminlen; /* min. length for multibyte strings */ unsigned int mbmaxlen; /* max. length for multibyte strings */ } MY_CHARSET_INFO; struct st_mysql_methods; struct st_mysql_stmt; typedef struct st_mysql { NET net; /* Communication parameters */ unsigned char *connector_fd; /* ConnectorFd for SSL */ char *host,*user,*passwd,*unix_socket,*server_version,*host_info; char *info, *db; const struct charset_info_st *charset; MEM_ROOT field_alloc; my_ulonglong affected_rows; my_ulonglong insert_id; /* id if insert on table with NEXTNR */ my_ulonglong extra_info; /* Not used */ unsigned long thread_id; /* Id for connection in server */ unsigned long packet_length; unsigned int port; unsigned long client_flag,server_capabilities; unsigned int protocol_version; unsigned int field_count; unsigned int server_status; unsigned int server_language; unsigned int warning_count; struct st_mysql_options options; enum mysql_status status; my_bool free_me; /* If free in mysql_close */ my_bool reconnect; /* set to 1 if automatic reconnect */ /* session-wide random string */ char scramble[SCRAMBLE_LENGTH+1]; my_bool auto_local_infile; void *unused2, *unused3, *unused4; MYSQL_FIELD *fields; LIST *stmts; /* list of all statements */ const struct st_mysql_methods *methods; void *thd; /* Points to boolean flag in MYSQL_RES or MYSQL_STMT. We set this flag from mysql_stmt_close if close had to cancel result set of this object. */ my_bool *unbuffered_fetch_owner; /* needed for embedded server - no net buffer to store the 'info' */ char *info_buffer; void *extension; } MYSQL; typedef struct st_mysql_res { my_ulonglong row_count; MYSQL_FIELD *fields; MYSQL_DATA *data; MYSQL_ROWS *data_cursor; unsigned long *lengths; /* column lengths of current row */ MYSQL *handle; /* for unbuffered reads */ const struct st_mysql_methods *methods; MYSQL_ROW row; /* If unbuffered read */ MYSQL_ROW current_row; /* buffer to current row */ MEM_ROOT field_alloc; unsigned int field_count, current_field; my_bool eof; /* Used by mysql_fetch_row */ /* mysql_stmt_close() had to cancel this result */ my_bool unbuffered_fetch_cancelled; void *extension; } MYSQL_RES; #if !defined(MYSQL_SERVICE_SQL) && !defined(MYSQL_CLIENT) #define MYSQL_CLIENT #endif typedef struct st_mysql_parameters { unsigned long *p_max_allowed_packet; unsigned long *p_net_buffer_length; void *extension; } MYSQL_PARAMETERS; /* Flag bits, the asynchronous methods return a combination of these ORed together to let the application know when to resume the suspended operation. */ /* Wait for data to be available on socket to read. mysql_get_socket_fd() will return socket descriptor. */ #define MYSQL_WAIT_READ 1 /* Wait for socket to be ready to write data. */ #define MYSQL_WAIT_WRITE 2 /* Wait for select() to mark exception on socket. */ #define MYSQL_WAIT_EXCEPT 4 /* Wait until timeout occurs. Value of timeout can be obtained from mysql_get_timeout_value(). */ #define MYSQL_WAIT_TIMEOUT 8 #if !defined(MYSQL_SERVICE_SQL) #define max_allowed_packet (*mysql_get_parameters()->p_max_allowed_packet) #define net_buffer_length (*mysql_get_parameters()->p_net_buffer_length) #endif /* Set up and bring down the server; to ensure that applications will work when linked against either the standard client library or the embedded server library, these functions should be called. */ int STDCALL mysql_server_init(int argc, char **argv, char **groups); void STDCALL mysql_server_end(void); /* mysql_server_init/end need to be called when using libmysqld or libmysqlclient (exactly, mysql_server_init() is called by mysql_init() so you don't need to call it explicitly; but you need to call mysql_server_end() to free memory). The names are a bit misleading (mysql_SERVER* to be used when using libmysqlCLIENT). So we add more general names which suit well whether you're using libmysqld or libmysqlclient. We intend to promote these aliases over the mysql_server* ones. */ #define mysql_library_init mysql_server_init #define mysql_library_end mysql_server_end MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void); /* Set up and bring down a thread; these function should be called for each thread in an application which opens at least one MySQL connection. All uses of the connection(s) should be between these function calls. */ my_bool STDCALL mysql_thread_init(void); void STDCALL mysql_thread_end(void); /* Functions to get information from the MYSQL and MYSQL_RES structures Should definitely be used if one uses shared libraries. */ my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res); unsigned int STDCALL mysql_num_fields(MYSQL_RES *res); my_bool STDCALL mysql_eof(MYSQL_RES *res); MYSQL_FIELD *STDCALL mysql_fetch_field_direct(MYSQL_RES *res, unsigned int fieldnr); MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res); MYSQL_ROW_OFFSET STDCALL mysql_row_tell(MYSQL_RES *res); MYSQL_FIELD_OFFSET STDCALL mysql_field_tell(MYSQL_RES *res); int STDCALL mariadb_field_attr(MARIADB_CONST_STRING *attr, const MYSQL_FIELD *field, enum mariadb_field_attr_t type); unsigned int STDCALL mysql_field_count(MYSQL *mysql); my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql); my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql); unsigned int STDCALL mysql_errno(MYSQL *mysql); const char * STDCALL mysql_error(MYSQL *mysql); const char *STDCALL mysql_sqlstate(MYSQL *mysql); unsigned int STDCALL mysql_warning_count(MYSQL *mysql); const char * STDCALL mysql_info(MYSQL *mysql); unsigned long STDCALL mysql_thread_id(MYSQL *mysql); const char * STDCALL mysql_character_set_name(MYSQL *mysql); int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname); int STDCALL mysql_set_character_set_start(int *ret, MYSQL *mysql, const char *csname); int STDCALL mysql_set_character_set_cont(int *ret, MYSQL *mysql, int status); MYSQL * STDCALL mysql_init(MYSQL *mysql); my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); const char * STDCALL mysql_get_ssl_cipher(MYSQL *mysql); my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, const char *passwd, const char *db); int STDCALL mysql_change_user_start(my_bool *ret, MYSQL *mysql, const char *user, const char *passwd, const char *db); int STDCALL mysql_change_user_cont(my_bool *ret, MYSQL *mysql, int status); MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); int STDCALL mysql_real_connect_start(MYSQL **ret, MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); int STDCALL mysql_real_connect_cont(MYSQL **ret, MYSQL *mysql, int status); int STDCALL mysql_select_db(MYSQL *mysql, const char *db); int STDCALL mysql_select_db_start(int *ret, MYSQL *mysql, const char *db); int STDCALL mysql_select_db_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_query(MYSQL *mysql, const char *q); int STDCALL mysql_query_start(int *ret, MYSQL *mysql, const char *q); int STDCALL mysql_query_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_send_query(MYSQL *mysql, const char *q, unsigned long length); int STDCALL mysql_send_query_start(int *ret, MYSQL *mysql, const char *q, unsigned long length); int STDCALL mysql_send_query_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_real_query(MYSQL *mysql, const char *q, unsigned long length); int STDCALL mysql_real_query_start(int *ret, MYSQL *mysql, const char *q, unsigned long length); int STDCALL mysql_real_query_cont(int *ret, MYSQL *mysql, int status); MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql); int STDCALL mysql_store_result_start(MYSQL_RES **ret, MYSQL *mysql); int STDCALL mysql_store_result_cont(MYSQL_RES **ret, MYSQL *mysql, int status); MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql); void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *charset); /* local infile support */ #define LOCAL_INFILE_ERROR_LEN 512 void mysql_set_local_infile_handler(MYSQL *mysql, int (*local_infile_init)(void **, const char *, void *), int (*local_infile_read)(void *, char *, unsigned int), void (*local_infile_end)(void *), int (*local_infile_error)(void *, char*, unsigned int), void *); void mysql_set_local_infile_default(MYSQL *mysql); int STDCALL mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level); int STDCALL mysql_shutdown_start(int *ret, MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level); int STDCALL mysql_shutdown_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_dump_debug_info(MYSQL *mysql); int STDCALL mysql_dump_debug_info_start(int *ret, MYSQL *mysql); int STDCALL mysql_dump_debug_info_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_refresh(MYSQL *mysql, unsigned int refresh_options); int STDCALL mysql_refresh_start(int *ret, MYSQL *mysql, unsigned int refresh_options); int STDCALL mysql_refresh_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_kill(MYSQL *mysql,unsigned long pid); int STDCALL mysql_kill_start(int *ret, MYSQL *mysql, unsigned long pid); int STDCALL mysql_kill_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_set_server_option(MYSQL *mysql, enum enum_mysql_set_option option); int STDCALL mysql_set_server_option_start(int *ret, MYSQL *mysql, enum enum_mysql_set_option option); int STDCALL mysql_set_server_option_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_ping(MYSQL *mysql); int STDCALL mysql_ping_start(int *ret, MYSQL *mysql); int STDCALL mysql_ping_cont(int *ret, MYSQL *mysql, int status); const char * STDCALL mysql_stat(MYSQL *mysql); int STDCALL mysql_stat_start(const char **ret, MYSQL *mysql); int STDCALL mysql_stat_cont(const char **ret, MYSQL *mysql, int status); const char * STDCALL mysql_get_server_info(MYSQL *mysql); const char * STDCALL mysql_get_server_name(MYSQL *mysql); const char * STDCALL mysql_get_client_info(void); unsigned long STDCALL mysql_get_client_version(void); const char * STDCALL mysql_get_host_info(MYSQL *mysql); unsigned long STDCALL mysql_get_server_version(MYSQL *mysql); unsigned int STDCALL mysql_get_proto_info(MYSQL *mysql); MYSQL_RES * STDCALL mysql_list_dbs(MYSQL *mysql,const char *wild); int STDCALL mysql_list_dbs_start(MYSQL_RES **ret, MYSQL *mysql, const char *wild); int STDCALL mysql_list_dbs_cont(MYSQL_RES **ret, MYSQL *mysql, int status); MYSQL_RES * STDCALL mysql_list_tables(MYSQL *mysql,const char *wild); int STDCALL mysql_list_tables_start(MYSQL_RES **ret, MYSQL *mysql, const char *wild); int STDCALL mysql_list_tables_cont(MYSQL_RES **ret, MYSQL *mysql, int status); MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql); int STDCALL mysql_list_processes_start(MYSQL_RES **ret, MYSQL *mysql); int STDCALL mysql_list_processes_cont(MYSQL_RES **ret, MYSQL *mysql, int status); int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg); int STDCALL mysql_options4(MYSQL *mysql,enum mysql_option option, const void *arg1, const void *arg2); void STDCALL mysql_free_result(MYSQL_RES *result); int STDCALL mysql_free_result_start(MYSQL_RES *result); int STDCALL mysql_free_result_cont(MYSQL_RES *result, int status); void STDCALL mysql_data_seek(MYSQL_RES *result, my_ulonglong offset); MYSQL_ROW_OFFSET STDCALL mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET offset); MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset); MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result); int STDCALL mysql_fetch_row_start(MYSQL_ROW *ret, MYSQL_RES *result); int STDCALL mysql_fetch_row_cont(MYSQL_ROW *ret, MYSQL_RES *result, int status); unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result); MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result); MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table, const char *wild); int STDCALL mysql_list_fields_start(MYSQL_RES **ret, MYSQL *mysql, const char *table, const char *wild); int STDCALL mysql_list_fields_cont(MYSQL_RES **ret, MYSQL *mysql, int status); unsigned long STDCALL mysql_escape_string(char *to,const char *from, unsigned long from_length); unsigned long STDCALL mysql_hex_string(char *to,const char *from, unsigned long from_length); unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); void STDCALL mysql_debug(const char *debug); void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int STDCALL mysql_thread_safe(void); my_bool STDCALL mysql_embedded(void); my_bool STDCALL mariadb_connection(MYSQL *mysql); my_bool STDCALL mysql_read_query_result(MYSQL *mysql); int STDCALL mysql_read_query_result_start(my_bool *ret, MYSQL *mysql); int STDCALL mysql_read_query_result_cont(my_bool *ret, MYSQL *mysql, int status); /* The following definitions are added for the enhanced client-server protocol */ /* statement state */ enum enum_mysql_stmt_state { MYSQL_STMT_INIT_DONE= 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE, MYSQL_STMT_FETCH_DONE }; /* This structure is used to define bind information, and internally by the client library. Public members with their descriptions are listed below (conventionally `On input' refers to the binds given to mysql_stmt_bind_param, `On output' refers to the binds given to mysql_stmt_bind_result): buffer_type - One of the MYSQL_* types, used to describe the host language type of buffer. On output: if column type is different from buffer_type, column value is automatically converted to buffer_type before it is stored in the buffer. buffer - On input: points to the buffer with input data. On output: points to the buffer capable to store output data. The type of memory pointed by buffer must correspond to buffer_type. See the correspondence table in the comment to mysql_stmt_bind_param. The two above members are mandatory for any kind of bind. buffer_length - the length of the buffer. You don't have to set it for any fixed length buffer: float, double, int, etc. It must be set however for variable-length types, such as BLOBs or STRINGs. length - On input: in case when lengths of input values are different for each execute, you can set this to point at a variable containing value length. This way the value length can be different in each execute. If length is not NULL, buffer_length is not used. Note, length can even point at buffer_length if you keep bind structures around while fetching: this way you can change buffer_length before each execution, everything will work ok. On output: if length is set, mysql_stmt_fetch will write column length into it. is_null - On input: points to a boolean variable that should be set to TRUE for NULL values. This member is useful only if your data may be NULL in some but not all cases. If your data is never NULL, is_null should be set to 0. If your data is always NULL, set buffer_type to MYSQL_TYPE_NULL, and is_null will not be used. is_unsigned - On input: used to signify that values provided for one of numeric types are unsigned. On output describes signedness of the output buffer. If, taking into account is_unsigned flag, column data is out of range of the output buffer, data for this column is regarded truncated. Note that this has no correspondence to the sign of result set column, if you need to find it out use mysql_stmt_result_metadata. error - where to write a truncation error if it is present. possible error value is: 0 no truncation 1 value is out of range or buffer is too small Please note that MYSQL_BIND also has internals members. */ typedef struct st_mysql_bind { unsigned long *length; /* output length pointer */ my_bool *is_null; /* Pointer to null indicator */ void *buffer; /* buffer to get/put data */ /* set this if you want to track data truncations happened during fetch */ my_bool *error; unsigned char *row_ptr; /* for the current data position */ void (*store_param_func)(NET *net, struct st_mysql_bind *param); void (*fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *, unsigned char **row); void (*skip_result)(struct st_mysql_bind *, MYSQL_FIELD *, unsigned char **row); /* output buffer length, must be set when fetching str/binary */ unsigned long buffer_length; unsigned long offset; /* offset position for char/binary fetch */ unsigned long length_value; /* Used if length is 0 */ unsigned int param_number; /* For null count and error messages */ unsigned int pack_length; /* Internal length for packed data */ enum enum_field_types buffer_type; /* buffer type */ my_bool error_value; /* used if error is 0 */ my_bool is_unsigned; /* set if integer type is unsigned */ my_bool long_data_used; /* If used with mysql_send_long_data */ my_bool is_null_value; /* Used if is_null is 0 */ void *extension; } MYSQL_BIND; struct st_mysql_stmt_extension; /* statement handler */ typedef struct st_mysql_stmt { MEM_ROOT mem_root; /* root allocations */ LIST list; /* list to keep track of all stmts */ MYSQL *mysql; /* connection handle */ MYSQL_BIND *params; /* input parameters */ MYSQL_BIND *bind; /* output parameters */ MYSQL_FIELD *fields; /* result set metadata */ MYSQL_DATA result; /* cached result set */ MYSQL_ROWS *data_cursor; /* current row in cached result */ /* mysql_stmt_fetch() calls this function to fetch one row (it's different for buffered, unbuffered and cursor fetch). */ int (*read_row_func)(struct st_mysql_stmt *stmt, unsigned char **row); /* copy of mysql->affected_rows after statement execution */ my_ulonglong affected_rows; my_ulonglong insert_id; /* copy of mysql->insert_id */ unsigned long stmt_id; /* Id for prepared statement */ unsigned long flags; /* i.e. type of cursor to open */ unsigned long prefetch_rows; /* number of rows per one COM_FETCH */ /* Copied from mysql->server_status after execute/fetch to know server-side cursor status for this statement. */ unsigned int server_status; unsigned int last_errno; /* error code */ unsigned int param_count; /* input parameter count */ unsigned int field_count; /* number of columns in result set */ enum enum_mysql_stmt_state state; /* statement state */ char last_error[MYSQL_ERRMSG_SIZE]; /* error message */ char sqlstate[SQLSTATE_LENGTH+1]; /* Types of input parameters should be sent to server */ my_bool send_types_to_server; my_bool bind_param_done; /* input buffers were supplied */ unsigned char bind_result_done; /* output buffers were supplied */ /* mysql_stmt_close() had to cancel this result */ my_bool unbuffered_fetch_cancelled; /* Is set to true if we need to calculate field->max_length for metadata fields when doing mysql_stmt_store_result. */ my_bool update_max_length; struct st_mysql_stmt_extension *extension; } MYSQL_STMT; enum enum_stmt_attr_type { /* When doing mysql_stmt_store_result calculate max_length attribute of statement metadata. This is to be consistent with the old API, where this was done automatically. In the new API we do that only by request because it slows down mysql_stmt_store_result sufficiently. */ STMT_ATTR_UPDATE_MAX_LENGTH, /* unsigned long with combination of cursor flags (read only, for update, etc) */ STMT_ATTR_CURSOR_TYPE, /* Amount of rows to retrieve from server per one fetch if using cursors. Accepts unsigned long attribute in the range 1 - ulong_max */ STMT_ATTR_PREFETCH_ROWS }; MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql); int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length); int STDCALL mysql_stmt_prepare_start(int *ret, MYSQL_STMT *stmt, const char *query, unsigned long length); int STDCALL mysql_stmt_prepare_cont(int *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt); int STDCALL mysql_stmt_execute_start(int *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_execute_cont(int *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt); int STDCALL mysql_stmt_fetch_start(int *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_fetch_cont(int *ret, MYSQL_STMT *stmt, int status); int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg, unsigned int column, unsigned long offset); int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt); int STDCALL mysql_stmt_store_result_start(int *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_store_result_cont(int *ret, MYSQL_STMT *stmt, int status); unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT * stmt); my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *attr); my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *attr); my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); my_bool STDCALL mysql_stmt_close(MYSQL_STMT * stmt); int STDCALL mysql_stmt_close_start(my_bool *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_close_cont(my_bool *ret, MYSQL_STMT * stmt, int status); my_bool STDCALL mysql_stmt_reset(MYSQL_STMT * stmt); int STDCALL mysql_stmt_reset_start(my_bool *ret, MYSQL_STMT * stmt); int STDCALL mysql_stmt_reset_cont(my_bool *ret, MYSQL_STMT *stmt, int status); my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt); int STDCALL mysql_stmt_free_result_start(my_bool *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_free_result_cont(my_bool *ret, MYSQL_STMT *stmt, int status); my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length); int STDCALL mysql_stmt_send_long_data_start(my_bool *ret, MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long len); int STDCALL mysql_stmt_send_long_data_cont(my_bool *ret, MYSQL_STMT *stmt, int status); MYSQL_RES *STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt); MYSQL_RES *STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt); unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT * stmt); const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt); const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt); MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET offset); MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt); void STDCALL mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong offset); my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt); my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt); my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt); unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt); my_bool STDCALL mysql_commit(MYSQL * mysql); int STDCALL mysql_commit_start(my_bool *ret, MYSQL * mysql); int STDCALL mysql_commit_cont(my_bool *ret, MYSQL * mysql, int status); my_bool STDCALL mysql_rollback(MYSQL * mysql); int STDCALL mysql_rollback_start(my_bool *ret, MYSQL * mysql); int STDCALL mysql_rollback_cont(my_bool *ret, MYSQL * mysql, int status); my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode); int STDCALL mysql_autocommit_start(my_bool *ret, MYSQL * mysql, my_bool auto_mode); int STDCALL mysql_autocommit_cont(my_bool *ret, MYSQL * mysql, int status); my_bool STDCALL mysql_more_results(MYSQL *mysql); int STDCALL mysql_next_result(MYSQL *mysql); int STDCALL mysql_next_result_start(int *ret, MYSQL *mysql); int STDCALL mysql_next_result_cont(int *ret, MYSQL *mysql, int status); int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt); int STDCALL mysql_stmt_next_result_start(int *ret, MYSQL_STMT *stmt); int STDCALL mysql_stmt_next_result_cont(int *ret, MYSQL_STMT *stmt, int status); void STDCALL mysql_close_slow_part(MYSQL *mysql); void STDCALL mysql_close(MYSQL *sock); int STDCALL mysql_close_start(MYSQL *sock); int STDCALL mysql_close_cont(MYSQL *sock, int status); my_socket STDCALL mysql_get_socket(const MYSQL *mysql); unsigned int STDCALL mysql_get_timeout_value(const MYSQL *mysql); unsigned int STDCALL mysql_get_timeout_value_ms(const MYSQL *mysql); /******************************************************************** mysql_net_ functions - low-level API to MySQL protocol *********************************************************************/ unsigned long STDCALL mysql_net_read_packet(MYSQL *mysql); unsigned long STDCALL mysql_net_field_length(unsigned char **packet); /* status return codes */ #define MYSQL_NO_DATA 100 #define MYSQL_DATA_TRUNCATED 101 #define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT) #ifdef USE_OLD_FUNCTIONS MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd); int STDCALL mysql_create_db(MYSQL *mysql, const char *DB); int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB); #endif #define HAVE_MYSQL_REAL_CONNECT #ifdef __cplusplus } #endif #endif /* _mysql_h */ server/mysql_com.h000064400000074223151031265050010234 0ustar00/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. Copyright (c) 2010, 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* ** Common definition between mysql server & client */ #ifndef _mysql_com_h #define _mysql_com_h #include "my_decimal_limits.h" #define HOSTNAME_LENGTH 255 #define HOSTNAME_LENGTH_STR STRINGIFY_ARG(HOSTNAME_LENGTH) #define SYSTEM_CHARSET_MBMAXLEN 3 #define NAME_CHAR_LEN 64 /* Field/table name length */ #define USERNAME_CHAR_LENGTH 128 #define USERNAME_CHAR_LENGTH_STR STRINGIFY_ARG(USERNAME_CHAR_LENGTH) #define NAME_LEN (NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN) #define USERNAME_LENGTH (USERNAME_CHAR_LENGTH*SYSTEM_CHARSET_MBMAXLEN) #define DEFINER_CHAR_LENGTH (USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 1) #define DEFINER_LENGTH (USERNAME_LENGTH + HOSTNAME_LENGTH + 1) #define MYSQL_AUTODETECT_CHARSET_NAME "auto" #define MYSQL50_TABLE_NAME_PREFIX "#mysql50#" #define MYSQL50_TABLE_NAME_PREFIX_LENGTH (sizeof(MYSQL50_TABLE_NAME_PREFIX)-1) #define SAFE_NAME_LEN (NAME_LEN + MYSQL50_TABLE_NAME_PREFIX_LENGTH) /* MDEV-4088 MySQL (and MariaDB 5.x before the fix) was using the first character of the server version string (as sent in the first handshake protocol packet) to decide on the replication event formats. And for 10.x the first character is "1", which the slave thought comes from some ancient 1.x version (ignoring the fact that the first ever MySQL version was 3.x). To support replication to these old clients, we fake the version in the first handshake protocol packet to start from "5.5.5-" (for example, it might be "5.5.5-10.0.1-MariaDB-debug-log". On the client side we remove this fake version prefix to restore the correct server version. The version "5.5.5" did not support pluggable authentication, so any version starting from "5.5.5-" and claiming to support pluggable auth, must be using this fake prefix. */ /* this version must be the one that *does not* support pluggable auth */ #define RPL_VERSION_HACK "5.5.5-" #define SERVER_VERSION_LENGTH 60 #define SQLSTATE_LENGTH 5 #define LIST_PROCESS_HOST_LEN 64 /* Maximum length of comments */ #define TABLE_COMMENT_INLINE_MAXLEN 180 /* pre 5.5: 60 characters */ #define TABLE_COMMENT_MAXLEN 2048 #define COLUMN_COMMENT_MAXLEN 1024 #define INDEX_COMMENT_MAXLEN 1024 #define TABLE_PARTITION_COMMENT_MAXLEN 1024 #define DATABASE_COMMENT_MAXLEN 1024 /* Maximum length of protocol packet. OK packet length limit also restricted to this value as any length greater than this value will have first byte of OK packet to be 254 thus does not provide a means to identify if this is OK or EOF packet. */ #define MAX_PACKET_LENGTH (256L*256L*256L-1) /* USER_HOST_BUFF_SIZE -- length of string buffer, that is enough to contain username and hostname parts of the user identifier with trailing zero in MySQL standard format: user_name_part@host_name_part\0 */ #define USER_HOST_BUFF_SIZE HOSTNAME_LENGTH + USERNAME_LENGTH + 2 #define LOCAL_HOST "localhost" #define LOCAL_HOST_NAMEDPIPE "." #if defined(_WIN32) && !defined( _CUSTOMCONFIG_) #define MYSQL_NAMEDPIPE "MySQL" #define MYSQL_SERVICENAME "MySQL" #endif /* You should add new commands to the end of this list, otherwise old servers won't be able to handle them as 'unsupported'. */ enum enum_server_command { COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE, COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE, COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON, COM_UNIMPLEMENTED, /* COM_BINLOG_DUMP_GTID in MySQL */ COM_RESET_CONNECTION, /* don't forget to update const char *command_name[] in sql_parse.cc */ COM_MDB_GAP_BEG, COM_MDB_GAP_END=249, COM_STMT_BULK_EXECUTE=250, COM_SLAVE_WORKER=251, COM_SLAVE_IO=252, COM_SLAVE_SQL=253, COM_RESERVED_1=254, /* Old COM_MULTI, now removed */ /* Must be last */ COM_END=255 }; /* Bulk PS protocol indicator value: */ enum enum_indicator_type { STMT_INDICATOR_NONE= 0, STMT_INDICATOR_NULL, STMT_INDICATOR_DEFAULT, STMT_INDICATOR_IGNORE }; /* bulk PS flags */ #define STMT_BULK_FLAG_CLIENT_SEND_TYPES 128 #define STMT_BULK_FLAG_INSERT_ID_REQUEST 64 /* sql type stored in .frm files for virtual fields */ #define MYSQL_TYPE_VIRTUAL 245 /* Length of random string sent by server on handshake; this is also length of obfuscated password, received from client */ #define SCRAMBLE_LENGTH 20 #define SCRAMBLE_LENGTH_323 8 /* length of password stored in the db: new passwords are preceded with '*' */ #define SCRAMBLED_PASSWORD_CHAR_LENGTH (SCRAMBLE_LENGTH*2+1) #define SCRAMBLED_PASSWORD_CHAR_LENGTH_323 (SCRAMBLE_LENGTH_323*2) #define NOT_NULL_FLAG 1U /* Field can't be NULL */ #define PRI_KEY_FLAG 2U /* Field is part of a primary key */ #define UNIQUE_KEY_FLAG 4U /* Field is part of a unique key */ #define MULTIPLE_KEY_FLAG 8U /* Field is part of a key */ #define BLOB_FLAG 16U /* Field is a blob */ #define UNSIGNED_FLAG 32U /* Field is unsigned */ #define ZEROFILL_FLAG 64U /* Field is zerofill */ #define BINARY_FLAG 128U /* Field is binary */ /* The following are only sent to new clients */ #define ENUM_FLAG 256U /* field is an enum */ #define AUTO_INCREMENT_FLAG 512U /* field is a autoincrement field */ #define TIMESTAMP_FLAG 1024U /* Field is a timestamp */ #define SET_FLAG 2048U /* field is a set */ #define NO_DEFAULT_VALUE_FLAG 4096U /* Field doesn't have default value */ #define ON_UPDATE_NOW_FLAG 8192U /* Field is set to NOW on UPDATE */ #define NUM_FLAG 32768U /* Field is num (for clients) */ #define PART_KEY_FLAG 16384U /* Intern; Part of some key */ #define GROUP_FLAG 32768U /* Intern: Group field */ #define BINCMP_FLAG 131072U /* Intern: Used by sql_yacc */ #define GET_FIXED_FIELDS_FLAG (1U << 18) /* Used to get fields in item tree */ #define FIELD_IN_PART_FUNC_FLAG (1U << 19)/* Field part of partition func */ #define PART_INDIRECT_KEY_FLAG (1U << 20) /** Intern: Field in TABLE object for new version of altered table, which participates in a newly added index. */ #define FIELD_IN_ADD_INDEX (1U << 20) #define FIELD_IS_RENAMED (1U << 21) /* Intern: Field is being renamed */ #define FIELD_FLAGS_STORAGE_MEDIA 22 /* Field storage media, bit 22-23 */ #define FIELD_FLAGS_STORAGE_MEDIA_MASK (3U << FIELD_FLAGS_STORAGE_MEDIA) #define FIELD_FLAGS_COLUMN_FORMAT 24 /* Field column format, bit 24-25 */ #define FIELD_FLAGS_COLUMN_FORMAT_MASK (3U << FIELD_FLAGS_COLUMN_FORMAT) #define FIELD_IS_DROPPED (1U << 26) /* Intern: Field is being dropped */ #define VERS_ROW_START (1 << 27) /* autogenerated column declared with `generated always as row start` (see II.a SQL Standard) */ #define VERS_ROW_END (1 << 28) /* autogenerated column declared with `generated always as row end` (see II.a SQL Standard).*/ #define VERS_SYSTEM_FIELD (VERS_ROW_START | VERS_ROW_END) #define VERS_UPDATE_UNVERSIONED_FLAG (1 << 29) /* column that doesn't support system versioning when table itself supports it*/ #define LONG_UNIQUE_HASH_FIELD (1<< 30) /* This field will store hash for unique column */ #define FIELD_PART_OF_TMP_UNIQUE (1<< 31) /* part of an unique constrain for a tmporary table*/ #define REFRESH_GRANT (1ULL << 0) /* Refresh grant tables */ #define REFRESH_LOG (1ULL << 1) /* Start on new log file */ #define REFRESH_TABLES (1ULL << 2) /* close all tables */ #define REFRESH_HOSTS (1ULL << 3) /* Flush host cache */ #define REFRESH_STATUS (1ULL << 4) /* Flush status variables */ #define REFRESH_THREADS (1ULL << 5) /* Flush thread cache */ #define REFRESH_SLAVE (1ULL << 6) /* Reset master info and restart slave thread */ #define REFRESH_MASTER (1ULL << 7) /* Remove all bin logs in the index and truncate the index */ /* The following can't be set with mysql_refresh() */ #define REFRESH_ERROR_LOG (1ULL << 8) /* Rotate only the error log */ #define REFRESH_ENGINE_LOG (1ULL << 9) /* Flush all storage engine logs */ #define REFRESH_BINARY_LOG (1ULL << 10) /* Flush the binary log */ #define REFRESH_RELAY_LOG (1ULL << 11) /* Flush the relay log */ #define REFRESH_GENERAL_LOG (1ULL << 12) /* Flush the general log */ #define REFRESH_SLOW_LOG (1ULL << 13) /* Flush the slow query log */ #define REFRESH_READ_LOCK (1ULL << 14) /* Lock tables for read */ #define REFRESH_CHECKPOINT (1ULL << 15) /* With REFRESH_READ_LOCK: block checkpoints too */ #define REFRESH_QUERY_CACHE (1ULL << 16) /* clear the query cache */ #define REFRESH_QUERY_CACHE_FREE (1ULL << 17) /* pack query cache */ #define REFRESH_DES_KEY_FILE (1ULL << 18) #define REFRESH_USER_RESOURCES (1ULL << 19) #define REFRESH_FOR_EXPORT (1ULL << 20) /* FLUSH TABLES ... FOR EXPORT */ #define REFRESH_SSL (1ULL << 21) #define REFRESH_GENERIC (1ULL << 30) #define REFRESH_FAST (1ULL << 31) /* Intern flag */ #define CLIENT_LONG_PASSWORD 0 /* obsolete flag */ #define CLIENT_MYSQL 1ULL /* mysql/old mariadb server/client */ #define CLIENT_FOUND_ROWS 2ULL /* Found instead of affected rows */ #define CLIENT_LONG_FLAG 4ULL /* Get all column flags */ #define CLIENT_CONNECT_WITH_DB 8ULL /* One can specify db on connect */ #define CLIENT_NO_SCHEMA 16ULL /* Don't allow database.table.column */ #define CLIENT_COMPRESS 32ULL /* Can use compression protocol */ #define CLIENT_ODBC 64ULL /* Odbc client */ #define CLIENT_LOCAL_FILES 128ULL /* Can use LOAD DATA LOCAL */ #define CLIENT_IGNORE_SPACE 256ULL /* Ignore spaces before '(' */ #define CLIENT_PROTOCOL_41 512ULL /* New 4.1 protocol */ #define CLIENT_INTERACTIVE 1024ULL /* This is an interactive client */ #define CLIENT_SSL 2048ULL /* Switch to SSL after handshake */ #define CLIENT_IGNORE_SIGPIPE 4096ULL /* IGNORE sigpipes */ #define CLIENT_TRANSACTIONS 8192ULL /* Client knows about transactions */ #define CLIENT_RESERVED 16384ULL /* Old flag for 4.1 protocol */ #define CLIENT_SECURE_CONNECTION 32768ULL /* New 4.1 authentication */ #define CLIENT_MULTI_STATEMENTS (1ULL << 16) /* Enable/disable multi-stmt support */ #define CLIENT_MULTI_RESULTS (1ULL << 17) /* Enable/disable multi-results */ #define CLIENT_PS_MULTI_RESULTS (1ULL << 18) /* Multi-results in PS-protocol */ #define CLIENT_PLUGIN_AUTH (1ULL << 19) /* Client supports plugin authentication */ #define CLIENT_CONNECT_ATTRS (1ULL << 20) /* Client supports connection attributes */ /* Enable authentication response packet to be larger than 255 bytes. */ #define CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA (1ULL << 21) /* Don't close the connection for a connection with expired password. */ #define CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS (1ULL << 22) /** Capable of handling server state change information. Its a hint to the server to include the state change information in Ok packet. */ #define CLIENT_SESSION_TRACK (1ULL << 23) /* Client no longer needs EOF packet */ #define CLIENT_DEPRECATE_EOF (1ULL << 24) #define CLIENT_PROGRESS_OBSOLETE (1ULL << 29) #define CLIENT_SSL_VERIFY_SERVER_CERT_OBSOLETE (1ULL << 30) /* It used to be that if mysql_real_connect() failed, it would delete any options set by the client, unless the CLIENT_REMEMBER_OPTIONS flag was given. That behaviour does not appear very useful, and it seems unlikely that any applications would actually depend on this. So from MariaDB 5.5 we always preserve any options set in case of failed connect, and this option is effectively always set. */ #define CLIENT_REMEMBER_OPTIONS (1ULL << 31) /* MariaDB extended capability flags */ #define MARIADB_CLIENT_FLAGS_MASK 0xffffffff00000000ULL /* Client support progress indicator */ #define MARIADB_CLIENT_PROGRESS (1ULL << 32) /* Old COM_MULTI experiment (functionality removed).*/ #define MARIADB_CLIENT_RESERVED_1 (1ULL << 33) /* support of array binding */ #define MARIADB_CLIENT_STMT_BULK_OPERATIONS (1ULL << 34) /* support of extended metadata (e.g. type/format information) */ #define MARIADB_CLIENT_EXTENDED_METADATA (1ULL << 35) /* Do not resend metadata for prepared statements, since 10.6*/ #define MARIADB_CLIENT_CACHE_METADATA (1ULL << 36) #ifdef HAVE_COMPRESS #define CAN_CLIENT_COMPRESS CLIENT_COMPRESS #else #define CAN_CLIENT_COMPRESS 0 #endif /* Gather all possible capabilities (flags) supported by the server MARIADB_* flags supported only by MariaDB connector(s). */ #define CLIENT_ALL_FLAGS (\ CLIENT_FOUND_ROWS | \ CLIENT_LONG_FLAG | \ CLIENT_CONNECT_WITH_DB | \ CLIENT_NO_SCHEMA | \ CLIENT_COMPRESS | \ CLIENT_ODBC | \ CLIENT_LOCAL_FILES | \ CLIENT_IGNORE_SPACE | \ CLIENT_PROTOCOL_41 | \ CLIENT_INTERACTIVE | \ CLIENT_SSL | \ CLIENT_IGNORE_SIGPIPE | \ CLIENT_TRANSACTIONS | \ CLIENT_RESERVED | \ CLIENT_SECURE_CONNECTION | \ CLIENT_MULTI_STATEMENTS | \ CLIENT_MULTI_RESULTS | \ CLIENT_PS_MULTI_RESULTS | \ CLIENT_REMEMBER_OPTIONS | \ MARIADB_CLIENT_PROGRESS | \ CLIENT_PLUGIN_AUTH | \ CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | \ CLIENT_SESSION_TRACK |\ CLIENT_DEPRECATE_EOF |\ CLIENT_CONNECT_ATTRS |\ MARIADB_CLIENT_STMT_BULK_OPERATIONS |\ MARIADB_CLIENT_EXTENDED_METADATA|\ MARIADB_CLIENT_CACHE_METADATA |\ CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS) /* Switch off the flags that are optional and depending on build flags If any of the optional flags is supported by the build it will be switched on before sending to the client during the connection handshake. */ #define CLIENT_BASIC_FLAGS ((CLIENT_ALL_FLAGS & ~CLIENT_SSL) \ & ~CLIENT_COMPRESS) enum mariadb_field_attr_t { MARIADB_FIELD_ATTR_DATA_TYPE_NAME= 0, MARIADB_FIELD_ATTR_FORMAT_NAME= 1 }; #define MARIADB_FIELD_ATTR_LAST MARIADB_FIELD_ATTR_FORMAT_NAME /** Is raised when a multi-statement transaction has been started, either explicitly, by means of BEGIN or COMMIT AND CHAIN, or implicitly, by the first transactional statement, when autocommit=off. */ #define SERVER_STATUS_IN_TRANS 1U #define SERVER_STATUS_AUTOCOMMIT 2U /* Server in auto_commit mode */ #define SERVER_MORE_RESULTS_EXISTS 8U /* Multi query - next query exists */ #define SERVER_QUERY_NO_GOOD_INDEX_USED 16U #define SERVER_QUERY_NO_INDEX_USED 32U /** The server was able to fulfill the clients request and opened a read-only non-scrollable cursor for a query. This flag comes in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands. */ #define SERVER_STATUS_CURSOR_EXISTS 64U /** This flag is sent when a read-only cursor is exhausted, in reply to COM_STMT_FETCH command. */ #define SERVER_STATUS_LAST_ROW_SENT 128U #define SERVER_STATUS_DB_DROPPED 256U /* A database was dropped */ #define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512U /** Sent to the client if after a prepared statement reprepare we discovered that the new statement returns a different number of result set columns. */ #define SERVER_STATUS_METADATA_CHANGED 1024U #define SERVER_QUERY_WAS_SLOW 2048U /** To mark ResultSet containing output parameter values. */ #define SERVER_PS_OUT_PARAMS 4096U /** Set at the same time as SERVER_STATUS_IN_TRANS if the started multi-statement transaction is a read-only transaction. Cleared when the transaction commits or aborts. Since this flag is sent to clients in OK and EOF packets, the flag indicates the transaction status at the end of command execution. */ #define SERVER_STATUS_IN_TRANS_READONLY 8192U /** This status flag, when on, implies that one of the state information has changed on the server because of the execution of the last statement. */ #define SERVER_SESSION_STATE_CHANGED 16384U #define SERVER_STATUS_ANSI_QUOTES 32768U /** Server status flags that must be cleared when starting execution of a new SQL statement. Flags from this set are only added to the current server status by the execution engine, but never removed -- the execution engine expects them to disappear automagically by the next command. */ #define SERVER_STATUS_CLEAR_SET (SERVER_QUERY_NO_GOOD_INDEX_USED| \ SERVER_QUERY_NO_INDEX_USED|\ SERVER_MORE_RESULTS_EXISTS|\ SERVER_STATUS_METADATA_CHANGED |\ SERVER_QUERY_WAS_SLOW |\ SERVER_STATUS_DB_DROPPED |\ SERVER_STATUS_CURSOR_EXISTS|\ SERVER_STATUS_LAST_ROW_SENT|\ SERVER_SESSION_STATE_CHANGED) #define MYSQL_ERRMSG_SIZE 512 #define NET_READ_TIMEOUT 30 /* Timeout on read */ #define NET_WRITE_TIMEOUT 60 /* Timeout on write */ #define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */ struct st_vio; /* Only C */ typedef struct st_vio Vio; #define MAX_TINYINT_WIDTH 3 /* Max width for a TINY w.o. sign */ #define MAX_SMALLINT_WIDTH 5 /* Max width for a SHORT w.o. sign */ #define MAX_MEDIUMINT_WIDTH 8 /* Max width for a INT24 w.o. sign */ #define MAX_INT_WIDTH 10 /* Max width for a LONG w.o. sign */ #define MAX_BIGINT_WIDTH 20 /* Max width for a LONGLONG */ #define MAX_CHAR_WIDTH 255 /* Max length for a CHAR column */ #define MAX_BLOB_WIDTH 16777216 /* Default width for blob */ typedef struct st_net { #if !defined(CHECK_EMBEDDED_DIFFERENCES) || !defined(EMBEDDED_LIBRARY) Vio *vio; unsigned char *buff,*buff_end,*write_pos,*read_pos; my_socket fd; /* For Perl DBI/dbd */ /* The following variable is set if we are doing several queries in one command ( as in LOAD TABLE ... FROM MASTER ), and do not want to confuse the client with OK at the wrong time */ unsigned long remain_in_buf,length, buf_length, where_b; unsigned long max_packet,max_packet_size; unsigned int pkt_nr,compress_pkt_nr; unsigned int write_timeout, read_timeout, retry_count; int fcntl; unsigned int *return_status; unsigned char reading_or_writing; char save_char; char net_skip_rest_factor; my_bool thread_specific_malloc; unsigned char compress; my_bool pkt_nr_can_be_reset; my_bool using_proxy_protocol; /* Pointer to query object in query cache, do not equal NULL (0) for queries in cache that have not stored its results yet */ #endif void *thd; /* Used by MariaDB server to avoid calling current_thd */ unsigned int last_errno; unsigned char error; my_bool unused4; /* Please remove with the next incompatible ABI change. */ my_bool unused5; /* Please remove with the next incompatible ABI change. */ /** Client library error message buffer. Actually belongs to struct MYSQL. */ char last_error[MYSQL_ERRMSG_SIZE]; /** Client library sqlstate buffer. Set along with the error message. */ char sqlstate[SQLSTATE_LENGTH+1]; void *extension; } NET; #define packet_error ~0UL enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE, MYSQL_TYPE_NULL, MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24, MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR, MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR, MYSQL_TYPE_BIT, /* mysql-5.6 compatibility temporal types. They're only used internally for reading RBR mysql-5.6 binary log events and mysql-5.6 frm files. They're never sent to the client. */ MYSQL_TYPE_TIMESTAMP2, MYSQL_TYPE_DATETIME2, MYSQL_TYPE_TIME2, /* Compressed types are only used internally for RBR. */ MYSQL_TYPE_BLOB_COMPRESSED= 140, MYSQL_TYPE_VARCHAR_COMPRESSED= 141, MYSQL_TYPE_NEWDECIMAL=246, MYSQL_TYPE_ENUM=247, MYSQL_TYPE_SET=248, MYSQL_TYPE_TINY_BLOB=249, MYSQL_TYPE_MEDIUM_BLOB=250, MYSQL_TYPE_LONG_BLOB=251, MYSQL_TYPE_BLOB=252, MYSQL_TYPE_VAR_STRING=253, MYSQL_TYPE_STRING=254, MYSQL_TYPE_GEOMETRY=255 }; /* For backward compatibility */ #define CLIENT_MULTI_QUERIES CLIENT_MULTI_STATEMENTS #define FIELD_TYPE_DECIMAL MYSQL_TYPE_DECIMAL #define FIELD_TYPE_NEWDECIMAL MYSQL_TYPE_NEWDECIMAL #define FIELD_TYPE_TINY MYSQL_TYPE_TINY #define FIELD_TYPE_SHORT MYSQL_TYPE_SHORT #define FIELD_TYPE_LONG MYSQL_TYPE_LONG #define FIELD_TYPE_FLOAT MYSQL_TYPE_FLOAT #define FIELD_TYPE_DOUBLE MYSQL_TYPE_DOUBLE #define FIELD_TYPE_NULL MYSQL_TYPE_NULL #define FIELD_TYPE_TIMESTAMP MYSQL_TYPE_TIMESTAMP #define FIELD_TYPE_LONGLONG MYSQL_TYPE_LONGLONG #define FIELD_TYPE_INT24 MYSQL_TYPE_INT24 #define FIELD_TYPE_DATE MYSQL_TYPE_DATE #define FIELD_TYPE_TIME MYSQL_TYPE_TIME #define FIELD_TYPE_DATETIME MYSQL_TYPE_DATETIME #define FIELD_TYPE_YEAR MYSQL_TYPE_YEAR #define FIELD_TYPE_NEWDATE MYSQL_TYPE_NEWDATE #define FIELD_TYPE_ENUM MYSQL_TYPE_ENUM #define FIELD_TYPE_SET MYSQL_TYPE_SET #define FIELD_TYPE_TINY_BLOB MYSQL_TYPE_TINY_BLOB #define FIELD_TYPE_MEDIUM_BLOB MYSQL_TYPE_MEDIUM_BLOB #define FIELD_TYPE_LONG_BLOB MYSQL_TYPE_LONG_BLOB #define FIELD_TYPE_BLOB MYSQL_TYPE_BLOB #define FIELD_TYPE_VAR_STRING MYSQL_TYPE_VAR_STRING #define FIELD_TYPE_STRING MYSQL_TYPE_STRING #define FIELD_TYPE_CHAR MYSQL_TYPE_TINY #define FIELD_TYPE_INTERVAL MYSQL_TYPE_ENUM #define FIELD_TYPE_GEOMETRY MYSQL_TYPE_GEOMETRY #define FIELD_TYPE_BIT MYSQL_TYPE_BIT /* Shutdown/kill enums and constants */ /* Bits for THD::killable. */ #define MYSQL_SHUTDOWN_KILLABLE_CONNECT (unsigned char)(1 << 0) #define MYSQL_SHUTDOWN_KILLABLE_TRANS (unsigned char)(1 << 1) #define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) #define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3) enum mysql_enum_shutdown_level { /* We want levels to be in growing order of hardness (because we use number comparisons). Note that DEFAULT does not respect the growing property, but it's ok. */ SHUTDOWN_DEFAULT = 0, /* wait for existing connections to finish */ SHUTDOWN_WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, /* wait for existing trans to finish */ SHUTDOWN_WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, /* wait for existing updates to finish (=> no partial MyISAM update) */ SHUTDOWN_WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, /* flush InnoDB buffers and other storage engines' buffers*/ SHUTDOWN_WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), /* don't flush InnoDB buffers, flush other storage engines' buffers*/ SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1 }; enum enum_cursor_type { CURSOR_TYPE_NO_CURSOR= 0, CURSOR_TYPE_READ_ONLY= 1, CURSOR_TYPE_FOR_UPDATE= 2, CURSOR_TYPE_SCROLLABLE= 4 }; /* options for mysql_set_option */ enum enum_mysql_set_option { MYSQL_OPTION_MULTI_STATEMENTS_ON, MYSQL_OPTION_MULTI_STATEMENTS_OFF }; /* Type of state change information that the server can include in the Ok packet. */ enum enum_session_state_type { SESSION_TRACK_SYSTEM_VARIABLES, /* Session system variables */ SESSION_TRACK_SCHEMA, /* Current schema */ SESSION_TRACK_STATE_CHANGE, /* track session state changes */ SESSION_TRACK_GTIDS, SESSION_TRACK_TRANSACTION_CHARACTERISTICS, /* Transaction chistics */ SESSION_TRACK_TRANSACTION_STATE, /* Transaction state */ #ifdef USER_VAR_TRACKING SESSION_TRACK_MYSQL_RESERVED1, SESSION_TRACK_MYSQL_RESERVED2, SESSION_TRACK_MYSQL_RESERVED3, SESSION_TRACK_MYSQL_RESERVED4, SESSION_TRACK_MYSQL_RESERVED5, SESSION_TRACK_MYSQL_RESERVED6, SESSION_TRACK_USER_VARIABLES, #endif // USER_VAR_TRACKING SESSION_TRACK_always_at_the_end /* must be last */ }; #define SESSION_TRACK_BEGIN SESSION_TRACK_SYSTEM_VARIABLES #define IS_SESSION_STATE_TYPE(T) \ (((int)(T) >= SESSION_TRACK_BEGIN) && ((T) < SESSION_TRACK_always_at_the_end)) #define net_new_transaction(net) ((net)->pkt_nr=0) #ifdef __cplusplus extern "C" { #endif my_bool my_net_init(NET *net, Vio* vio, void *thd, unsigned int my_flags); void my_net_local_init(NET *net); void net_end(NET *net); void net_clear(NET *net, my_bool clear_buffer); my_bool net_realloc(NET *net, size_t length); my_bool net_flush(NET *net); my_bool my_net_write(NET *net,const unsigned char *packet, size_t len); my_bool net_write_command(NET *net,unsigned char command, const unsigned char *header, size_t head_len, const unsigned char *packet, size_t len); int net_real_write(NET *net,const unsigned char *packet, size_t len); unsigned long my_net_read_packet(NET *net, my_bool read_from_server); unsigned long my_net_read_packet_reallen(NET *net, my_bool read_from_server, unsigned long* reallen); #define my_net_read(A) my_net_read_packet((A), 0) #ifdef MY_GLOBAL_INCLUDED void my_net_set_write_timeout(NET *net, uint timeout); void my_net_set_read_timeout(NET *net, uint timeout); #endif struct sockaddr; int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen, unsigned int timeout); struct my_rnd_struct; #ifdef __cplusplus } #endif /* The following is for user defined functions */ enum Item_result { STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT, DECIMAL_RESULT, TIME_RESULT }; typedef struct st_udf_args { unsigned int arg_count; /* Number of arguments */ enum Item_result *arg_type; /* Pointer to item_results */ char **args; /* Pointer to argument */ unsigned long *lengths; /* Length of string arguments */ char *maybe_null; /* Set to 1 for all maybe_null args */ const char **attributes; /* Pointer to attribute name */ unsigned long *attribute_lengths; /* Length of attribute arguments */ void *extension; } UDF_ARGS; /* This holds information about the result */ typedef struct st_udf_init { my_bool maybe_null; /* 1 if function can return NULL */ unsigned int decimals; /* for real functions */ unsigned long max_length; /* For string functions */ char *ptr; /* free pointer for function data */ my_bool const_item; /* 1 if function always returns the same value */ void *extension; } UDF_INIT; /* TODO: add a notion for determinism of the UDF. See Item_udf_func::update_used_tables () */ /* Constants when using compression */ #define NET_HEADER_SIZE 4 /* standard header size */ #define COMP_HEADER_SIZE 3 /* compression header extra size */ /* Prototypes to password functions */ #ifdef __cplusplus extern "C" { #endif /* These functions are used for authentication by client and server and implemented in sql/password.c */ void create_random_string(char *to, unsigned int length, struct my_rnd_struct *rand_st); void hash_password(unsigned long *to, const char *password, unsigned int password_len); void make_scrambled_password_323(char *to, const char *password); void scramble_323(char *to, const char *message, const char *password); my_bool check_scramble_323(const unsigned char *reply, const char *message, unsigned long *salt); void get_salt_from_password_323(unsigned long *res, const char *password); void make_scrambled_password(char *to, const char *password); void scramble(char *to, const char *message, const char *password); my_bool check_scramble(const unsigned char *reply, const char *message, const unsigned char *hash_stage2); void get_salt_from_password(unsigned char *res, const char *password); char *octet2hex(char *to, const char *str, size_t len); /* end of password.c */ char *get_tty_password(const char *opt_message); void get_tty_password_buff(const char *opt_message, char *to, size_t length); const char *mysql_errno_to_sqlstate(unsigned int mysql_errno); /* Some other useful functions */ my_bool my_thread_init(void); void my_thread_end(void); #ifdef MY_GLOBAL_INCLUDED #include "pack.h" #endif #ifdef __cplusplus } #endif #define NULL_LENGTH ~0UL /* For net_store_length */ #define MYSQL_STMT_HEADER 4U #define MYSQL_LONG_DATA_HEADER 6U /* If a float or double field have more than this number of decimals, it's regarded as floating point field without any specific number of decimals */ #endif server/ma_dyncol.h000064400000017555151031265050010203 0ustar00/* Copyright (c) 2011, Monty Program Ab Copyright (c) 2011, Oleksandr Byelkin Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ma_dyncol_h #define ma_dyncol_h #ifdef __cplusplus extern "C" { #endif #include #include #include #ifndef _my_sys_h typedef struct st_dynamic_string { char *str; size_t length,max_length,alloc_increment; } DYNAMIC_STRING; #endif #ifndef MY_GLOBAL_INCLUDED struct st_mysql_lex_string { char *str; size_t length; }; typedef struct st_mysql_lex_string MYSQL_LEX_STRING; typedef struct st_mysql_lex_string LEX_STRING; #endif /* Limits of implementation */ #define MAX_TOTAL_NAME_LENGTH 65535 #define MAX_NAME_LENGTH (MAX_TOTAL_NAME_LENGTH/4) /* NO and OK is the same used just to show semantics */ #define ER_DYNCOL_NO ER_DYNCOL_OK #ifdef HAVE_CHARSET_utf8mb4 #define DYNCOL_UTF (&my_charset_utf8mb4_general_ci) #else #define DYNCOL_UTF (&my_charset_utf8mb3_general_ci) #endif /* escape json strings */ #define DYNCOL_JSON_ESC ((char)1) enum enum_dyncol_func_result { ER_DYNCOL_OK= 0, ER_DYNCOL_YES= 1, /* For functions returning 0/1 */ ER_DYNCOL_FORMAT= -1, /* Wrong format of the encoded string */ ER_DYNCOL_LIMIT= -2, /* Some limit reached */ ER_DYNCOL_RESOURCE= -3, /* Out of resources */ ER_DYNCOL_DATA= -4, /* Incorrect input data */ ER_DYNCOL_UNKNOWN_CHARSET= -5, /* Unknown character set */ ER_DYNCOL_TRUNCATED= 2 /* OK, but data was truncated */ }; typedef DYNAMIC_STRING DYNAMIC_COLUMN; enum enum_dynamic_column_type { DYN_COL_NULL= 0, DYN_COL_INT, DYN_COL_UINT, DYN_COL_DOUBLE, DYN_COL_STRING, DYN_COL_DECIMAL, DYN_COL_DATETIME, DYN_COL_DATE, DYN_COL_TIME, DYN_COL_DYNCOL }; typedef enum enum_dynamic_column_type DYNAMIC_COLUMN_TYPE; struct st_dynamic_column_value { DYNAMIC_COLUMN_TYPE type; union { long long long_value; unsigned long long ulong_value; double double_value; struct { MYSQL_LEX_STRING value; CHARSET_INFO *charset; } string; struct { decimal_digit_t buffer[DECIMAL_BUFF_LENGTH]; decimal_t value; } decimal; MYSQL_TIME time_value; } x; }; typedef struct st_dynamic_column_value DYNAMIC_COLUMN_VALUE; #ifdef MADYNCOL_DEPRECATED enum enum_dyncol_func_result dynamic_column_create(DYNAMIC_COLUMN *str, uint column_nr, DYNAMIC_COLUMN_VALUE *value); enum enum_dyncol_func_result dynamic_column_create_many(DYNAMIC_COLUMN *str, uint column_count, uint *column_numbers, DYNAMIC_COLUMN_VALUE *values); enum enum_dyncol_func_result dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr, DYNAMIC_COLUMN_VALUE *value); enum enum_dyncol_func_result dynamic_column_update_many(DYNAMIC_COLUMN *str, uint add_column_count, uint *column_numbers, DYNAMIC_COLUMN_VALUE *values); enum enum_dyncol_func_result dynamic_column_exists(DYNAMIC_COLUMN *org, uint column_nr); enum enum_dyncol_func_result dynamic_column_list(DYNAMIC_COLUMN *org, DYNAMIC_ARRAY *array_of_uint); enum enum_dyncol_func_result dynamic_column_get(DYNAMIC_COLUMN *org, uint column_nr, DYNAMIC_COLUMN_VALUE *store_it_here); #endif /* new functions */ enum enum_dyncol_func_result mariadb_dyncol_create_many_num(DYNAMIC_COLUMN *str, uint column_count, uint *column_numbers, DYNAMIC_COLUMN_VALUE *values, my_bool new_string); enum enum_dyncol_func_result mariadb_dyncol_create_many_named(DYNAMIC_COLUMN *str, uint column_count, MYSQL_LEX_STRING *column_keys, DYNAMIC_COLUMN_VALUE *values, my_bool new_string); enum enum_dyncol_func_result mariadb_dyncol_update_many_num(DYNAMIC_COLUMN *str, uint add_column_count, uint *column_keys, DYNAMIC_COLUMN_VALUE *values); enum enum_dyncol_func_result mariadb_dyncol_update_many_named(DYNAMIC_COLUMN *str, uint add_column_count, MYSQL_LEX_STRING *column_keys, DYNAMIC_COLUMN_VALUE *values); enum enum_dyncol_func_result mariadb_dyncol_exists_num(DYNAMIC_COLUMN *org, uint column_nr); enum enum_dyncol_func_result mariadb_dyncol_exists_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *name); /* List of not NULL columns */ enum enum_dyncol_func_result mariadb_dyncol_list_num(DYNAMIC_COLUMN *str, uint *count, uint **nums); enum enum_dyncol_func_result mariadb_dyncol_list_named(DYNAMIC_COLUMN *str, uint *count, MYSQL_LEX_STRING **names); /* if the column do not exists it is NULL */ enum enum_dyncol_func_result mariadb_dyncol_get_num(DYNAMIC_COLUMN *org, uint column_nr, DYNAMIC_COLUMN_VALUE *store_it_here); enum enum_dyncol_func_result mariadb_dyncol_get_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *name, DYNAMIC_COLUMN_VALUE *store_it_here); my_bool mariadb_dyncol_has_names(DYNAMIC_COLUMN *str); enum enum_dyncol_func_result mariadb_dyncol_check(DYNAMIC_COLUMN *str); enum enum_dyncol_func_result mariadb_dyncol_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json); #define mariadb_dyncol_init(A) memset((A), 0, sizeof(*(A))) void mariadb_dyncol_free(DYNAMIC_COLUMN *str); /* conversion of values to 3 base types */ enum enum_dyncol_func_result mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val, CHARSET_INFO *cs, my_bool quote); enum enum_dyncol_func_result mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val); enum enum_dyncol_func_result mariadb_dyncol_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val); enum enum_dyncol_func_result mariadb_dyncol_unpack(DYNAMIC_COLUMN *str, uint *count, MYSQL_LEX_STRING **names, DYNAMIC_COLUMN_VALUE **vals); void mariadb_dyncol_unpack_free(MYSQL_LEX_STRING *names, DYNAMIC_COLUMN_VALUE *vals); int mariadb_dyncol_column_cmp_named(const MYSQL_LEX_STRING *s1, const MYSQL_LEX_STRING *s2); enum enum_dyncol_func_result mariadb_dyncol_column_count(DYNAMIC_COLUMN *str, uint *column_count); #define mariadb_dyncol_value_init(V) (V)->type= DYN_COL_NULL /* Prepare value for using as decimal */ void mariadb_dyncol_prepare_decimal(DYNAMIC_COLUMN_VALUE *value); #ifdef __cplusplus } #endif #endif server/handler_state.h000064400000001366151031265050011044 0ustar00/* Map handler error message to sql states. Note that this list MUST be in increasing order! See sql_state.c for usage */ { HA_ERR_KEY_NOT_FOUND, "02000", "" }, { HA_ERR_FOUND_DUPP_KEY, "23000", "" }, { HA_ERR_WRONG_COMMAND, "0A000", "" }, { HA_ERR_UNSUPPORTED, "0A000", "" }, { HA_WRONG_CREATE_OPTION, "0A000", "" }, { HA_ERR_FOUND_DUPP_UNIQUE, "23000", "" }, { HA_ERR_UNKNOWN_CHARSET, "0A000", "" }, { HA_ERR_READ_ONLY_TRANSACTION, "25000", "" }, { HA_ERR_LOCK_DEADLOCK, "40001", "" }, { HA_ERR_NO_REFERENCED_ROW, "23000", "" }, { HA_ERR_ROW_IS_REFERENCED, "23000", "" }, { HA_ERR_TABLE_EXIST, "42S01", "" }, { HA_ERR_FOREIGN_DUPLICATE_KEY, "23000", "" }, { HA_ERR_TABLE_READONLY, "25000", "" }, { HA_ERR_AUTOINC_ERANGE, "22003", "" }, server/my_global.h000064400000100031151031265050010161 0ustar00/* Copyright (c) 2001, 2013, Oracle and/or its affiliates. Copyright (c) 2009, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* This is the include file that should be included 'first' in every C file. */ #ifndef MY_GLOBAL_INCLUDED #define MY_GLOBAL_INCLUDED /* MDEV-25602 Deprecate __WIN__ symbol. */ #if defined (_MSC_VER) && !defined(__clang__) #pragma deprecated("__WIN__") #elif defined (__GNUC__) #pragma GCC poison __WIN__ #endif /* InnoDB depends on some MySQL internals which other plugins should not need. This is because of InnoDB's foreign key support, "safe" binlog truncation, and other similar legacy features. We define accessors for these internals unconditionally, but do not expose them in mysql/plugin.h. They are declared in ha_innodb.h for InnoDB's use. */ #define INNODB_COMPATIBILITY_HOOKS #ifdef __CYGWIN__ /* We use a Unix API, so pretend it's not Windows */ #undef WIN #undef WIN32 #undef _WIN #undef _WIN32 #undef _WIN64 #undef _WIN32 #undef __WIN32__ #define HAVE_ERRNO_AS_DEFINE #define _POSIX_MONOTONIC_CLOCK #define _POSIX_THREAD_CPUTIME #endif /* __CYGWIN__ */ #if defined(__OpenBSD__) && (OpenBSD >= 200411) #define HAVE_ERRNO_AS_DEFINE #endif #if defined(i386) && !defined(__i386__) #define __i386__ #endif /* Macros to make switching between C and C++ mode easier */ #ifdef __cplusplus #define C_MODE_START extern "C" { #define C_MODE_END } #else #define C_MODE_START #define C_MODE_END #endif #ifdef __cplusplus #define CPP_UNNAMED_NS_START namespace { #define CPP_UNNAMED_NS_END } #endif #include #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE #define HAVE_PSI_INTERFACE #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ /* Make it easier to add conditional code in _expressions_ */ #ifdef _WIN32 #define IF_WIN(A,B) A #else #define IF_WIN(A,B) B #endif #ifdef EMBEDDED_LIBRARY #define IF_EMBEDDED(A,B) A #else #define IF_EMBEDDED(A,B) B #endif #ifdef WITH_PARTITION_STORAGE_ENGINE #define IF_PARTITIONING(A,B) A #else #define IF_PARTITIONING(A,B) B #endif #if defined (_WIN32) /* off_t is 32 bit long. We do not use C runtime functions with off_t but native Win32 file IO APIs, that work with 64 bit offsets. */ #undef SIZEOF_OFF_T #define SIZEOF_OFF_T 8 /* Prevent inclusion of Windows GDI headers - they define symbol ERROR that conflicts with mysql headers. */ #ifndef NOGDI #define NOGDI #endif /* Include common headers.*/ #include #include /* SOCKET */ #include /* access(), chmod() */ #include /* getpid() */ #define sleep(a) Sleep((a)*1000) /* Define missing access() modes. */ #define F_OK 0 #define W_OK 2 #define R_OK 4 /* Test for read permission. */ /* Define missing file locking constants. */ #define F_RDLCK 1 #define F_WRLCK 2 #define F_UNLCK 3 #define F_TO_EOF 0x3FFFFFFF #endif /* _WIN32*/ /* The macros below are used to allow build of Universal/fat binaries of MySQL and MySQL applications under darwin. */ #if defined(__APPLE__) && defined(__MACH__) # undef SIZEOF_CHARP # undef SIZEOF_INT # undef SIZEOF_LONG # undef SIZEOF_LONG_LONG # undef SIZEOF_OFF_T # undef WORDS_BIGENDIAN # define SIZEOF_INT 4 # define SIZEOF_LONG_LONG 8 # define SIZEOF_OFF_T 8 # if defined(__i386__) || defined(__ppc__) # define SIZEOF_CHARP 4 # define SIZEOF_LONG 4 # elif defined(__x86_64__) || defined(__ppc64__) || defined(__aarch64__) || defined(__arm64__) # define SIZEOF_CHARP 8 # define SIZEOF_LONG 8 # else # error Building FAT binary for an unknown architecture. # endif # if defined(__ppc__) || defined(__ppc64__) # define WORDS_BIGENDIAN # endif #endif /* defined(__APPLE__) && defined(__MACH__) */ /* The macros below are borrowed from include/linux/compiler.h in the Linux kernel. Use them to indicate the likelihood of the truthfulness of a condition. This serves two purposes - newer versions of gcc will be able to optimize for branch predication, which could yield siginficant performance gains in frequently executed sections of the code, and the other reason to use them is for documentation */ #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) #define __builtin_expect(x, expected_value) (x) #endif /* Fix problem with S_ISLNK() on Linux */ #if defined(TARGET_OS_LINUX) || defined(__GLIBC__) #undef _GNU_SOURCE #define _GNU_SOURCE 1 #endif /* Temporary solution to solve bug#7156. Include "sys/types.h" before the thread headers, else the function madvise() will not be defined */ #if defined(HAVE_SYS_TYPES_H) && ( defined(sun) || defined(__sun) ) #include #endif #define __EXTENSIONS__ 1 /* We want some extension */ #ifndef __STDC_EXT__ #define __STDC_EXT__ 1 /* To get large file support on hpux */ #endif /* Solaris 9 include file refers to X/Open document System Interfaces and Headers, Issue 5 saying we should define _XOPEN_SOURCE=500 to get POSIX.1c prototypes, but apparently other systems (namely FreeBSD) don't agree. On a newer Solaris 10, the above file recognizes also _XOPEN_SOURCE=600. Furthermore, it tests that if a program requires older standard (_XOPEN_SOURCE<600 or _POSIX_C_SOURCE<200112L) it cannot be run on a new compiler (that defines _STDC_C99) and issues an #error. It's also an #error if a program requires new standard (_XOPEN_SOURCE=600 or _POSIX_C_SOURCE=200112L) and a compiler does not define _STDC_C99. To add more to this mess, Sun Studio C compiler defines _STDC_C99 while C++ compiler does not! So, in a desperate attempt to get correct prototypes for both C and C++ code, we define either _XOPEN_SOURCE=600 or _XOPEN_SOURCE=500 depending on the compiler's announced C standard support. Cleaner solutions are welcome. */ #ifdef __sun #if __STDC_VERSION__ - 0 >= 199901L #define _XOPEN_SOURCE 600 #else #define _XOPEN_SOURCE 500 #endif #endif #ifdef _AIX /* AIX includes inttypes.h from sys/types.h Explicitly request format macros before the first inclusion of inttypes.h */ #if !defined(__STDC_FORMAT_MACROS) #define __STDC_FORMAT_MACROS #endif // !defined(__STDC_FORMAT_MACROS) #endif #if !defined(_WIN32) #ifndef _POSIX_PTHREAD_SEMANTICS #define _POSIX_PTHREAD_SEMANTICS /* We want posix threads */ #endif #if !defined(SCO) #define _REENTRANT 1 /* Some thread libraries require this */ #endif #if !defined(_THREAD_SAFE) && !defined(_AIX) #define _THREAD_SAFE /* Required for OSF1 */ #endif #if defined(HPUX10) || defined(HPUX11) C_MODE_START /* HPUX needs this, signal.h bug */ #include C_MODE_END #else #include /* AIX must have this included first */ #endif #if !defined(SCO) && !defined(_REENTRANT) #define _REENTRANT 1 /* Threads requires reentrant code */ #endif #endif /* !defined(_WIN32) */ /* gcc/egcs issues */ #if defined(__GNUC) && defined(__EXCEPTIONS) #error "Please add -fno-exceptions to CXXFLAGS and reconfigure/recompile" #endif #if defined(_lint) && !defined(lint) #define lint #endif #ifndef stdin #include #endif #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STDDEF_H #include #endif #include #ifdef HAVE_LIMITS_H #include #endif #ifdef HAVE_FLOAT_H #include #endif #ifdef HAVE_FENV_H #include /* For fesetround() */ #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif /* TIME_WITH_SYS_TIME */ #ifdef HAVE_UNISTD_H #include #endif #include /* Recommended by debian */ /* We need the following to go around a problem with openssl on solaris */ #if defined(HAVE_CRYPT_H) #include #endif /* Add checking if we are using likely/unlikely wrong */ #ifdef CHECK_UNLIKELY C_MODE_START extern void init_my_likely(), end_my_likely(FILE *); extern int my_likely_ok(const char *file_name, uint line); extern int my_likely_fail(const char *file_name, uint line); C_MODE_END #define likely(A) ((A) ? (my_likely_ok(__FILE__, __LINE__),1) : (my_likely_fail(__FILE__, __LINE__), 0)) #define unlikely(A) ((A) ? (my_likely_fail(__FILE__, __LINE__),1) : (my_likely_ok(__FILE__, __LINE__), 0)) /* These macros should be used when the check fails often when running benchmarks but we know for sure that the check is correct in a production environment */ #define checked_likely(A) (A) #define checked_unlikely(A) (A) #else /** The semantics of builtin_expect() are that 1) its two arguments are long 2) it's likely that they are == Those of our likely(x) are that x can be bool/int/longlong/pointer. */ #define likely(x) __builtin_expect(((x) != 0),1) #define unlikely(x) __builtin_expect(((x) != 0),0) #define checked_likely(x) likely(x) #define checked_unlikely(x) unlikely(x) #endif /* CHECK_UNLIKELY */ /* A lot of our programs uses asserts, so better to always include it This also fixes a problem when people uses DBUG_ASSERT without including assert.h */ #include /* an assert that works at compile-time. only for constant expression */ #ifdef _some_old_compiler_that_does_not_understand_the_construct_below_ #define compile_time_assert(X) do { } while(0) #else #define compile_time_assert(X) \ do \ { \ typedef char compile_time_assert[(X) ? 1 : -1] __attribute__((unused)); \ } while(0) #endif /* Go around some bugs in different OS and compilers */ #if defined (HPUX11) && defined(_LARGEFILE_SOURCE) #ifndef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE #endif #endif #if defined(_HPUX_SOURCE) && defined(HAVE_SYS_STREAM_H) #include /* HPUX 10.20 defines ulong here. UGLY !!! */ #define HAVE_ULONG #endif #if defined(HPUX10) && defined(_LARGEFILE64_SOURCE) /* Fix bug in setrlimit */ #undef setrlimit #define setrlimit cma_setrlimit64 #endif /* Declare madvise where it is not declared for C++, like Solaris */ #if HAVE_MADVISE && !HAVE_DECL_MADVISE && defined(__cplusplus) extern "C" int madvise(void *addr, size_t len, int behav); #endif #ifdef HAVE_SYS_MMAN_H #include #endif /** FreeBSD equivalent */ #if defined(MADV_CORE) && !defined(MADV_DODUMP) #define MADV_DODUMP MADV_CORE #define MADV_DONTDUMP MADV_NOCORE #define DODUMP_STR "MADV_CORE" #define DONTDUMP_STR "MADV_NOCORE" #else #define DODUMP_STR "MADV_DODUMP" #define DONTDUMP_STR "MADV_DONTDUMP" #endif #define QUOTE_ARG(x) #x /* Quote argument (before cpp) */ #define STRINGIFY_ARG(x) QUOTE_ARG(x) /* Quote argument, after cpp */ /* Paranoid settings. Define I_AM_PARANOID if you are paranoid */ #ifdef I_AM_PARANOID #define DONT_ALLOW_USER_CHANGE 1 #define DONT_USE_MYSQL_PWD 1 #endif /* Does the system remember a signal handler after a signal ? */ #if !defined(HAVE_BSD_SIGNALS) && !defined(HAVE_SIGACTION) #define SIGNAL_HANDLER_RESET_ON_DELIVERY #endif /* don't assume that STDERR_FILENO is 2, mysqld can freopen */ #undef STDERR_FILENO #ifndef SO_EXT #ifdef _WIN32 #define SO_EXT ".dll" #else #define SO_EXT ".so" #endif #endif /* Suppress uninitialized variable warning without generating code. */ #if defined(__GNUC__) /* GCC specific self-initialization which inhibits the warning. */ #define UNINIT_VAR(x) x= x #elif defined(_lint) || defined(FORCE_INIT_OF_VARS) #define UNINIT_VAR(x) x= 0 #else #define UNINIT_VAR(x) x #endif /* This is only to be used when resetting variables in a class constructor */ #if defined(_lint) || defined(FORCE_INIT_OF_VARS) #define LINT_INIT(x) x= 0 #else #define LINT_INIT(x) #endif #if !defined(HAVE_UINT) #undef HAVE_UINT #define HAVE_UINT typedef unsigned int uint; typedef unsigned short ushort; #endif #define swap_variables(t, a, b) do { t dummy; dummy= a; a= b; b= dummy; } while(0) #define MY_TEST(a) ((a) ? 1 : 0) #define set_if_bigger(a,b) do { if ((a) < (b)) (a)=(b); } while(0) #define set_if_smaller(a,b) do { if ((a) > (b)) (a)=(b); } while(0) #define set_bits(type, bit_count) (sizeof(type)*8 <= (bit_count) ? ~(type) 0 : ((((type) 1) << (bit_count)) - (type) 1)) #define test_all_bits(a,b) (((a) & (b)) == (b)) #define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0]))) /* Define some general constants */ #ifndef TRUE #define TRUE (1) /* Logical true */ #define FALSE (0) /* Logical false */ #endif #include #include /* Wen using the embedded library, users might run into link problems, duplicate declaration of __cxa_pure_virtual, solved by declaring it a weak symbol. */ #if defined(USE_MYSYS_NEW) && ! defined(DONT_DECLARE_CXA_PURE_VIRTUAL) C_MODE_START int __cxa_pure_virtual () __attribute__ ((weak)); C_MODE_END #endif /* The DBUG_ON flag always takes precedence over default DBUG_OFF */ #if defined(DBUG_ON) && defined(DBUG_OFF) #undef DBUG_OFF #endif /* We might be forced to turn debug off, if not turned off already */ #if (defined(FORCE_DBUG_OFF) || defined(_lint)) && !defined(DBUG_OFF) # define DBUG_OFF # ifdef DBUG_ON # undef DBUG_ON # endif #endif #ifdef DBUG_OFF #undef EXTRA_DEBUG #endif /* Some types that is different between systems */ typedef int File; /* File descriptor */ #ifdef _WIN32 typedef SOCKET my_socket; #else typedef int my_socket; /* File descriptor for sockets */ #define INVALID_SOCKET -1 #endif /* Type for functions that handles signals */ #define sig_handler RETSIGTYPE #if defined(__GNUC__) && !defined(_lint) typedef char pchar; /* Mixed prototypes can take char */ typedef char puchar; /* Mixed prototypes can take char */ typedef char pbool; /* Mixed prototypes can take char */ typedef short pshort; /* Mixed prototypes can take short int */ typedef float pfloat; /* Mixed prototypes can take float */ #else typedef int pchar; /* Mixed prototypes can't take char */ typedef uint puchar; /* Mixed prototypes can't take char */ typedef int pbool; /* Mixed prototypes can't take char */ typedef int pshort; /* Mixed prototypes can't take short int */ typedef double pfloat; /* Mixed prototypes can't take float */ #endif #include #define qsort_t RETQSORTTYPE /* Broken GCC can't handle typedef !!!! */ #ifdef HAVE_SYS_SOCKET_H #include #endif typedef SOCKET_SIZE_TYPE size_socket; #ifndef SOCKOPT_OPTLEN_TYPE #define SOCKOPT_OPTLEN_TYPE size_socket #endif /* file create flags */ #ifndef O_SHARE /* Probably not windows */ #define O_SHARE 0 /* Flag to my_open for shared files */ #ifndef O_BINARY #define O_BINARY 0 /* Flag to my_open for binary files */ #endif #ifndef FILE_BINARY #define FILE_BINARY O_BINARY /* Flag to my_fopen for binary streams */ #endif #ifdef HAVE_FCNTL #define HAVE_FCNTL_LOCK #define F_TO_EOF 0L /* Param to lockf() to lock rest of file */ #endif #endif /* O_SHARE */ #ifndef O_SEQUENTIAL #define O_SEQUENTIAL 0 #endif #ifndef O_SHORT_LIVED #define O_SHORT_LIVED 0 #endif #ifndef O_NOFOLLOW #define O_NOFOLLOW 0 #endif #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif #ifdef __GLIBC__ #define STR_O_CLOEXEC "e" #else #define STR_O_CLOEXEC "" #endif #ifndef SOCK_CLOEXEC #define SOCK_CLOEXEC 0 #else #define HAVE_SOCK_CLOEXEC #endif /* additional file share flags for win32 */ #ifdef _WIN32 #define _SH_DENYRWD 0x110 /* deny read/write mode & delete */ #define _SH_DENYWRD 0x120 /* deny write mode & delete */ #define _SH_DENYRDD 0x130 /* deny read mode & delete */ #define _SH_DENYDEL 0x140 /* deny delete only */ #endif /* _WIN32 */ /* General constants */ #define FN_LEN 256 /* Max file name len */ #define FN_HEADLEN 253 /* Max length of filepart of file name */ #define FN_EXTLEN 20 /* Max length of extension (part of FN_LEN) */ #define FN_REFLEN 512 /* Max length of full path-name */ #define FN_EXTCHAR '.' #define FN_HOMELIB '~' /* ~/ is used as abbrev for home dir */ #define FN_CURLIB '.' /* ./ is used as abbrev for current dir */ #define FN_PARENTDIR ".." /* Parent directory; Must be a string */ #ifdef _WIN32 #define FN_LIBCHAR '\\' #define FN_LIBCHAR2 '/' #define FN_DIRSEP "/\\" /* Valid directory separators */ #define FN_EXEEXT ".exe" #define FN_SOEXT ".dll" #define FN_ROOTDIR "\\" #define FN_DEVCHAR ':' #define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */ #define FN_NO_CASE_SENCE /* Files are not case-sensitive */ #else #define FN_LIBCHAR '/' #define FN_LIBCHAR2 '/' #define FN_DIRSEP "/" /* Valid directory separators */ #define FN_EXEEXT "" #define FN_SOEXT ".so" #define FN_ROOTDIR "/" #endif /* MY_FILE_MIN is Windows speciality and is used to quickly detect the mismatch of CRT and mysys file IO usage on Windows at runtime. CRT file descriptors can be in the range 0-2047, whereas descriptors returned by my_open() will start with 2048. If a file descriptor with value less then MY_FILE_MIN is passed to mysys IO function, chances are it stems from open()/fileno() and not my_open()/my_fileno. For Posix, mysys functions are light wrappers around libc, and MY_FILE_MIN is logically 0. */ #ifdef _WIN32 #define MY_FILE_MIN 2048 #else #define MY_FILE_MIN 0 #endif /* MY_NFILE is the default size of my_file_info array. It is larger on Windows, because it all file handles are stored in my_file_info Default size is 16384 and this should be enough for most cases.If it is not enough, --max-open-files with larger value can be used. For Posix , my_file_info array is only used to store filenames for error reporting and its size is not a limitation for number of open files. */ #ifdef _WIN32 #define MY_NFILE (16384 + MY_FILE_MIN) #else #define MY_NFILE 64 #endif #ifndef OS_FILE_LIMIT #define OS_FILE_LIMIT UINT_MAX #endif /* Io buffer size; Must be a power of 2 and a multiple of 512. May be smaller what the disk page size. This influences the speed of the isam btree library. eg to big to slow. */ #define IO_SIZE 4096U /* How much overhead does malloc/my_malloc have. The code often allocates something like 1024-MALLOC_OVERHEAD bytes */ #define MALLOC_OVERHEAD (8+24) /* get memory in huncs */ #define ONCE_ALLOC_INIT (uint) 4096 /* Typical record cache */ #define RECORD_CACHE_SIZE (uint) (128*1024) /* Typical key cache */ #define KEY_CACHE_SIZE (uint) (128L*1024L*1024L) /* Default size of a key cache block */ #define KEY_CACHE_BLOCK_SIZE (uint) 1024 /* Some things that this system doesn't have */ #ifdef _WIN32 #define NO_DIR_LIBRARY /* Not standard dir-library */ #endif /* Some defines of functions for portability */ #undef remove /* Crashes MySQL on SCO 5.0.0 */ #ifndef _WIN32 #define closesocket(A) close(A) #endif #if defined(_MSC_VER) #if !defined(_WIN64) inline double my_ulonglong2double(unsigned long long value) { long long nr=(long long) value; if (nr >= 0) return (double) nr; return (18446744073709551616.0 + (double) nr); } #define ulonglong2double my_ulonglong2double #define my_off_t2double my_ulonglong2double #endif /* _WIN64 */ inline unsigned long long my_double2ulonglong(double d) { double t= d - (double) 0x8000000000000000ULL; if (t >= 0) return ((unsigned long long) t) + 0x8000000000000000ULL; return (unsigned long long) d; } #define double2ulonglong my_double2ulonglong #endif #ifndef ulonglong2double #define ulonglong2double(A) ((double) (ulonglong) (A)) #define my_off_t2double(A) ((double) (my_off_t) (A)) #endif #ifndef double2ulonglong #define double2ulonglong(A) ((ulonglong) (double) (A)) #endif #ifndef offsetof #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif #define ulong_to_double(X) ((double) (ulong) (X)) #ifndef STACK_DIRECTION #error "please add -DSTACK_DIRECTION=1 or -1 to your CPPFLAGS" #endif #if !defined(HAVE_STRTOK_R) #define strtok_r(A,B,C) strtok((A),(B)) #endif #if SIZEOF_LONG_LONG >= 8 #define HAVE_LONG_LONG 1 #else #error WHAT? sizeof(long long) < 8 ??? #endif /* Some pre-ANSI-C99 systems like AIX 5.1 and Linux/GCC 2.95 define ULONGLONG_MAX, LONGLONG_MIN, LONGLONG_MAX; we use them if they're defined. */ #if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN) #define LONGLONG_MIN ((long long) 0x8000000000000000LL) #define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL) #endif /* Max length needed for a buffer to hold a longlong or ulonglong + end \0 */ #define LONGLONG_BUFFER_SIZE 21 #if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX) /* First check for ANSI C99 definition: */ #ifdef ULLONG_MAX #define ULONGLONG_MAX ULLONG_MAX #else #define ULONGLONG_MAX ((unsigned long long)(~0ULL)) #endif #endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ #define INT_MIN64 (~0x7FFFFFFFFFFFFFFFLL) #define INT_MAX64 0x7FFFFFFFFFFFFFFFLL #define INT_MIN32 (~0x7FFFFFFFL) #define INT_MAX32 0x7FFFFFFFL #define UINT_MAX32 0xFFFFFFFFL #define INT_MIN24 (~0x007FFFFF) #define INT_MAX24 0x007FFFFF #define UINT_MAX24 0x00FFFFFF #define INT_MIN16 (~0x7FFF) #define INT_MAX16 0x7FFF #define UINT_MAX16 0xFFFF #define INT_MIN8 (~0x7F) #define INT_MAX8 0x7F #define UINT_MAX8 0xFF /* From limits.h instead */ #ifndef DBL_MIN #define DBL_MIN 4.94065645841246544e-324 #define FLT_MIN ((float)1.40129846432481707e-45) #endif #ifndef DBL_MAX #define DBL_MAX 1.79769313486231470e+308 #define FLT_MAX ((float)3.40282346638528860e+38) #endif #ifndef SIZE_T_MAX #define SIZE_T_MAX (~((size_t) 0)) #endif /* Define missing math constants. */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef M_E #define M_E 2.7182818284590452354 #endif #ifndef M_LN2 #define M_LN2 0.69314718055994530942 #endif /* Max size that must be added to a so that we know Size to make addressable obj. */ #if SIZEOF_CHARP == 4 typedef long my_ptrdiff_t; #else typedef long long my_ptrdiff_t; #endif #define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) #define MY_ALIGN_DOWN(A,L) ((A) & ~((L) - 1)) #define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) #define ALIGN_MAX_UNIT (sizeof(double)) /* Size to make addressable obj. */ #define ALIGN_PTR(A, t) ((t*) MY_ALIGN((A), sizeof(double))) #define ADD_TO_PTR(ptr,size,type) (type) ((uchar*) (ptr)+size) #define PTR_BYTE_DIFF(A,B) (my_ptrdiff_t) ((uchar*) (A) - (uchar*) (B)) /* Custom version of standard offsetof() macro which can be used to get offsets of members in class for non-POD types (according to the current version of C++ standard offsetof() macro can't be used in such cases and attempt to do so causes warnings to be emitted, OTOH in many cases it is still OK to assume that all instances of the class has the same offsets for the same members). This is temporary solution which should be removed once File_parser class and related routines are refactored. */ #define my_offsetof(TYPE, MEMBER) PTR_BYTE_DIFF(&((TYPE *)0x10)->MEMBER, 0x10) #define NullS (char *) 0 #ifdef STDCALL #undef STDCALL #endif #ifdef _WIN32 #define STDCALL __stdcall #else #define STDCALL #endif /* Typdefs for easier portability */ #ifndef HAVE_UCHAR typedef unsigned char uchar; /* Short for unsigned char */ #endif #ifndef HAVE_INT8 typedef signed char int8; /* Signed integer >= 8 bits */ #endif #ifndef HAVE_UINT8 typedef unsigned char uint8; /* Unsigned integer >= 8 bits */ #endif #ifndef HAVE_INT16 typedef short int16; #endif #ifndef HAVE_UINT16 typedef unsigned short uint16; #endif #if SIZEOF_INT == 4 #ifndef HAVE_INT32 typedef int int32; #endif #ifndef HAVE_UINT32 typedef unsigned int uint32; #endif #elif SIZEOF_LONG == 4 #ifndef HAVE_INT32 typedef long int32; #endif #ifndef HAVE_UINT32 typedef unsigned long uint32; #endif #else #error Neither int or long is of 4 bytes width #endif #if !defined(HAVE_ULONG) && !defined(__USE_MISC) typedef unsigned long ulong; /* Short for unsigned long */ #endif #ifndef longlong_defined /* Using [unsigned] long long is preferable as [u]longlong because we use [unsigned] long long unconditionally in many places, for example in constants with [U]LL suffix. */ #if defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8 typedef unsigned long long int ulonglong; /* ulong or unsigned long long */ typedef long long int longlong; #else typedef unsigned long ulonglong; /* ulong or unsigned long long */ typedef long longlong; #endif #endif #ifndef HAVE_INT64 typedef longlong int64; #endif #ifndef HAVE_UINT64 typedef ulonglong uint64; #endif #if defined(NO_CLIENT_LONG_LONG) typedef unsigned long my_ulonglong; #elif defined (_WIN32) typedef unsigned __int64 my_ulonglong; #else typedef unsigned long long my_ulonglong; #endif #if SIZEOF_CHARP == SIZEOF_INT typedef unsigned int intptr; #elif SIZEOF_CHARP == SIZEOF_LONG typedef unsigned long intptr; #elif SIZEOF_CHARP == SIZEOF_LONG_LONG typedef unsigned long long intptr; #else #error sizeof(void *) is neither sizeof(int) nor sizeof(long) nor sizeof(long long) #endif #define MY_ERRPTR ((void*)(intptr)1) #if defined(_WIN32) typedef unsigned long long my_off_t; typedef unsigned long long os_off_t; #else typedef off_t os_off_t; #if SIZEOF_OFF_T > 4 typedef ulonglong my_off_t; #else typedef unsigned long my_off_t; #endif #endif /*_WIN32*/ #define MY_FILEPOS_ERROR (~(my_off_t) 0) /* TODO Convert these to use Bitmap class. */ typedef ulonglong table_map; /* Used for table bits in join */ /* often used type names - opaque declarations */ typedef const struct charset_info_st CHARSET_INFO; typedef struct st_mysql_lex_string LEX_STRING; #if defined(_WIN32) #define socket_errno WSAGetLastError() #define SOCKET_EINTR WSAEINTR #define SOCKET_ETIMEDOUT WSAETIMEDOUT #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK #define SOCKET_EADDRINUSE WSAEADDRINUSE #define SOCKET_ECONNRESET WSAECONNRESET #define SOCKET_ENFILE ENFILE #define SOCKET_EMFILE EMFILE #define SOCKET_CLOSED EIO #else /* Unix */ #define socket_errno errno #define closesocket(A) close(A) #define SOCKET_EINTR EINTR #define SOCKET_EAGAIN EAGAIN #define SOCKET_EWOULDBLOCK EWOULDBLOCK #define SOCKET_EADDRINUSE EADDRINUSE #define SOCKET_ETIMEDOUT ETIMEDOUT #define SOCKET_ECONNRESET ECONNRESET #define SOCKET_CLOSED EIO #define SOCKET_ENFILE ENFILE #define SOCKET_EMFILE EMFILE #endif #include /* my_bool */ typedef ulong myf; /* Type of MyFlags in my_funcs */ #define MYF(v) (myf) (v) /* Defines to make it possible to prioritize register assignments. No longer that important with modern compilers. */ #ifndef USING_X #define reg1 register #define reg2 register #define reg3 register #define reg4 register #define reg5 register #define reg6 register #define reg7 register #define reg8 register #define reg9 register #define reg10 register #define reg11 register #define reg12 register #define reg13 register #define reg14 register #define reg15 register #define reg16 register #endif /* MYSQL_PLUGIN_IMPORT macro is used to export mysqld data (i.e variables) for usage in storage engine loadable plugins. Outside of Windows, it is dummy. */ #ifndef MYSQL_PLUGIN_IMPORT #if (defined(_WIN32) && defined(MYSQL_DYNAMIC_PLUGIN)) #define MYSQL_PLUGIN_IMPORT __declspec(dllimport) #else #define MYSQL_PLUGIN_IMPORT #endif #endif #include /* Some helper macros */ #define YESNO(X) ((X) ? "yes" : "no") #define MY_HOW_OFTEN_TO_ALARM 2 /* How often we want info on screen */ #define MY_HOW_OFTEN_TO_WRITE 10000 /* How often we want info on screen */ #include #ifdef HAVE_CHARSET_utf8mb4 #define MYSQL_UNIVERSAL_CLIENT_CHARSET "utf8mb4" #elif defined(HAVE_CHARSET_utf8mb3) #define MYSQL_UNIVERSAL_CLIENT_CHARSET "utf8mb3" #else #define MYSQL_UNIVERSAL_CLIENT_CHARSET MYSQL_DEFAULT_CHARSET_NAME #endif #if defined(EMBEDDED_LIBRARY) && !defined(HAVE_EMBEDDED_PRIVILEGE_CONTROL) #define NO_EMBEDDED_ACCESS_CHECKS #endif #ifdef _WIN32 #define dlsym(lib, name) (void*)GetProcAddress((HMODULE)lib, name) #define dlopen(libname, unused) LoadLibraryEx(libname, NULL, 0) #define RTLD_DEFAULT GetModuleHandle(NULL) #define dlclose(lib) FreeLibrary((HMODULE)lib) static inline char *dlerror(void) { static char win_errormsg[2048]; FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, 0, GetLastError(), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), win_errormsg, 2048, NULL); return win_errormsg; } #define HAVE_DLOPEN 1 #define HAVE_DLERROR 1 #endif #ifdef HAVE_DLFCN_H #include #endif #ifdef HAVE_DLOPEN #ifndef HAVE_DLERROR #define dlerror() "" #endif #ifndef HAVE_DLADDR #define dladdr(A, B) 0 /* Dummy definition in case we're missing dladdr() */ typedef struct { const char *dli_fname, dli_fbase; } Dl_info; #endif #else #define dlerror() "No support for dynamic loading (static build?)" #define dlopen(A,B) 0 #define dlsym(A,B) 0 #define dlclose(A) 0 #define dladdr(A, B) 0 /* Dummy definition in case we're missing dladdr() */ typedef struct { const char *dli_fname, dli_fbase; } Dl_info; #endif /* * Include standard definitions of operator new and delete. */ #ifdef __cplusplus #include #endif /* Length of decimal number represented by INT32. */ #define MY_INT32_NUM_DECIMAL_DIGITS 11 /* Length of decimal number represented by INT64. */ #define MY_INT64_NUM_DECIMAL_DIGITS 21 #ifdef __cplusplus #include /* should be included before min/max macros */ #endif /* Define some useful general macros (should be done after all headers). */ #define MY_MAX(a, b) ((a) > (b) ? (a) : (b)) #define MY_MIN(a, b) ((a) < (b) ? (a) : (b)) #define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1) /* Only Linux is known to need an explicit sync of the directory to make sure a file creation/deletion/renaming in(from,to) this directory durable. */ #ifdef TARGET_OS_LINUX #define NEED_EXPLICIT_SYNC_DIR 1 #else /* On linux default rwlock scheduling policy is good enough for waiting_threads.c, on other systems use our special implementation (which is slower). QQ perhaps this should be tested in configure ? how ? */ #define WT_RWLOCKS_USE_MUTEXES 1 #endif #if !defined(__cplusplus) && !defined(bool) #define bool In_C_you_should_use_my_bool_instead() #endif /* Provide __func__ macro definition for platforms that miss it. */ #if !defined (__func__) #if defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L # if __GNUC__ >= 2 # define __func__ __FUNCTION__ # else # define __func__ "" # endif #elif defined(_MSC_VER) # if _MSC_VER < 1300 # define __func__ "" # else # define __func__ __FUNCTION__ # endif #elif defined(__BORLANDC__) # define __func__ __FUNC__ #else # define __func__ "" #endif #endif /* !defined(__func__) */ /* Defines that are unique to the embedded version of MySQL */ #ifdef EMBEDDED_LIBRARY /* Things we don't need in the embedded version of MySQL */ /* TODO HF add #undef HAVE_VIO if we don't want client in embedded library */ #else #define HAVE_REPLICATION #define HAVE_EXTERNAL_CLIENT #endif /* EMBEDDED_LIBRARY */ /* Provide defaults for the CPU cache line size, if it has not been detected by CMake using getconf */ #if !defined(CPU_LEVEL1_DCACHE_LINESIZE) || CPU_LEVEL1_DCACHE_LINESIZE == 0 #if defined(CPU_LEVEL1_DCACHE_LINESIZE) && CPU_LEVEL1_DCACHE_LINESIZE == 0 #undef CPU_LEVEL1_DCACHE_LINESIZE #endif #if defined(__s390__) #define CPU_LEVEL1_DCACHE_LINESIZE 256 #elif defined(__powerpc__) || defined(__aarch64__) #define CPU_LEVEL1_DCACHE_LINESIZE 128 #else #define CPU_LEVEL1_DCACHE_LINESIZE 64 #endif #endif #define FLOATING_POINT_DECIMALS 31 /* Keep client compatible with earlier versions */ #ifdef MYSQL_SERVER #define NOT_FIXED_DEC DECIMAL_NOT_SPECIFIED #else #define NOT_FIXED_DEC FLOATING_POINT_DECIMALS #endif #endif /* my_global_h */ server/handler_ername.h000064400000010773151031265050011175 0ustar00/* Copyright (c) 2013, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* Names of all handler error numbers. Used by mysqltest */ { "HA_ERR_KEY_NOT_FOUND", HA_ERR_KEY_NOT_FOUND, "" }, { "HA_ERR_FOUND_DUPP_KEY", HA_ERR_FOUND_DUPP_KEY, "" }, { "HA_ERR_INTERNAL_ERROR", HA_ERR_INTERNAL_ERROR, "" }, { "HA_ERR_RECORD_CHANGED", HA_ERR_RECORD_CHANGED, "" }, { "HA_ERR_WRONG_INDEX", HA_ERR_WRONG_INDEX, "" }, { "HA_ERR_CRASHED", HA_ERR_CRASHED, "" }, { "HA_ERR_WRONG_IN_RECORD", HA_ERR_WRONG_IN_RECORD, "" }, { "HA_ERR_OUT_OF_MEM", HA_ERR_OUT_OF_MEM, "" }, { "HA_ERR_NOT_A_TABLE", HA_ERR_NOT_A_TABLE, "" }, { "HA_ERR_WRONG_COMMAND", HA_ERR_WRONG_COMMAND, "" }, { "HA_ERR_OLD_FILE", HA_ERR_OLD_FILE, "" }, { "HA_ERR_NO_ACTIVE_RECORD", HA_ERR_NO_ACTIVE_RECORD, "" }, { "HA_ERR_RECORD_DELETED", HA_ERR_RECORD_DELETED, "" }, { "HA_ERR_RECORD_FILE_FULL", HA_ERR_RECORD_FILE_FULL, "" }, { "HA_ERR_INDEX_FILE_FULL", HA_ERR_INDEX_FILE_FULL, "" }, { "HA_ERR_END_OF_FILE", HA_ERR_END_OF_FILE, "" }, { "HA_ERR_UNSUPPORTED", HA_ERR_UNSUPPORTED, "" }, { "HA_ERR_TO_BIG_ROW", HA_ERR_TO_BIG_ROW, "" }, { "HA_WRONG_CREATE_OPTION", HA_WRONG_CREATE_OPTION, "" }, { "HA_ERR_FOUND_DUPP_UNIQUE", HA_ERR_FOUND_DUPP_UNIQUE, "" }, { "HA_ERR_UNKNOWN_CHARSET", HA_ERR_UNKNOWN_CHARSET, "" }, { "HA_ERR_WRONG_MRG_TABLE_DEF", HA_ERR_WRONG_MRG_TABLE_DEF, "" }, { "HA_ERR_CRASHED_ON_REPAIR", HA_ERR_CRASHED_ON_REPAIR, "" }, { "HA_ERR_CRASHED_ON_USAGE", HA_ERR_CRASHED_ON_USAGE, "" }, { "HA_ERR_LOCK_WAIT_TIMEOUT", HA_ERR_LOCK_WAIT_TIMEOUT, "" }, { "HA_ERR_LOCK_TABLE_FULL", HA_ERR_LOCK_TABLE_FULL, "" }, { "HA_ERR_READ_ONLY_TRANSACTION", HA_ERR_READ_ONLY_TRANSACTION, "" }, { "HA_ERR_LOCK_DEADLOCK", HA_ERR_LOCK_DEADLOCK, "" }, { "HA_ERR_CANNOT_ADD_FOREIGN", HA_ERR_CANNOT_ADD_FOREIGN, "" }, { "HA_ERR_NO_REFERENCED_ROW", HA_ERR_NO_REFERENCED_ROW, "" }, { "HA_ERR_ROW_IS_REFERENCED", HA_ERR_ROW_IS_REFERENCED, "" }, { "HA_ERR_NO_SAVEPOINT", HA_ERR_NO_SAVEPOINT, "" }, { "HA_ERR_NON_UNIQUE_BLOCK_SIZE", HA_ERR_NON_UNIQUE_BLOCK_SIZE, "" }, { "HA_ERR_NO_SUCH_TABLE", HA_ERR_NO_SUCH_TABLE, "" }, { "HA_ERR_TABLE_EXIST", HA_ERR_TABLE_EXIST, "" }, { "HA_ERR_NO_CONNECTION", HA_ERR_NO_CONNECTION, "" }, { "HA_ERR_NULL_IN_SPATIAL", HA_ERR_NULL_IN_SPATIAL, "" }, { "HA_ERR_TABLE_DEF_CHANGED", HA_ERR_TABLE_DEF_CHANGED, "" }, { "HA_ERR_NO_PARTITION_FOUND", HA_ERR_NO_PARTITION_FOUND, "" }, { "HA_ERR_RBR_LOGGING_FAILED", HA_ERR_RBR_LOGGING_FAILED, "" }, { "HA_ERR_DROP_INDEX_FK", HA_ERR_DROP_INDEX_FK, "" }, { "HA_ERR_FOREIGN_DUPLICATE_KEY", HA_ERR_FOREIGN_DUPLICATE_KEY, "" }, { "HA_ERR_TABLE_NEEDS_UPGRADE", HA_ERR_TABLE_NEEDS_UPGRADE, "" }, { "HA_ERR_TABLE_READONLY", HA_ERR_TABLE_READONLY, "" }, { "HA_ERR_AUTOINC_READ_FAILED", HA_ERR_AUTOINC_READ_FAILED, "" }, { "HA_ERR_AUTOINC_ERANGE", HA_ERR_AUTOINC_ERANGE, "" }, { "HA_ERR_GENERIC", HA_ERR_GENERIC, "" }, { "HA_ERR_RECORD_IS_THE_SAME", HA_ERR_RECORD_IS_THE_SAME, "" }, { "HA_ERR_LOGGING_IMPOSSIBLE", HA_ERR_LOGGING_IMPOSSIBLE, "" }, { "HA_ERR_CORRUPT_EVENT", HA_ERR_CORRUPT_EVENT, "" }, { "HA_ERR_NEW_FILE", HA_ERR_NEW_FILE, "" }, { "HA_ERR_ROWS_EVENT_APPLY", HA_ERR_ROWS_EVENT_APPLY, "" }, { "HA_ERR_INITIALIZATION", HA_ERR_INITIALIZATION, "" }, { "HA_ERR_FILE_TOO_SHORT", HA_ERR_FILE_TOO_SHORT, "" }, { "HA_ERR_WRONG_CRC", HA_ERR_WRONG_CRC, "" }, { "HA_ERR_TOO_MANY_CONCURRENT_TRXS", HA_ERR_TOO_MANY_CONCURRENT_TRXS, "" }, { "HA_ERR_INDEX_COL_TOO_LONG", HA_ERR_INDEX_COL_TOO_LONG, "" }, { "HA_ERR_INDEX_CORRUPT", HA_ERR_INDEX_CORRUPT, "" }, { "HA_ERR_UNDO_REC_TOO_BIG", HA_ERR_UNDO_REC_TOO_BIG, "" }, { "HA_ERR_ROW_NOT_VISIBLE", HA_ERR_ROW_NOT_VISIBLE, "" }, { "HA_ERR_ABORTED_BY_USER", HA_ERR_ABORTED_BY_USER, "" }, { "HA_ERR_DISK_FULL", HA_ERR_DISK_FULL, "" }, { "HA_ERR_INCOMPATIBLE_DEFINITION", HA_ERR_INCOMPATIBLE_DEFINITION, "" }, { "HA_ERR_COMMIT_ERROR", HA_ERR_COMMIT_ERROR, "" }, { "HA_ERR_PARTITION_LIST", HA_ERR_PARTITION_LIST, ""}, { "HA_ERR_NO_ENCRYPTION", HA_ERR_NO_ENCRYPTION, ""}, { "HA_ERR_ROLLBACK", HA_ERR_ROLLBACK, "" }, server/my_dbug.h000064400000023577151031265050007665 0ustar00/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. Copyright (C) 2000, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_dbug_h #define _my_dbug_h #ifndef _WIN32 #include #endif #ifdef __cplusplus extern "C" { #endif #if !defined(DBUG_OFF) && !defined(_lint) struct _db_stack_frame_ { const char *func; /* function name of the previous stack frame */ const char *file; /* filename of the function of previous frame */ uint level; /* this nesting level, highest bit enables tracing */ int line; /* line of DBUG_RETURN */ struct _db_stack_frame_ *prev; /* pointer to the previous frame */ }; struct _db_code_state_; extern my_bool _dbug_on_; extern my_bool _db_keyword_(struct _db_code_state_ *, const char *, int); extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len); extern int _db_explain_init_(char *buf, size_t len); extern int _db_is_pushed_(void); extern void _db_setjmp_(void); extern void _db_longjmp_(void); extern void _db_process_(const char *name); extern void _db_push_(const char *control); extern void _db_pop_(void); extern void _db_set_(const char *control); extern void _db_set_init_(const char *control); extern void _db_enter_(const char *_func_, const char *_file_, uint _line_, struct _db_stack_frame_ *_stack_frame_); extern void _db_return_(struct _db_stack_frame_ *_stack_frame_); extern int _db_pargs_(uint _line_,const char *keyword); extern void _db_doprnt_(const char *format,...) #ifdef WAITING_FOR_BUGFIX_TO_VSPRINTF ATTRIBUTE_FORMAT(printf, 1, 2) #endif ; extern void _db_dump_(uint _line_,const char *keyword, const unsigned char *memory, size_t length); extern void _db_end_(void); extern void _db_lock_file_(void); extern void _db_unlock_file_(void); ATTRIBUTE_COLD extern my_bool _db_my_assert(const char *file, int line, const char *msg); extern FILE *_db_fp_(void); extern void _db_flush_(void); extern void dbug_swap_code_state(void **code_state_store); extern void dbug_free_code_state(void **code_state_store); extern const char* _db_get_func_(void); extern int (*dbug_sanity)(void); #ifdef DBUG_TRACE #define DBUG_LEAVE do { \ _db_stack_frame_.line= __LINE__; \ _db_return_ (&_db_stack_frame_); \ _db_stack_frame_.line= 0; \ } while(0) #define DBUG_PRINT(keyword,arglist) \ do if (_db_pargs_(__LINE__,keyword)) _db_doprnt_ arglist; while(0) #ifdef HAVE_ATTRIBUTE_CLEANUP #define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_ __attribute__((cleanup(_db_return_))); \ _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_) #define DBUG_RETURN(a1) do { _db_stack_frame_.line=__LINE__; return(a1);} while(0) #define DBUG_VOID_RETURN do { _db_stack_frame_.line=__LINE__; return;} while(0) #else #define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \ _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_) #define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0) #define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0) #endif #else #define DBUG_LEAVE #define DBUG_ENTER(a) #define DBUG_RETURN(a1) return(a1) #define DBUG_VOID_RETURN return #define DBUG_PRINT(keyword,arglist) do{} while(0) #endif #define DBUG_EXECUTE(keyword,a1) \ do {if (_db_keyword_(0, (keyword), 0)) { a1 }} while(0) #define DBUG_EXECUTE_IF(keyword,a1) \ do {if (_db_keyword_(0, (keyword), 1)) { a1 }} while(0) #define DBUG_EVALUATE(keyword,a1,a2) \ (_db_keyword_(0,(keyword), 0) ? (a1) : (a2)) #define DBUG_EVALUATE_IF(keyword,a1,a2) \ (_db_keyword_(0,(keyword), 1) ? (a1) : (a2)) #define DBUG_PUSH_EMPTY if (_dbug_on_) { DBUG_PUSH(""); } #define DBUG_POP_EMPTY if (_dbug_on_) { DBUG_POP(); } #define DBUG_PUSH(a1) _db_push_ (a1) #define DBUG_POP() _db_pop_ () #define DBUG_SET(a1) _db_set_ (a1) #define DBUG_SET_INITIAL(a1) _db_set_init_ (a1) #define DBUG_PROCESS(a1) _db_process_(a1) #define DBUG_FILE _db_fp_() #define DBUG_DUMP(keyword,a1,a2) _db_dump_(__LINE__,keyword,a1,a2) #define DBUG_END() _db_end_ () #define DBUG_LOCK_FILE _db_lock_file_() #define DBUG_UNLOCK_FILE _db_unlock_file_() #define DBUG_ASSERT(A) do { \ if (unlikely(!(A)) && _db_my_assert(__FILE__, __LINE__, #A)) assert(A); \ } while (0) #define DBUG_SLOW_ASSERT(A) DBUG_ASSERT(A) #define DBUG_ASSERT_EXISTS #define DBUG_EXPLAIN(buf,len) _db_explain_(0, (buf),(len)) #define DBUG_EXPLAIN_INITIAL(buf,len) _db_explain_init_((buf),(len)) #define DEBUGGER_OFF do { _dbug_on_= 0; } while(0) #define DEBUGGER_ON do { _dbug_on_= 1; } while(0) #define IF_DBUG(A,B) A #define IF_DBUG_ASSERT(A,B) A #define DBUG_SWAP_CODE_STATE(arg) dbug_swap_code_state(arg) #define DBUG_FREE_CODE_STATE(arg) dbug_free_code_state(arg) #undef DBUG_ASSERT_AS_PRINTF #ifndef _WIN32 #define DBUG_ABORT() (_db_flush_(), abort()) #else /* Avoid popup with abort/retry/ignore buttons. When BUG#31745 is fixed we can call abort() instead of _exit(3) (now it would cause a "test signal" popup). */ #include #define DBUG_ABORT() (_db_flush_(),\ (void)_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE),\ (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR),\ TerminateProcess(GetCurrentProcess(),3)) #endif /* Make the program fail, without creating a core file. abort() will send SIGABRT which (most likely) generates core. Use SIGKILL instead, which cannot be caught. We also pause the current thread, until the signal is actually delivered. An alternative would be to use _exit(EXIT_FAILURE), but then valgrind would report lots of memory leaks. */ #ifdef _WIN32 #define DBUG_SUICIDE() DBUG_ABORT() #else extern void _db_suicide_(void); #define DBUG_SUICIDE() (_db_flush_(), _db_suicide_()) #endif /* _WIN32 */ #else /* No debugger */ #define DBUG_ENTER(a1) #define DBUG_VIOLATION_HELPER_LEAVE do { } while(0) #define DBUG_LEAVE #define DBUG_RETURN(a1) do { return(a1); } while(0) #define DBUG_VOID_RETURN do { return; } while(0) #define DBUG_PRINT(keyword, arglist) do { } while(0) #define DBUG_EXECUTE(keyword,a1) do { } while(0) #define DBUG_EXECUTE_IF(keyword,a1) do { } while(0) #define DBUG_EVALUATE(keyword,a1,a2) (a2) #define DBUG_EVALUATE_IF(keyword,a1,a2) (a2) #define DBUG_PRINT(keyword,arglist) do { } while(0) #define DBUG_PUSH_EMPTY do { } while(0) #define DBUG_POP_EMPTY do { } while(0) #define DBUG_PUSH(a1) do { } while(0) #define DBUG_SET(a1) do { } while(0) #define DBUG_SET_INITIAL(a1) do { } while(0) #define DBUG_POP() do { } while(0) #define DBUG_PROCESS(a1) do { } while(0) #define DBUG_DUMP(keyword,a1,a2) do { } while(0) #define DBUG_END() do { } while(0) #define DBUG_SLOW_ASSERT(A) do { } while(0) #define DBUG_LOCK_FILE do { } while(0) #define DBUG_FILE (stderr) #define DBUG_UNLOCK_FILE do { } while(0) #define DBUG_EXPLAIN(buf,len) #define DBUG_EXPLAIN_INITIAL(buf,len) #define DEBUGGER_OFF do { } while(0) #define DEBUGGER_ON do { } while(0) #define IF_DBUG(A,B) B #define DBUG_SWAP_CODE_STATE(arg) do { } while(0) #define DBUG_FREE_CODE_STATE(arg) do { } while(0) #define DBUG_ABORT() do { } while(0) #define DBUG_CRASH_ENTER(func) #define DBUG_CRASH_RETURN(val) do { return(val); } while(0) #define DBUG_CRASH_VOID_RETURN do { return; } while(0) #define DBUG_SUICIDE() do { } while(0) #ifdef DBUG_ASSERT_AS_PRINTF extern void (*my_dbug_assert_failed)(const char *assert_expr, const char* file, unsigned long line); #define DBUG_ASSERT(assert_expr) do { if (!(assert_expr)) { my_dbug_assert_failed(#assert_expr, __FILE__, __LINE__); }} while (0) #define DBUG_ASSERT_EXISTS #define IF_DBUG_ASSERT(A,B) A #else #define DBUG_ASSERT(A) do { } while(0) #define IF_DBUG_ASSERT(A,B) B #endif /* DBUG_ASSERT_AS_PRINTF */ #endif /* !defined(DBUG_OFF) && !defined(_lint) */ #ifdef EXTRA_DEBUG /** Sync points allow us to force the server to reach a certain line of code and block there until the client tells the server it is ok to go on. The client tells the server to block with SELECT GET_LOCK() and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult concurrency problems */ #define DBUG_SYNC_POINT(lock_name,lock_timeout) \ debug_sync_point(lock_name,lock_timeout) void debug_sync_point(const char* lock_name, uint lock_timeout); #else #define DBUG_SYNC_POINT(lock_name,lock_timeout) #endif /* EXTRA_DEBUG */ #ifdef __cplusplus } /* DBUG_LOG() was initially intended for InnoDB. To be able to use it elsewhere one should #include . We intentionally avoid including it here to save compilation time. */ # ifdef DBUG_OFF # define DBUG_LOG(keyword, v) do {} while (0) # else # define DBUG_LOG(keyword, v) do { \ if (_db_pargs_(__LINE__, keyword)) { \ std::ostringstream _db_s; _db_s << v; \ _db_doprnt_("%s", _db_s.str().c_str()); \ }} while (0) # endif #endif #endif /* _my_dbug_h */ server/my_compiler.h000064400000012222151031265050010537 0ustar00#ifndef MY_COMPILER_INCLUDED #define MY_COMPILER_INCLUDED /* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2017, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /** Header for compiler-dependent features. Intended to contain a set of reusable wrappers for preprocessor macros, attributes, pragmas, and any other features that are specific to a target compiler. */ /** Compiler-dependent internal convenience macros. */ /* C vs C++ */ #ifdef __cplusplus #define CONSTEXPR constexpr #else #define CONSTEXPR #endif /* __cplusplus */ /* GNU C/C++ */ #if defined __GNUC__ # define MY_ALIGN_EXT /* __builtin_unreachable() removes the "statement may fall through" warning-as- error when MY_ASSERT_UNREACHABLE() is used in "case xxx:" in switch (...) statements. abort() is there to prevent the execution from reaching the __builtin_unreachable() as this may cause misleading stack traces. */ # define MY_ASSERT_UNREACHABLE() { abort(); __builtin_unreachable(); } /* Microsoft Visual C++ */ #elif defined _MSC_VER # define MY_ALIGNOF(type) __alignof(type) # define MY_ALIGNED(n) __declspec(align(n)) /* Oracle Solaris Studio */ #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) # if __SUNPRO_C >= 0x590 # define MY_ALIGN_EXT # endif /* IBM XL C/C++ */ #elif defined __xlC__ # if __xlC__ >= 0x0600 # define MY_ALIGN_EXT # endif /* HP aCC */ #elif defined(__HP_aCC) || defined(__HP_cc) # if (__HP_aCC >= 60000) || (__HP_cc >= 60000) # define MY_ALIGN_EXT # endif #endif #ifdef MY_ALIGN_EXT /** Specifies the minimum alignment of a type. */ # define MY_ALIGNOF(type) __alignof__(type) /** Determine the alignment requirement of a type. */ # define MY_ALIGNED(n) __attribute__((__aligned__((n)))) #endif /** Generic (compiler-independent) features. */ #ifndef MY_ALIGNOF # ifdef __cplusplus template struct my_alignof_helper { char m1; type m2; }; /* Invalid for non-POD types, but most compilers give the right answer. */ # define MY_ALIGNOF(type) offsetof(my_alignof_helper, m2) # else # define MY_ALIGNOF(type) offsetof(struct { char m1; type m2; }, m2) # endif #endif #ifndef MY_ASSERT_UNREACHABLE # define MY_ASSERT_UNREACHABLE() do { abort(); } while (0) #endif /** C++ Type Traits */ #ifdef __cplusplus /** Opaque storage with a particular alignment. */ # if defined(MY_ALIGNED) /* Partial specialization used due to MSVC++. */ template struct my_alignment_imp; template<> struct MY_ALIGNED(1) my_alignment_imp<1> {}; template<> struct MY_ALIGNED(2) my_alignment_imp<2> {}; template<> struct MY_ALIGNED(4) my_alignment_imp<4> {}; template<> struct MY_ALIGNED(8) my_alignment_imp<8> {}; template<> struct MY_ALIGNED(16) my_alignment_imp<16> {}; /* ... expand as necessary. */ # else template struct my_alignment_imp { double m1; }; # endif /** A POD type with a given size and alignment. @remark If the compiler does not support a alignment attribute (MY_ALIGN macro), the default alignment of a double is used instead. @tparam size The minimum size. @tparam alignment The desired alignment: 1, 2, 4, 8 or 16. */ template struct my_aligned_storage { union { char data[size]; my_alignment_imp align; }; }; #endif /* __cplusplus */ # ifndef MY_ALIGNED /* Make sure MY_ALIGNED can be used also on platforms where we don't have a way of aligning data structures. */ #define MY_ALIGNED(size) #endif #ifdef __GNUC__ # define ATTRIBUTE_NORETURN __attribute__((noreturn)) # define ATTRIBUTE_NOINLINE __attribute__((noinline)) /** Starting with GCC 4.3, the "cold" attribute is used to inform the compiler that a function is unlikely executed. The function is optimized for size rather than speed and on many targets it is placed into special subsection of the text section so all cold functions appears close together improving code locality of non-cold parts of program. The paths leading to call of cold functions within code are marked as unlikely by the branch prediction mechanism. optimize a rarely invoked function for size instead for speed. */ # define ATTRIBUTE_COLD __attribute__((cold)) #elif defined _MSC_VER # define ATTRIBUTE_NORETURN __declspec(noreturn) # define ATTRIBUTE_NOINLINE __declspec(noinline) #else # define ATTRIBUTE_NORETURN /* empty */ # define ATTRIBUTE_NOINLINE /* empty */ #endif #ifndef ATTRIBUTE_COLD # define ATTRIBUTE_COLD /* empty */ #endif #include #endif /* MY_COMPILER_INCLUDED */ server/sql_common.h000064400000012224151031265050010371 0ustar00#ifndef SQL_COMMON_INCLUDED #define SQL_COMMON_INCLUDED /* Copyright (c) 2003, 2018, Oracle and/or its affiliates. Copyright (c) 2010, 2018, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifdef __cplusplus extern "C" { #endif #include #include extern const char *unknown_sqlstate; extern const char *cant_connect_sqlstate; extern const char *not_error_sqlstate; struct st_mysql_options_extention { char *plugin_dir; char *default_auth; char *ssl_crl; /* PEM CRL file */ char *ssl_crlpath; /* PEM directory of CRL-s? */ void (*report_progress)(const MYSQL *mysql, unsigned int stage, unsigned int max_stage, double progress, const char *proc_info, uint proc_info_length); HASH connection_attributes; size_t connection_attributes_length; my_bool tls_verify_server_cert; }; typedef struct st_mysql_methods { my_bool (*read_query_result)(MYSQL *mysql); my_bool (*advanced_command)(MYSQL *mysql, enum enum_server_command command, const unsigned char *header, unsigned long header_length, const unsigned char *arg, unsigned long arg_length, my_bool skip_check, MYSQL_STMT *stmt); MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields, unsigned int fields); MYSQL_RES * (*use_result)(MYSQL *mysql); void (*fetch_lengths)(unsigned long *to, MYSQL_ROW column, unsigned int field_count); void (*flush_use_result)(MYSQL *mysql, my_bool flush_all_results); int (*read_change_user_result)(MYSQL *mysql); void (*on_close_free)(MYSQL *mysql); #if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) MYSQL_FIELD * (*list_fields)(MYSQL *mysql); my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt); int (*stmt_execute)(MYSQL_STMT *stmt); int (*read_binary_rows)(MYSQL_STMT *stmt); int (*unbuffered_fetch)(MYSQL *mysql, char **row); const char *(*read_statistics)(MYSQL *mysql); my_bool (*next_result)(MYSQL *mysql); int (*read_rows_from_cursor)(MYSQL_STMT *stmt); #endif } MYSQL_METHODS; #ifdef LIBMARIADB #define simple_command(mysql, command, arg, length, skip_check) ma_simple_command(mysql, command, (char *)arg, length, skip_check, NULL) #else #define simple_command(mysql, command, arg, length, skip_check) \ (*(mysql)->methods->advanced_command)(mysql, command, 0, \ 0, arg, length, skip_check, NULL) #endif #define stmt_command(mysql, command, arg, length, stmt) \ (*(mysql)->methods->advanced_command)(mysql, command, 0, \ 0, arg, length, 1, stmt) extern CHARSET_INFO *default_client_charset_info; MYSQL_FIELD *unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc, uint fields, my_bool default_value, uint server_capabilities); void free_rows(MYSQL_DATA *cur); void free_old_query(MYSQL *mysql); void end_server(MYSQL *mysql); my_bool mysql_reconnect(MYSQL *mysql); void mysql_read_default_options(struct st_mysql_options *options, const char *filename,const char *group); my_bool cli_advanced_command(MYSQL *mysql, enum enum_server_command command, const unsigned char *header, ulong header_length, const unsigned char *arg, ulong arg_length, my_bool skip_check, MYSQL_STMT *stmt); unsigned long cli_safe_read(MYSQL *mysql); unsigned long cli_safe_read_reallen(MYSQL *mysql, ulong* reallen); void net_clear_error(NET *net); void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net); void set_stmt_error(MYSQL_STMT *stmt, int errcode, const char *sqlstate, const char *err); void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate); void set_mysql_extended_error(MYSQL *mysql, int errcode, const char *sqlstate, const char *format, ...); /* client side of the pluggable authentication */ struct st_vio; struct st_plugin_vio_info; void mpvio_info(struct st_vio *vio, struct st_plugin_vio_info *info); int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, const char *data_plugin, const char *db); int mysql_client_plugin_init(); void mysql_client_plugin_deinit(); struct st_mysql_client_plugin; extern struct st_mysql_client_plugin *mysql_client_builtins[]; uchar * send_client_connect_attrs(MYSQL *mysql, uchar *buf); #ifdef __cplusplus } #endif #define protocol_41(A) ((A)->server_capabilities & CLIENT_PROTOCOL_41) #endif /* SQL_COMMON_INCLUDED */ server/big_endian.h000064400000010631151031265050010301 0ustar00/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Data in big-endian format. */ #define float4store(T,A) do { *(T)= ((uchar *) &A)[3];\ *((T)+1)=(char) ((uchar *) &A)[2];\ *((T)+2)=(char) ((uchar *) &A)[1];\ *((T)+3)=(char) ((uchar *) &A)[0]; } while(0) #define float4get(V,M) do { float def_temp;\ ((uchar*) &def_temp)[0]=(M)[3];\ ((uchar*) &def_temp)[1]=(M)[2];\ ((uchar*) &def_temp)[2]=(M)[1];\ ((uchar*) &def_temp)[3]=(M)[0];\ (V)=def_temp; } while(0) #define float8store(T,V) do { *(T)= ((uchar *) &V)[7];\ *((T)+1)=(char) ((uchar *) &V)[6];\ *((T)+2)=(char) ((uchar *) &V)[5];\ *((T)+3)=(char) ((uchar *) &V)[4];\ *((T)+4)=(char) ((uchar *) &V)[3];\ *((T)+5)=(char) ((uchar *) &V)[2];\ *((T)+6)=(char) ((uchar *) &V)[1];\ *((T)+7)=(char) ((uchar *) &V)[0]; } while(0) #define float8get(V,M) do { double def_temp;\ ((uchar*) &def_temp)[0]=(M)[7];\ ((uchar*) &def_temp)[1]=(M)[6];\ ((uchar*) &def_temp)[2]=(M)[5];\ ((uchar*) &def_temp)[3]=(M)[4];\ ((uchar*) &def_temp)[4]=(M)[3];\ ((uchar*) &def_temp)[5]=(M)[2];\ ((uchar*) &def_temp)[6]=(M)[1];\ ((uchar*) &def_temp)[7]=(M)[0];\ (V) = def_temp; } while(0) #define ushortget(V,M) do { V = (uint16) (((uint16) ((uchar) (M)[1]))+\ ((uint16) ((uint16) (M)[0]) << 8)); } while(0) #define shortget(V,M) do { V = (short) (((short) ((uchar) (M)[1]))+\ ((short) ((short) (M)[0]) << 8)); } while(0) #define longget(V,M) do { int32 def_temp;\ ((uchar*) &def_temp)[0]=(M)[0];\ ((uchar*) &def_temp)[1]=(M)[1];\ ((uchar*) &def_temp)[2]=(M)[2];\ ((uchar*) &def_temp)[3]=(M)[3];\ (V)=def_temp; } while(0) #define ulongget(V,M) do { uint32 def_temp;\ ((uchar*) &def_temp)[0]=(M)[0];\ ((uchar*) &def_temp)[1]=(M)[1];\ ((uchar*) &def_temp)[2]=(M)[2];\ ((uchar*) &def_temp)[3]=(M)[3];\ (V)=def_temp; } while(0) #define shortstore(T,A) do { uint def_temp=(uint) (A) ;\ *(((char*)T)+1)=(char)(def_temp); \ *(((char*)T)+0)=(char)(def_temp >> 8); } while(0) #define longstore(T,A) do { *(((char*)T)+3)=((A));\ *(((char*)T)+2)=(((A) >> 8));\ *(((char*)T)+1)=(((A) >> 16));\ *(((char*)T)+0)=(((A) >> 24)); } while(0) #define floatget(V,M) memcpy(&V, (M), sizeof(float)) /* Cast away type qualifiers (necessary as macro takes argument by value). */ #define floatstore(T,V) memcpy((T), (void*) (&V), sizeof(float)) #define doubleget(V,M) memcpy(&V, (M), sizeof(double)) /* Cast away type qualifiers (necessary as macro takes argument by value). */ #define doublestore(T,V) memcpy((T), (void*) &V, sizeof(double)) #define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong)) #define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong)) server/m_ctype.h000064400000177412151031265050007675 0ustar00/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. Copyright (c) 2009, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* A better implementation of the UNIX ctype(3) library. */ #ifndef _m_ctype_h #define _m_ctype_h #include #include enum loglevel { ERROR_LEVEL= 0, WARNING_LEVEL= 1, INFORMATION_LEVEL= 2 }; #ifdef __cplusplus extern "C" { #endif #define MY_CS_NAME_SIZE 32 #define MY_CS_CTYPE_TABLE_SIZE 257 #define MY_CS_TO_LOWER_TABLE_SIZE 256 #define MY_CS_TO_UPPER_TABLE_SIZE 256 #define MY_CS_SORT_ORDER_TABLE_SIZE 256 #define MY_CS_TO_UNI_TABLE_SIZE 256 #define CHARSET_DIR "charsets/" #define my_wc_t ulong #define MY_CS_REPLACEMENT_CHARACTER 0xFFFD /** Maximum character length of a string produced by wc_to_printable(). Note, wc_to_printable() is currently limited to BMP. One non-printable or non-convertable character can produce a string with at most 5 characters: \hhhh. If we ever modify wc_to_printable() to support supplementary characters, e.g. \+hhhhhh, this constant should be changed to 8. Note, maximum octet length of a wc_to_printable() result can be calculated as: (MY_CS_PRINTABLE_CHAR_LENGTH*cs->mbminlen). */ #define MY_CS_PRINTABLE_CHAR_LENGTH 5 /* On i386 we store Unicode->CS conversion tables for some character sets using Big-endian order, to copy two bytes at once. This gives some performance improvement. */ #ifdef __i386__ #define MB2(x) (((x) >> 8) + (((x) & 0xFF) << 8)) #define MY_PUT_MB2(s, code) { *((uint16*)(s))= (code); } #else #define MB2(x) (x) #define MY_PUT_MB2(s, code) { (s)[0]= code >> 8; (s)[1]= code & 0xFF; } #endif typedef const struct my_charset_handler_st MY_CHARSET_HANDLER; typedef const struct my_collation_handler_st MY_COLLATION_HANDLER; typedef const struct unicase_info_st MY_UNICASE_INFO; typedef const struct uni_ctype_st MY_UNI_CTYPE; typedef const struct my_uni_idx_st MY_UNI_IDX; typedef uint16 decimal_digits_t; typedef struct unicase_info_char_st { uint32 toupper; uint32 tolower; uint32 sort; } MY_UNICASE_CHARACTER; struct unicase_info_st { my_wc_t maxchar; MY_UNICASE_CHARACTER **page; }; extern MY_UNICASE_INFO my_unicase_default; extern MY_UNICASE_INFO my_unicase_turkish; extern MY_UNICASE_INFO my_unicase_mysql500; extern MY_UNICASE_INFO my_unicase_unicode520; #define MY_UCA_MAX_CONTRACTION 6 /* The DUCET tables in ctype-uca.c are dumped with a limit of 8 weights per character. cs->strxfrm_multiply is set to 8 for all UCA based collations. In language-specific UCA collations (with tailorings) we also do not allow a single character to have more than 8 weights to stay with the same strxfrm_multiply limit. Note, contractions are allowed to have twice longer weight strings (up to 16 weights). As a contraction consists of at least 2 characters, this makes sure that strxfrm_multiply ratio of 8 is respected. */ #define MY_UCA_MAX_WEIGHT_SIZE (8+1) /* Including 0 terminator */ #define MY_UCA_CONTRACTION_MAX_WEIGHT_SIZE (2*8+1) /* Including 0 terminator */ #define MY_UCA_WEIGHT_LEVELS 2 typedef struct my_contraction_t { my_wc_t ch[MY_UCA_MAX_CONTRACTION]; /* Character sequence */ uint16 weight[MY_UCA_CONTRACTION_MAX_WEIGHT_SIZE];/* Its weight string, 0-terminated */ my_bool with_context; } MY_CONTRACTION; typedef struct my_contraction_list_t { size_t nitems; /* Number of items in the list */ MY_CONTRACTION *item; /* List of contractions */ char *flags; /* Character flags, e.g. "is contraction head") */ } MY_CONTRACTIONS; my_bool my_uca_can_be_contraction_head(const MY_CONTRACTIONS *c, my_wc_t wc); my_bool my_uca_can_be_contraction_tail(const MY_CONTRACTIONS *c, my_wc_t wc); uint16 *my_uca_contraction2_weight(const MY_CONTRACTIONS *c, my_wc_t wc1, my_wc_t wc2); /* Collation weights on a single level (e.g. primary, secondary, tertiary) */ typedef struct my_uca_level_info_st { my_wc_t maxchar; uchar *lengths; uint16 **weights; MY_CONTRACTIONS contractions; uint levelno; } MY_UCA_WEIGHT_LEVEL; typedef struct uca_info_st { MY_UCA_WEIGHT_LEVEL level[MY_UCA_WEIGHT_LEVELS]; /* Logical positions */ my_wc_t first_non_ignorable; my_wc_t last_non_ignorable; my_wc_t first_primary_ignorable; my_wc_t last_primary_ignorable; my_wc_t first_secondary_ignorable; my_wc_t last_secondary_ignorable; my_wc_t first_tertiary_ignorable; my_wc_t last_tertiary_ignorable; my_wc_t first_trailing; my_wc_t last_trailing; my_wc_t first_variable; my_wc_t last_variable; } MY_UCA_INFO; extern MY_UCA_INFO my_uca_v400; struct uni_ctype_st { uchar pctype; const uchar *ctype; }; extern MY_UNI_CTYPE my_uni_ctype[256]; /* wm_wc and wc_mb return codes */ #define MY_CS_ILSEQ 0 /* Wrong by sequence: wb_wc */ #define MY_CS_ILUNI 0 /* Cannot encode Unicode to charset: wc_mb */ #define MY_CS_TOOSMALL -101 /* Need at least one byte: wc_mb and mb_wc */ #define MY_CS_TOOSMALL2 -102 /* Need at least two bytes: wc_mb and mb_wc */ #define MY_CS_TOOSMALL3 -103 /* Need at least three bytes: wc_mb and mb_wc */ /* These following three are currently not really used */ #define MY_CS_TOOSMALL4 -104 /* Need at least 4 bytes: wc_mb and mb_wc */ #define MY_CS_TOOSMALL5 -105 /* Need at least 5 bytes: wc_mb and mb_wc */ #define MY_CS_TOOSMALL6 -106 /* Need at least 6 bytes: wc_mb and mb_wc */ /* A helper macros for "need at least n bytes" */ #define MY_CS_TOOSMALLN(n) (-100-(n)) #define MY_CS_MBMAXLEN 6 /* Maximum supported mbmaxlen */ #define MY_CS_IS_TOOSMALL(rc) ((rc) >= MY_CS_TOOSMALL6 && (rc) <= MY_CS_TOOSMALL) #define MY_SEQ_INTTAIL 1 #define MY_SEQ_SPACES 2 #define MY_SEQ_NONSPACES 3 /* Skip non-space characters, including bad bytes */ /* My charsets_list flags */ #define MY_CS_COMPILED 1 /* compiled-in sets */ #define MY_CS_CONFIG 2 /* sets that have a *.conf file */ #define MY_CS_INDEX 4 /* sets listed in the Index file */ #define MY_CS_LOADED 8 /* sets that are currently loaded */ #define MY_CS_BINSORT 16 /* if binary sort order */ #define MY_CS_PRIMARY 32 /* if primary collation */ #define MY_CS_STRNXFRM 64 /* if strnxfrm is used for sort */ #define MY_CS_UNICODE 128 /* is a charset is BMP Unicode */ #define MY_CS_READY 256 /* if a charset is initialized */ #define MY_CS_AVAILABLE 512 /* If either compiled-in or loaded*/ #define MY_CS_CSSORT 1024 /* if case sensitive sort order */ #define MY_CS_HIDDEN 2048 /* don't display in SHOW */ #define MY_CS_PUREASCII 4096 /* if a charset is pure ascii */ #define MY_CS_NONASCII 8192 /* if not ASCII-compatible */ #define MY_CS_UNICODE_SUPPLEMENT 16384 /* Non-BMP Unicode characters */ #define MY_CS_LOWER_SORT 32768 /* If use lower case as weight */ #define MY_CS_STRNXFRM_BAD_NWEIGHTS 0x10000 /* strnxfrm ignores "nweights" */ #define MY_CS_NOPAD 0x20000 /* if does not ignore trailing spaces */ #define MY_CS_NON1TO1 0x40000 /* Has a complex mapping from characters to weights, e.g. contractions, expansions, ignorable characters */ #define MY_CHARSET_UNDEFINED 0 /* Character repertoire flags */ typedef enum enum_repertoire_t { MY_REPERTOIRE_NONE= 0, MY_REPERTOIRE_ASCII= 1, /* Pure ASCII U+0000..U+007F */ MY_REPERTOIRE_EXTENDED= 2, /* Extended characters: U+0080..U+FFFF */ MY_REPERTOIRE_UNICODE30= 3 /* ASCII | EXTENDED: U+0000..U+FFFF */ } my_repertoire_t; /* Flags for strxfrm */ #define MY_STRXFRM_LEVEL1 0x00000001 /* for primary weights */ #define MY_STRXFRM_LEVEL2 0x00000002 /* for secondary weights */ #define MY_STRXFRM_LEVEL3 0x00000004 /* for tertiary weights */ #define MY_STRXFRM_LEVEL4 0x00000008 /* fourth level weights */ #define MY_STRXFRM_LEVEL5 0x00000010 /* fifth level weights */ #define MY_STRXFRM_LEVEL6 0x00000020 /* sixth level weights */ #define MY_STRXFRM_LEVEL_ALL 0x0000003F /* Bit OR for the above six */ #define MY_STRXFRM_NLEVELS 6 /* Number of possible levels*/ #define MY_STRXFRM_PAD_WITH_SPACE 0x00000040 /* if pad result with spaces */ #define MY_STRXFRM_PAD_TO_MAXLEN 0x00000080 /* if pad tail(for filesort) */ #define MY_STRXFRM_DESC_LEVEL1 0x00000100 /* if desc order for level1 */ #define MY_STRXFRM_DESC_LEVEL2 0x00000200 /* if desc order for level2 */ #define MY_STRXFRM_DESC_LEVEL3 0x00000300 /* if desc order for level3 */ #define MY_STRXFRM_DESC_LEVEL4 0x00000800 /* if desc order for level4 */ #define MY_STRXFRM_DESC_LEVEL5 0x00001000 /* if desc order for level5 */ #define MY_STRXFRM_DESC_LEVEL6 0x00002000 /* if desc order for level6 */ #define MY_STRXFRM_DESC_SHIFT 8 #define MY_STRXFRM_UNUSED_00004000 0x00004000 /* for future extensions */ #define MY_STRXFRM_UNUSED_00008000 0x00008000 /* for future extensions */ #define MY_STRXFRM_REVERSE_LEVEL1 0x00010000 /* if reverse order for level1 */ #define MY_STRXFRM_REVERSE_LEVEL2 0x00020000 /* if reverse order for level2 */ #define MY_STRXFRM_REVERSE_LEVEL3 0x00040000 /* if reverse order for level3 */ #define MY_STRXFRM_REVERSE_LEVEL4 0x00080000 /* if reverse order for level4 */ #define MY_STRXFRM_REVERSE_LEVEL5 0x00100000 /* if reverse order for level5 */ #define MY_STRXFRM_REVERSE_LEVEL6 0x00200000 /* if reverse order for level6 */ #define MY_STRXFRM_REVERSE_SHIFT 16 /* Flags to strnncollsp_nchars */ /* MY_STRNNCOLLSP_NCHARS_EMULATE_TRIMMED_TRAILING_SPACES - defines if inside strnncollsp_nchars() short strings should be virtually extended to "nchars" characters by emulating trimmed trailing spaces. This flag is needed when comparing packed strings of the CHAR data type, when trailing spaces are trimmed on storage (like in InnoDB), however the actual values (after unpacking) will have those trailing spaces. If this flag is passed, strnncollsp_nchars() performs both truncating longer strings and extending shorter strings to exactly "nchars". If this flag is not passed, strnncollsp_nchars() only truncates longer strings to "nchars", but does not extend shorter strings to "nchars". */ #define MY_STRNNCOLLSP_NCHARS_EMULATE_TRIMMED_TRAILING_SPACES 1 /* Collation IDs for MariaDB that should not conflict with MySQL. We reserve 256..511, because MySQL will most likely use this range when the range 0..255 is full. We use the next 256 IDs starting from 512 and divide them into 8 chunks, 32 collations each, as follows: 512 + (0..31) for single byte collations (e.g. latin9) 512 + (32..63) reserved (e.g. for utf32le, or more single byte collations) 512 + (64..95) for utf8 512 + (96..127) for utf8mb4 512 + (128..159) for ucs2 512 + (160..192) for utf16 512 + (192..223) for utf16le 512 + (224..255) for utf32 */ #define MY_PAGE2_COLLATION_ID_8BIT 0x200 #define MY_PAGE2_COLLATION_ID_RESERVED 0x220 #define MY_PAGE2_COLLATION_ID_UTF8 0x240 #define MY_PAGE2_COLLATION_ID_UTF8MB4 0x260 #define MY_PAGE2_COLLATION_ID_UCS2 0x280 #define MY_PAGE2_COLLATION_ID_UTF16 0x2A0 #define MY_PAGE2_COLLATION_ID_UTF16LE 0x2C0 #define MY_PAGE2_COLLATION_ID_UTF32 0x2E0 struct my_uni_idx_st { uint16 from; uint16 to; const uchar *tab; }; typedef struct { uint beg; uint end; uint mb_len; } my_match_t; enum my_lex_states { MY_LEX_START, MY_LEX_CHAR, MY_LEX_IDENT, MY_LEX_IDENT_SEP, MY_LEX_IDENT_START, MY_LEX_REAL, MY_LEX_HEX_NUMBER, MY_LEX_BIN_NUMBER, MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END, MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL, MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE, MY_LEX_LONG_COMMENT, MY_LEX_END_LONG_COMMENT, MY_LEX_SEMICOLON, MY_LEX_SET_VAR, MY_LEX_USER_END, MY_LEX_HOSTNAME, MY_LEX_SKIP, MY_LEX_USER_VARIABLE_DELIMITER, MY_LEX_SYSTEM_VAR, MY_LEX_IDENT_OR_KEYWORD, MY_LEX_IDENT_OR_HEX, MY_LEX_IDENT_OR_BIN, MY_LEX_IDENT_OR_NCHAR, MY_LEX_STRING_OR_DELIMITER, MY_LEX_MINUS_OR_COMMENT, MY_LEX_PLACEHOLDER, MY_LEX_COMMA, MY_LEX_IDENT_OR_QUALIFIED_SPECIAL_FUNC }; struct charset_info_st; typedef struct my_charset_loader_st { char error[128]; void *(*once_alloc)(size_t); void *(*malloc)(size_t); void *(*realloc)(void *, size_t); void (*free)(void *); void (*reporter)(enum loglevel, const char *format, ...); int (*add_collation)(struct charset_info_st *cs); } MY_CHARSET_LOADER; extern int (*my_string_stack_guard)(int); /* See strings/CHARSET_INFO.txt for information about this structure */ struct my_collation_handler_st { my_bool (*init)(struct charset_info_st *, MY_CHARSET_LOADER *); /* Collation routines */ int (*strnncoll)(CHARSET_INFO *, const uchar *, size_t, const uchar *, size_t, my_bool); int (*strnncollsp)(CHARSET_INFO *, const uchar *, size_t, const uchar *, size_t); /* strnncollsp_nchars() - similar to strnncollsp() but assumes that both strings were originally CHAR(N) values with the same N, then were optionally space-padded, or optionally space-trimmed. In other words, this function compares in the way if we insert both values into a CHAR(N) column and then compare the two column values. It compares the same amount of characters from the two strings. This is especially important for NOPAD collations. If CHAR_LENGTH of the two strings are different, the shorter string is virtually padded with trailing spaces up to CHAR_LENGTH of the longer string, to guarantee that the same amount of characters are compared. This is important if the two CHAR(N) strings are space-trimmed (e.g. like in InnoDB compact format for CHAR). The function compares not more than "nchars" characters only. This can be useful to compare CHAR(N) space-padded strings (when the exact N is known) without having to truncate them before the comparison. For example, Field_string stores a "CHAR(3) CHARACTER SET utf8mb4" value of "aaa" as 12 bytes in a record buffer: - 3 bytes of the actual data, followed by - 9 bytes of spaces (just fillers, not real data) The caller can pass nchars=3 to compare CHAR(3) record values. In such case, the comparator won't go inside the 9 bytes of the fillers. If N is not known, the caller can pass max(len1,len2) as the "nchars" value (i.e. the maximum of the OCTET_LENGTH of the two strings). Notes on complex collations. This function counts contraction parts as individual characters. For example, the Czech letter 'ch' (in Czech collations) is ordinarily counted by the "nchars" limit as TWO characters (although it is only one letter). This corresponds to what CHAR(N) does in INSERT. If the "nchars" limit tears apart a contraction, only the part fitting into "nchars" characters is used. For example, in case of a Czech collation, the string "ach" with nchars=2 is compared as 'ac': the contraction 'ch' is torn apart and the letter 'c' acts as an individual character. This emulates the same comparison result with the scenario when we insert 'ach' into a CHAR(2) column and then compare it. */ int (*strnncollsp_nchars)(CHARSET_INFO *, const uchar *str1, size_t len1, const uchar *str2, size_t len2, size_t nchars, uint flags); size_t (*strnxfrm)(CHARSET_INFO *, uchar *dst, size_t dstlen, uint nweights, const uchar *src, size_t srclen, uint flags); size_t (*strnxfrmlen)(CHARSET_INFO *, size_t); my_bool (*like_range)(CHARSET_INFO *, const char *s, size_t s_length, pchar w_prefix, pchar w_one, pchar w_many, size_t res_length, char *min_str, char *max_str, size_t *min_len, size_t *max_len); int (*wildcmp)(CHARSET_INFO *, const char *str,const char *str_end, const char *wildstr,const char *wildend, int escape,int w_one, int w_many); int (*strcasecmp)(CHARSET_INFO *, const char *, const char *); uint (*instr)(CHARSET_INFO *, const char *b, size_t b_length, const char *s, size_t s_length, my_match_t *match, uint nmatch); /* Hash calculation */ void (*hash_sort)(CHARSET_INFO *cs, const uchar *key, size_t len, ulong *nr1, ulong *nr2); my_bool (*propagate)(CHARSET_INFO *cs, const uchar *str, size_t len); /* Make minimum and maximum strings for the collation. Put not more than "nchars" characters. */ size_t (*min_str)(CHARSET_INFO *cs, uchar *dst, size_t dstlen, size_t nchars); size_t (*max_str)(CHARSET_INFO *cs, uchar *dst, size_t dstlen, size_t nchars); }; extern MY_COLLATION_HANDLER my_collation_8bit_bin_handler; extern MY_COLLATION_HANDLER my_collation_8bit_simple_ci_handler; extern MY_COLLATION_HANDLER my_collation_8bit_nopad_bin_handler; extern MY_COLLATION_HANDLER my_collation_8bit_simple_nopad_ci_handler; /* Some typedef to make it easy for C++ to make function pointers */ typedef int (*my_charset_conv_mb_wc)(CHARSET_INFO *, my_wc_t *, const uchar *, const uchar *); typedef int (*my_charset_conv_wc_mb)(CHARSET_INFO *, my_wc_t, uchar *, uchar *); typedef size_t (*my_charset_conv_case)(CHARSET_INFO *, const char *, size_t, char *, size_t); /* A structure to return the statistics of a native string copying, when no Unicode conversion is involved. The structure is OK to be uninitialized before calling a copying routine. A copying routine must populate the structure as follows: - m_source_end_pos must be set by to a non-NULL value in the range of the input string. - m_well_formed_error_pos must be set to NULL if the string was well formed, or to the position of the leftmost bad byte sequence. */ typedef struct { const char *m_source_end_pos; /* Position where reading stopped */ const char *m_well_formed_error_pos; /* Position where a bad byte was found*/ } MY_STRCOPY_STATUS; /* A structure to return the statistics of a Unicode string conversion. */ typedef struct { const char *m_cannot_convert_error_pos; } MY_STRCONV_STATUS; /* See strings/CHARSET_INFO.txt about information on this structure */ struct my_charset_handler_st { my_bool (*init)(struct charset_info_st *, MY_CHARSET_LOADER *loader); /* Multibyte routines */ size_t (*numchars)(CHARSET_INFO *, const char *b, const char *e); size_t (*charpos)(CHARSET_INFO *, const char *b, const char *e, size_t pos); size_t (*lengthsp)(CHARSET_INFO *, const char *ptr, size_t length); size_t (*numcells)(CHARSET_INFO *, const char *b, const char *e); /* Unicode conversion */ my_charset_conv_mb_wc mb_wc; my_charset_conv_wc_mb wc_mb; /* CTYPE scanner */ int (*ctype)(CHARSET_INFO *cs, int *ctype, const uchar *s, const uchar *e); /* Functions for case and sort conversion */ size_t (*caseup_str)(CHARSET_INFO *, char *); size_t (*casedn_str)(CHARSET_INFO *, char *); my_charset_conv_case caseup; my_charset_conv_case casedn; /* Charset dependent snprintf() */ size_t (*snprintf)(CHARSET_INFO *, char *to, size_t n, const char *fmt, ...) ATTRIBUTE_FORMAT_FPTR(printf, 4, 5); size_t (*long10_to_str)(CHARSET_INFO *, char *to, size_t n, int radix, long int val); size_t (*longlong10_to_str)(CHARSET_INFO *, char *to, size_t n, int radix, longlong val); void (*fill)(CHARSET_INFO *, char *to, size_t len, int fill); /* String-to-number conversion routines */ long (*strntol)(CHARSET_INFO *, const char *s, size_t l, int base, char **e, int *err); ulong (*strntoul)(CHARSET_INFO *, const char *s, size_t l, int base, char **e, int *err); longlong (*strntoll)(CHARSET_INFO *, const char *s, size_t l, int base, char **e, int *err); ulonglong (*strntoull)(CHARSET_INFO *, const char *s, size_t l, int base, char **e, int *err); double (*strntod)(CHARSET_INFO *, char *s, size_t l, char **e, int *err); longlong (*strtoll10)(CHARSET_INFO *cs, const char *nptr, char **endptr, int *error); ulonglong (*strntoull10rnd)(CHARSET_INFO *cs, const char *str, size_t length, int unsigned_fl, char **endptr, int *error); size_t (*scan)(CHARSET_INFO *, const char *b, const char *e, int sq); /* String copying routines and helpers for them */ /* charlen() - calculate length of the left-most character in bytes. @param cs Character set @param str The beginning of the string @param end The end of the string @return MY_CS_ILSEQ if a bad byte sequence was found. @return MY_CS_TOOSMALLN(x) if the string ended unexpectedly. @return a positive number in the range 1..mbmaxlen, if a valid character was found. */ int (*charlen)(CHARSET_INFO *cs, const uchar *str, const uchar *end); /* well_formed_char_length() - returns character length of a string. @param cs Character set @param str The beginning of the string @param end The end of the string @param nchars Not more than "nchars" left-most characters are checked. @param status[OUT] Additional statistics is returned here. "status" can be uninitialized before the call, and it is fully initialized after the call. status->m_source_end_pos is set to the position where reading stopped. If a bad byte sequence is found, the function returns immediately and status->m_well_formed_error_pos is set to the position where a bad byte sequence was found. status->m_well_formed_error_pos is set to NULL if no bad bytes were found. If status->m_well_formed_error_pos is NULL after the call, that means: - either the function reached the end of the string, - or all "nchars" characters were read. The caller can check status->m_source_end_pos to detect which of these two happened. */ size_t (*well_formed_char_length)(CHARSET_INFO *cs, const char *str, const char *end, size_t nchars, MY_STRCOPY_STATUS *status); /* copy_fix() - copy a string, replace bad bytes to '?'. Not more than "nchars" characters are copied. status->m_source_end_pos is set to a position in the range between "src" and "src + src_length", where reading stopped. status->m_well_formed_error_pos is set to NULL if the string in the range "src" and "status->m_source_end_pos" was well formed, or is set to a position between "src" and "src + src_length" where the leftmost bad byte sequence was found. */ size_t (*copy_fix)(CHARSET_INFO *, char *dst, size_t dst_length, const char *src, size_t src_length, size_t nchars, MY_STRCOPY_STATUS *status); /** Write a character to the target string, using its native code. For Unicode character sets (utf8, ucs2, utf16, utf16le, utf32, filename) native codes are equivalent to Unicode code points. For 8bit character sets the native code is just the byte value. For Asian characters sets: - MB1 native code is just the byte value (e.g. on the ASCII range) - MB2 native code is ((b0 << 8) + b1). - MB3 native code is ((b0 <<16) + (b1 << 8) + b2) Note, CHARSET_INFO::min_sort_char and CHARSET_INFO::max_sort_char are defined in native notation and should be written using my_ci_native_to_mb() rather than my_ci_wc_mb(). */ my_charset_conv_wc_mb native_to_mb; my_charset_conv_wc_mb wc_to_printable; }; extern MY_CHARSET_HANDLER my_charset_8bit_handler; extern MY_CHARSET_HANDLER my_charset_ucs2_handler; extern MY_CHARSET_HANDLER my_charset_utf8mb3_handler; /* We define this CHARSET_INFO_DEFINED here to prevent a repeat of the typedef in hash.c, which will cause a compiler error. */ #define CHARSET_INFO_DEFINED /* See strings/CHARSET_INFO.txt about information on this structure */ struct charset_info_st { uint number; uint primary_number; uint binary_number; uint state; LEX_CSTRING cs_name; LEX_CSTRING coll_name; const char *comment; const char *tailoring; const uchar *m_ctype; const uchar *to_lower; const uchar *to_upper; const uchar *sort_order; MY_UCA_INFO *uca; const uint16 *tab_to_uni; MY_UNI_IDX *tab_from_uni; MY_UNICASE_INFO *caseinfo; const uchar *state_map; const uchar *ident_map; uint strxfrm_multiply; uchar caseup_multiply; uchar casedn_multiply; uint mbminlen; uint mbmaxlen; /* min_sort_char and max_sort_char represent the minimum and the maximum character in the collation respectively. For Unicode collations, these numbers are Unicode code points. For non-Unicode collations these numbers are native character codes. For example, in all 8bit collations these numbers are in the range 0x00..0xFF. min_sort_char and max_sort_char normally should not be used directly. They are used internally in the following virtual functions: - MY_COLLATION_HANDLER::like_range() - MY_COLLATION_HANDLER::min_str() - MY_COLLATION_HANDLER::max_str() */ my_wc_t min_sort_char; my_wc_t max_sort_char; uchar pad_char; my_bool escape_with_backslash_is_dangerous; uchar levels_for_order; MY_CHARSET_HANDLER *cset; MY_COLLATION_HANDLER *coll; #ifdef __cplusplus /* Character set routines */ bool use_mb() const { return mbmaxlen > 1; } size_t numchars(const char *b, const char *e) const { return (cset->numchars)(this, b, e); } size_t charpos(const char *b, const char *e, size_t pos) const { return (cset->charpos)(this, b, e, pos); } size_t charpos(const uchar *b, const uchar *e, size_t pos) const { return (cset->charpos)(this, (const char *) b, (const char*) e, pos); } size_t lengthsp(const char *str, size_t length) const { return (cset->lengthsp)(this, str, length); } size_t numcells(const char *b, const char *e) const { return (cset->numcells)(this, b, e); } size_t caseup(const char *src, size_t srclen, char *dst, size_t dstlen) const { return (cset->caseup)(this, src, srclen, dst, dstlen); } size_t casedn(const char *src, size_t srclen, char *dst, size_t dstlen) const { return (cset->casedn)(this, src, srclen, dst, dstlen); } size_t long10_to_str(char *dst, size_t dstlen, int radix, long int val) const { return (cset->long10_to_str)(this, dst, dstlen, radix, val); } size_t (longlong10_to_str)(char *dst, size_t dstlen, int radix, longlong val) const { return (cset->longlong10_to_str)(this, dst, dstlen, radix, val); } int mb_wc(my_wc_t *wc, const uchar *b, const uchar *e) const { return (cset->mb_wc)(this, wc, b, e); } int wc_mb(my_wc_t wc, uchar *s, uchar *e) const { return (cset->wc_mb)(this, wc, s, e); } int native_to_mb(my_wc_t wc, uchar *s, uchar *e) const { return (cset->native_to_mb)(this, wc, s, e); } int wc_to_printable(my_wc_t wc, uchar *s, uchar *e) const { return (cset->wc_to_printable)(this, wc, s, e); } int ctype(int *to, const uchar *s, const uchar *e) const { return (cset->ctype)(this, to, s, e); } void fill(char *to, size_t len, int ch) const { (cset->fill)(this, to, len, ch); } long strntol(const char *str, size_t length, int base, char **endptr, int *error) const { return (cset->strntol)(this, str, length, base, endptr, error); } ulong strntoul(const char *str, size_t length, int base, char **endptr, int *error) const { return (cset->strntoul)(this, str, length, base, endptr, error); } longlong strntoll(const char *str, size_t length, int base, char **endptr, int *error) const { return (cset->strntoll)(this, str, length, base, endptr, error); } ulonglong strntoull(const char *str, size_t length, int base, char **endptr, int *error) const { return (cset->strntoull)(this, str, length, base, endptr, error); } double strntod(char *str, size_t length, char **endptr, int *error) const { return (cset->strntod)(this, str, length, endptr, error); } longlong strtoll10(const char *str, char **endptr, int *error) const { return (cset->strtoll10)(this, str, endptr, error); } ulonglong strntoull10rnd(const char *str, size_t length, int unsigned_fl, char **endptr, int *error) const { return (cset->strntoull10rnd)(this, str, length, unsigned_fl, endptr, error); } size_t scan(const char *b, const char *e, int seq) const { return (cset->scan)(this, b, e, seq); } int charlen(const uchar *str, const uchar *end) const { return (cset->charlen)(this, str, end); } int charlen(const char *str, const char *end) const { return (cset->charlen)(this, (const uchar *) str, (const uchar *) end); } uint charlen_fix(const uchar *str, const uchar *end) const { int char_length= (cset->charlen)(this, str, end); DBUG_ASSERT(str < end); return char_length > 0 ? (uint) char_length : (uint) 1U; } uint charlen_fix(const char *str, const char *end) const { return charlen_fix((const uchar *) str, (const uchar *) end); } size_t well_formed_char_length(const char *str, const char *end, size_t nchars, MY_STRCOPY_STATUS *status) const { return (cset->well_formed_char_length)(this, str, end, nchars, status); } size_t copy_fix(char *dst, size_t dst_length, const char *src, size_t src_length, size_t nchars, MY_STRCOPY_STATUS *status) const { return (cset->copy_fix)(this, dst, dst_length, src, src_length, nchars, status); } /* Collation routines */ int strnncoll(const uchar *a, size_t alen, const uchar *b, size_t blen, my_bool b_is_prefix= FALSE) const { return (coll->strnncoll)(this, a, alen, b, blen, b_is_prefix); } int strnncoll(const char *a, size_t alen, const char *b, size_t blen, my_bool b_is_prefix= FALSE) const { return (coll->strnncoll)(this, (const uchar *) a, alen, (const uchar *) b, blen, b_is_prefix); } int strnncollsp(const uchar *a, size_t alen, const uchar *b, size_t blen) const { return (coll->strnncollsp)(this, a, alen, b, blen); } int strnncollsp(const char *a, size_t alen, const char *b, size_t blen) const { return (coll->strnncollsp)(this, (uchar *) a, alen, (uchar *) b, blen); } int strnncollsp(const LEX_CSTRING &a, const LEX_CSTRING &b) const { return (coll->strnncollsp)(this, (uchar *) a.str, a.length, (uchar *) b.str, b.length); } size_t strnxfrm(char *dst, size_t dstlen, uint nweights, const char *src, size_t srclen, uint flags) const { return (coll->strnxfrm)(this, (uchar *) dst, dstlen, nweights, (const uchar *) src, srclen, flags); } size_t strnxfrm(uchar *dst, size_t dstlen, uint nweights, const uchar *src, size_t srclen, uint flags) const { return (coll->strnxfrm)(this, dst, dstlen, nweights, src, srclen, flags); } size_t strnxfrm(uchar *dst, size_t dstlen, const uchar *src, size_t srclen) const { return (coll->strnxfrm)(this, dst, dstlen, (uint) dstlen, src, srclen, MY_STRXFRM_PAD_WITH_SPACE); } size_t strnxfrmlen(size_t length) const { return (coll->strnxfrmlen)(this, length); } my_bool like_range(const char *s, size_t s_length, pchar w_prefix, pchar w_one, pchar w_many, size_t res_length, char *min_str, char *max_str, size_t *min_len, size_t *max_len) const { return (coll->like_range)(this, s, s_length, w_prefix, w_one, w_many, res_length, min_str, max_str, min_len, max_len); } int wildcmp(const char *str,const char *str_end, const char *wildstr,const char *wildend, int escape,int w_one, int w_many) const { return (coll->wildcmp)(this, str, str_end, wildstr, wildend, escape, w_one, w_many); } uint instr(const char *b, size_t b_length, const char *s, size_t s_length, my_match_t *match, uint nmatch) const { return (coll->instr)(this, b, b_length, s, s_length, match, nmatch); } void hash_sort(const uchar *key, size_t len, ulong *nr1, ulong *nr2) const { (coll->hash_sort)(this, key, len, nr1, nr2); } my_bool propagate(const uchar *str, size_t len) const { return (coll->propagate)(this, str, len); } size_t min_str(uchar *dst, size_t dstlen, size_t nchars) const { return (coll->min_str)(this, dst, dstlen, nchars); } size_t max_str(uchar *dst, size_t dstlen, size_t nchars) const { return (coll->max_str)(this, dst, dstlen, nchars); } #endif /* __cplusplus */ }; /* Character set routines */ static inline my_bool my_ci_init_charset(struct charset_info_st *ci, MY_CHARSET_LOADER *loader) { if (!ci->cset->init) return FALSE; return (ci->cset->init)(ci, loader); } static inline my_bool my_ci_use_mb(CHARSET_INFO *ci) { return ci->mbmaxlen > 1 ? TRUE : FALSE; } static inline size_t my_ci_numchars(CHARSET_INFO *cs, const char *b, const char *e) { return (cs->cset->numchars)(cs, b, e); } static inline size_t my_ci_charpos(CHARSET_INFO *cs, const char *b, const char *e, size_t pos) { return (cs->cset->charpos)(cs, b, e, pos); } static inline size_t my_ci_lengthsp(CHARSET_INFO *cs, const char *str, size_t length) { return (cs->cset->lengthsp)(cs, str, length); } static inline size_t my_ci_numcells(CHARSET_INFO *cs, const char *b, const char *e) { return (cs->cset->numcells)(cs, b, e); } static inline size_t my_ci_caseup(CHARSET_INFO *ci, const char *src, size_t srclen, char *dst, size_t dstlen) { return (ci->cset->caseup)(ci, src, srclen, dst, dstlen); } static inline size_t my_ci_casedn(CHARSET_INFO *ci, const char *src, size_t srclen, char *dst, size_t dstlen) { return (ci->cset->casedn)(ci, src, srclen, dst, dstlen); } static inline size_t my_ci_long10_to_str(CHARSET_INFO *cs, char *dst, size_t dstlen, int radix, long int val) { return (cs->cset->long10_to_str)(cs, dst, dstlen, radix, val); } static inline size_t my_ci_longlong10_to_str(CHARSET_INFO *cs, char *dst, size_t dstlen, int radix, longlong val) { return (cs->cset->longlong10_to_str)(cs, dst, dstlen, radix, val); } #define my_ci_mb_wc(s, pwc, b, e) ((s)->cset->mb_wc)(s, pwc, b, e) #define my_ci_wc_mb(s, wc, b, e) ((s)->cset->wc_mb)(s, wc, b, e) #define my_ci_native_to_mb(s, wc, b, e) ((s)->cset->native_to_mb)(s, wc, b, e) #define my_ci_ctype(s, pctype, b, e) ((s)->cset->ctype)(s, pctype, b, e) static inline void my_ci_fill(CHARSET_INFO *cs, char *to, size_t len, int ch) { (cs->cset->fill)(cs, to, len, ch); } static inline long my_ci_strntol(CHARSET_INFO *cs, const char *str, size_t length, int base, char **endptr, int *error) { return (cs->cset->strntol)(cs, str, length, base, endptr, error); } static inline ulong my_ci_strntoul(CHARSET_INFO *cs, const char *str, size_t length, int base, char **endptr, int *error) { return (cs->cset->strntoul)(cs, str, length, base, endptr, error); } static inline longlong my_ci_strntoll(CHARSET_INFO *cs, const char *str, size_t length, int base, char **endptr, int *error) { return (cs->cset->strntoll)(cs, str, length, base, endptr, error); } static inline ulonglong my_ci_strntoull(CHARSET_INFO *cs, const char *str, size_t length, int base, char **endptr, int *error) { return (cs->cset->strntoull)(cs, str, length, base, endptr, error); } static inline double my_ci_strntod(CHARSET_INFO *cs, char *str, size_t length, char **endptr, int *error) { return (cs->cset->strntod)(cs, str, length, endptr, error); } static inline longlong my_ci_strtoll10(CHARSET_INFO *cs, const char *str, char **endptr, int *error) { return (cs->cset->strtoll10)(cs, str, endptr, error); } static inline ulonglong my_ci_strntoull10rnd(CHARSET_INFO *cs, const char *str, size_t length, int unsigned_fl, char **endptr, int *error) { return (cs->cset->strntoull10rnd)(cs, str, length, unsigned_fl, endptr, error); } static inline size_t my_ci_scan(CHARSET_INFO *cs, const char *b, const char *e, int seq) { return (cs->cset->scan)(cs, b, e, seq); } /** Return length of the leftmost character in a string. @param cs - character set @param str - the beginning of the string @param end - the string end (the next byte after the string) @return <=0 on errors (EOL, wrong byte sequence) @return 1 on a single byte character @return >1 on a multi-byte character Note, inlike my_ismbchar(), 1 is returned for a single byte character. */ static inline int my_ci_charlen(CHARSET_INFO *cs, const uchar *str, const uchar *end) { return (cs->cset->charlen)(cs, str, end); } static inline size_t my_ci_well_formed_char_length(CHARSET_INFO *cs, const char *str, const char *end, size_t nchars, MY_STRCOPY_STATUS *status) { return (cs->cset->well_formed_char_length)(cs, str, end, nchars, status); } static inline size_t my_ci_copy_fix(CHARSET_INFO *cs, char *dst, size_t dst_length, const char *src, size_t src_length, size_t nchars, MY_STRCOPY_STATUS *status) { return (cs->cset->copy_fix)(cs, dst, dst_length, src, src_length, nchars, status); } /* Collation routines */ static inline my_bool my_ci_init_collation(struct charset_info_st *ci, MY_CHARSET_LOADER *loader) { if (!ci->coll->init) return FALSE; return (ci->coll->init)(ci, loader); } static inline int my_ci_strnncoll(CHARSET_INFO *ci, const uchar *a, size_t alen, const uchar *b, size_t blen, my_bool b_is_prefix) { return (ci->coll->strnncoll)(ci, a, alen, b, blen, b_is_prefix); } static inline int my_ci_strnncollsp(CHARSET_INFO *ci, const uchar *a, size_t alen, const uchar *b, size_t blen) { return (ci->coll->strnncollsp)(ci, a, alen, b, blen); } static inline my_bool my_ci_like_range(CHARSET_INFO *ci, const char *s, size_t s_length, pchar w_prefix, pchar w_one, pchar w_many, size_t res_length, char *min_str, char *max_str, size_t *min_len, size_t *max_len) { return (ci->coll->like_range)(ci, s, s_length, w_prefix, w_one, w_many, res_length, min_str, max_str, min_len, max_len); } static inline uint my_ci_instr(CHARSET_INFO *ci, const char *b, size_t b_length, const char *s, size_t s_length, my_match_t *match, uint nmatch) { return (ci->coll->instr)(ci, b, b_length, s, s_length, match, nmatch); } static inline void my_ci_hash_sort(CHARSET_INFO *ci, const uchar *key, size_t len, ulong *nr1, ulong *nr2) { (ci->coll->hash_sort)(ci, key, len, nr1, nr2); } #define ILLEGAL_CHARSET_INFO_NUMBER (~0U) extern MYSQL_PLUGIN_IMPORT struct charset_info_st my_charset_bin; extern MYSQL_PLUGIN_IMPORT struct charset_info_st my_charset_latin1; extern MYSQL_PLUGIN_IMPORT struct charset_info_st my_charset_latin1_nopad; extern MYSQL_PLUGIN_IMPORT struct charset_info_st my_charset_filename; extern MYSQL_PLUGIN_IMPORT struct charset_info_st my_charset_utf8mb3_general_ci; extern struct charset_info_st my_charset_big5_bin; extern struct charset_info_st my_charset_big5_chinese_ci; extern struct charset_info_st my_charset_big5_nopad_bin; extern struct charset_info_st my_charset_big5_chinese_nopad_ci; extern struct charset_info_st my_charset_cp1250_czech_cs; extern struct charset_info_st my_charset_cp932_bin; extern struct charset_info_st my_charset_cp932_japanese_ci; extern struct charset_info_st my_charset_cp932_nopad_bin; extern struct charset_info_st my_charset_cp932_japanese_nopad_ci; extern struct charset_info_st my_charset_eucjpms_bin; extern struct charset_info_st my_charset_eucjpms_japanese_ci; extern struct charset_info_st my_charset_eucjpms_nopad_bin; extern struct charset_info_st my_charset_eucjpms_japanese_nopad_ci; extern struct charset_info_st my_charset_euckr_bin; extern struct charset_info_st my_charset_euckr_korean_ci; extern struct charset_info_st my_charset_euckr_nopad_bin; extern struct charset_info_st my_charset_euckr_korean_nopad_ci; extern struct charset_info_st my_charset_gb2312_bin; extern struct charset_info_st my_charset_gb2312_chinese_ci; extern struct charset_info_st my_charset_gb2312_nopad_bin; extern struct charset_info_st my_charset_gb2312_chinese_nopad_ci; extern struct charset_info_st my_charset_gbk_bin; extern struct charset_info_st my_charset_gbk_chinese_ci; extern struct charset_info_st my_charset_gbk_nopad_bin; extern struct charset_info_st my_charset_gbk_chinese_nopad_ci; extern struct charset_info_st my_charset_latin1_bin; extern struct charset_info_st my_charset_latin1_nopad_bin; extern struct charset_info_st my_charset_latin1_german2_ci; extern struct charset_info_st my_charset_latin2_czech_cs; extern struct charset_info_st my_charset_sjis_bin; extern struct charset_info_st my_charset_sjis_japanese_ci; extern struct charset_info_st my_charset_sjis_nopad_bin; extern struct charset_info_st my_charset_sjis_japanese_nopad_ci; extern struct charset_info_st my_charset_tis620_bin; extern struct charset_info_st my_charset_tis620_thai_ci; extern struct charset_info_st my_charset_tis620_nopad_bin; extern struct charset_info_st my_charset_tis620_thai_nopad_ci; extern struct charset_info_st my_charset_ucs2_bin; extern struct charset_info_st my_charset_ucs2_general_ci; extern struct charset_info_st my_charset_ucs2_nopad_bin; extern struct charset_info_st my_charset_ucs2_general_nopad_ci; extern struct charset_info_st my_charset_ucs2_general_mysql500_ci; extern struct charset_info_st my_charset_ucs2_unicode_ci; extern struct charset_info_st my_charset_ucs2_unicode_nopad_ci; extern struct charset_info_st my_charset_ucs2_general_mysql500_ci; extern struct charset_info_st my_charset_ujis_bin; extern struct charset_info_st my_charset_ujis_japanese_ci; extern struct charset_info_st my_charset_ujis_nopad_bin; extern struct charset_info_st my_charset_ujis_japanese_nopad_ci; extern struct charset_info_st my_charset_utf16_bin; extern struct charset_info_st my_charset_utf16_general_ci; extern struct charset_info_st my_charset_utf16_unicode_ci; extern struct charset_info_st my_charset_utf16_unicode_nopad_ci; extern struct charset_info_st my_charset_utf16le_bin; extern struct charset_info_st my_charset_utf16le_general_ci; extern struct charset_info_st my_charset_utf16_general_nopad_ci; extern struct charset_info_st my_charset_utf16_nopad_bin; extern struct charset_info_st my_charset_utf16le_nopad_bin; extern struct charset_info_st my_charset_utf16le_general_nopad_ci; extern struct charset_info_st my_charset_utf32_bin; extern struct charset_info_st my_charset_utf32_general_ci; extern struct charset_info_st my_charset_utf32_unicode_ci; extern struct charset_info_st my_charset_utf32_unicode_nopad_ci; extern struct charset_info_st my_charset_utf32_nopad_bin; extern struct charset_info_st my_charset_utf32_general_nopad_ci; extern MYSQL_PLUGIN_IMPORT struct charset_info_st my_charset_utf8mb3_bin; extern struct charset_info_st my_charset_utf8mb3_nopad_bin; extern struct charset_info_st my_charset_utf8mb3_general_nopad_ci; extern struct charset_info_st my_charset_utf8mb3_general_mysql500_ci; extern struct charset_info_st my_charset_utf8mb3_unicode_ci; extern struct charset_info_st my_charset_utf8mb3_unicode_nopad_ci; extern MYSQL_PLUGIN_IMPORT struct charset_info_st my_charset_utf8mb4_bin; extern struct charset_info_st my_charset_utf8mb4_general_ci; extern struct charset_info_st my_charset_utf8mb4_nopad_bin; extern struct charset_info_st my_charset_utf8mb4_general_nopad_ci; extern struct charset_info_st my_charset_utf8mb4_unicode_ci; extern struct charset_info_st my_charset_utf8mb4_unicode_nopad_ci; #define MY_UTF8MB3 "utf8mb3" #define MY_UTF8MB4 "utf8mb4" my_bool my_cs_have_contractions(CHARSET_INFO *cs); my_bool my_cs_can_be_contraction_head(CHARSET_INFO *cs, my_wc_t wc); my_bool my_cs_can_be_contraction_tail(CHARSET_INFO *cs, my_wc_t wc); const uint16 *my_cs_contraction2_weight(CHARSET_INFO *cs, my_wc_t wc1, my_wc_t wc2); /* declarations for simple charsets */ extern size_t my_strnxfrm_simple(CHARSET_INFO *, uchar *dst, size_t dstlen, uint nweights, const uchar *src, size_t srclen, uint flags); size_t my_strnxfrmlen_simple(CHARSET_INFO *, size_t); extern int my_strnncoll_simple(CHARSET_INFO *, const uchar *, size_t, const uchar *, size_t, my_bool); extern int my_strnncollsp_simple(CHARSET_INFO *, const uchar *, size_t, const uchar *, size_t); extern void my_hash_sort_simple(CHARSET_INFO *cs, const uchar *key, size_t len, ulong *nr1, ulong *nr2); extern void my_hash_sort_simple_nopad(CHARSET_INFO *cs, const uchar *key, size_t len, ulong *nr1, ulong *nr2); extern void my_hash_sort_bin(CHARSET_INFO *cs, const uchar *key, size_t len, ulong *nr1, ulong *nr2); /** Compare a string to an array of spaces, for PAD SPACE comparison. The function iterates through the string and compares every byte to 0x20. @param - the string @param - its length @return <0 - if a byte less than 0x20 was found in the string. @return 0 - if all bytes in the string were 0x20, or if length was 0. @return >0 - if a byte greater than 0x20 was found in the string. */ extern int my_strnncollsp_padspace_bin(const uchar *str, size_t length); extern size_t my_lengthsp_8bit(CHARSET_INFO *cs, const char *ptr, size_t length); extern uint my_instr_simple(CHARSET_INFO *, const char *b, size_t b_length, const char *s, size_t s_length, my_match_t *match, uint nmatch); size_t my_copy_8bit(CHARSET_INFO *, char *dst, size_t dst_length, const char *src, size_t src_length, size_t nchars, MY_STRCOPY_STATUS *); size_t my_copy_fix_mb(CHARSET_INFO *cs, char *dst, size_t dst_length, const char *src, size_t src_length, size_t nchars, MY_STRCOPY_STATUS *); /* Functions for 8bit */ extern size_t my_caseup_str_8bit(CHARSET_INFO *, char *); extern size_t my_casedn_str_8bit(CHARSET_INFO *, char *); extern size_t my_caseup_8bit(CHARSET_INFO *, const char *src, size_t srclen, char *dst, size_t dstlen); extern size_t my_casedn_8bit(CHARSET_INFO *, const char *src, size_t srclen, char *dst, size_t dstlen); extern int my_strcasecmp_8bit(CHARSET_INFO * cs, const char *, const char *); int my_mb_wc_8bit(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e); int my_wc_mb_8bit(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e); int my_wc_mb_bin(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e); int my_mb_ctype_8bit(CHARSET_INFO *,int *, const uchar *,const uchar *); int my_mb_ctype_mb(CHARSET_INFO *,int *, const uchar *,const uchar *); size_t my_scan_8bit(CHARSET_INFO *cs, const char *b, const char *e, int sq); size_t my_snprintf_8bit(CHARSET_INFO *, char *to, size_t n, const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 4, 5); long my_strntol_8bit(CHARSET_INFO *, const char *s, size_t l, int base, char **e, int *err); ulong my_strntoul_8bit(CHARSET_INFO *, const char *s, size_t l, int base, char **e, int *err); longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, size_t l, int base, char **e, int *err); ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, size_t l, int base, char **e, int *err); double my_strntod_8bit(CHARSET_INFO *, char *s, size_t l,char **e, int *err); size_t my_long10_to_str_8bit(CHARSET_INFO *, char *to, size_t l, int radix, long int val); size_t my_longlong10_to_str_8bit(CHARSET_INFO *, char *to, size_t l, int radix, longlong val); longlong my_strtoll10_8bit(CHARSET_INFO *cs, const char *nptr, char **endptr, int *error); longlong my_strtoll10_ucs2(CHARSET_INFO *cs, const char *nptr, char **endptr, int *error); ulonglong my_strntoull10rnd_8bit(CHARSET_INFO *cs, const char *str, size_t length, int unsigned_fl, char **endptr, int *error); ulonglong my_strntoull10rnd_ucs2(CHARSET_INFO *cs, const char *str, size_t length, int unsigned_fl, char **endptr, int *error); void my_fill_8bit(CHARSET_INFO *cs, char* to, size_t l, int fill); /* For 8-bit character set */ my_bool my_like_range_simple(CHARSET_INFO *cs, const char *ptr, size_t ptr_length, pbool escape, pbool w_one, pbool w_many, size_t res_length, char *min_str, char *max_str, size_t *min_length, size_t *max_length); /* For ASCII-based multi-byte character sets with mbminlen=1 */ my_bool my_like_range_mb(CHARSET_INFO *cs, const char *ptr, size_t ptr_length, pbool escape, pbool w_one, pbool w_many, size_t res_length, char *min_str, char *max_str, size_t *min_length, size_t *max_length); /* For other character sets, with arbitrary mbminlen and mbmaxlen numbers */ my_bool my_like_range_generic(CHARSET_INFO *cs, const char *ptr, size_t ptr_length, pbool escape, pbool w_one, pbool w_many, size_t res_length, char *min_str, char *max_str, size_t *min_length, size_t *max_length); int my_wildcmp_8bit(CHARSET_INFO *, const char *str,const char *str_end, const char *wildstr,const char *wildend, int escape, int w_one, int w_many); int my_wildcmp_bin(CHARSET_INFO *, const char *str,const char *str_end, const char *wildstr,const char *wildend, int escape, int w_one, int w_many); size_t my_numchars_8bit(CHARSET_INFO *, const char *b, const char *e); size_t my_numcells_8bit(CHARSET_INFO *, const char *b, const char *e); size_t my_charpos_8bit(CHARSET_INFO *, const char *b, const char *e, size_t pos); size_t my_well_formed_char_length_8bit(CHARSET_INFO *cs, const char *b, const char *e, size_t nchars, MY_STRCOPY_STATUS *status); int my_charlen_8bit(CHARSET_INFO *, const uchar *str, const uchar *end); /* Functions for multibyte charsets */ extern size_t my_caseup_str_mb(CHARSET_INFO *, char *); extern size_t my_casedn_str_mb(CHARSET_INFO *, char *); extern size_t my_caseup_mb(CHARSET_INFO *, const char *src, size_t srclen, char *dst, size_t dstlen); extern size_t my_casedn_mb(CHARSET_INFO *, const char *src, size_t srclen, char *dst, size_t dstlen); extern size_t my_caseup_ujis(CHARSET_INFO *, const char *src, size_t srclen, char *dst, size_t dstlen); extern size_t my_casedn_ujis(CHARSET_INFO *, const char *src, size_t srclen, char *dst, size_t dstlen); extern int my_strcasecmp_mb(CHARSET_INFO * cs,const char *, const char *); int my_wildcmp_mb(CHARSET_INFO *, const char *str,const char *str_end, const char *wildstr,const char *wildend, int escape, int w_one, int w_many); size_t my_numchars_mb(CHARSET_INFO *, const char *b, const char *e); size_t my_numcells_mb(CHARSET_INFO *, const char *b, const char *e); size_t my_charpos_mb(CHARSET_INFO *, const char *b, const char *e, size_t pos); uint my_instr_mb(CHARSET_INFO *, const char *b, size_t b_length, const char *s, size_t s_length, my_match_t *match, uint nmatch); int my_wildcmp_mb_bin(CHARSET_INFO *cs, const char *str,const char *str_end, const char *wildstr,const char *wildend, int escape, int w_one, int w_many); int my_strcasecmp_mb_bin(CHARSET_INFO * cs __attribute__((unused)), const char *s, const char *t); void my_hash_sort_mb_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *key, size_t len,ulong *nr1, ulong *nr2); void my_hash_sort_mb_nopad_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *key, size_t len, ulong *nr1, ulong *nr2); size_t my_strnxfrm_mb(CHARSET_INFO *, uchar *dst, size_t dstlen, uint nweights, const uchar *src, size_t srclen, uint flags); size_t my_strnxfrm_mb_nopad(CHARSET_INFO *, uchar *dst, size_t dstlen, uint nweights, const uchar *src, size_t srclen, uint flags); size_t my_strnxfrmlen_unicode(CHARSET_INFO *, size_t); size_t my_strnxfrm_unicode_full_bin(CHARSET_INFO *, uchar *dst, size_t dstlen, uint nweights, const uchar *src, size_t srclen, uint flags); size_t my_strnxfrm_unicode_full_nopad_bin(CHARSET_INFO *, uchar *dst, size_t dstlen, uint nweights, const uchar *src, size_t srclen, uint flags); size_t my_strnxfrmlen_unicode_full_bin(CHARSET_INFO *, size_t); int my_wildcmp_unicode(CHARSET_INFO *cs, const char *str, const char *str_end, const char *wildstr, const char *wildend, int escape, int w_one, int w_many, MY_UNICASE_INFO *weights); extern my_bool my_parse_charset_xml(MY_CHARSET_LOADER *loader, const char *buf, size_t buflen); extern char *my_strchr(CHARSET_INFO *cs, const char *str, const char *end, pchar c); extern size_t my_strcspn(CHARSET_INFO *cs, const char *str, const char *end, const char *accept); my_bool my_propagate_simple(CHARSET_INFO *cs, const uchar *str, size_t len); my_bool my_propagate_complex(CHARSET_INFO *cs, const uchar *str, size_t len); typedef struct { size_t char_length; my_repertoire_t repertoire; } MY_STRING_METADATA; void my_string_metadata_get(MY_STRING_METADATA *metadata, CHARSET_INFO *cs, const char *str, size_t len); my_repertoire_t my_string_repertoire(CHARSET_INFO *cs, const char *str, size_t len); my_bool my_charset_is_ascii_based(CHARSET_INFO *cs); my_repertoire_t my_charset_repertoire(CHARSET_INFO *cs); uint my_strxfrm_flag_normalize(uint flags, uint nlevels); void my_strxfrm_desc_and_reverse(uchar *str, uchar *strend, uint flags, uint level); size_t my_strxfrm_pad_desc_and_reverse(CHARSET_INFO *cs, uchar *str, uchar *frmend, uchar *strend, uint nweights, uint flags, uint level); size_t my_strxfrm_pad_desc_and_reverse_nopad(CHARSET_INFO *cs, uchar *str, uchar *frmend, uchar *strend, uint nweights, uint flags, uint level); const MY_CONTRACTIONS *my_charset_get_contractions(CHARSET_INFO *cs, int level); extern size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n, const char* fmt, va_list ap); /* Convert a string between two character sets. Bad byte sequences as well as characters that cannot be encoded in the destination character set are replaced to '?'. */ uint32 my_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, const char *from, uint32 from_length, CHARSET_INFO *from_cs, uint *errors); /** An extended version of my_convert(), to pass non-default mb_wc() and wc_mb(). For example, String::copy_printable() which is used in Protocol::store_warning() uses this to escape control and non-convertible characters. */ uint32 my_convert_using_func(char *to, size_t to_length, CHARSET_INFO *to_cs, my_charset_conv_wc_mb mb_wc, const char *from, size_t from_length, CHARSET_INFO *from_cs, my_charset_conv_mb_wc wc_mb, uint *errors); /* Convert a string between two character sets. Bad byte sequences as well as characters that cannot be encoded in the destination character set are replaced to '?'. Not more than "nchars" characters are copied. Conversion statistics is returned in "status" and is set as follows: - status->m_native_copy_status.m_source_end_pos - to the position between (src) and (src+src_length), where the function stopped reading the source string. - status->m_native_copy_status.m_well_formed_error_pos - to the position between (src) and (src+src_length), where the first badly formed byte sequence was found, or to NULL if the string was well formed in the given range. - status->m_cannot_convert_error_pos - to the position between (src) and (src+src_length), where the first character that cannot be represented in the destination character set was found, or to NULL if all characters in the given range were successfully converted. "src" is allowed to be a NULL pointer. In this case "src_length" must be equal to 0. All "status" members are initialized to NULL, and 0 is returned. */ size_t my_convert_fix(CHARSET_INFO *dstcs, char *dst, size_t dst_length, CHARSET_INFO *srccs, const char *src, size_t src_length, size_t nchars, MY_STRCOPY_STATUS *copy_status, MY_STRCONV_STATUS *conv_status); #define _MY_U 01 /* Upper case */ #define _MY_L 02 /* Lower case */ #define _MY_NMR 04 /* Numeral (digit) */ #define _MY_SPC 010 /* Spacing character */ #define _MY_PNT 020 /* Punctuation */ #define _MY_CTR 040 /* Control character */ #define _MY_B 0100 /* Blank */ #define _MY_X 0200 /* heXadecimal digit */ #define my_isascii(c) (!((c) & ~0177)) #define my_toascii(c) ((c) & 0177) #define my_tocntrl(c) ((c) & 31) #define my_toprint(c) ((c) | 64) #define my_toupper(s,c) (char) ((s)->to_upper[(uchar) (c)]) #define my_tolower(s,c) (char) ((s)->to_lower[(uchar) (c)]) #define my_isalpha(s, c) (((s)->m_ctype+1)[(uchar) (c)] & (_MY_U | _MY_L)) #define my_isupper(s, c) (((s)->m_ctype+1)[(uchar) (c)] & _MY_U) #define my_islower(s, c) (((s)->m_ctype+1)[(uchar) (c)] & _MY_L) #define my_isdigit(s, c) (((s)->m_ctype+1)[(uchar) (c)] & _MY_NMR) #define my_isxdigit(s, c) (((s)->m_ctype+1)[(uchar) (c)] & _MY_X) #define my_isalnum(s, c) (((s)->m_ctype+1)[(uchar) (c)] & (_MY_U | _MY_L | _MY_NMR)) #define my_isspace(s, c) (((s)->m_ctype+1)[(uchar) (c)] & _MY_SPC) #define my_ispunct(s, c) (((s)->m_ctype+1)[(uchar) (c)] & _MY_PNT) #define my_isprint(s, c) (((s)->m_ctype+1)[(uchar) (c)] & (_MY_PNT | _MY_U | _MY_L | _MY_NMR | _MY_B)) #define my_isgraph(s, c) (((s)->m_ctype+1)[(uchar) (c)] & (_MY_PNT | _MY_U | _MY_L | _MY_NMR)) #define my_iscntrl(s, c) (((s)->m_ctype+1)[(uchar) (c)] & _MY_CTR) /* Some macros that should be cleaned up a little */ #define my_isvar(s,c) (my_isalnum(s,c) || (c) == '_') #define my_isvar_start(s,c) (my_isalpha(s,c) || (c) == '_') #define my_binary_compare(s) ((s)->state & MY_CS_BINSORT) #define use_strnxfrm(s) ((s)->state & MY_CS_STRNXFRM) #define my_strnncoll(s, a, b, c, d) ((s)->coll->strnncoll((s), (a), (b), (c), (d), 0)) #define my_strcasecmp(s, a, b) ((s)->coll->strcasecmp((s), (a), (b))) /** Detect if the leftmost character in a string is a valid multi-byte character and return its length, or return 0 otherwise. @param cs - character set @param str - the beginning of the string @param end - the string end (the next byte after the string) @return >0, for a multi-byte character @return 0, for a single byte character, broken sequence, empty string. */ static inline uint my_ismbchar(CHARSET_INFO *cs, const char *str, const char *end) { int char_length= (cs->cset->charlen)(cs, (const uchar *) str, (const uchar *) end); return char_length > 1 ? (uint) char_length : 0U; } /** Convert broken and incomplete byte sequences to 1 byte. */ static inline uint my_ci_charlen_fix(CHARSET_INFO *cs, const uchar *str, const uchar *end) { int char_length= my_ci_charlen(cs, str, end); DBUG_ASSERT(str < end); return char_length > 0 ? (uint) char_length : (uint) 1U; } /* A compatibility replacement pure C function for the former cs->cset->well_formed_len(). In C++ code please use Well_formed_prefix::length() instead. */ static inline size_t my_well_formed_length(CHARSET_INFO *cs, const char *b, const char *e, size_t nchars, int *error) { MY_STRCOPY_STATUS status; (void) my_ci_well_formed_char_length(cs, b, e, nchars, &status); *error= status.m_well_formed_error_pos == NULL ? 0 : 1; return (size_t) (status.m_source_end_pos - b); } #define my_caseup_str(s, a) ((s)->cset->caseup_str((s), (a))) #define my_casedn_str(s, a) ((s)->cset->casedn_str((s), (a))) /* XXX: still need to take care of this one */ #ifdef MY_CHARSET_TIS620 #error The TIS620 charset is broken at the moment. Tell tim to fix it. #define USE_TIS620 #include "t_ctype.h" #endif int my_wc_mb_utf8mb4_bmp_only(CHARSET_INFO *cs, my_wc_t wc, uchar *r, uchar *e); #ifdef __cplusplus } #endif #endif /* _m_ctype_h */ server/mysql_embed.h000064400000002144151031265050010523 0ustar00#ifndef MYSQL_EMBED_INCLUDED #define MYSQL_EMBED_INCLUDED /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Defines that are unique to the embedded version of MySQL */ #ifdef EMBEDDED_LIBRARY /* Things we don't need in the embedded version of MySQL */ /* TODO HF add #undef HAVE_VIO if we don't want client in embedded library */ #undef HAVE_DLOPEN /* No udf functions */ #endif /* EMBEDDED_LIBRARY */ #endif /* MYSQL_EMBED_INCLUDED */ server/keycache.h000064400000021173151031265050010001 0ustar00/* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Key cache variable structures */ #ifndef _keycache_h #define _keycache_h #include "my_sys.h" /* flush_type */ C_MODE_START /* Currently the default key cache is created as non-partitioned at the start of the server unless the server is started with the parameter --key-cache-partitions that is greater than 0 */ #define DEFAULT_KEY_CACHE_PARTITIONS 0 /* MAX_KEY_CACHE_PARTITIONS cannot be greater than sizeof(MYISAM_SHARE::dirty_part_map) Currently sizeof(MYISAM_SHARE::dirty_part_map)=sizeof(ulonglong) */ #define MAX_KEY_CACHE_PARTITIONS 64 /* The structure to get statistical data about a key cache */ typedef struct st_key_cache_statistics { ulonglong mem_size; /* memory for cache buffers/auxiliary structures */ ulonglong block_size; /* size of the each buffers in the key cache */ ulonglong blocks_used; /* maximum number of used blocks/buffers */ ulonglong blocks_unused; /* number of currently unused blocks */ ulonglong blocks_changed; /* number of currently dirty blocks */ ulonglong blocks_warm; /* number of blocks in warm sub-chain */ ulonglong read_requests; /* number of read requests (read hits) */ ulonglong reads; /* number of actual reads from files into buffers */ ulonglong write_requests; /* number of write requests (write hits) */ ulonglong writes; /* number of actual writes from buffers into files */ } KEY_CACHE_STATISTICS; #define NUM_LONG_KEY_CACHE_STAT_VARIABLES 3 /* The type of a key cache object */ typedef enum key_cache_type { SIMPLE_KEY_CACHE, PARTITIONED_KEY_CACHE } KEY_CACHE_TYPE; typedef int (*INIT_KEY_CACHE) (void *, uint key_cache_block_size, size_t use_mem, uint division_limit, uint age_threshold, uint changed_blocks_hash_size); typedef int (*RESIZE_KEY_CACHE) (void *, uint key_cache_block_size, size_t use_mem, uint division_limit, uint age_threshold, uint changed_blocks_hash_size); typedef void (*CHANGE_KEY_CACHE_PARAM) (void *keycache_cb, uint division_limit, uint age_threshold); typedef uchar* (*KEY_CACHE_READ) (void *keycache_cb, File file, my_off_t filepos, int level, uchar *buff, uint length, uint block_length, int return_buffer); typedef int (*KEY_CACHE_INSERT) (void *keycache_cb, File file, my_off_t filepos, int level, uchar *buff, uint length); typedef int (*KEY_CACHE_WRITE) (void *keycache_cb, File file, void *file_extra, my_off_t filepos, int level, uchar *buff, uint length, uint block_length, int force_write); typedef int (*FLUSH_KEY_BLOCKS) (void *keycache_cb, int file, void *file_extra, enum flush_type type); typedef int (*RESET_KEY_CACHE_COUNTERS) (const char *name, void *keycache_cb); typedef void (*END_KEY_CACHE) (void *keycache_cb, my_bool cleanup); typedef void (*GET_KEY_CACHE_STATISTICS) (void *keycache_cb, uint partition_no, KEY_CACHE_STATISTICS *key_cache_stats); /* An object of the type KEY_CACHE_FUNCS contains pointers to all functions from the key cache interface. Currently a key cache can be of two types: simple and partitioned. For each of them its own static structure of the type KEY_CACHE_FUNCS is defined . The structures contain the pointers to the implementations of the interface functions used by simple key caches and partitioned key caches respectively. Pointers to these structures are assigned to key cache objects at the time of their creation. */ typedef struct st_key_cache_funcs { INIT_KEY_CACHE init; RESIZE_KEY_CACHE resize; CHANGE_KEY_CACHE_PARAM change_param; KEY_CACHE_READ read; KEY_CACHE_INSERT insert; KEY_CACHE_WRITE write; FLUSH_KEY_BLOCKS flush; RESET_KEY_CACHE_COUNTERS reset_counters; END_KEY_CACHE end; GET_KEY_CACHE_STATISTICS get_stats; } KEY_CACHE_FUNCS; typedef struct st_key_cache { KEY_CACHE_TYPE key_cache_type; /* type of the key cache used for debugging */ void *keycache_cb; /* control block of the used key cache */ KEY_CACHE_FUNCS *interface_funcs; /* interface functions of the key cache */ ulonglong param_buff_size; /* size the memory allocated for the cache */ ulonglong param_block_size; /* size of the blocks in the key cache */ ulonglong param_division_limit;/* min. percentage of warm blocks */ ulonglong param_age_threshold; /* determines when hot block is downgraded */ ulonglong param_partitions; /* number of the key cache partitions */ ulonglong changed_blocks_hash_size; /* number of hash buckets for changed files */ my_bool key_cache_inited; /* <=> key cache has been created */ my_bool can_be_used; /* usage of cache for read/write is allowed */ my_bool in_init; /* set to 1 in MySQL during init/resize */ uint partitions; /* actual number of partitions */ size_t key_cache_mem_size; /* specified size of the cache memory */ pthread_mutex_t op_lock; /* to serialize operations like 'resize' */ } KEY_CACHE; /* The default key cache */ extern KEY_CACHE dflt_key_cache_var, *dflt_key_cache; extern int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, size_t use_mem, uint division_limit, uint age_threshold, uint changed_blocks_hash_size, uint partitions); extern int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, size_t use_mem, uint division_limit, uint age_threshold, uint changed_blocks_hash_size); extern void change_key_cache_param(KEY_CACHE *keycache, uint division_limit, uint age_threshold); extern uchar *key_cache_read(KEY_CACHE *keycache, File file, my_off_t filepos, int level, uchar *buff, uint length, uint block_length,int return_buffer); extern int key_cache_insert(KEY_CACHE *keycache, File file, my_off_t filepos, int level, uchar *buff, uint length); extern int key_cache_write(KEY_CACHE *keycache, File file, void *file_extra, my_off_t filepos, int level, uchar *buff, uint length, uint block_length, int force_write); extern int flush_key_blocks(KEY_CACHE *keycache, int file, void *file_extra, enum flush_type type); extern void end_key_cache(KEY_CACHE *keycache, my_bool cleanup); extern void get_key_cache_statistics(KEY_CACHE *keycache, uint partition_no, KEY_CACHE_STATISTICS *key_cache_stats); /* Functions to handle multiple key caches */ extern my_bool multi_keycache_init(void); extern void multi_keycache_free(void); extern KEY_CACHE *multi_key_cache_search(uchar *key, uint length, KEY_CACHE *def); extern my_bool multi_key_cache_set(const uchar *key, uint length, KEY_CACHE *key_cache); extern void multi_key_cache_change(KEY_CACHE *old_data, KEY_CACHE *new_data); extern int reset_key_cache_counters(const char *name, KEY_CACHE *key_cache, void *); extern int repartition_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, size_t use_mem, uint division_limit, uint age_threshold, uint changed_blocks_hash_size, uint partitions); C_MODE_END #endif /* _keycache_h */ server/mysqld_ername.h000064400000371032151031265050011067 0ustar00/* Autogenerated file, please don't edit */ { "ER_HASHCHK", 1000, "hashchk" }, { "ER_NISAMCHK", 1001, "isamchk" }, { "ER_NO", 1002, "NO" }, { "ER_YES", 1003, "YES" }, { "ER_CANT_CREATE_FILE", 1004, "Can\'t create file \'%-.200s\' (errno: %M)" }, { "ER_CANT_CREATE_TABLE", 1005, "Can\'t create table %`s.%`s (errno: %M)" }, { "ER_CANT_CREATE_DB", 1006, "Can\'t create database \'%-.192s\' (errno: %M)" }, { "ER_DB_CREATE_EXISTS", 1007, "Can\'t create database \'%-.192s\'; database exists" }, { "ER_DB_DROP_EXISTS", 1008, "Can\'t drop database \'%-.192s\'; database doesn\'t exist" }, { "ER_DB_DROP_DELETE", 1009, "Error dropping database (can\'t delete \'%-.192s\', errno: %M)" }, { "ER_DB_DROP_RMDIR", 1010, "Error dropping database (can\'t rmdir \'%-.192s\', errno: %M)" }, { "ER_CANT_DELETE_FILE", 1011, "Error on delete of \'%-.192s\' (errno: %M)" }, { "ER_CANT_FIND_SYSTEM_REC", 1012, "Can\'t read record in system table" }, { "ER_CANT_GET_STAT", 1013, "Can\'t get status of \'%-.200s\' (errno: %M)" }, { "ER_CANT_GET_WD", 1014, "Can\'t get working directory (errno: %M)" }, { "ER_CANT_LOCK", 1015, "Can\'t lock file (errno: %M)" }, { "ER_CANT_OPEN_FILE", 1016, "Can\'t open file: \'%-.200s\' (errno: %M)" }, { "ER_FILE_NOT_FOUND", 1017, "Can\'t find file: \'%-.200s\' (errno: %M)" }, { "ER_CANT_READ_DIR", 1018, "Can\'t read dir of \'%-.192s\' (errno: %M)" }, { "ER_CANT_SET_WD", 1019, "Can\'t change dir to \'%-.192s\' (errno: %M)" }, { "ER_CHECKREAD", 1020, "Record has changed since last read in table \'%-.192s\'" }, { "ER_DISK_FULL", 1021, "Disk full (%s); waiting for someone to free some space... (errno: %M)" }, { "ER_DUP_KEY", 1022, "Can\'t write; duplicate key in table \'%-.192s\'" }, { "ER_ERROR_ON_CLOSE", 1023, "Error on close of \'%-.192s\' (errno: %M)" }, { "ER_ERROR_ON_READ", 1024, "Error reading file \'%-.200s\' (errno: %M)" }, { "ER_ERROR_ON_RENAME", 1025, "Error on rename of \'%-.210s\' to \'%-.210s\' (errno: %M)" }, { "ER_ERROR_ON_WRITE", 1026, "Error writing file \'%-.200s\' (errno: %M)" }, { "ER_FILE_USED", 1027, "\'%-.192s\' is locked against change" }, { "ER_FILSORT_ABORT", 1028, "Sort aborted" }, { "ER_FORM_NOT_FOUND", 1029, "View \'%-.192s\' doesn\'t exist for \'%-.192s\'" }, { "ER_GET_ERRNO", 1030, "Got error %M from storage engine %s" }, { "ER_ILLEGAL_HA", 1031, "Storage engine %s of the table %`s.%`s doesn\'t have this option" }, { "ER_KEY_NOT_FOUND", 1032, "Can\'t find record in \'%-.192s\'" }, { "ER_NOT_FORM_FILE", 1033, "Incorrect information in file: \'%-.200s\'" }, { "ER_NOT_KEYFILE", 1034, "Index for table \'%-.200s\' is corrupt; try to repair it" }, { "ER_OLD_KEYFILE", 1035, "Old key file for table \'%-.192s\'; repair it!" }, { "ER_OPEN_AS_READONLY", 1036, "Table \'%-.192s\' is read only" }, { "ER_OUTOFMEMORY", 1037, "Out of memory; restart server and try again (needed %d bytes)" }, { "ER_OUT_OF_SORTMEMORY", 1038, "Out of sort memory, consider increasing server sort buffer size" }, { "ER_UNEXPECTED_EOF", 1039, "Unexpected EOF found when reading file \'%-.192s\' (errno: %M)" }, { "ER_CON_COUNT_ERROR", 1040, "Too many connections" }, { "ER_OUT_OF_RESOURCES", 1041, "Out of memory." }, { "ER_BAD_HOST_ERROR", 1042, "Can\'t get hostname for your address" }, { "ER_HANDSHAKE_ERROR", 1043, "Bad handshake" }, { "ER_DBACCESS_DENIED_ERROR", 1044, "Access denied for user \'%s\'@\'%s\' to database \'%-.192s\'" }, { "ER_ACCESS_DENIED_ERROR", 1045, "Access denied for user \'%s\'@\'%s\' (using password: %s)" }, { "ER_NO_DB_ERROR", 1046, "No database selected" }, { "ER_UNKNOWN_COM_ERROR", 1047, "Unknown command" }, { "ER_BAD_NULL_ERROR", 1048, "Column \'%-.192s\' cannot be null" }, { "ER_BAD_DB_ERROR", 1049, "Unknown database \'%-.192s\'" }, { "ER_TABLE_EXISTS_ERROR", 1050, "Table \'%-.192s\' already exists" }, { "ER_BAD_TABLE_ERROR", 1051, "Unknown table \'%-.100T\'" }, { "ER_NON_UNIQ_ERROR", 1052, "Column \'%-.192s\' in %-.192s is ambiguous" }, { "ER_SERVER_SHUTDOWN", 1053, "Server shutdown in progress" }, { "ER_BAD_FIELD_ERROR", 1054, "Unknown column \'%-.192s\' in \'%-.192s\'" }, { "ER_WRONG_FIELD_WITH_GROUP", 1055, "\'%-.192s\' isn\'t in GROUP BY" }, { "ER_WRONG_GROUP_FIELD", 1056, "Can\'t group on \'%-.192s\'" }, { "ER_WRONG_SUM_SELECT", 1057, "Statement has sum functions and columns in same statement" }, { "ER_WRONG_VALUE_COUNT", 1058, "Column count doesn\'t match value count" }, { "ER_TOO_LONG_IDENT", 1059, "Identifier name \'%-.100T\' is too long" }, { "ER_DUP_FIELDNAME", 1060, "Duplicate column name \'%-.192s\'" }, { "ER_DUP_KEYNAME", 1061, "Duplicate key name \'%-.192s\'" }, { "ER_DUP_ENTRY", 1062, "Duplicate entry \'%-.192T\' for key %d" }, { "ER_WRONG_FIELD_SPEC", 1063, "Incorrect column specifier for column \'%-.192s\'" }, { "ER_PARSE_ERROR", 1064, "%s near \'%-.80T\' at line %d" }, { "ER_EMPTY_QUERY", 1065, "Query was empty" }, { "ER_NONUNIQ_TABLE", 1066, "Not unique table/alias: \'%-.192s\'" }, { "ER_INVALID_DEFAULT", 1067, "Invalid default value for \'%-.192s\'" }, { "ER_MULTIPLE_PRI_KEY", 1068, "Multiple primary key defined" }, { "ER_TOO_MANY_KEYS", 1069, "Too many keys specified; max %d keys allowed" }, { "ER_TOO_MANY_KEY_PARTS", 1070, "Too many key parts specified; max %d parts allowed" }, { "ER_TOO_LONG_KEY", 1071, "Specified key was too long; max key length is %d bytes" }, { "ER_KEY_COLUMN_DOES_NOT_EXITS", 1072, "Key column \'%-.192s\' doesn\'t exist in table" }, { "ER_BLOB_USED_AS_KEY", 1073, "BLOB column %`s can\'t be used in key specification in the %s table" }, { "ER_TOO_BIG_FIELDLENGTH", 1074, "Column length too big for column \'%-.192s\' (max = %lu); use BLOB or TEXT instead" }, { "ER_WRONG_AUTO_KEY", 1075, "Incorrect table definition; there can be only one auto column and it must be defined as a key" }, { "ER_BINLOG_CANT_DELETE_GTID_DOMAIN", 1076, "Could not delete gtid domain. Reason: %s." }, { "ER_NORMAL_SHUTDOWN", 1077, "%s (initiated by: %s): Normal shutdown" }, { "ER_GOT_SIGNAL", 1078, "%s: Got signal %d. Aborting!" }, { "ER_SHUTDOWN_COMPLETE", 1079, "%s: Shutdown complete" }, { "ER_FORCING_CLOSE", 1080, "%s: Forcing close of thread %ld user: \'%-.48s\'" }, { "ER_IPSOCK_ERROR", 1081, "Can\'t create IP socket" }, { "ER_NO_SUCH_INDEX", 1082, "Table \'%-.192s\' has no index like the one used in CREATE INDEX; recreate the table" }, { "ER_WRONG_FIELD_TERMINATORS", 1083, "Field separator argument is not what is expected; check the manual" }, { "ER_BLOBS_AND_NO_TERMINATED", 1084, "You can\'t use fixed rowlength with BLOBs; please use \'fields terminated by\'" }, { "ER_TEXTFILE_NOT_READABLE", 1085, "The file \'%-.128s\' must be in the database directory or be readable by all" }, { "ER_FILE_EXISTS_ERROR", 1086, "File \'%-.200s\' already exists" }, { "ER_LOAD_INFO", 1087, "Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld" }, { "ER_ALTER_INFO", 1088, "Records: %ld Duplicates: %ld" }, { "ER_WRONG_SUB_KEY", 1089, "Incorrect prefix key; the used key part isn\'t a string, the used length is longer than the key part, or the storage engine doesn\'t support unique prefix keys" }, { "ER_CANT_REMOVE_ALL_FIELDS", 1090, "You can\'t delete all columns with ALTER TABLE; use DROP TABLE instead" }, { "ER_CANT_DROP_FIELD_OR_KEY", 1091, "Can\'t DROP %s %`-.192s; check that it exists" }, { "ER_INSERT_INFO", 1092, "Records: %ld Duplicates: %ld Warnings: %ld" }, { "ER_UPDATE_TABLE_USED", 1093, "Table \'%-.192s\' is specified twice, both as a target for \'%s\' and as a separate source for data" }, { "ER_NO_SUCH_THREAD", 1094, "Unknown thread id: %lu" }, { "ER_KILL_DENIED_ERROR", 1095, "You are not owner of thread %lld" }, { "ER_NO_TABLES_USED", 1096, "No tables used" }, { "ER_TOO_BIG_SET", 1097, "Too many strings for column %-.192s and SET" }, { "ER_NO_UNIQUE_LOGFILE", 1098, "Can\'t generate a unique log-filename %-.200s.(1-999)" }, { "ER_TABLE_NOT_LOCKED_FOR_WRITE", 1099, "Table \'%-.192s\' was locked with a READ lock and can\'t be updated" }, { "ER_TABLE_NOT_LOCKED", 1100, "Table \'%-.192s\' was not locked with LOCK TABLES" }, { "ER_UNUSED_17", 1101, "You should never see it" }, { "ER_WRONG_DB_NAME", 1102, "Incorrect database name \'%-.100T\'" }, { "ER_WRONG_TABLE_NAME", 1103, "Incorrect table name \'%-.100s\'" }, { "ER_TOO_BIG_SELECT", 1104, "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay" }, { "ER_UNKNOWN_ERROR", 1105, "Unknown error" }, { "ER_UNKNOWN_PROCEDURE", 1106, "Unknown procedure \'%-.192s\'" }, { "ER_WRONG_PARAMCOUNT_TO_PROCEDURE", 1107, "Incorrect parameter count to procedure \'%-.192s\'" }, { "ER_WRONG_PARAMETERS_TO_PROCEDURE", 1108, "Incorrect parameters to procedure \'%-.192s\'" }, { "ER_UNKNOWN_TABLE", 1109, "Unknown table \'%-.192s\' in %-.32s" }, { "ER_FIELD_SPECIFIED_TWICE", 1110, "Column \'%-.192s\' specified twice" }, { "ER_INVALID_GROUP_FUNC_USE", 1111, "Invalid use of group function" }, { "ER_UNSUPPORTED_EXTENSION", 1112, "Table \'%-.192s\' uses an extension that doesn\'t exist in this MariaDB version" }, { "ER_TABLE_MUST_HAVE_COLUMNS", 1113, "A table must have at least 1 column" }, { "ER_RECORD_FILE_FULL", 1114, "The table \'%-.192s\' is full" }, { "ER_UNKNOWN_CHARACTER_SET", 1115, "Unknown character set: \'%-.64s\'" }, { "ER_TOO_MANY_TABLES", 1116, "Too many tables; MariaDB can only use %d tables in a join" }, { "ER_TOO_MANY_FIELDS", 1117, "Too many columns" }, { "ER_TOO_BIG_ROWSIZE", 1118, "Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs" }, { "ER_STACK_OVERRUN", 1119, "Thread stack overrun: Used: %ld of a %ld stack. Use \'mariadbd --thread_stack=#\' to specify a bigger stack if needed" }, { "ER_WRONG_OUTER_JOIN", 1120, "Cross dependency found in OUTER JOIN; examine your ON conditions" }, { "ER_NULL_COLUMN_IN_INDEX", 1121, "Table handler doesn\'t support NULL in given index. Please change column \'%-.192s\' to be NOT NULL or use another handler" }, { "ER_CANT_FIND_UDF", 1122, "Can\'t load function \'%-.192s\'" }, { "ER_CANT_INITIALIZE_UDF", 1123, "Can\'t initialize function \'%-.192s\'; %-.80s" }, { "ER_UDF_NO_PATHS", 1124, "No paths allowed for shared library" }, { "ER_UDF_EXISTS", 1125, "Function \'%-.192s\' already exists" }, { "ER_CANT_OPEN_LIBRARY", 1126, "Can\'t open shared library \'%-.192s\' (errno: %d, %-.128s)" }, { "ER_CANT_FIND_DL_ENTRY", 1127, "Can\'t find symbol \'%-.128s\' in library" }, { "ER_FUNCTION_NOT_DEFINED", 1128, "Function \'%-.192s\' is not defined" }, { "ER_HOST_IS_BLOCKED", 1129, "Host \'%-.64s\' is blocked because of many connection errors; unblock with \'mariadb-admin flush-hosts\'" }, { "ER_HOST_NOT_PRIVILEGED", 1130, "Host \'%-.64s\' is not allowed to connect to this MariaDB server" }, { "ER_PASSWORD_ANONYMOUS_USER", 1131, "You are using MariaDB as an anonymous user and anonymous users are not allowed to modify user settings" }, { "ER_PASSWORD_NOT_ALLOWED", 1132, "You must have privileges to update tables in the mysql database to be able to change passwords for others" }, { "ER_PASSWORD_NO_MATCH", 1133, "Can\'t find any matching row in the user table" }, { "ER_UPDATE_INFO", 1134, "Rows matched: %ld Changed: %ld Warnings: %ld" }, { "ER_CANT_CREATE_THREAD", 1135, "Can\'t create a new thread (errno %M); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug" }, { "ER_WRONG_VALUE_COUNT_ON_ROW", 1136, "Column count doesn\'t match value count at row %lu" }, { "ER_CANT_REOPEN_TABLE", 1137, "Can\'t reopen table: \'%-.192s\'" }, { "ER_INVALID_USE_OF_NULL", 1138, "Invalid use of NULL value" }, { "ER_REGEXP_ERROR", 1139, "Regex error \'%s\'" }, { "ER_MIX_OF_GROUP_FUNC_AND_FIELDS", 1140, "Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause" }, { "ER_NONEXISTING_GRANT", 1141, "There is no such grant defined for user \'%-.48s\' on host \'%-.64s\'" }, { "ER_TABLEACCESS_DENIED_ERROR", 1142, "%-.100T command denied to user \'%s\'@\'%s\' for table %`s.%`s" }, { "ER_COLUMNACCESS_DENIED_ERROR", 1143, "%-.32s command denied to user \'%s\'@\'%s\' for column \'%-.192s\' in table \'%-.192s\'" }, { "ER_ILLEGAL_GRANT_FOR_TABLE", 1144, "Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used" }, { "ER_GRANT_WRONG_HOST_OR_USER", 1145, "The host or user argument to GRANT is too long" }, { "ER_NO_SUCH_TABLE", 1146, "Table \'%-.192s.%-.192s\' doesn\'t exist" }, { "ER_NONEXISTING_TABLE_GRANT", 1147, "There is no such grant defined for user \'%-.48s\' on host \'%-.64s\' on table \'%-.192s\'" }, { "ER_NOT_ALLOWED_COMMAND", 1148, "The used command is not allowed with this MariaDB version" }, { "ER_SYNTAX_ERROR", 1149, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use" }, { "ER_DELAYED_CANT_CHANGE_LOCK", 1150, "Delayed insert thread couldn\'t get requested lock for table %-.192s" }, { "ER_TOO_MANY_DELAYED_THREADS", 1151, "Too many delayed threads in use" }, { "ER_ABORTING_CONNECTION", 1152, "Aborted connection %ld to db: \'%-.192s\' user: \'%-.48s\' (%-.64s)" }, { "ER_NET_PACKET_TOO_LARGE", 1153, "Got a packet bigger than \'max_allowed_packet\' bytes" }, { "ER_NET_READ_ERROR_FROM_PIPE", 1154, "Got a read error from the connection pipe" }, { "ER_NET_FCNTL_ERROR", 1155, "Got an error from fcntl()" }, { "ER_NET_PACKETS_OUT_OF_ORDER", 1156, "Got packets out of order" }, { "ER_NET_UNCOMPRESS_ERROR", 1157, "Couldn\'t uncompress communication packet" }, { "ER_NET_READ_ERROR", 1158, "Got an error reading communication packets" }, { "ER_NET_READ_INTERRUPTED", 1159, "Got timeout reading communication packets" }, { "ER_NET_ERROR_ON_WRITE", 1160, "Got an error writing communication packets" }, { "ER_NET_WRITE_INTERRUPTED", 1161, "Got timeout writing communication packets" }, { "ER_TOO_LONG_STRING", 1162, "Result string is longer than \'max_allowed_packet\' bytes" }, { "ER_TABLE_CANT_HANDLE_BLOB", 1163, "Storage engine %s doesn\'t support BLOB/TEXT columns" }, { "ER_TABLE_CANT_HANDLE_AUTO_INCREMENT", 1164, "Storage engine %s doesn\'t support AUTO_INCREMENT columns" }, { "ER_DELAYED_INSERT_TABLE_LOCKED", 1165, "INSERT DELAYED can\'t be used with table \'%-.192s\' because it is locked with LOCK TABLES" }, { "ER_WRONG_COLUMN_NAME", 1166, "Incorrect column name \'%-.100s\'" }, { "ER_WRONG_KEY_COLUMN", 1167, "The storage engine %s can\'t index column %`s" }, { "ER_WRONG_MRG_TABLE", 1168, "Unable to open underlying table which is differently defined or of non-MyISAM type or doesn\'t exist" }, { "ER_DUP_UNIQUE", 1169, "Can\'t write, because of unique constraint, to table \'%-.192s\'" }, { "ER_BLOB_KEY_WITHOUT_LENGTH", 1170, "BLOB/TEXT column \'%-.192s\' used in key specification without a key length" }, { "ER_PRIMARY_CANT_HAVE_NULL", 1171, "All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead" }, { "ER_TOO_MANY_ROWS", 1172, "Result consisted of more than one row" }, { "ER_REQUIRES_PRIMARY_KEY", 1173, "This table type requires a primary key" }, { "ER_NO_RAID_COMPILED", 1174, "This version of MariaDB is not compiled with RAID support" }, { "ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE", 1175, "You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column" }, { "ER_KEY_DOES_NOT_EXISTS", 1176, "Key \'%-.192s\' doesn\'t exist in table \'%-.192s\'" }, { "ER_CHECK_NO_SUCH_TABLE", 1177, "Can\'t open table" }, { "ER_CHECK_NOT_IMPLEMENTED", 1178, "The storage engine for the table doesn\'t support %s" }, { "ER_CANT_DO_THIS_DURING_AN_TRANSACTION", 1179, "You are not allowed to execute this command in a transaction" }, { "ER_ERROR_DURING_COMMIT", 1180, "Got error %M during COMMIT" }, { "ER_ERROR_DURING_ROLLBACK", 1181, "Got error %M during ROLLBACK" }, { "ER_ERROR_DURING_FLUSH_LOGS", 1182, "Got error %M during FLUSH_LOGS" }, { "ER_ERROR_DURING_CHECKPOINT", 1183, "Got error %M during CHECKPOINT" }, { "ER_NEW_ABORTING_CONNECTION", 1184, "Aborted connection %lld to db: \'%-.192s\' user: \'%-.48s\' host: \'%-.64s\'%-.64s (%-.64s)" }, { "ER_UNUSED_10", 1185, "You should never see it" }, { "ER_FLUSH_MASTER_BINLOG_CLOSED", 1186, "Binlog closed, cannot RESET MASTER" }, { "ER_INDEX_REBUILD", 1187, "Failed rebuilding the index of dumped table \'%-.192s\'" }, { "ER_MASTER", 1188, "Error from master: \'%-.64s\'" }, { "ER_MASTER_NET_READ", 1189, "Net error reading from master" }, { "ER_MASTER_NET_WRITE", 1190, "Net error writing to master" }, { "ER_FT_MATCHING_KEY_NOT_FOUND", 1191, "Can\'t find FULLTEXT index matching the column list" }, { "ER_LOCK_OR_ACTIVE_TRANSACTION", 1192, "Can\'t execute the given command because you have active locked tables or an active transaction" }, { "ER_UNKNOWN_SYSTEM_VARIABLE", 1193, "Unknown system variable \'%-.*s\'" }, { "ER_CRASHED_ON_USAGE", 1194, "Table \'%-.192s\' is marked as crashed and should be repaired" }, { "ER_CRASHED_ON_REPAIR", 1195, "Table \'%-.192s\' is marked as crashed and last (automatic?) repair failed" }, { "ER_WARNING_NOT_COMPLETE_ROLLBACK", 1196, "Some non-transactional changed tables couldn\'t be rolled back" }, { "ER_TRANS_CACHE_FULL", 1197, "Multi-statement transaction required more than \'max_binlog_cache_size\' bytes of storage; increase this mariadbd variable and try again" }, { "ER_SLAVE_MUST_STOP", 1198, "This operation cannot be performed as you have a running slave \'%2$*1$s\'; run STOP SLAVE \'%2$*1$s\' first" }, { "ER_SLAVE_NOT_RUNNING", 1199, "This operation requires a running slave; configure slave and do START SLAVE" }, { "ER_BAD_SLAVE", 1200, "The server is not configured as slave; fix in config file or with CHANGE MASTER TO" }, { "ER_MASTER_INFO", 1201, "Could not initialize master info structure for \'%.*s\'; more error messages can be found in the MariaDB error log" }, { "ER_SLAVE_THREAD", 1202, "Could not create slave thread; check system resources" }, { "ER_TOO_MANY_USER_CONNECTIONS", 1203, "User %-.64s already has more than \'max_user_connections\' active connections" }, { "ER_SET_CONSTANTS_ONLY", 1204, "You may only use constant expressions in this statement" }, { "ER_LOCK_WAIT_TIMEOUT", 1205, "Lock wait timeout exceeded; try restarting transaction" }, { "ER_LOCK_TABLE_FULL", 1206, "The total number of locks exceeds the lock table size" }, { "ER_READ_ONLY_TRANSACTION", 1207, "Update locks cannot be acquired during a READ UNCOMMITTED transaction" }, { "ER_DROP_DB_WITH_READ_LOCK", 1208, "DROP DATABASE not allowed while thread is holding global read lock" }, { "ER_CREATE_DB_WITH_READ_LOCK", 1209, "CREATE DATABASE not allowed while thread is holding global read lock" }, { "ER_WRONG_ARGUMENTS", 1210, "Incorrect arguments to %s" }, { "ER_NO_PERMISSION_TO_CREATE_USER", 1211, "\'%s\'@\'%s\' is not allowed to create new users" }, { "ER_UNION_TABLES_IN_DIFFERENT_DIR", 1212, "Incorrect table definition; all MERGE tables must be in the same database" }, { "ER_LOCK_DEADLOCK", 1213, "Deadlock found when trying to get lock; try restarting transaction" }, { "ER_TABLE_CANT_HANDLE_FT", 1214, "The storage engine %s doesn\'t support FULLTEXT indexes" }, { "ER_CANNOT_ADD_FOREIGN", 1215, "Cannot add foreign key constraint for `%s`" }, { "ER_NO_REFERENCED_ROW", 1216, "Cannot add or update a child row: a foreign key constraint fails" }, { "ER_ROW_IS_REFERENCED", 1217, "Cannot delete or update a parent row: a foreign key constraint fails" }, { "ER_CONNECT_TO_MASTER", 1218, "Error connecting to master: %-.128s" }, { "ER_QUERY_ON_MASTER", 1219, "Error running query on master: %-.128s" }, { "ER_ERROR_WHEN_EXECUTING_COMMAND", 1220, "Error when executing command %s: %-.128s" }, { "ER_WRONG_USAGE", 1221, "Incorrect usage of %s and %s" }, { "ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT", 1222, "The used SELECT statements have a different number of columns" }, { "ER_CANT_UPDATE_WITH_READLOCK", 1223, "Can\'t execute the query because you have a conflicting read lock" }, { "ER_MIXING_NOT_ALLOWED", 1224, "Mixing of transactional and non-transactional tables is disabled" }, { "ER_DUP_ARGUMENT", 1225, "Option \'%s\' used twice in statement" }, { "ER_USER_LIMIT_REACHED", 1226, "User \'%-.64s\' has exceeded the \'%s\' resource (current value: %ld)" }, { "ER_SPECIFIC_ACCESS_DENIED_ERROR", 1227, "Access denied; you need (at least one of) the %-.128s privilege(s) for this operation" }, { "ER_LOCAL_VARIABLE", 1228, "Variable \'%-.64s\' is a SESSION variable and can\'t be used with SET GLOBAL" }, { "ER_GLOBAL_VARIABLE", 1229, "Variable \'%-.64s\' is a GLOBAL variable and should be set with SET GLOBAL" }, { "ER_NO_DEFAULT", 1230, "Variable \'%-.64s\' doesn\'t have a default value" }, { "ER_WRONG_VALUE_FOR_VAR", 1231, "Variable \'%-.64s\' can\'t be set to the value of \'%-.200T\'" }, { "ER_WRONG_TYPE_FOR_VAR", 1232, "Incorrect argument type to variable \'%-.64s\'" }, { "ER_VAR_CANT_BE_READ", 1233, "Variable \'%-.64s\' can only be set, not read" }, { "ER_CANT_USE_OPTION_HERE", 1234, "Incorrect usage/placement of \'%s\'" }, { "ER_NOT_SUPPORTED_YET", 1235, "This version of MariaDB doesn\'t yet support \'%s\'" }, { "ER_MASTER_FATAL_ERROR_READING_BINLOG", 1236, "Got fatal error %d from master when reading data from binary log: \'%-.320s\'" }, { "ER_SLAVE_IGNORED_TABLE", 1237, "Slave SQL thread ignored the query because of replicate-*-table rules" }, { "ER_INCORRECT_GLOBAL_LOCAL_VAR", 1238, "Variable \'%-.192s\' is a %s variable" }, { "ER_WRONG_FK_DEF", 1239, "Incorrect foreign key definition for \'%-.192s\': %s" }, { "ER_KEY_REF_DO_NOT_MATCH_TABLE_REF", 1240, "Key reference and table reference don\'t match" }, { "ER_OPERAND_COLUMNS", 1241, "Operand should contain %d column(s)" }, { "ER_SUBQUERY_NO_1_ROW", 1242, "Subquery returns more than 1 row" }, { "ER_UNKNOWN_STMT_HANDLER", 1243, "Unknown prepared statement handler (%.*s) given to %s" }, { "ER_CORRUPT_HELP_DB", 1244, "Help database is corrupt or does not exist" }, { "ER_CYCLIC_REFERENCE", 1245, "Cyclic reference on subqueries" }, { "ER_AUTO_CONVERT", 1246, "Converting column \'%s\' from %s to %s" }, { "ER_ILLEGAL_REFERENCE", 1247, "Reference \'%-.64s\' not supported (%s)" }, { "ER_DERIVED_MUST_HAVE_ALIAS", 1248, "Every derived table must have its own alias" }, { "ER_SELECT_REDUCED", 1249, "Select %u was reduced during optimization" }, { "ER_TABLENAME_NOT_ALLOWED_HERE", 1250, "Table \'%-.192s\' from one of the SELECTs cannot be used in %-.32s" }, { "ER_NOT_SUPPORTED_AUTH_MODE", 1251, "Client does not support authentication protocol requested by server; consider upgrading MariaDB client" }, { "ER_SPATIAL_CANT_HAVE_NULL", 1252, "All parts of a SPATIAL index must be NOT NULL" }, { "ER_COLLATION_CHARSET_MISMATCH", 1253, "COLLATION \'%s\' is not valid for CHARACTER SET \'%s\'" }, { "ER_SLAVE_WAS_RUNNING", 1254, "Slave is already running" }, { "ER_SLAVE_WAS_NOT_RUNNING", 1255, "Slave already has been stopped" }, { "ER_TOO_BIG_FOR_UNCOMPRESS", 1256, "Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)" }, { "ER_ZLIB_Z_MEM_ERROR", 1257, "ZLIB: Not enough memory" }, { "ER_ZLIB_Z_BUF_ERROR", 1258, "ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)" }, { "ER_ZLIB_Z_DATA_ERROR", 1259, "ZLIB: Input data corrupted" }, { "ER_CUT_VALUE_GROUP_CONCAT", 1260, "Row %u was cut by %s)" }, { "ER_WARN_TOO_FEW_RECORDS", 1261, "Row %lu doesn\'t contain data for all columns" }, { "ER_WARN_TOO_MANY_RECORDS", 1262, "Row %lu was truncated; it contained more data than there were input columns" }, { "ER_WARN_NULL_TO_NOTNULL", 1263, "Column set to default value; NULL supplied to NOT NULL column \'%s\' at row %lu" }, { "ER_WARN_DATA_OUT_OF_RANGE", 1264, "Out of range value for column \'%s\' at row %lu" }, { "WARN_DATA_TRUNCATED", 1265, "Data truncated for column \'%s\' at row %lu" }, { "ER_WARN_USING_OTHER_HANDLER", 1266, "Using storage engine %s for table \'%s\'" }, { "ER_CANT_AGGREGATE_2COLLATIONS", 1267, "Illegal mix of collations (%s,%s) and (%s,%s) for operation \'%s\'" }, { "ER_DROP_USER", 1268, "Cannot drop one or more of the requested users" }, { "ER_REVOKE_GRANTS", 1269, "Can\'t revoke all privileges for one or more of the requested users" }, { "ER_CANT_AGGREGATE_3COLLATIONS", 1270, "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation \'%s\'" }, { "ER_CANT_AGGREGATE_NCOLLATIONS", 1271, "Illegal mix of collations for operation \'%s\'" }, { "ER_VARIABLE_IS_NOT_STRUCT", 1272, "Variable \'%-.64s\' is not a variable component (can\'t be used as XXXX.variable_name)" }, { "ER_UNKNOWN_COLLATION", 1273, "Unknown collation: \'%-.64s\'" }, { "ER_SLAVE_IGNORED_SSL_PARAMS", 1274, "SSL parameters in CHANGE MASTER are ignored because this MariaDB slave was compiled without SSL support; they can be used later if MariaDB slave with SSL is started" }, { "ER_SERVER_IS_IN_SECURE_AUTH_MODE", 1275, "Server is running in --secure-auth mode, but \'%s\'@\'%s\' has a password in the old format; please change the password to the new format" }, { "ER_WARN_FIELD_RESOLVED", 1276, "Field or reference \'%-.192s%s%-.192s%s%-.192s\' of SELECT #%d was resolved in SELECT #%d" }, { "ER_BAD_SLAVE_UNTIL_COND", 1277, "Incorrect parameter or combination of parameters for START SLAVE UNTIL" }, { "ER_MISSING_SKIP_SLAVE", 1278, "It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you will get problems if you get an unexpected slave\'s mariadbd restart" }, { "ER_UNTIL_COND_IGNORED", 1279, "SQL thread is not to be started so UNTIL options are ignored" }, { "ER_WRONG_NAME_FOR_INDEX", 1280, "Incorrect index name \'%-.100s\'" }, { "ER_WRONG_NAME_FOR_CATALOG", 1281, "Incorrect catalog name \'%-.100s\'" }, { "ER_WARN_QC_RESIZE", 1282, "Query cache failed to set size %llu; new query cache size is %lu" }, { "ER_BAD_FT_COLUMN", 1283, "Column \'%-.192s\' cannot be part of FULLTEXT index" }, { "ER_UNKNOWN_KEY_CACHE", 1284, "Unknown key cache \'%-.100s\'" }, { "ER_WARN_HOSTNAME_WONT_WORK", 1285, "MariaDB is started in --skip-name-resolve mode; you must restart it without this switch for this grant to work" }, { "ER_UNKNOWN_STORAGE_ENGINE", 1286, "Unknown storage engine \'%s\'" }, { "ER_WARN_DEPRECATED_SYNTAX", 1287, "\'%s\' is deprecated and will be removed in a future release. Please use %s instead" }, { "ER_NON_UPDATABLE_TABLE", 1288, "The target table %-.100s of the %s is not updatable" }, { "ER_FEATURE_DISABLED", 1289, "The \'%s\' feature is disabled; you need MariaDB built with \'%s\' to have it working" }, { "ER_OPTION_PREVENTS_STATEMENT", 1290, "The MariaDB server is running with the %s option so it cannot execute this statement" }, { "ER_DUPLICATED_VALUE_IN_TYPE", 1291, "Column \'%-.100s\' has duplicated value \'%-.64s\' in %s" }, { "ER_TRUNCATED_WRONG_VALUE", 1292, "Truncated incorrect %-.32T value: \'%-.128T\'" }, { "ER_TOO_MUCH_AUTO_TIMESTAMP_COLS", 1293, "Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" }, { "ER_INVALID_ON_UPDATE", 1294, "Invalid ON UPDATE clause for \'%-.192s\' column" }, { "ER_UNSUPPORTED_PS", 1295, "This command is not supported in the prepared statement protocol yet" }, { "ER_GET_ERRMSG", 1296, "Got error %d \'%-.200s\' from %s" }, { "ER_GET_TEMPORARY_ERRMSG", 1297, "Got temporary error %d \'%-.200s\' from %s" }, { "ER_UNKNOWN_TIME_ZONE", 1298, "Unknown or incorrect time zone: \'%-.64s\'" }, { "ER_WARN_INVALID_TIMESTAMP", 1299, "Invalid TIMESTAMP value in column \'%s\' at row %lu" }, { "ER_INVALID_CHARACTER_STRING", 1300, "Invalid %s character string: \'%.64T\'" }, { "ER_WARN_ALLOWED_PACKET_OVERFLOWED", 1301, "Result of %s() was larger than max_allowed_packet (%ld) - truncated" }, { "ER_CONFLICTING_DECLARATIONS", 1302, "Conflicting declarations: \'%s%s\' and \'%s%s\'" }, { "ER_SP_NO_RECURSIVE_CREATE", 1303, "Can\'t create a %s from within another stored routine" }, { "ER_SP_ALREADY_EXISTS", 1304, "%s %s already exists" }, { "ER_SP_DOES_NOT_EXIST", 1305, "%s %s does not exist" }, { "ER_SP_DROP_FAILED", 1306, "Failed to DROP %s %s" }, { "ER_SP_STORE_FAILED", 1307, "Failed to CREATE %s %s" }, { "ER_SP_LILABEL_MISMATCH", 1308, "%s with no matching label: %s" }, { "ER_SP_LABEL_REDEFINE", 1309, "Redefining label %s" }, { "ER_SP_LABEL_MISMATCH", 1310, "End-label %s without match" }, { "ER_SP_UNINIT_VAR", 1311, "Referring to uninitialized variable %s" }, { "ER_SP_BADSELECT", 1312, "PROCEDURE %s can\'t return a result set in the given context" }, { "ER_SP_BADRETURN", 1313, "RETURN is only allowed in a FUNCTION" }, { "ER_SP_BADSTATEMENT", 1314, "%s is not allowed in stored procedures" }, { "ER_UPDATE_LOG_DEPRECATED_IGNORED", 1315, "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored. This option will be removed in MariaDB 5.6" }, { "ER_UPDATE_LOG_DEPRECATED_TRANSLATED", 1316, "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN. This option will be removed in MariaDB 5.6" }, { "ER_QUERY_INTERRUPTED", 1317, "Query execution was interrupted" }, { "ER_SP_WRONG_NO_OF_ARGS", 1318, "Incorrect number of arguments for %s %s; expected %u, got %u" }, { "ER_SP_COND_MISMATCH", 1319, "Undefined CONDITION: %s" }, { "ER_SP_NORETURN", 1320, "No RETURN found in FUNCTION %s" }, { "ER_SP_NORETURNEND", 1321, "FUNCTION %s ended without RETURN" }, { "ER_SP_BAD_CURSOR_QUERY", 1322, "Cursor statement must be a SELECT" }, { "ER_SP_BAD_CURSOR_SELECT", 1323, "Cursor SELECT must not have INTO" }, { "ER_SP_CURSOR_MISMATCH", 1324, "Undefined CURSOR: %s" }, { "ER_SP_CURSOR_ALREADY_OPEN", 1325, "Cursor is already open" }, { "ER_SP_CURSOR_NOT_OPEN", 1326, "Cursor is not open" }, { "ER_SP_UNDECLARED_VAR", 1327, "Undeclared variable: %s" }, { "ER_SP_WRONG_NO_OF_FETCH_ARGS", 1328, "Incorrect number of FETCH variables" }, { "ER_SP_FETCH_NO_DATA", 1329, "No data - zero rows fetched, selected, or processed" }, { "ER_SP_DUP_PARAM", 1330, "Duplicate parameter: %s" }, { "ER_SP_DUP_VAR", 1331, "Duplicate variable: %s" }, { "ER_SP_DUP_COND", 1332, "Duplicate condition: %s" }, { "ER_SP_DUP_CURS", 1333, "Duplicate cursor: %s" }, { "ER_SP_CANT_ALTER", 1334, "Failed to ALTER %s %s" }, { "ER_SP_SUBSELECT_NYI", 1335, "Subquery value not supported" }, { "ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG", 1336, "%s is not allowed in stored function or trigger" }, { "ER_SP_VARCOND_AFTER_CURSHNDLR", 1337, "Variable or condition declaration after cursor or handler declaration" }, { "ER_SP_CURSOR_AFTER_HANDLER", 1338, "Cursor declaration after handler declaration" }, { "ER_SP_CASE_NOT_FOUND", 1339, "Case not found for CASE statement" }, { "ER_FPARSER_TOO_BIG_FILE", 1340, "Configuration file \'%-.192s\' is too big" }, { "ER_FPARSER_BAD_HEADER", 1341, "Malformed file type header in file \'%-.192s\'" }, { "ER_FPARSER_EOF_IN_COMMENT", 1342, "Unexpected end of file while parsing comment \'%-.200s\'" }, { "ER_FPARSER_ERROR_IN_PARAMETER", 1343, "Error while parsing parameter \'%-.192s\' (line: \'%-.192s\')" }, { "ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER", 1344, "Unexpected end of file while skipping unknown parameter \'%-.192s\'" }, { "ER_VIEW_NO_EXPLAIN", 1345, "ANALYZE/EXPLAIN/SHOW can not be issued; lacking privileges for underlying table" }, { "ER_FRM_UNKNOWN_TYPE", 1346, "File \'%-.192s\' has unknown type \'%-.64s\' in its header" }, { "ER_WRONG_OBJECT", 1347, "\'%-.192s.%-.192s\' is not of type \'%s\'" }, { "ER_NONUPDATEABLE_COLUMN", 1348, "Column \'%-.192s\' is not updatable" }, { "ER_VIEW_SELECT_DERIVED", 1349, "View\'s SELECT contains a subquery in the FROM clause" }, { "ER_VIEW_SELECT_CLAUSE", 1350, "View\'s SELECT contains a \'%s\' clause" }, { "ER_VIEW_SELECT_VARIABLE", 1351, "View\'s SELECT contains a variable or parameter" }, { "ER_VIEW_SELECT_TMPTABLE", 1352, "View\'s SELECT refers to a temporary table \'%-.192s\'" }, { "ER_VIEW_WRONG_LIST", 1353, "View\'s SELECT and view\'s field list have different column counts" }, { "ER_WARN_VIEW_MERGE", 1354, "View merge algorithm can\'t be used here for now (assumed undefined algorithm)" }, { "ER_WARN_VIEW_WITHOUT_KEY", 1355, "View being updated does not have complete key of underlying table in it" }, { "ER_VIEW_INVALID", 1356, "View \'%-.192s.%-.192s\' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them" }, { "ER_SP_NO_DROP_SP", 1357, "Can\'t drop or alter a %s from within another stored routine" }, { "ER_SP_GOTO_IN_HNDLR", 1358, "GOTO is not allowed in a stored procedure handler" }, { "ER_TRG_ALREADY_EXISTS", 1359, "Trigger \'%s\' already exists" }, { "ER_TRG_DOES_NOT_EXIST", 1360, "Trigger does not exist" }, { "ER_TRG_ON_VIEW_OR_TEMP_TABLE", 1361, "Trigger\'s \'%-.192s\' is a view, temporary table or sequence" }, { "ER_TRG_CANT_CHANGE_ROW", 1362, "Updating of %s row is not allowed in %strigger" }, { "ER_TRG_NO_SUCH_ROW_IN_TRG", 1363, "There is no %s row in %s trigger" }, { "ER_NO_DEFAULT_FOR_FIELD", 1364, "Field \'%-.192s\' doesn\'t have a default value" }, { "ER_DIVISION_BY_ZERO", 1365, "Division by 0" }, { "ER_TRUNCATED_WRONG_VALUE_FOR_FIELD", 1366, "Incorrect %-.32s value: \'%-.128T\' for column `%.192s`.`%.192s`.`%.192s` at row %lu" }, { "ER_ILLEGAL_VALUE_FOR_TYPE", 1367, "Illegal %s \'%-.192T\' value found during parsing" }, { "ER_VIEW_NONUPD_CHECK", 1368, "CHECK OPTION on non-updatable view %`-.192s.%`-.192s" }, { "ER_VIEW_CHECK_FAILED", 1369, "CHECK OPTION failed %`-.192s.%`-.192s" }, { "ER_PROCACCESS_DENIED_ERROR", 1370, "%-.32s command denied to user \'%s\'@\'%s\' for routine \'%-.192s\'" }, { "ER_RELAY_LOG_FAIL", 1371, "Failed purging old relay logs: %s" }, { "ER_PASSWD_LENGTH", 1372, "Password hash should be a %d-digit hexadecimal number" }, { "ER_UNKNOWN_TARGET_BINLOG", 1373, "Target log not found in binlog index" }, { "ER_IO_ERR_LOG_INDEX_READ", 1374, "I/O error reading log index file" }, { "ER_BINLOG_PURGE_PROHIBITED", 1375, "Server configuration does not permit binlog purge" }, { "ER_FSEEK_FAIL", 1376, "Failed on fseek()" }, { "ER_BINLOG_PURGE_FATAL_ERR", 1377, "Fatal error during log purge" }, { "ER_LOG_IN_USE", 1378, "A purgeable log is in use, will not purge" }, { "ER_LOG_PURGE_UNKNOWN_ERR", 1379, "Unknown error during log purge" }, { "ER_RELAY_LOG_INIT", 1380, "Failed initializing relay log position: %s" }, { "ER_NO_BINARY_LOGGING", 1381, "You are not using binary logging" }, { "ER_RESERVED_SYNTAX", 1382, "The \'%-.64s\' syntax is reserved for purposes internal to the MariaDB server" }, { "ER_WSAS_FAILED", 1383, "WSAStartup Failed" }, { "ER_DIFF_GROUPS_PROC", 1384, "Can\'t handle procedures with different groups yet" }, { "ER_NO_GROUP_FOR_PROC", 1385, "Select must have a group with this procedure" }, { "ER_ORDER_WITH_PROC", 1386, "Can\'t use ORDER clause with this procedure" }, { "ER_LOGGING_PROHIBIT_CHANGING_OF", 1387, "Binary logging and replication forbid changing the global server %s" }, { "ER_NO_FILE_MAPPING", 1388, "Can\'t map file: %-.200s, errno: %M" }, { "ER_WRONG_MAGIC", 1389, "Wrong magic in %-.64s" }, { "ER_PS_MANY_PARAM", 1390, "Prepared statement contains too many placeholders" }, { "ER_KEY_PART_0", 1391, "Key part \'%-.192s\' length cannot be 0" }, { "ER_VIEW_CHECKSUM", 1392, "View text checksum failed" }, { "ER_VIEW_MULTIUPDATE", 1393, "Can not modify more than one base table through a join view \'%-.192s.%-.192s\'" }, { "ER_VIEW_NO_INSERT_FIELD_LIST", 1394, "Can not insert into join view \'%-.192s.%-.192s\' without fields list" }, { "ER_VIEW_DELETE_MERGE_VIEW", 1395, "Can not delete from join view \'%-.192s.%-.192s\'" }, { "ER_CANNOT_USER", 1396, "Operation %s failed for %.256s" }, { "ER_XAER_NOTA", 1397, "XAER_NOTA: Unknown XID" }, { "ER_XAER_INVAL", 1398, "XAER_INVAL: Invalid arguments (or unsupported command)" }, { "ER_XAER_RMFAIL", 1399, "XAER_RMFAIL: The command cannot be executed when global transaction is in the %.64s state" }, { "ER_XAER_OUTSIDE", 1400, "XAER_OUTSIDE: Some work is done outside global transaction" }, { "ER_XAER_RMERR", 1401, "XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency" }, { "ER_XA_RBROLLBACK", 1402, "XA_RBROLLBACK: Transaction branch was rolled back" }, { "ER_NONEXISTING_PROC_GRANT", 1403, "There is no such grant defined for user \'%-.48s\' on host \'%-.64s\' on routine \'%-.192s\'" }, { "ER_PROC_AUTO_GRANT_FAIL", 1404, "Failed to grant EXECUTE and ALTER ROUTINE privileges" }, { "ER_PROC_AUTO_REVOKE_FAIL", 1405, "Failed to revoke all privileges to dropped routine" }, { "ER_DATA_TOO_LONG", 1406, "Data too long for column \'%s\' at row %lu" }, { "ER_SP_BAD_SQLSTATE", 1407, "Bad SQLSTATE: \'%s\'" }, { "ER_STARTUP", 1408, "%s: ready for connections.\nVersion: \'%s\' socket: \'%s\' port: %d %s" }, { "ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR", 1409, "Can\'t load value from file with fixed size rows to variable" }, { "ER_CANT_CREATE_USER_WITH_GRANT", 1410, "You are not allowed to create a user with GRANT" }, { "ER_WRONG_VALUE_FOR_TYPE", 1411, "Incorrect %-.32s value: \'%-.128T\' for function %-.32s" }, { "ER_TABLE_DEF_CHANGED", 1412, "Table definition has changed, please retry transaction" }, { "ER_SP_DUP_HANDLER", 1413, "Duplicate handler declared in the same block" }, { "ER_SP_NOT_VAR_ARG", 1414, "OUT or INOUT argument %d for routine %s is not a variable or NEW pseudo-variable in BEFORE trigger" }, { "ER_SP_NO_RETSET", 1415, "Not allowed to return a result set from a %s" }, { "ER_CANT_CREATE_GEOMETRY_OBJECT", 1416, "Cannot get geometry object from data you send to the GEOMETRY field" }, { "ER_FAILED_ROUTINE_BREAK_BINLOG", 1417, "A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes" }, { "ER_BINLOG_UNSAFE_ROUTINE", 1418, "This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)" }, { "ER_BINLOG_CREATE_ROUTINE_NEED_SUPER", 1419, "You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)" }, { "ER_EXEC_STMT_WITH_OPEN_CURSOR", 1420, "You can\'t execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it" }, { "ER_STMT_HAS_NO_OPEN_CURSOR", 1421, "The statement (%lu) has no open cursor" }, { "ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG", 1422, "Explicit or implicit commit is not allowed in stored function or trigger" }, { "ER_NO_DEFAULT_FOR_VIEW_FIELD", 1423, "Field of view \'%-.192s.%-.192s\' underlying table doesn\'t have a default value" }, { "ER_SP_NO_RECURSION", 1424, "Recursive stored functions and triggers are not allowed" }, { "ER_TOO_BIG_SCALE", 1425, "Too big scale %llu specified for \'%-.192s\'. Maximum is %u" }, { "ER_TOO_BIG_PRECISION", 1426, "Too big precision %llu specified for \'%-.192s\'. Maximum is %u" }, { "ER_M_BIGGER_THAN_D", 1427, "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column \'%-.192s\')" }, { "ER_WRONG_LOCK_OF_SYSTEM_TABLE", 1428, "You can\'t combine write-locking of system tables with other tables or lock types" }, { "ER_CONNECT_TO_FOREIGN_DATA_SOURCE", 1429, "Unable to connect to foreign data source: %.64s" }, { "ER_QUERY_ON_FOREIGN_DATA_SOURCE", 1430, "There was a problem processing the query on the foreign data source. Data source error: %-.64s" }, { "ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST", 1431, "The foreign data source you are trying to reference does not exist. Data source error: %-.64s" }, { "ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE", 1432, "Can\'t create federated table. The data source connection string \'%-.64s\' is not in the correct format" }, { "ER_FOREIGN_DATA_STRING_INVALID", 1433, "The data source connection string \'%-.64s\' is not in the correct format" }, { "ER_CANT_CREATE_FEDERATED_TABLE", 1434, "Can\'t create federated table. Foreign data src error: %-.64s" }, { "ER_TRG_IN_WRONG_SCHEMA", 1435, "Trigger in wrong schema" }, { "ER_STACK_OVERRUN_NEED_MORE", 1436, "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Consider increasing the thread_stack system variable." }, { "ER_TOO_LONG_BODY", 1437, "Routine body for \'%-.100s\' is too long" }, { "ER_WARN_CANT_DROP_DEFAULT_KEYCACHE", 1438, "Cannot drop default keycache" }, { "ER_TOO_BIG_DISPLAYWIDTH", 1439, "Display width out of range for \'%-.192s\' (max = %lu)" }, { "ER_XAER_DUPID", 1440, "XAER_DUPID: The XID already exists" }, { "ER_DATETIME_FUNCTION_OVERFLOW", 1441, "Datetime function: %-.32s field overflow" }, { "ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG", 1442, "Can\'t update table \'%-.192s\' in stored function/trigger because it is already used by statement which invoked this stored function/trigger" }, { "ER_VIEW_PREVENT_UPDATE", 1443, "The definition of table \'%-.192s\' prevents operation %-.192s on table \'%-.192s\'" }, { "ER_PS_NO_RECURSION", 1444, "The prepared statement contains a stored routine call that refers to that same statement. It\'s not allowed to execute a prepared statement in such a recursive manner" }, { "ER_SP_CANT_SET_AUTOCOMMIT", 1445, "Not allowed to set autocommit from a stored function or trigger" }, { "ER_MALFORMED_DEFINER", 1446, "Invalid definer" }, { "ER_VIEW_FRM_NO_USER", 1447, "View \'%-.192s\'.\'%-.192s\' has no definer information (old table format). Current user is used as definer. Please recreate the view!" }, { "ER_VIEW_OTHER_USER", 1448, "You need the SUPER privilege for creation view with \'%-.192s\'@\'%-.192s\' definer" }, { "ER_NO_SUCH_USER", 1449, "The user specified as a definer (\'%-.64s\'@\'%-.64s\') does not exist" }, { "ER_FORBID_SCHEMA_CHANGE", 1450, "Changing schema from \'%-.192s\' to \'%-.192s\' is not allowed" }, { "ER_ROW_IS_REFERENCED_2", 1451, "Cannot delete or update a parent row: a foreign key constraint fails (%s)" }, { "ER_NO_REFERENCED_ROW_2", 1452, "Cannot add or update a child row: a foreign key constraint fails (%s)" }, { "ER_SP_BAD_VAR_SHADOW", 1453, "Variable \'%-.64s\' must be quoted with `...`, or renamed" }, { "ER_TRG_NO_DEFINER", 1454, "No definer attribute for trigger \'%-.192s\'.\'%-.192s\'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger" }, { "ER_OLD_FILE_FORMAT", 1455, "\'%-.192s\' has an old format, you should re-create the \'%s\' object(s)" }, { "ER_SP_RECURSION_LIMIT", 1456, "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.192s" }, { "ER_SP_PROC_TABLE_CORRUPT", 1457, "Failed to load routine %-.192s (internal code %d). For more details, run SHOW WARNINGS" }, { "ER_SP_WRONG_NAME", 1458, "Incorrect routine name \'%-.192s\'" }, { "ER_TABLE_NEEDS_UPGRADE", 1459, "Upgrade required. Please do \"REPAIR %s %`s\" or dump/reload to fix it!" }, { "ER_SP_NO_AGGREGATE", 1460, "AGGREGATE is not supported for stored functions" }, { "ER_MAX_PREPARED_STMT_COUNT_REACHED", 1461, "Can\'t create more than max_prepared_stmt_count statements (current value: %u)" }, { "ER_VIEW_RECURSIVE", 1462, "%`s.%`s contains view recursion" }, { "ER_NON_GROUPING_FIELD_USED", 1463, "Non-grouping field \'%-.192s\' is used in %-.64s clause" }, { "ER_TABLE_CANT_HANDLE_SPKEYS", 1464, "The storage engine %s doesn\'t support SPATIAL indexes" }, { "ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA", 1465, "Triggers can not be created on system tables" }, { "ER_REMOVED_SPACES", 1466, "Leading spaces are removed from name \'%s\'" }, { "ER_AUTOINC_READ_FAILED", 1467, "Failed to read auto-increment value from storage engine" }, { "ER_USERNAME", 1468, "user name" }, { "ER_HOSTNAME", 1469, "host name" }, { "ER_WRONG_STRING_LENGTH", 1470, "String \'%-.70T\' is too long for %s (should be no longer than %d)" }, { "ER_NON_INSERTABLE_TABLE", 1471, "The target table %-.100s of the %s is not insertable-into" }, { "ER_ADMIN_WRONG_MRG_TABLE", 1472, "Table \'%-.64s\' is differently defined or of non-MyISAM type or doesn\'t exist" }, { "ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT", 1473, "Too high level of nesting for select" }, { "ER_NAME_BECOMES_EMPTY", 1474, "Name \'%-.64s\' has become \'\'" }, { "ER_AMBIGUOUS_FIELD_TERM", 1475, "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" }, { "ER_FOREIGN_SERVER_EXISTS", 1476, "Cannot create foreign server \'%s\' as it already exists" }, { "ER_FOREIGN_SERVER_DOESNT_EXIST", 1477, "The foreign server name you are trying to reference does not exist. Data source error: %-.64s" }, { "ER_ILLEGAL_HA_CREATE_OPTION", 1478, "Table storage engine \'%-.64s\' does not support the create option \'%.64s\'" }, { "ER_PARTITION_REQUIRES_VALUES_ERROR", 1479, "Syntax error: %-.64s PARTITIONING requires definition of VALUES %-.64s for each partition" }, { "ER_PARTITION_WRONG_VALUES_ERROR", 1480, "Only %-.64s PARTITIONING can use VALUES %-.64s in partition definition" }, { "ER_PARTITION_MAXVALUE_ERROR", 1481, "MAXVALUE can only be used in last partition definition" }, { "ER_PARTITION_SUBPARTITION_ERROR", 1482, "Subpartitions can only be hash partitions and by key" }, { "ER_PARTITION_SUBPART_MIX_ERROR", 1483, "Must define subpartitions on all partitions if on one partition" }, { "ER_PARTITION_WRONG_NO_PART_ERROR", 1484, "Wrong number of partitions defined, mismatch with previous setting" }, { "ER_PARTITION_WRONG_NO_SUBPART_ERROR", 1485, "Wrong number of subpartitions defined, mismatch with previous setting" }, { "ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR", 1486, "Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed" }, { "ER_NOT_CONSTANT_EXPRESSION", 1487, "Expression in %s must be constant" }, { "ER_FIELD_NOT_FOUND_PART_ERROR", 1488, "Field in list of fields for partition function not found in table" }, { "ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR", 1489, "List of fields is only allowed in KEY partitions" }, { "ER_INCONSISTENT_PARTITION_INFO_ERROR", 1490, "The partition info in the frm file is not consistent with what can be written into the frm file" }, { "ER_PARTITION_FUNC_NOT_ALLOWED_ERROR", 1491, "The %-.192s function returns the wrong type" }, { "ER_PARTITIONS_MUST_BE_DEFINED_ERROR", 1492, "For %-.64s partitions each partition must be defined" }, { "ER_RANGE_NOT_INCREASING_ERROR", 1493, "VALUES LESS THAN value must be strictly increasing for each partition" }, { "ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR", 1494, "VALUES value must be of same type as partition function" }, { "ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR", 1495, "Multiple definition of same constant in list partitioning" }, { "ER_PARTITION_ENTRY_ERROR", 1496, "Partitioning can not be used stand-alone in query" }, { "ER_MIX_HANDLER_ERROR", 1497, "The mix of handlers in the partitions is not allowed in this version of MariaDB" }, { "ER_PARTITION_NOT_DEFINED_ERROR", 1498, "For the partitioned engine it is necessary to define all %-.64s" }, { "ER_TOO_MANY_PARTITIONS_ERROR", 1499, "Too many partitions (including subpartitions) were defined" }, { "ER_SUBPARTITION_ERROR", 1500, "It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning" }, { "ER_CANT_CREATE_HANDLER_FILE", 1501, "Failed to create specific handler file" }, { "ER_BLOB_FIELD_IN_PART_FUNC_ERROR", 1502, "A BLOB field is not allowed in partition function" }, { "ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF", 1503, "A %-.192s must include all columns in the table\'s partitioning function" }, { "ER_NO_PARTS_ERROR", 1504, "Number of %-.64s = 0 is not an allowed value" }, { "ER_PARTITION_MGMT_ON_NONPARTITIONED", 1505, "Partition management on a not partitioned table is not possible" }, { "ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING", 1506, "Partitioned tables do not support %s" }, { "ER_DROP_PARTITION_NON_EXISTENT", 1507, "Error in list of partitions to %-.64s" }, { "ER_DROP_LAST_PARTITION", 1508, "Cannot remove all partitions, use DROP TABLE instead" }, { "ER_COALESCE_ONLY_ON_HASH_PARTITION", 1509, "COALESCE PARTITION can only be used on HASH/KEY partitions" }, { "ER_REORG_HASH_ONLY_ON_SAME_NO", 1510, "REORGANIZE PARTITION can only be used to reorganize partitions not to change their numbers" }, { "ER_REORG_NO_PARAM_ERROR", 1511, "REORGANIZE PARTITION without parameters can only be used on auto-partitioned tables using HASH PARTITIONs" }, { "ER_ONLY_ON_RANGE_LIST_PARTITION", 1512, "%-.64s PARTITION can only be used on RANGE/LIST partitions" }, { "ER_ADD_PARTITION_SUBPART_ERROR", 1513, "Trying to Add partition(s) with wrong number of subpartitions" }, { "ER_ADD_PARTITION_NO_NEW_PARTITION", 1514, "At least one partition must be added" }, { "ER_COALESCE_PARTITION_NO_PARTITION", 1515, "At least one partition must be coalesced" }, { "ER_REORG_PARTITION_NOT_EXIST", 1516, "More partitions to reorganize than there are partitions" }, { "ER_SAME_NAME_PARTITION", 1517, "Duplicate partition name %-.192s" }, { "ER_NO_BINLOG_ERROR", 1518, "It is not allowed to shut off binlog on this command" }, { "ER_CONSECUTIVE_REORG_PARTITIONS", 1519, "When reorganizing a set of partitions they must be in consecutive order" }, { "ER_REORG_OUTSIDE_RANGE", 1520, "Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range" }, { "ER_PARTITION_FUNCTION_FAILURE", 1521, "Partition function not supported in this version for this handler" }, { "ER_PART_STATE_ERROR", 1522, "Partition state cannot be defined from CREATE/ALTER TABLE" }, { "ER_LIMITED_PART_RANGE", 1523, "The %-.64s handler only supports 32 bit integers in VALUES" }, { "ER_PLUGIN_IS_NOT_LOADED", 1524, "Plugin \'%-.192s\' is not loaded" }, { "ER_WRONG_VALUE", 1525, "Incorrect %-.32s value: \'%-.128T\'" }, { "ER_NO_PARTITION_FOR_GIVEN_VALUE", 1526, "Table has no partition for value %-.64s" }, { "ER_FILEGROUP_OPTION_ONLY_ONCE", 1527, "It is not allowed to specify %s more than once" }, { "ER_CREATE_FILEGROUP_FAILED", 1528, "Failed to create %s" }, { "ER_DROP_FILEGROUP_FAILED", 1529, "Failed to drop %s" }, { "ER_TABLESPACE_AUTO_EXTEND_ERROR", 1530, "The handler doesn\'t support autoextend of tablespaces" }, { "ER_WRONG_SIZE_NUMBER", 1531, "A size parameter was incorrectly specified, either number or on the form 10M" }, { "ER_SIZE_OVERFLOW_ERROR", 1532, "The size number was correct but we don\'t allow the digit part to be more than 2 billion" }, { "ER_ALTER_FILEGROUP_FAILED", 1533, "Failed to alter: %s" }, { "ER_BINLOG_ROW_LOGGING_FAILED", 1534, "Writing one row to the row-based binary log failed" }, { "ER_BINLOG_ROW_WRONG_TABLE_DEF", 1535, "Table definition on master and slave does not match: %s" }, { "ER_BINLOG_ROW_RBR_TO_SBR", 1536, "Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events" }, { "ER_EVENT_ALREADY_EXISTS", 1537, "Event \'%-.192s\' already exists" }, { "ER_EVENT_STORE_FAILED", 1538, "Failed to store event %s. Error code %M from storage engine" }, { "ER_EVENT_DOES_NOT_EXIST", 1539, "Unknown event \'%-.192s\'" }, { "ER_EVENT_CANT_ALTER", 1540, "Failed to alter event \'%-.192s\'" }, { "ER_EVENT_DROP_FAILED", 1541, "Failed to drop %s" }, { "ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG", 1542, "INTERVAL is either not positive or too big" }, { "ER_EVENT_ENDS_BEFORE_STARTS", 1543, "ENDS is either invalid or before STARTS" }, { "ER_EVENT_EXEC_TIME_IN_THE_PAST", 1544, "Event execution time is in the past. Event has been disabled" }, { "ER_EVENT_OPEN_TABLE_FAILED", 1545, "Failed to open mysql.event" }, { "ER_EVENT_NEITHER_M_EXPR_NOR_M_AT", 1546, "No datetime expression provided" }, { "ER_UNUSED_2", 1547, "You should never see it" }, { "ER_UNUSED_3", 1548, "You should never see it" }, { "ER_EVENT_CANNOT_DELETE", 1549, "Failed to delete the event from mysql.event" }, { "ER_EVENT_COMPILE_ERROR", 1550, "Error during compilation of event\'s body" }, { "ER_EVENT_SAME_NAME", 1551, "Same old and new event name" }, { "ER_EVENT_DATA_TOO_LONG", 1552, "Data for column \'%s\' too long" }, { "ER_DROP_INDEX_FK", 1553, "Cannot drop index \'%-.192s\': needed in a foreign key constraint" }, { "ER_WARN_DEPRECATED_SYNTAX_WITH_VER", 1554, "The syntax \'%s\' is deprecated and will be removed in MariaDB %s. Please use %s instead" }, { "ER_CANT_WRITE_LOCK_LOG_TABLE", 1555, "You can\'t write-lock a log table. Only read access is possible" }, { "ER_CANT_LOCK_LOG_TABLE", 1556, "You can\'t use locks with log tables" }, { "ER_UNUSED_4", 1557, "You should never see it" }, { "ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE", 1558, "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MariaDB %d, now running %d. Please use mariadb-upgrade to fix this error" }, { "ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR", 1559, "Cannot switch out of the row-based binary log format when the session has open temporary tables" }, { "ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT", 1560, "Cannot change the binary logging format inside a stored function or trigger" }, { "ER_UNUSED_13", 1561, "You should never see it" }, { "ER_PARTITION_NO_TEMPORARY", 1562, "Cannot create temporary table with partitions" }, { "ER_PARTITION_CONST_DOMAIN_ERROR", 1563, "Partition constant is out of partition function domain" }, { "ER_PARTITION_FUNCTION_IS_NOT_ALLOWED", 1564, "This partition function is not allowed" }, { "ER_DDL_LOG_ERROR", 1565, "Error in DDL log" }, { "ER_NULL_IN_VALUES_LESS_THAN", 1566, "Not allowed to use NULL value in VALUES LESS THAN" }, { "ER_WRONG_PARTITION_NAME", 1567, "Incorrect partition name" }, { "ER_CANT_CHANGE_TX_CHARACTERISTICS", 1568, "Transaction characteristics can\'t be changed while a transaction is in progress" }, { "ER_DUP_ENTRY_AUTOINCREMENT_CASE", 1569, "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry \'%-.192T\' for key \'%-.192s\'" }, { "ER_EVENT_MODIFY_QUEUE_ERROR", 1570, "Internal scheduler error %d" }, { "ER_EVENT_SET_VAR_ERROR", 1571, "Error during starting/stopping of the scheduler. Error code %M" }, { "ER_PARTITION_MERGE_ERROR", 1572, "Engine cannot be used in partitioned tables" }, { "ER_CANT_ACTIVATE_LOG", 1573, "Cannot activate \'%-.64s\' log" }, { "ER_RBR_NOT_AVAILABLE", 1574, "The server was not built with row-based replication" }, { "ER_BASE64_DECODE_ERROR", 1575, "Decoding of base64 string failed" }, { "ER_EVENT_RECURSION_FORBIDDEN", 1576, "Recursion of EVENT DDL statements is forbidden when body is present" }, { "ER_EVENTS_DB_ERROR", 1577, "Cannot proceed, because event scheduler is disabled" }, { "ER_ONLY_INTEGERS_ALLOWED", 1578, "Only integers allowed as number here" }, { "ER_UNSUPORTED_LOG_ENGINE", 1579, "Storage engine %s cannot be used for log tables" }, { "ER_BAD_LOG_STATEMENT", 1580, "You cannot \'%s\' a log table if logging is enabled" }, { "ER_CANT_RENAME_LOG_TABLE", 1581, "Cannot rename \'%s\'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to \'%s\'" }, { "ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT", 1582, "Incorrect parameter count in the call to native function \'%-.192s\'" }, { "ER_WRONG_PARAMETERS_TO_NATIVE_FCT", 1583, "Incorrect parameters in the call to native function \'%-.192s\'" }, { "ER_WRONG_PARAMETERS_TO_STORED_FCT", 1584, "Incorrect parameters in the call to stored function \'%-.192s\'" }, { "ER_NATIVE_FCT_NAME_COLLISION", 1585, "This function \'%-.192s\' has the same name as a native function" }, { "ER_DUP_ENTRY_WITH_KEY_NAME", 1586, "Duplicate entry \'%-.64T\' for key \'%-.192s\'" }, { "ER_BINLOG_PURGE_EMFILE", 1587, "Too many files opened, please execute the command again" }, { "ER_EVENT_CANNOT_CREATE_IN_THE_PAST", 1588, "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation" }, { "ER_EVENT_CANNOT_ALTER_IN_THE_PAST", 1589, "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was not changed. Specify a time in the future" }, { "ER_SLAVE_INCIDENT", 1590, "The incident %s occurred on the master. Message: %-.64s" }, { "ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT", 1591, "Table has no partition for some existing values" }, { "ER_BINLOG_UNSAFE_STATEMENT", 1592, "Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. %s" }, { "ER_SLAVE_FATAL_ERROR", 1593, "Fatal error: %s" }, { "ER_SLAVE_RELAY_LOG_READ_FAILURE", 1594, "Relay log read failure: %s" }, { "ER_SLAVE_RELAY_LOG_WRITE_FAILURE", 1595, "Relay log write failure: %s" }, { "ER_SLAVE_CREATE_EVENT_FAILURE", 1596, "Failed to create %s" }, { "ER_SLAVE_MASTER_COM_FAILURE", 1597, "Master command %s failed: %s" }, { "ER_BINLOG_LOGGING_IMPOSSIBLE", 1598, "Binary logging not possible. Message: %s" }, { "ER_VIEW_NO_CREATION_CTX", 1599, "View %`s.%`s has no creation context" }, { "ER_VIEW_INVALID_CREATION_CTX", 1600, "Creation context of view %`s.%`s is invalid" }, { "ER_SR_INVALID_CREATION_CTX", 1601, "Creation context of stored routine %`s.%`s is invalid" }, { "ER_TRG_CORRUPTED_FILE", 1602, "Corrupted TRG file for table %`s.%`s" }, { "ER_TRG_NO_CREATION_CTX", 1603, "Triggers for table %`s.%`s have no creation context" }, { "ER_TRG_INVALID_CREATION_CTX", 1604, "Trigger creation context of table %`s.%`s is invalid" }, { "ER_EVENT_INVALID_CREATION_CTX", 1605, "Creation context of event %`s.%`s is invalid" }, { "ER_TRG_CANT_OPEN_TABLE", 1606, "Cannot open table for trigger %`s.%`s" }, { "ER_CANT_CREATE_SROUTINE", 1607, "Cannot create stored routine %`s. Check warnings" }, { "ER_UNUSED_11", 1608, "You should never see it" }, { "ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT", 1609, "The BINLOG statement of type %s was not preceded by a format description BINLOG statement" }, { "ER_SLAVE_CORRUPT_EVENT", 1610, "Corrupted replication event was detected" }, { "ER_LOAD_DATA_INVALID_COLUMN", 1611, "Invalid column reference (%-.64s) in LOAD DATA" }, { "ER_LOG_PURGE_NO_FILE", 1612, "Being purged log %s was not found" }, { "ER_XA_RBTIMEOUT", 1613, "XA_RBTIMEOUT: Transaction branch was rolled back: took too long" }, { "ER_XA_RBDEADLOCK", 1614, "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected" }, { "ER_NEED_REPREPARE", 1615, "Prepared statement needs to be re-prepared" }, { "ER_DELAYED_NOT_SUPPORTED", 1616, "DELAYED option not supported for table \'%-.192s\'" }, { "WARN_NO_MASTER_INFO", 1617, "There is no master connection \'%.*s\'" }, { "WARN_OPTION_IGNORED", 1618, "<%-.64s> option ignored" }, { "ER_PLUGIN_DELETE_BUILTIN", 1619, "Built-in plugins cannot be deleted" }, { "WARN_PLUGIN_BUSY", 1620, "Plugin is busy and will be uninstalled on shutdown" }, { "ER_VARIABLE_IS_READONLY", 1621, "%s variable \'%s\' is read-only. Use SET %s to assign the value" }, { "ER_WARN_ENGINE_TRANSACTION_ROLLBACK", 1622, "Storage engine %s does not support rollback for this statement. Transaction rolled back and must be restarted" }, { "ER_SLAVE_HEARTBEAT_FAILURE", 1623, "Unexpected master\'s heartbeat data: %s" }, { "ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE", 1624, "The requested value for the heartbeat period is either negative or exceeds the maximum allowed (%u seconds)" }, { "ER_UNUSED_14", 1625, "You should never see it" }, { "ER_CONFLICT_FN_PARSE_ERROR", 1626, "Error in parsing conflict function. Message: %-.64s" }, { "ER_EXCEPTIONS_WRITE_ERROR", 1627, "Write to exceptions table failed. Message: %-.128s\"" }, { "ER_TOO_LONG_TABLE_COMMENT", 1628, "Comment for table \'%-.64s\' is too long (max = %u)" }, { "ER_TOO_LONG_FIELD_COMMENT", 1629, "Comment for field \'%-.64s\' is too long (max = %u)" }, { "ER_FUNC_INEXISTENT_NAME_COLLISION", 1630, "FUNCTION %s does not exist. Check the \'Function Name Parsing and Resolution\' section in the Reference Manual" }, { "ER_DATABASE_NAME", 1631, "Database" }, { "ER_TABLE_NAME", 1632, "Table" }, { "ER_PARTITION_NAME", 1633, "Partition" }, { "ER_SUBPARTITION_NAME", 1634, "Subpartition" }, { "ER_TEMPORARY_NAME", 1635, "Temporary" }, { "ER_RENAMED_NAME", 1636, "Renamed" }, { "ER_TOO_MANY_CONCURRENT_TRXS", 1637, "Too many active concurrent transactions" }, { "WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED", 1638, "Non-ASCII separator arguments are not fully supported" }, { "ER_DEBUG_SYNC_TIMEOUT", 1639, "debug sync point wait timed out" }, { "ER_DEBUG_SYNC_HIT_LIMIT", 1640, "debug sync point hit limit reached" }, { "ER_DUP_SIGNAL_SET", 1641, "Duplicate condition information item \'%s\'" }, { "ER_SIGNAL_WARN", 1642, "Unhandled user-defined warning condition" }, { "ER_SIGNAL_NOT_FOUND", 1643, "Unhandled user-defined not found condition" }, { "ER_SIGNAL_EXCEPTION", 1644, "Unhandled user-defined exception condition" }, { "ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER", 1645, "RESIGNAL when handler not active" }, { "ER_SIGNAL_BAD_CONDITION_TYPE", 1646, "SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE" }, { "WARN_COND_ITEM_TRUNCATED", 1647, "Data truncated for condition item \'%s\'" }, { "ER_COND_ITEM_TOO_LONG", 1648, "Data too long for condition item \'%s\'" }, { "ER_UNKNOWN_LOCALE", 1649, "Unknown locale: \'%-.64s\'" }, { "ER_SLAVE_IGNORE_SERVER_IDS", 1650, "The requested server id %d clashes with the slave startup option --replicate-same-server-id" }, { "ER_QUERY_CACHE_DISABLED", 1651, "Query cache is disabled; set query_cache_type to ON or DEMAND to enable it" }, { "ER_SAME_NAME_PARTITION_FIELD", 1652, "Duplicate partition field name \'%-.192s\'" }, { "ER_PARTITION_COLUMN_LIST_ERROR", 1653, "Inconsistency in usage of column lists for partitioning" }, { "ER_WRONG_TYPE_COLUMN_VALUE_ERROR", 1654, "Partition column values of incorrect type" }, { "ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR", 1655, "Too many fields in \'%-.192s\'" }, { "ER_MAXVALUE_IN_VALUES_IN", 1656, "Cannot use MAXVALUE as value in VALUES IN" }, { "ER_TOO_MANY_VALUES_ERROR", 1657, "Cannot have more than one value for this type of %-.64s partitioning" }, { "ER_ROW_SINGLE_PARTITION_FIELD_ERROR", 1658, "Row expressions in VALUES IN only allowed for multi-field column partitioning" }, { "ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD", 1659, "Field \'%-.192s\' is of a not allowed type for this type of partitioning" }, { "ER_PARTITION_FIELDS_TOO_LONG", 1660, "The total length of the partitioning fields is too large" }, { "ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE", 1661, "Cannot execute statement: impossible to write to binary log since both row-incapable engines and statement-incapable engines are involved" }, { "ER_BINLOG_ROW_MODE_AND_STMT_ENGINE", 1662, "Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging" }, { "ER_BINLOG_UNSAFE_AND_STMT_ENGINE", 1663, "Cannot execute statement: impossible to write to binary log since statement is unsafe, storage engine is limited to statement-based logging, and BINLOG_FORMAT = MIXED. %s" }, { "ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE", 1664, "Cannot execute statement: impossible to write to binary log since statement is in row format and at least one table uses a storage engine limited to statement-based logging" }, { "ER_BINLOG_STMT_MODE_AND_ROW_ENGINE", 1665, "Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging.%s" }, { "ER_BINLOG_ROW_INJECTION_AND_STMT_MODE", 1666, "Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT" }, { "ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE", 1667, "Cannot execute statement: impossible to write to binary log since more than one engine is involved and at least one engine is self-logging" }, { "ER_BINLOG_UNSAFE_LIMIT", 1668, "The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted" }, { "ER_BINLOG_UNSAFE_INSERT_DELAYED", 1669, "The statement is unsafe because it uses INSERT DELAYED. This is unsafe because the times when rows are inserted cannot be predicted" }, { "ER_BINLOG_UNSAFE_SYSTEM_TABLE", 1670, "The statement is unsafe because it uses the general log, slow query log, or performance_schema table(s). This is unsafe because system tables may differ on slaves" }, { "ER_BINLOG_UNSAFE_AUTOINC_COLUMNS", 1671, "Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly" }, { "ER_BINLOG_UNSAFE_UDF", 1672, "Statement is unsafe because it uses a UDF which may not return the same value on the slave" }, { "ER_BINLOG_UNSAFE_SYSTEM_VARIABLE", 1673, "Statement is unsafe because it uses a system variable that may have a different value on the slave" }, { "ER_BINLOG_UNSAFE_SYSTEM_FUNCTION", 1674, "Statement is unsafe because it uses a system function that may return a different value on the slave" }, { "ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS", 1675, "Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction" }, { "ER_MESSAGE_AND_STATEMENT", 1676, "%s. Statement: %s" }, { "ER_SLAVE_CONVERSION_FAILED", 1677, "Column %d of table \'%-.192s.%-.192s\' cannot be converted from type \'%-.50s\' to type \'%-.50s\'" }, { "ER_SLAVE_CANT_CREATE_CONVERSION", 1678, "Can\'t create conversion table for table \'%-.192s.%-.192s\'" }, { "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT", 1679, "Cannot modify @@session.binlog_format inside a transaction" }, { "ER_PATH_LENGTH", 1680, "The path specified for %.64T is too long" }, { "ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT", 1681, "\'%s\' is deprecated and will be removed in a future release" }, { "ER_WRONG_NATIVE_TABLE_STRUCTURE", 1682, "Native table \'%-.64s\'.\'%-.64s\' has the wrong structure" }, { "ER_WRONG_PERFSCHEMA_USAGE", 1683, "Invalid performance_schema usage" }, { "ER_WARN_I_S_SKIPPED_TABLE", 1684, "Table \'%s\'.\'%s\' was skipped since its definition is being modified by concurrent DDL statement" }, { "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT", 1685, "Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction" }, { "ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT", 1686, "Cannot change the binlog direct flag inside a stored function or trigger" }, { "ER_SPATIAL_MUST_HAVE_GEOM_COL", 1687, "A SPATIAL index may only contain a geometrical type column" }, { "ER_TOO_LONG_INDEX_COMMENT", 1688, "Comment for index \'%-.64s\' is too long (max = %lu)" }, { "ER_LOCK_ABORTED", 1689, "Wait on a lock was aborted due to a pending exclusive lock" }, { "ER_DATA_OUT_OF_RANGE", 1690, "%s value is out of range in \'%s\'" }, { "ER_WRONG_SPVAR_TYPE_IN_LIMIT", 1691, "A variable of a non-integer based type in LIMIT clause" }, { "ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE", 1692, "Mixing self-logging and non-self-logging engines in a statement is unsafe" }, { "ER_BINLOG_UNSAFE_MIXED_STATEMENT", 1693, "Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them" }, { "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN", 1694, "Cannot modify @@session.sql_log_bin inside a transaction" }, { "ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN", 1695, "Cannot change the sql_log_bin inside a stored function or trigger" }, { "ER_FAILED_READ_FROM_PAR_FILE", 1696, "Failed to read from the .par file" }, { "ER_VALUES_IS_NOT_INT_TYPE_ERROR", 1697, "VALUES value for partition \'%-.64s\' must have type INT" }, { "ER_ACCESS_DENIED_NO_PASSWORD_ERROR", 1698, "Access denied for user \'%s\'@\'%s\'" }, { "ER_SET_PASSWORD_AUTH_PLUGIN", 1699, "SET PASSWORD is not applicable for users authenticating via %s plugin" }, { "ER_GRANT_PLUGIN_USER_EXISTS", 1700, "GRANT with IDENTIFIED WITH is illegal because the user %-.*s already exists" }, { "ER_TRUNCATE_ILLEGAL_FK", 1701, "Cannot truncate a table referenced in a foreign key constraint (%.192s)" }, { "ER_PLUGIN_IS_PERMANENT", 1702, "Plugin \'%s\' is force_plus_permanent and can not be unloaded" }, { "ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN", 1703, "The requested value for the heartbeat period is less than 1 millisecond. The value is reset to 0, meaning that heartbeating will effectively be disabled" }, { "ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX", 1704, "The requested value for the heartbeat period exceeds the value of `slave_net_timeout\' seconds. A sensible value for the period should be less than the timeout" }, { "ER_STMT_CACHE_FULL", 1705, "Multi-row statements required more than \'max_binlog_stmt_cache_size\' bytes of storage." }, { "ER_MULTI_UPDATE_KEY_CONFLICT", 1706, "Primary key/partition key update is not allowed since the table is updated both as \'%-.192s\' and \'%-.192s\'" }, { "ER_TABLE_NEEDS_REBUILD", 1707, "Table rebuild required. Please do \"ALTER TABLE %`s FORCE\" or dump/reload to fix it!" }, { "WARN_OPTION_BELOW_LIMIT", 1708, "The value of \'%s\' should be no less than the value of \'%s\'" }, { "ER_INDEX_COLUMN_TOO_LONG", 1709, "Index column size too large. The maximum column size is %lu bytes" }, { "ER_ERROR_IN_TRIGGER_BODY", 1710, "Trigger \'%-.64s\' has an error in its body: \'%-.256s\'" }, { "ER_ERROR_IN_UNKNOWN_TRIGGER_BODY", 1711, "Unknown trigger has an error in its body: \'%-.256s\'" }, { "ER_INDEX_CORRUPT", 1712, "Index %s is corrupted" }, { "ER_UNDO_RECORD_TOO_BIG", 1713, "Undo log record is too big" }, { "ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT", 1714, "INSERT IGNORE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave" }, { "ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE", 1715, "INSERT... SELECT... ON DUPLICATE KEY UPDATE is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are updated. This order cannot be predicted and may differ on master and the slave" }, { "ER_BINLOG_UNSAFE_REPLACE_SELECT", 1716, "REPLACE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave" }, { "ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT", 1717, "CREATE... IGNORE SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave" }, { "ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT", 1718, "CREATE... REPLACE SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave" }, { "ER_BINLOG_UNSAFE_UPDATE_IGNORE", 1719, "UPDATE IGNORE is unsafe because the order in which rows are updated determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave" }, { "ER_UNUSED_15", 1720, "You should never see it" }, { "ER_UNUSED_16", 1721, "You should never see it" }, { "ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT", 1722, "Statements writing to a table with an auto-increment column after selecting from another table are unsafe because the order in which rows are retrieved determines what (if any) rows will be written. This order cannot be predicted and may differ on master and the slave" }, { "ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC", 1723, "CREATE TABLE... SELECT... on a table with an auto-increment column is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are inserted. This order cannot be predicted and may differ on master and the slave" }, { "ER_BINLOG_UNSAFE_INSERT_TWO_KEYS", 1724, "INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe" }, { "ER_UNUSED_28", 1725, "You should never see it" }, { "ER_VERS_NOT_ALLOWED", 1726, "Not allowed for system-versioned table %`s.%`s" }, { "ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST", 1727, "INSERT into autoincrement field which is not the first part in the composed primary key is unsafe" }, { "ER_CANNOT_LOAD_FROM_TABLE_V2", 1728, "Cannot load from %s.%s. The table is probably corrupted" }, { "ER_MASTER_DELAY_VALUE_OUT_OF_RANGE", 1729, "The requested value %lu for the master delay exceeds the maximum %lu" }, { "ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT", 1730, "Only Format_description_log_event and row events are allowed in BINLOG statements (but %s was provided)" }, { "ER_PARTITION_EXCHANGE_DIFFERENT_OPTION", 1731, "Non matching attribute \'%-.64s\' between partition and table" }, { "ER_PARTITION_EXCHANGE_PART_TABLE", 1732, "Table to exchange with partition is partitioned: \'%-.64s\'" }, { "ER_PARTITION_EXCHANGE_TEMP_TABLE", 1733, "Table to exchange with partition is temporary: \'%-.64s\'" }, { "ER_PARTITION_INSTEAD_OF_SUBPARTITION", 1734, "Subpartitioned table, use subpartition instead of partition" }, { "ER_UNKNOWN_PARTITION", 1735, "Unknown partition \'%-.64s\' in table \'%-.64s\'" }, { "ER_TABLES_DIFFERENT_METADATA", 1736, "Tables have different definitions" }, { "ER_ROW_DOES_NOT_MATCH_PARTITION", 1737, "Found a row that does not match the partition" }, { "ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX", 1738, "Option binlog_cache_size (%lu) is greater than max_binlog_cache_size (%lu); setting binlog_cache_size equal to max_binlog_cache_size" }, { "ER_WARN_INDEX_NOT_APPLICABLE", 1739, "Cannot use %-.64s access on index \'%-.64s\' due to type or collation conversion on field \'%-.64s\'" }, { "ER_PARTITION_EXCHANGE_FOREIGN_KEY", 1740, "Table to exchange with partition has foreign key references: \'%-.64s\'" }, { "ER_NO_SUCH_KEY_VALUE", 1741, "Key value \'%-.192s\' was not found in table \'%-.192s.%-.192s\'" }, { "ER_VALUE_TOO_LONG", 1742, "Too long value for \'%s\'" }, { "ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE", 1743, "Replication event checksum verification failed while reading from network" }, { "ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE", 1744, "Replication event checksum verification failed while reading from a log file" }, { "ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX", 1745, "Option binlog_stmt_cache_size (%lu) is greater than max_binlog_stmt_cache_size (%lu); setting binlog_stmt_cache_size equal to max_binlog_stmt_cache_size" }, { "ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT", 1746, "Can\'t update table \'%-.192s\' while \'%-.192s\' is being created" }, { "ER_PARTITION_CLAUSE_ON_NONPARTITIONED", 1747, "PARTITION () clause on non partitioned table" }, { "ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET", 1748, "Found a row not matching the given partition set" }, { "ER_UNUSED_5", 1749, "You should never see it" }, { "ER_CHANGE_RPL_INFO_REPOSITORY_FAILURE", 1750, "Failure while changing the type of replication repository: %s" }, { "ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE", 1751, "The creation of some temporary tables could not be rolled back" }, { "ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE", 1752, "Some temporary tables were dropped, but these operations could not be rolled back" }, { "ER_MTS_FEATURE_IS_NOT_SUPPORTED", 1753, "%s is not supported in multi-threaded slave mode. %s" }, { "ER_MTS_UPDATED_DBS_GREATER_MAX", 1754, "The number of modified databases exceeds the maximum %d; the database names will not be included in the replication event metadata" }, { "ER_MTS_CANT_PARALLEL", 1755, "Cannot execute the current event group in the parallel mode. Encountered event %s, relay-log name %s, position %s which prevents execution of this event group in parallel mode. Reason: %s" }, { "ER_MTS_INCONSISTENT_DATA", 1756, "%s" }, { "ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING", 1757, "FULLTEXT index is not supported for partitioned tables" }, { "ER_DA_INVALID_CONDITION_NUMBER", 1758, "Invalid condition number" }, { "ER_INSECURE_PLAIN_TEXT", 1759, "Sending passwords in plain text without SSL/TLS is extremely insecure" }, { "ER_INSECURE_CHANGE_MASTER", 1760, "Storing MariaDB user name or password information in the master.info repository is not secure and is therefore not recommended. Please see the MariaDB Manual for more about this issue and possible alternatives" }, { "ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO", 1761, "Foreign key constraint for table \'%.192s\', record \'%-.192s\' would lead to a duplicate entry in table \'%.192s\', key \'%.192s\'" }, { "ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO", 1762, "Foreign key constraint for table \'%.192s\', record \'%-.192s\' would lead to a duplicate entry in a child table" }, { "ER_SQLTHREAD_WITH_SECURE_SLAVE", 1763, "Setting authentication options is not possible when only the Slave SQL Thread is being started" }, { "ER_TABLE_HAS_NO_FT", 1764, "The table does not have FULLTEXT index to support this query" }, { "ER_VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER", 1765, "The system variable %.200s cannot be set in stored functions or triggers" }, { "ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION", 1766, "The system variable %.200s cannot be set when there is an ongoing transaction" }, { "ER_GTID_NEXT_IS_NOT_IN_GTID_NEXT_LIST", 1767, "The system variable @@SESSION.GTID_NEXT has the value %.200s, which is not listed in @@SESSION.GTID_NEXT_LIST" }, { "ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION_WHEN_GTID_NEXT_LIST_IS_NULL", 1768, "When @@SESSION.GTID_NEXT_LIST == NULL, the system variable @@SESSION.GTID_NEXT cannot change inside a transaction" }, { "ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION", 1769, "The statement \'SET %.200s\' cannot invoke a stored function" }, { "ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL", 1770, "The system variable @@SESSION.GTID_NEXT cannot be \'AUTOMATIC\' when @@SESSION.GTID_NEXT_LIST is non-NULL" }, { "ER_SKIPPING_LOGGED_TRANSACTION", 1771, "Skipping transaction %.200s because it has already been executed and logged" }, { "ER_MALFORMED_GTID_SET_SPECIFICATION", 1772, "Malformed GTID set specification \'%.200s\'" }, { "ER_MALFORMED_GTID_SET_ENCODING", 1773, "Malformed GTID set encoding" }, { "ER_MALFORMED_GTID_SPECIFICATION", 1774, "Malformed GTID specification \'%.200s\'" }, { "ER_GNO_EXHAUSTED", 1775, "Impossible to generate Global Transaction Identifier: the integer component reached the maximal value. Restart the server with a new server_uuid" }, { "ER_BAD_SLAVE_AUTO_POSITION", 1776, "Parameters MASTER_LOG_FILE, MASTER_LOG_POS, RELAY_LOG_FILE and RELAY_LOG_POS cannot be set when MASTER_AUTO_POSITION is active" }, { "ER_AUTO_POSITION_REQUIRES_GTID_MODE_ON", 1777, "CHANGE MASTER TO MASTER_AUTO_POSITION = 1 can only be executed when GTID_MODE = ON" }, { "ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET", 1778, "Cannot execute statements with implicit commit inside a transaction when GTID_NEXT != AUTOMATIC or GTID_NEXT_LIST != NULL" }, { "ER_GTID_MODE_2_OR_3_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON", 1779, "GTID_MODE = ON or GTID_MODE = UPGRADE_STEP_2 requires ENFORCE_GTID_CONSISTENCY = 1" }, { "ER_GTID_MODE_REQUIRES_BINLOG", 1780, "GTID_MODE = ON or UPGRADE_STEP_1 or UPGRADE_STEP_2 requires --log-bin and --log-slave-updates" }, { "ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF", 1781, "GTID_NEXT cannot be set to UUID:NUMBER when GTID_MODE = OFF" }, { "ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON", 1782, "GTID_NEXT cannot be set to ANONYMOUS when GTID_MODE = ON" }, { "ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF", 1783, "GTID_NEXT_LIST cannot be set to a non-NULL value when GTID_MODE = OFF" }, { "ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF", 1784, "Found a Gtid_log_event or Previous_gtids_log_event when GTID_MODE = OFF" }, { "ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE", 1785, "When ENFORCE_GTID_CONSISTENCY = 1, updates to non-transactional tables can only be done in either autocommitted statements or single-statement transactions, and never in the same statement as updates to transactional tables" }, { "ER_GTID_UNSAFE_CREATE_SELECT", 1786, "CREATE TABLE ... SELECT is forbidden when ENFORCE_GTID_CONSISTENCY = 1" }, { "ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION", 1787, "When ENFORCE_GTID_CONSISTENCY = 1, the statements CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE can be executed in a non-transactional context only, and require that AUTOCOMMIT = 1" }, { "ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME", 1788, "The value of GTID_MODE can only change one step at a time: OFF <-> UPGRADE_STEP_1 <-> UPGRADE_STEP_2 <-> ON. Also note that this value must be stepped up or down simultaneously on all servers; see the Manual for instructions." }, { "ER_MASTER_HAS_PURGED_REQUIRED_GTIDS", 1789, "The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires" }, { "ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID", 1790, "GTID_NEXT cannot be changed by a client that owns a GTID. The client owns %s. Ownership is released on COMMIT or ROLLBACK" }, { "ER_UNKNOWN_EXPLAIN_FORMAT", 1791, "Unknown %s format name: \'%s\'" }, { "ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION", 1792, "Cannot execute statement in a READ ONLY transaction" }, { "ER_TOO_LONG_TABLE_PARTITION_COMMENT", 1793, "Comment for table partition \'%-.64s\' is too long (max = %lu)" }, { "ER_SLAVE_CONFIGURATION", 1794, "Slave is not configured or failed to initialize properly. You must at least set --server-id to enable either a master or a slave. Additional error messages can be found in the MariaDB error log" }, { "ER_INNODB_FT_LIMIT", 1795, "InnoDB presently supports one FULLTEXT index creation at a time" }, { "ER_INNODB_NO_FT_TEMP_TABLE", 1796, "Cannot create FULLTEXT index on temporary InnoDB table" }, { "ER_INNODB_FT_WRONG_DOCID_COLUMN", 1797, "Column \'%-.192s\' is of wrong type for an InnoDB FULLTEXT index" }, { "ER_INNODB_FT_WRONG_DOCID_INDEX", 1798, "Index \'%-.192s\' is of wrong type for an InnoDB FULLTEXT index" }, { "ER_INNODB_ONLINE_LOG_TOO_BIG", 1799, "Creating index \'%-.192s\' required more than \'innodb_online_alter_log_max_size\' bytes of modification log. Please try again" }, { "ER_UNKNOWN_ALTER_ALGORITHM", 1800, "Unknown ALGORITHM \'%s\'" }, { "ER_UNKNOWN_ALTER_LOCK", 1801, "Unknown LOCK type \'%s\'" }, { "ER_MTS_CHANGE_MASTER_CANT_RUN_WITH_GAPS", 1802, "CHANGE MASTER cannot be executed when the slave was stopped with an error or killed in MTS mode. Consider using RESET SLAVE or START SLAVE UNTIL" }, { "ER_MTS_RECOVERY_FAILURE", 1803, "Cannot recover after SLAVE errored out in parallel execution mode. Additional error messages can be found in the MariaDB error log" }, { "ER_MTS_RESET_WORKERS", 1804, "Cannot clean up worker info tables. Additional error messages can be found in the MariaDB error log" }, { "ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2", 1805, "Column count of %s.%s is wrong. Expected %d, found %d. The table is probably corrupted" }, { "ER_SLAVE_SILENT_RETRY_TRANSACTION", 1806, "Slave must silently retry current transaction" }, { "ER_UNUSED_22", 1807, "You should never see it" }, { "ER_TABLE_SCHEMA_MISMATCH", 1808, "Schema mismatch (%s)" }, { "ER_TABLE_IN_SYSTEM_TABLESPACE", 1809, "Table %-.192s in system tablespace" }, { "ER_IO_READ_ERROR", 1810, "IO Read error: (%lu, %s) %s" }, { "ER_IO_WRITE_ERROR", 1811, "IO Write error: (%lu, %s) %s" }, { "ER_TABLESPACE_MISSING", 1812, "Tablespace is missing for table \'%-.192s\'" }, { "ER_TABLESPACE_EXISTS", 1813, "Tablespace for table \'%-.192s\' exists. Please DISCARD the tablespace before IMPORT" }, { "ER_TABLESPACE_DISCARDED", 1814, "Tablespace has been discarded for table %`s" }, { "ER_INTERNAL_ERROR", 1815, "Internal error: %-.192s" }, { "ER_INNODB_IMPORT_ERROR", 1816, "ALTER TABLE \'%-.192s\' IMPORT TABLESPACE failed with error %lu : \'%s\'" }, { "ER_INNODB_INDEX_CORRUPT", 1817, "Index corrupt: %s" }, { "ER_INVALID_YEAR_COLUMN_LENGTH", 1818, "YEAR(%lu) column type is deprecated. Creating YEAR(4) column instead" }, { "ER_NOT_VALID_PASSWORD", 1819, "Your password does not satisfy the current policy requirements (%s)" }, { "ER_MUST_CHANGE_PASSWORD", 1820, "You must SET PASSWORD before executing this statement" }, { "ER_FK_NO_INDEX_CHILD", 1821, "Failed to add the foreign key constraint. Missing index for constraint \'%s\' in the foreign table \'%s\'" }, { "ER_FK_NO_INDEX_PARENT", 1822, "Failed to add the foreign key constraint. Missing index for constraint \'%s\' in the referenced table \'%s\'" }, { "ER_FK_FAIL_ADD_SYSTEM", 1823, "Failed to add the foreign key constraint \'%s\' to system tables" }, { "ER_FK_CANNOT_OPEN_PARENT", 1824, "Failed to open the referenced table \'%s\'" }, { "ER_FK_INCORRECT_OPTION", 1825, "Failed to add the foreign key constraint on table \'%s\'. Incorrect options in FOREIGN KEY constraint \'%s\'" }, { "ER_DUP_CONSTRAINT_NAME", 1826, "Duplicate %s constraint name \'%s\'" }, { "ER_PASSWORD_FORMAT", 1827, "The password hash doesn\'t have the expected format. Check if the correct password algorithm is being used with the PASSWORD() function" }, { "ER_FK_COLUMN_CANNOT_DROP", 1828, "Cannot drop column \'%-.192s\': needed in a foreign key constraint \'%-.192s\'" }, { "ER_FK_COLUMN_CANNOT_DROP_CHILD", 1829, "Cannot drop column \'%-.192s\': needed in a foreign key constraint \'%-.192s\' of table %-.192s" }, { "ER_FK_COLUMN_NOT_NULL", 1830, "Column \'%-.192s\' cannot be NOT NULL: needed in a foreign key constraint \'%-.192s\' SET NULL" }, { "ER_DUP_INDEX", 1831, "Duplicate index %`s. This is deprecated and will be disallowed in a future release" }, { "ER_FK_COLUMN_CANNOT_CHANGE", 1832, "Cannot change column \'%-.192s\': used in a foreign key constraint \'%-.192s\'" }, { "ER_FK_COLUMN_CANNOT_CHANGE_CHILD", 1833, "Cannot change column \'%-.192s\': used in a foreign key constraint \'%-.192s\' of table \'%-.192s\'" }, { "ER_FK_CANNOT_DELETE_PARENT", 1834, "Cannot delete rows from table which is parent in a foreign key constraint \'%-.192s\' of table \'%-.192s\'" }, { "ER_MALFORMED_PACKET", 1835, "Malformed communication packet" }, { "ER_READ_ONLY_MODE", 1836, "Running in read-only mode" }, { "ER_GTID_NEXT_TYPE_UNDEFINED_GROUP", 1837, "When GTID_NEXT is set to a GTID, you must explicitly set it again after a COMMIT or ROLLBACK. If you see this error message in the slave SQL thread, it means that a table in the current transaction is transactional on the master and non-transactional on the slave. In a client connection, it means that you executed SET GTID_NEXT before a transaction and forgot to set GTID_NEXT to a different identifier or to \'AUTOMATIC\' after COMMIT or ROLLBACK. Current GTID_NEXT is \'%s\'" }, { "ER_VARIABLE_NOT_SETTABLE_IN_SP", 1838, "The system variable %.200s cannot be set in stored procedures" }, { "ER_CANT_SET_GTID_PURGED_WHEN_GTID_MODE_IS_OFF", 1839, "GTID_PURGED can only be set when GTID_MODE = ON" }, { "ER_CANT_SET_GTID_PURGED_WHEN_GTID_EXECUTED_IS_NOT_EMPTY", 1840, "GTID_PURGED can only be set when GTID_EXECUTED is empty" }, { "ER_CANT_SET_GTID_PURGED_WHEN_OWNED_GTIDS_IS_NOT_EMPTY", 1841, "GTID_PURGED can only be set when there are no ongoing transactions (not even in other clients)" }, { "ER_GTID_PURGED_WAS_CHANGED", 1842, "GTID_PURGED was changed from \'%s\' to \'%s\'" }, { "ER_GTID_EXECUTED_WAS_CHANGED", 1843, "GTID_EXECUTED was changed from \'%s\' to \'%s\'" }, { "ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES", 1844, "Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT, and both replicated and non replicated tables are written to" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED", 1845, "%s is not supported for this operation. Try %s" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON", 1846, "%s is not supported. Reason: %s. Try %s" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY", 1847, "COPY algorithm requires a lock" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION", 1848, "Partition specific operations do not yet support LOCK/ALGORITHM" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME", 1849, "Columns participating in a foreign key are renamed" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE", 1850, "Cannot change column type" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_CHECK", 1851, "Adding foreign keys needs foreign_key_checks=OFF" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_IGNORE", 1852, "Creating unique indexes with IGNORE requires COPY algorithm to remove duplicate rows" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOPK", 1853, "Dropping a primary key is not allowed without also adding a new primary key" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_AUTOINC", 1854, "Adding an auto-increment column requires a lock" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_HIDDEN_FTS", 1855, "Cannot replace hidden FTS_DOC_ID with a user-visible one" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_CHANGE_FTS", 1856, "Cannot drop or rename FTS_DOC_ID" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS", 1857, "Fulltext index creation requires a lock" }, { "ER_SQL_SLAVE_SKIP_COUNTER_NOT_SETTABLE_IN_GTID_MODE", 1858, "sql_slave_skip_counter can not be set when the server is running with GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction" }, { "ER_DUP_UNKNOWN_IN_INDEX", 1859, "Duplicate entry for key \'%-.192s\'" }, { "ER_IDENT_CAUSES_TOO_LONG_PATH", 1860, "Long database name and identifier for object resulted in path length exceeding %d characters. Path: \'%s\'" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL", 1861, "cannot convert NULL to non-constant DEFAULT" }, { "ER_MUST_CHANGE_PASSWORD_LOGIN", 1862, "Your password has expired. To log in you must change it using a client that supports expired passwords" }, { "ER_ROW_IN_WRONG_PARTITION", 1863, "Found a row in wrong partition %s" }, { "ER_MTS_EVENT_BIGGER_PENDING_JOBS_SIZE_MAX", 1864, "Cannot schedule event %s, relay-log name %s, position %s to Worker thread because its size %lu exceeds %lu of slave_pending_jobs_size_max" }, { "ER_INNODB_NO_FT_USES_PARSER", 1865, "Cannot CREATE FULLTEXT INDEX WITH PARSER on InnoDB table" }, { "ER_BINLOG_LOGICAL_CORRUPTION", 1866, "The binary log file \'%s\' is logically corrupted: %s" }, { "ER_WARN_PURGE_LOG_IN_USE", 1867, "file %s was not purged because it was being read by %d thread(s), purged only %d out of %d files" }, { "ER_WARN_PURGE_LOG_IS_ACTIVE", 1868, "file %s was not purged because it is the active log file" }, { "ER_AUTO_INCREMENT_CONFLICT", 1869, "Auto-increment value in UPDATE conflicts with internally generated values" }, { "WARN_ON_BLOCKHOLE_IN_RBR", 1870, "Row events are not logged for %s statements that modify BLACKHOLE tables in row format. Table(s): \'%-.192s\'" }, { "ER_SLAVE_MI_INIT_REPOSITORY", 1871, "Slave failed to initialize master info structure from the repository" }, { "ER_SLAVE_RLI_INIT_REPOSITORY", 1872, "Slave failed to initialize relay log info structure from the repository" }, { "ER_ACCESS_DENIED_CHANGE_USER_ERROR", 1873, "Access denied trying to change to user \'%-.48s\'@\'%-.64s\' (using password: %s). Disconnecting" }, { "ER_INNODB_READ_ONLY", 1874, "InnoDB is in read only mode" }, { "ER_STOP_SLAVE_SQL_THREAD_TIMEOUT", 1875, "STOP SLAVE command execution is incomplete: Slave SQL thread got the stop signal, thread is busy, SQL thread will stop once the current task is complete" }, { "ER_STOP_SLAVE_IO_THREAD_TIMEOUT", 1876, "STOP SLAVE command execution is incomplete: Slave IO thread got the stop signal, thread is busy, IO thread will stop once the current task is complete" }, { "ER_TABLE_CORRUPT", 1877, "Operation cannot be performed. The table \'%-.64s.%-.64s\' is missing, corrupt or contains bad data" }, { "ER_TEMP_FILE_WRITE_FAILURE", 1878, "Temporary file write failure" }, { "ER_INNODB_FT_AUX_NOT_HEX_ID", 1879, "Upgrade index name failed, please use create index(alter table) algorithm copy to rebuild index" }, { "ER_LAST_MYSQL_ERROR_MESSAGE", 1880, "\"" }, { "ER_UNUSED_18", 1900, "You should never see it" }, { "ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED", 1901, "Function or expression \'%s\' cannot be used in the %s clause of %`s" }, { "ER_UNUSED_19", 1902, "You should never see it" }, { "ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN", 1903, "Primary key cannot be defined upon a generated column" }, { "ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN", 1904, "Key/Index cannot be defined on a virtual generated column" }, { "ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN", 1905, "Cannot define foreign key with %s clause on a generated column" }, { "ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN", 1906, "The value specified for generated column \'%s\' in table \'%s\' has been ignored" }, { "ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN", 1907, "This is not yet supported for generated columns" }, { "ER_UNUSED_20", 1908, "You should never see it" }, { "ER_UNUSED_21", 1909, "You should never see it" }, { "ER_UNSUPPORTED_ENGINE_FOR_GENERATED_COLUMNS", 1910, "%s storage engine does not support generated columns" }, { "ER_UNKNOWN_OPTION", 1911, "Unknown option \'%-.64s\'" }, { "ER_BAD_OPTION_VALUE", 1912, "Incorrect value \'%-.64T\' for option \'%-.64s\'" }, { "ER_UNUSED_6", 1913, "You should never see it" }, { "ER_UNUSED_7", 1914, "You should never see it" }, { "ER_UNUSED_8", 1915, "You should never see it" }, { "ER_DATA_OVERFLOW", 1916, "Got overflow when converting \'%-.128s\' to %-.32s. Value truncated" }, { "ER_DATA_TRUNCATED", 1917, "Truncated value \'%-.128s\' when converting to %-.32s" }, { "ER_BAD_DATA", 1918, "Encountered illegal value \'%-.128s\' when converting to %-.32s" }, { "ER_DYN_COL_WRONG_FORMAT", 1919, "Encountered illegal format of dynamic column string" }, { "ER_DYN_COL_IMPLEMENTATION_LIMIT", 1920, "Dynamic column implementation limit reached" }, { "ER_DYN_COL_DATA", 1921, "Illegal value used as argument of dynamic column function" }, { "ER_DYN_COL_WRONG_CHARSET", 1922, "Dynamic column contains unknown character set" }, { "ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES", 1923, "At least one of the \'in_to_exists\' or \'materialization\' optimizer_switch flags must be \'on\'" }, { "ER_QUERY_CACHE_IS_DISABLED", 1924, "Query cache is disabled (resize or similar command in progress); repeat this command later" }, { "ER_QUERY_CACHE_IS_GLOBALY_DISABLED", 1925, "Query cache is globally disabled and you can\'t enable it only for this session" }, { "ER_VIEW_ORDERBY_IGNORED", 1926, "View \'%-.192s\'.\'%-.192s\' ORDER BY clause ignored because there is other ORDER BY clause already" }, { "ER_CONNECTION_KILLED", 1927, "Connection was killed" }, { "ER_UNUSED_12", 1928, "You should never see it" }, { "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION", 1929, "Cannot modify @@session.skip_replication inside a transaction" }, { "ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION", 1930, "Cannot modify @@session.skip_replication inside a stored function or trigger" }, { "ER_QUERY_RESULT_INCOMPLETE", 1931, "Query execution was interrupted. The query exceeded %s %llu. The query result may be incomplete" }, { "ER_NO_SUCH_TABLE_IN_ENGINE", 1932, "Table \'%-.192s.%-.192s\' doesn\'t exist in engine" }, { "ER_TARGET_NOT_EXPLAINABLE", 1933, "Target is not running an EXPLAINable command" }, { "ER_CONNECTION_ALREADY_EXISTS", 1934, "Connection \'%.*s\' conflicts with existing connection \'%.*s\'" }, { "ER_MASTER_LOG_PREFIX", 1935, "Master \'%.*s\': " }, { "ER_CANT_START_STOP_SLAVE", 1936, "Can\'t %s SLAVE \'%.*s\'" }, { "ER_SLAVE_STARTED", 1937, "SLAVE \'%.*s\' started" }, { "ER_SLAVE_STOPPED", 1938, "SLAVE \'%.*s\' stopped" }, { "ER_SQL_DISCOVER_ERROR", 1939, "Engine %s failed to discover table %`-.192s.%`-.192s with \'%s\'" }, { "ER_FAILED_GTID_STATE_INIT", 1940, "Failed initializing replication GTID state" }, { "ER_INCORRECT_GTID_STATE", 1941, "Could not parse GTID list" }, { "ER_CANNOT_UPDATE_GTID_STATE", 1942, "Could not update replication slave gtid state" }, { "ER_DUPLICATE_GTID_DOMAIN", 1943, "GTID %u-%u-%llu and %u-%u-%llu conflict (duplicate domain id %u)" }, { "ER_GTID_OPEN_TABLE_FAILED", 1944, "Failed to open %s.%s" }, { "ER_GTID_POSITION_NOT_FOUND_IN_BINLOG", 1945, "Connecting slave requested to start from GTID %u-%u-%llu, which is not in the master\'s binlog" }, { "ER_CANNOT_LOAD_SLAVE_GTID_STATE", 1946, "Failed to load replication slave GTID position from table %s.%s" }, { "ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG", 1947, "Specified GTID %u-%u-%llu conflicts with the binary log which contains a more recent GTID %u-%u-%llu. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos" }, { "ER_MASTER_GTID_POS_MISSING_DOMAIN", 1948, "Specified value for @@gtid_slave_pos contains no value for replication domain %u. This conflicts with the binary log which contains GTID %u-%u-%llu. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos" }, { "ER_UNTIL_REQUIRES_USING_GTID", 1949, "START SLAVE UNTIL master_gtid_pos requires that slave is using GTID" }, { "ER_GTID_STRICT_OUT_OF_ORDER", 1950, "An attempt was made to binlog GTID %u-%u-%llu which would create an out-of-order sequence number with existing GTID %u-%u-%llu, and gtid strict mode is enabled" }, { "ER_GTID_START_FROM_BINLOG_HOLE", 1951, "The binlog on the master is missing the GTID %u-%u-%llu requested by the slave (even though a subsequent sequence number does exist), and GTID strict mode is enabled" }, { "ER_SLAVE_UNEXPECTED_MASTER_SWITCH", 1952, "Unexpected GTID received from master after reconnect. This normally indicates that the master server was replaced without restarting the slave threads. %s" }, { "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO", 1953, "Cannot modify @@session.gtid_domain_id or @@session.gtid_seq_no inside a transaction" }, { "ER_STORED_FUNCTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO", 1954, "Cannot modify @@session.gtid_domain_id or @@session.gtid_seq_no inside a stored function or trigger" }, { "ER_GTID_POSITION_NOT_FOUND_IN_BINLOG2", 1955, "Connecting slave requested to start from GTID %u-%u-%llu, which is not in the master\'s binlog. Since the master\'s binlog contains GTIDs with higher sequence numbers, it probably means that the slave has diverged due to executing extra erroneous transactions" }, { "ER_BINLOG_MUST_BE_EMPTY", 1956, "This operation is not allowed if any GTID has been logged to the binary log. Run RESET MASTER first to erase the log" }, { "ER_NO_SUCH_QUERY", 1957, "Unknown query id: %lld" }, { "ER_BAD_BASE64_DATA", 1958, "Bad base64 data as position %u" }, { "ER_INVALID_ROLE", 1959, "Invalid role specification %`s" }, { "ER_INVALID_CURRENT_USER", 1960, "The current user is invalid" }, { "ER_CANNOT_GRANT_ROLE", 1961, "Cannot grant role \'%s\' to: %s" }, { "ER_CANNOT_REVOKE_ROLE", 1962, "Cannot revoke role \'%s\' from: %s" }, { "ER_CHANGE_SLAVE_PARALLEL_THREADS_ACTIVE", 1963, "Cannot change @@slave_parallel_threads while another change is in progress" }, { "ER_PRIOR_COMMIT_FAILED", 1964, "Commit failed due to failure of an earlier commit on which this one depends" }, { "ER_IT_IS_A_VIEW", 1965, "\'%-.192s\' is a view" }, { "ER_SLAVE_SKIP_NOT_IN_GTID", 1966, "When using parallel replication and GTID with multiple replication domains, @@sql_slave_skip_counter can not be used. Instead, setting @@gtid_slave_pos explicitly can be used to skip to after a given GTID position" }, { "ER_TABLE_DEFINITION_TOO_BIG", 1967, "The definition for table %`s is too big" }, { "ER_PLUGIN_INSTALLED", 1968, "Plugin \'%-.192s\' already installed" }, { "ER_STATEMENT_TIMEOUT", 1969, "Query execution was interrupted (max_statement_time exceeded)" }, { "ER_SUBQUERIES_NOT_SUPPORTED", 1970, "%s does not support subqueries or stored functions" }, { "ER_SET_STATEMENT_NOT_SUPPORTED", 1971, "The system variable %.200s cannot be set in SET STATEMENT." }, { "ER_UNUSED_9", 1972, "You should never see it" }, { "ER_USER_CREATE_EXISTS", 1973, "Can\'t create user \'%-.64s\'@\'%-.64s\'; it already exists" }, { "ER_USER_DROP_EXISTS", 1974, "Can\'t drop user \'%-.64s\'@\'%-.64s\'; it doesn\'t exist" }, { "ER_ROLE_CREATE_EXISTS", 1975, "Can\'t create role \'%-.64s\'; it already exists" }, { "ER_ROLE_DROP_EXISTS", 1976, "Can\'t drop role \'%-.64s\'; it doesn\'t exist" }, { "ER_CANNOT_CONVERT_CHARACTER", 1977, "Cannot convert \'%s\' character 0x%-.64s to \'%s\'" }, { "ER_INVALID_DEFAULT_VALUE_FOR_FIELD", 1978, "Incorrect default value \'%-.128T\' for column \'%.192s\'" }, { "ER_KILL_QUERY_DENIED_ERROR", 1979, "You are not owner of query %lld" }, { "ER_NO_EIS_FOR_FIELD", 1980, "Engine-independent statistics are not collected for column \'%s\'" }, { "ER_WARN_AGGFUNC_DEPENDENCE", 1981, "Aggregate function \'%-.192s)\' of SELECT #%d belongs to SELECT #%d" }, { "WARN_INNODB_PARTITION_OPTION_IGNORED", 1982, "<%-.64s> option ignored for InnoDB partition" }, { "ER_FILE_CORRUPT", 3000, "File %s is corrupted" }, { "ER_ERROR_ON_MASTER", 3001, "Query partially completed on the master (error on master: %d) and was aborted. There is a chance that your master is inconsistent at this point. If you are sure that your master is ok, run this query manually on the slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE;. Query:\'%s\'" }, { "ER_INCONSISTENT_ERROR", 3002, "Query caused different errors on master and slave. Error on master: message (format)=\'%s\' error code=%d; Error on slave:actual message=\'%s\', error code=%d. Default database:\'%s\'. Query:\'%s\'" }, { "ER_STORAGE_ENGINE_NOT_LOADED", 3003, "Storage engine for table \'%s\'.\'%s\' is not loaded." }, { "ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER", 3004, "GET STACKED DIAGNOSTICS when handler not active" }, { "ER_WARN_LEGACY_SYNTAX_CONVERTED", 3005, "%s is no longer supported. The statement was converted to %s." }, { "ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN", 3006, "Statement is unsafe because it uses a fulltext parser plugin which may not return the same value on the slave." }, { "ER_CANNOT_DISCARD_TEMPORARY_TABLE", 3007, "Cannot DISCARD/IMPORT tablespace associated with temporary table" }, { "ER_FK_DEPTH_EXCEEDED", 3008, "Foreign key cascade delete/update exceeds max depth of %d." }, { "ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2", 3009, "Column count of %s.%s is wrong. Expected %d, found %d. Created with MariaDB %d, now running %d. Please use mariadb-upgrade to fix this error." }, { "ER_WARN_TRIGGER_DOESNT_HAVE_CREATED", 3010, "Trigger %s.%s.%s does not have CREATED attribute." }, { "ER_REFERENCED_TRG_DOES_NOT_EXIST_MYSQL", 3011, "Referenced trigger \'%s\' for the given action time and event type does not exist." }, { "ER_EXPLAIN_NOT_SUPPORTED", 3012, "EXPLAIN FOR CONNECTION command is supported only for SELECT/UPDATE/INSERT/DELETE/REPLACE" }, { "ER_INVALID_FIELD_SIZE", 3013, "Invalid size for column \'%-.192s\'." }, { "ER_MISSING_HA_CREATE_OPTION", 3014, "Table storage engine \'%-.64s\' found required create option missing" }, { "ER_ENGINE_OUT_OF_MEMORY", 3015, "Out of memory in storage engine \'%-.64s\'." }, { "ER_PASSWORD_EXPIRE_ANONYMOUS_USER", 3016, "The password for anonymous user cannot be expired." }, { "ER_SLAVE_SQL_THREAD_MUST_STOP", 3017, "This operation cannot be performed with a running slave sql thread; run STOP SLAVE SQL_THREAD first" }, { "ER_NO_FT_MATERIALIZED_SUBQUERY", 3018, "Cannot create FULLTEXT index on materialized subquery" }, { "ER_INNODB_UNDO_LOG_FULL", 3019, "Undo Log error: %s" }, { "ER_INVALID_ARGUMENT_FOR_LOGARITHM", 3020, "Invalid argument for logarithm" }, { "ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP", 3021, "This operation cannot be performed with a running slave io thread; run STOP SLAVE IO_THREAD FOR CHANNEL \'%s\' first." }, { "ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO", 3022, "This operation may not be safe when the slave has temporary tables. The tables will be kept open until the server restarts or until the tables are deleted by any replicated DROP statement. Suggest to wait until slave_open_temp_tables = 0." }, { "ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS", 3023, "CHANGE MASTER TO with a MASTER_LOG_FILE clause but no MASTER_LOG_POS clause may not be safe. The old position value may not be valid for the new binary log file." }, { "ER_UNUSED_1", 3024, "You should never see it" }, { "ER_NON_RO_SELECT_DISABLE_TIMER", 3025, "Select is not a read only statement, disabling timer" }, { "ER_DUP_LIST_ENTRY", 3026, "Duplicate entry \'%-.192s\'." }, { "ER_SQL_MODE_NO_EFFECT", 3027, "\'%s\' mode no longer has any effect. Use STRICT_ALL_TABLES or STRICT_TRANS_TABLES instead." }, { "ER_AGGREGATE_ORDER_FOR_UNION", 3028, "Expression #%u of ORDER BY contains aggregate function and applies to a UNION" }, { "ER_AGGREGATE_ORDER_NON_AGG_QUERY", 3029, "Expression #%u of ORDER BY contains aggregate function and applies to the result of a non-aggregated query" }, { "ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR", 3030, "Slave worker has stopped after at least one previous worker encountered an error when slave-preserve-commit-order was enabled. To preserve commit order, the last transaction executed by this thread has not been committed. When restarting the slave after fixing any failed threads, you should fix this worker as well." }, { "ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER", 3031, "slave_preserve_commit_order is not supported %s." }, { "ER_SERVER_OFFLINE_MODE", 3032, "The server is currently in offline mode" }, { "ER_GIS_DIFFERENT_SRIDS", 3033, "Binary geometry function %s given two geometries of different srids: %u and %u, which should have been identical." }, { "ER_GIS_UNSUPPORTED_ARGUMENT", 3034, "Calling geometry function %s with unsupported types of arguments." }, { "ER_GIS_UNKNOWN_ERROR", 3035, "Unknown GIS error occurred in function %s." }, { "ER_GIS_UNKNOWN_EXCEPTION", 3036, "Unknown exception caught in GIS function %s." }, { "ER_GIS_INVALID_DATA", 3037, "Invalid GIS data provided to function %s." }, { "ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION", 3038, "The geometry has no data in function %s." }, { "ER_BOOST_GEOMETRY_CENTROID_EXCEPTION", 3039, "Unable to calculate centroid because geometry is empty in function %s." }, { "ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION", 3040, "Geometry overlay calculation error: geometry data is invalid in function %s." }, { "ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION", 3041, "Geometry turn info calculation error: geometry data is invalid in function %s." }, { "ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION", 3042, "Analysis procedures of intersection points interrupted unexpectedly in function %s." }, { "ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION", 3043, "Unknown exception thrown in function %s." }, { "ER_STD_BAD_ALLOC_ERROR", 3044, "Memory allocation error: %-.256s in function %s." }, { "ER_STD_DOMAIN_ERROR", 3045, "Domain error: %-.256s in function %s." }, { "ER_STD_LENGTH_ERROR", 3046, "Length error: %-.256s in function %s." }, { "ER_STD_INVALID_ARGUMENT", 3047, "Invalid argument error: %-.256s in function %s." }, { "ER_STD_OUT_OF_RANGE_ERROR", 3048, "Out of range error: %-.256s in function %s." }, { "ER_STD_OVERFLOW_ERROR", 3049, "Overflow error: %-.256s in function %s." }, { "ER_STD_RANGE_ERROR", 3050, "Range error: %-.256s in function %s." }, { "ER_STD_UNDERFLOW_ERROR", 3051, "Underflow error: %-.256s in function %s." }, { "ER_STD_LOGIC_ERROR", 3052, "Logic error: %-.256s in function %s." }, { "ER_STD_RUNTIME_ERROR", 3053, "Runtime error: %-.256s in function %s." }, { "ER_STD_UNKNOWN_EXCEPTION", 3054, "Unknown exception: %-.384s in function %s." }, { "ER_GIS_DATA_WRONG_ENDIANESS", 3055, "Geometry byte string must be little endian." }, { "ER_CHANGE_MASTER_PASSWORD_LENGTH", 3056, "The password provided for the replication user exceeds the maximum length of 32 characters" }, { "ER_USER_LOCK_WRONG_NAME", 3057, "Incorrect user-level lock name \'%-.192s\'." }, { "ER_USER_LOCK_DEADLOCK", 3058, "Deadlock found when trying to get user-level lock; try rolling back transaction/releasing locks and restarting lock acquisition." }, { "ER_REPLACE_INACCESSIBLE_ROWS", 3059, "REPLACE cannot be executed as it requires deleting rows that are not in the view" }, { "ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS", 3060, "Do not support online operation on table with GIS index" }, { "ER_UNUSED_26", 4000, "This error never happens" }, { "ER_UNUSED_27", 4001, "This error never happens" }, { "ER_WITH_COL_WRONG_LIST", 4002, "WITH column list and SELECT field list have different column counts" }, { "ER_TOO_MANY_DEFINITIONS_IN_WITH_CLAUSE", 4003, "Too many WITH elements in WITH clause" }, { "ER_DUP_QUERY_NAME", 4004, "Duplicate query name %`-.64s in WITH clause" }, { "ER_RECURSIVE_WITHOUT_ANCHORS", 4005, "No anchors for recursive WITH element \'%s\'" }, { "ER_UNACCEPTABLE_MUTUAL_RECURSION", 4006, "Unacceptable mutual recursion with anchored table \'%s\'" }, { "ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED", 4007, "Reference to recursive WITH table \'%s\' in materialized derived" }, { "ER_NOT_STANDARD_COMPLIANT_RECURSIVE", 4008, "Restrictions imposed on recursive definitions are violated for table \'%s\'" }, { "ER_WRONG_WINDOW_SPEC_NAME", 4009, "Window specification with name \'%s\' is not defined" }, { "ER_DUP_WINDOW_NAME", 4010, "Multiple window specifications with the same name \'%s\'" }, { "ER_PARTITION_LIST_IN_REFERENCING_WINDOW_SPEC", 4011, "Window specification referencing another one \'%s\' cannot contain partition list" }, { "ER_ORDER_LIST_IN_REFERENCING_WINDOW_SPEC", 4012, "Referenced window specification \'%s\' already contains order list" }, { "ER_WINDOW_FRAME_IN_REFERENCED_WINDOW_SPEC", 4013, "Referenced window specification \'%s\' cannot contain window frame" }, { "ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS", 4014, "Unacceptable combination of window frame bound specifications" }, { "ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION", 4015, "Window function is allowed only in SELECT list and ORDER BY clause" }, { "ER_WINDOW_FUNCTION_IN_WINDOW_SPEC", 4016, "Window function is not allowed in window specification" }, { "ER_NOT_ALLOWED_WINDOW_FRAME", 4017, "Window frame is not allowed with \'%s\'" }, { "ER_NO_ORDER_LIST_IN_WINDOW_SPEC", 4018, "No order list in window specification for \'%s\'" }, { "ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY", 4019, "RANGE-type frame requires ORDER BY clause with single sort key" }, { "ER_WRONG_TYPE_FOR_ROWS_FRAME", 4020, "Integer is required for ROWS-type frame" }, { "ER_WRONG_TYPE_FOR_RANGE_FRAME", 4021, "Numeric datatype is required for RANGE-type frame" }, { "ER_FRAME_EXCLUSION_NOT_SUPPORTED", 4022, "Frame exclusion is not supported yet" }, { "ER_WINDOW_FUNCTION_DONT_HAVE_FRAME", 4023, "This window function may not have a window frame" }, { "ER_INVALID_NTILE_ARGUMENT", 4024, "Argument of NTILE must be greater than 0" }, { "ER_CONSTRAINT_FAILED", 4025, "CONSTRAINT %`s failed for %`-.192s.%`-.192s" }, { "ER_EXPRESSION_IS_TOO_BIG", 4026, "Expression in the %s clause is too big" }, { "ER_ERROR_EVALUATING_EXPRESSION", 4027, "Got an error evaluating stored expression %s" }, { "ER_CALCULATING_DEFAULT_VALUE", 4028, "Got an error when calculating default value for %`s" }, { "ER_EXPRESSION_REFERS_TO_UNINIT_FIELD", 4029, "Expression for field %`-.64s is referring to uninitialized field %`s" }, { "ER_PARTITION_DEFAULT_ERROR", 4030, "Only one DEFAULT partition allowed" }, { "ER_REFERENCED_TRG_DOES_NOT_EXIST", 4031, "Referenced trigger \'%s\' for the given action time and event type does not exist" }, { "ER_INVALID_DEFAULT_PARAM", 4032, "Default/ignore value is not supported for such parameter usage" }, { "ER_BINLOG_NON_SUPPORTED_BULK", 4033, "Only row based replication supported for bulk operations" }, { "ER_BINLOG_UNCOMPRESS_ERROR", 4034, "Uncompress the compressed binlog failed" }, { "ER_JSON_BAD_CHR", 4035, "Broken JSON string in argument %d to function \'%s\' at position %d" }, { "ER_JSON_NOT_JSON_CHR", 4036, "Character disallowed in JSON in argument %d to function \'%s\' at position %d" }, { "ER_JSON_EOS", 4037, "Unexpected end of JSON text in argument %d to function \'%s\'" }, { "ER_JSON_SYNTAX", 4038, "Syntax error in JSON text in argument %d to function \'%s\' at position %d" }, { "ER_JSON_ESCAPING", 4039, "Incorrect escaping in JSON text in argument %d to function \'%s\' at position %d" }, { "ER_JSON_DEPTH", 4040, "Limit of %d on JSON nested structures depth is reached in argument %d to function \'%s\' at position %d" }, { "ER_JSON_PATH_EOS", 4041, "Unexpected end of JSON path in argument %d to function \'%s\'" }, { "ER_JSON_PATH_SYNTAX", 4042, "Syntax error in JSON path in argument %d to function \'%s\' at position %d" }, { "ER_JSON_PATH_DEPTH", 4043, "Limit of %d on JSON path depth is reached in argument %d to function \'%s\' at position %d" }, { "ER_JSON_PATH_NO_WILDCARD", 4044, "Wildcards in JSON path not allowed in argument %d to function \'%s\'" }, { "ER_JSON_PATH_ARRAY", 4045, "JSON path should end with an array identifier in argument %d to function \'%s\'" }, { "ER_JSON_ONE_OR_ALL", 4046, "Argument 2 to function \'%s\' must be \"one\" or \"all\"." }, { "ER_UNSUPPORTED_COMPRESSED_TABLE", 4047, "InnoDB refuses to write tables with ROW_FORMAT=COMPRESSED or KEY_BLOCK_SIZE." }, { "ER_GEOJSON_INCORRECT", 4048, "Incorrect GeoJSON format specified for st_geomfromgeojson function." }, { "ER_GEOJSON_TOO_FEW_POINTS", 4049, "Incorrect GeoJSON format - too few points for linestring specified." }, { "ER_GEOJSON_NOT_CLOSED", 4050, "Incorrect GeoJSON format - polygon not closed." }, { "ER_JSON_PATH_EMPTY", 4051, "Path expression \'$\' is not allowed in argument %d to function \'%s\'." }, { "ER_SLAVE_SAME_ID", 4052, "A slave with the same server_uuid/server_id as this slave has connected to the master" }, { "ER_FLASHBACK_NOT_SUPPORTED", 4053, "Flashback does not support %s %s" }, { "ER_KEYS_OUT_OF_ORDER", 4054, "Keys are out order during bulk load" }, { "ER_OVERLAPPING_KEYS", 4055, "Bulk load rows overlap existing rows" }, { "ER_REQUIRE_ROW_BINLOG_FORMAT", 4056, "Can\'t execute updates on master with binlog_format != ROW." }, { "ER_ISOLATION_MODE_NOT_SUPPORTED", 4057, "MyRocks supports only READ COMMITTED and REPEATABLE READ isolation levels. Please change from current isolation level %s" }, { "ER_ON_DUPLICATE_DISABLED", 4058, "When unique checking is disabled in MyRocks, INSERT,UPDATE,LOAD statements with clauses that update or replace the key (i.e. INSERT ON DUPLICATE KEY UPDATE, REPLACE) are not allowed. Query: %s" }, { "ER_UPDATES_WITH_CONSISTENT_SNAPSHOT", 4059, "Can\'t execute updates when you started a transaction with START TRANSACTION WITH CONSISTENT [ROCKSDB] SNAPSHOT." }, { "ER_ROLLBACK_ONLY", 4060, "This transaction was rolled back and cannot be committed. Only supported operation is to roll it back, so all pending changes will be discarded. Please restart another transaction." }, { "ER_ROLLBACK_TO_SAVEPOINT", 4061, "MyRocks currently does not support ROLLBACK TO SAVEPOINT if modifying rows." }, { "ER_ISOLATION_LEVEL_WITH_CONSISTENT_SNAPSHOT", 4062, "Only REPEATABLE READ isolation level is supported for START TRANSACTION WITH CONSISTENT SNAPSHOT in RocksDB Storage Engine." }, { "ER_UNSUPPORTED_COLLATION", 4063, "Unsupported collation on string indexed column %s.%s Use binary collation (%s)." }, { "ER_METADATA_INCONSISTENCY", 4064, "Table \'%s\' does not exist, but metadata information exists inside MyRocks. This is a sign of data inconsistency. Please check if \'%s.frm\' exists, and try to restore it if it does not exist." }, { "ER_CF_DIFFERENT", 4065, "Column family (\'%s\') flag (%d) is different from an existing flag (%d). Assign a new CF flag, or do not change existing CF flag." }, { "ER_RDB_TTL_DURATION_FORMAT", 4066, "TTL duration (%s) in MyRocks must be an unsigned non-null 64-bit integer." }, { "ER_RDB_STATUS_GENERAL", 4067, "Status error %d received from RocksDB: %s" }, { "ER_RDB_STATUS_MSG", 4068, "%s, Status error %d received from RocksDB: %s" }, { "ER_RDB_TTL_UNSUPPORTED", 4069, "TTL support is currently disabled when table has a hidden PK." }, { "ER_RDB_TTL_COL_FORMAT", 4070, "TTL column (%s) in MyRocks must be an unsigned non-null 64-bit integer, exist inside the table, and have an accompanying ttl duration." }, { "ER_PER_INDEX_CF_DEPRECATED", 4071, "The per-index column family option has been deprecated" }, { "ER_KEY_CREATE_DURING_ALTER", 4072, "MyRocks failed creating new key definitions during alter." }, { "ER_SK_POPULATE_DURING_ALTER", 4073, "MyRocks failed populating secondary key during alter." }, { "ER_SUM_FUNC_WITH_WINDOW_FUNC_AS_ARG", 4074, "Window functions can not be used as arguments to group functions." }, { "ER_NET_OK_PACKET_TOO_LARGE", 4075, "OK packet too large" }, { "ER_GEOJSON_EMPTY_COORDINATES", 4076, "Incorrect GeoJSON format - empty \'coordinates\' array." }, { "ER_MYROCKS_CANT_NOPAD_COLLATION", 4077, "MyRocks doesn\'t currently support collations with \"No pad\" attribute." }, { "ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION", 4078, "Illegal parameter data types %s and %s for operation \'%s\'" }, { "ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION", 4079, "Illegal parameter data type %s for operation \'%s\'" }, { "ER_WRONG_PARAMCOUNT_TO_CURSOR", 4080, "Incorrect parameter count to cursor \'%-.192s\'" }, { "ER_UNKNOWN_STRUCTURED_VARIABLE", 4081, "Unknown structured system variable or ROW routine variable \'%-.*s\'" }, { "ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD", 4082, "Row variable \'%-.192s\' does not have a field \'%-.192s\'" }, { "ER_END_IDENTIFIER_DOES_NOT_MATCH", 4083, "END identifier \'%-.192s\' does not match \'%-.192s\'" }, { "ER_SEQUENCE_RUN_OUT", 4084, "Sequence \'%-.64s.%-.64s\' has run out" }, { "ER_SEQUENCE_INVALID_DATA", 4085, "Sequence \'%-.64s.%-.64s\' has out of range value for options" }, { "ER_SEQUENCE_INVALID_TABLE_STRUCTURE", 4086, "Sequence \'%-.64s.%-.64s\' table structure is invalid (%s)" }, { "ER_SEQUENCE_ACCESS_ERROR", 4087, "Sequence \'%-.64s.%-.64s\' access error" }, { "ER_SEQUENCE_BINLOG_FORMAT", 4088, "Sequences requires binlog_format mixed or row" }, { "ER_NOT_SEQUENCE", 4089, "\'%-.64s.%-.64s\' is not a SEQUENCE" }, { "ER_NOT_SEQUENCE2", 4090, "\'%-.192s\' is not a SEQUENCE" }, { "ER_UNKNOWN_SEQUENCES", 4091, "Unknown SEQUENCE: \'%-.300s\'" }, { "ER_UNKNOWN_VIEW", 4092, "Unknown VIEW: \'%-.300s\'" }, { "ER_WRONG_INSERT_INTO_SEQUENCE", 4093, "Wrong INSERT into a SEQUENCE. One can only do single table INSERT into a sequence object (like with mariadb-dump). If you want to change the SEQUENCE, use ALTER SEQUENCE instead." }, { "ER_SP_STACK_TRACE", 4094, "At line %u in %s" }, { "ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY", 4095, "Subroutine \'%-.192s\' is declared in the package specification but is not defined in the package body" }, { "ER_PACKAGE_ROUTINE_FORWARD_DECLARATION_NOT_DEFINED", 4096, "Subroutine \'%-.192s\' has a forward declaration but is not defined" }, { "ER_COMPRESSED_COLUMN_USED_AS_KEY", 4097, "Compressed column \'%-.192s\' can\'t be used in key specification" }, { "ER_UNKNOWN_COMPRESSION_METHOD", 4098, "Unknown compression method: %s" }, { "ER_WRONG_NUMBER_OF_VALUES_IN_TVC", 4099, "The used table value constructor has a different number of values" }, { "ER_FIELD_REFERENCE_IN_TVC", 4100, "Field reference \'%-.192s\' can\'t be used in table value constructor" }, { "ER_WRONG_TYPE_FOR_PERCENTILE_FUNC", 4101, "Numeric datatype is required for %s function" }, { "ER_ARGUMENT_NOT_CONSTANT", 4102, "Argument to the %s function is not a constant for a partition" }, { "ER_ARGUMENT_OUT_OF_RANGE", 4103, "Argument to the %s function does not belong to the range [0,1]" }, { "ER_WRONG_TYPE_OF_ARGUMENT", 4104, "%s function only accepts arguments that can be converted to numerical types" }, { "ER_NOT_AGGREGATE_FUNCTION", 4105, "Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context" }, { "ER_INVALID_AGGREGATE_FUNCTION", 4106, "Aggregate specific instruction(FETCH GROUP NEXT ROW) missing from the aggregate function" }, { "ER_INVALID_VALUE_TO_LIMIT", 4107, "Limit only accepts integer values" }, { "ER_INVISIBLE_NOT_NULL_WITHOUT_DEFAULT", 4108, "Invisible column %`s must have a default value" }, { "ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING", 4109, "Rows matched: %ld Changed: %ld Inserted: %ld Warnings: %ld" }, { "ER_VERS_FIELD_WRONG_TYPE", 4110, "%`s must be of type %s for system-versioned table %`s" }, { "ER_VERS_ENGINE_UNSUPPORTED", 4111, "Transaction-precise system versioning for %`s is not supported" }, { "ER_UNUSED_23", 4112, "You should never see it" }, { "ER_PARTITION_WRONG_TYPE", 4113, "Wrong partitioning type, expected type: %`s" }, { "WARN_VERS_PART_FULL", 4114, "Versioned table %`s.%`s: last HISTORY partition (%`s) is out of %s, need more HISTORY partitions" }, { "WARN_VERS_PARAMETERS", 4115, "Maybe missing parameters: %s" }, { "ER_VERS_DROP_PARTITION_INTERVAL", 4116, "Can only drop oldest partitions when rotating by INTERVAL" }, { "ER_UNUSED_25", 4117, "You should never see it" }, { "WARN_VERS_PART_NON_HISTORICAL", 4118, "Partition %`s contains non-historical data" }, { "ER_VERS_ALTER_NOT_ALLOWED", 4119, "Not allowed for system-versioned %`s.%`s. Change @@system_versioning_alter_history to proceed with ALTER." }, { "ER_VERS_ALTER_ENGINE_PROHIBITED", 4120, "Not allowed for system-versioned %`s.%`s. Change to/from native system versioning engine is not supported." }, { "ER_VERS_RANGE_PROHIBITED", 4121, "SYSTEM_TIME range selector is not allowed" }, { "ER_CONFLICTING_FOR_SYSTEM_TIME", 4122, "Conflicting FOR SYSTEM_TIME clauses in WITH RECURSIVE" }, { "ER_VERS_TABLE_MUST_HAVE_COLUMNS", 4123, "Table %`s must have at least one versioned column" }, { "ER_VERS_NOT_VERSIONED", 4124, "Table %`s is not system-versioned" }, { "ER_MISSING", 4125, "Wrong parameters for %`s: missing \'%s\'" }, { "ER_VERS_PERIOD_COLUMNS", 4126, "PERIOD FOR SYSTEM_TIME must use columns %`s and %`s" }, { "ER_PART_WRONG_VALUE", 4127, "Wrong parameters for partitioned %`s: wrong value for \'%s\'" }, { "ER_VERS_WRONG_PARTS", 4128, "Wrong partitions for %`s: must have at least one HISTORY and exactly one last CURRENT" }, { "ER_VERS_NO_TRX_ID", 4129, "TRX_ID %llu not found in `mysql.transaction_registry`" }, { "ER_VERS_ALTER_SYSTEM_FIELD", 4130, "Can not change system versioning field %`s" }, { "ER_DROP_VERSIONING_SYSTEM_TIME_PARTITION", 4131, "Can not DROP SYSTEM VERSIONING for table %`s partitioned BY SYSTEM_TIME" }, { "ER_VERS_DB_NOT_SUPPORTED", 4132, "System-versioned tables in the %`s database are not supported" }, { "ER_VERS_TRT_IS_DISABLED", 4133, "Transaction registry is disabled" }, { "ER_VERS_DUPLICATE_ROW_START_END", 4134, "Duplicate ROW %s column %`s" }, { "ER_VERS_ALREADY_VERSIONED", 4135, "Table %`s is already system-versioned" }, { "ER_UNUSED_24", 4136, "You should never see it" }, { "ER_VERS_NOT_SUPPORTED", 4137, "System-versioned tables do not support %s" }, { "ER_VERS_TRX_PART_HISTORIC_ROW_NOT_SUPPORTED", 4138, "Transaction-precise system-versioned tables do not support partitioning by ROW START or ROW END" }, { "ER_INDEX_FILE_FULL", 4139, "The index file for table \'%-.192s\' is full" }, { "ER_UPDATED_COLUMN_ONLY_ONCE", 4140, "The column %`s.%`s cannot be changed more than once in a single UPDATE statement" }, { "ER_EMPTY_ROW_IN_TVC", 4141, "Row with no elements is not allowed in table value constructor in this context" }, { "ER_VERS_QUERY_IN_PARTITION", 4142, "SYSTEM_TIME partitions in table %`s does not support historical query" }, { "ER_KEY_DOESNT_SUPPORT", 4143, "%s index %`s does not support this operation" }, { "ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD", 4144, "Changing table options requires the table to be rebuilt" }, { "ER_BACKUP_LOCK_IS_ACTIVE", 4145, "Can\'t execute the command as you have a BACKUP STAGE active" }, { "ER_BACKUP_NOT_RUNNING", 4146, "You must start backup with \"BACKUP STAGE START\"" }, { "ER_BACKUP_WRONG_STAGE", 4147, "Backup stage \'%s\' is same or before current backup stage \'%s\'" }, { "ER_BACKUP_STAGE_FAILED", 4148, "Backup stage \'%s\' failed" }, { "ER_BACKUP_UNKNOWN_STAGE", 4149, "Unknown backup stage: \'%s\'. Stage should be one of START, FLUSH, BLOCK_DDL, BLOCK_COMMIT or END" }, { "ER_USER_IS_BLOCKED", 4150, "User is blocked because of too many credential errors; unblock with \'ALTER USER / FLUSH PRIVILEGES\'" }, { "ER_ACCOUNT_HAS_BEEN_LOCKED", 4151, "Access denied, this account is locked" }, { "ER_PERIOD_TEMPORARY_NOT_ALLOWED", 4152, "Application-time period table cannot be temporary" }, { "ER_PERIOD_TYPES_MISMATCH", 4153, "Fields of PERIOD FOR %`s have different types" }, { "ER_MORE_THAN_ONE_PERIOD", 4154, "Cannot specify more than one application-time period" }, { "ER_PERIOD_FIELD_WRONG_ATTRIBUTES", 4155, "Period field %`s cannot be %s" }, { "ER_PERIOD_NOT_FOUND", 4156, "Period %`s is not found in table" }, { "ER_PERIOD_COLUMNS_UPDATED", 4157, "Column %`s used in period %`s specified in update SET list" }, { "ER_PERIOD_CONSTRAINT_DROP", 4158, "Can\'t DROP CONSTRAINT `%s`. Use DROP PERIOD `%s` for this" }, { "ER_TOO_LONG_KEYPART", 4159, "Specified key part was too long; max key part length is %u bytes" }, { "ER_TOO_LONG_DATABASE_COMMENT", 4160, "Comment for database \'%-.64s\' is too long (max = %u)" }, { "ER_UNKNOWN_DATA_TYPE", 4161, "Unknown data type: \'%-.64s\'" }, { "ER_UNKNOWN_OPERATOR", 4162, "Operator does not exist: \'%-.128s\'" }, { "ER_WARN_HISTORY_ROW_START_TIME", 4163, "Table `%s.%s` history row start \'%s\' is later than row end \'%s\'" }, { "ER_PART_STARTS_BEYOND_INTERVAL", 4164, "%`s: STARTS is later than query time, first history partition may exceed INTERVAL value" }, { "ER_GALERA_REPLICATION_NOT_SUPPORTED", 4165, "Galera replication not supported" }, { "ER_LOAD_INFILE_CAPABILITY_DISABLED", 4166, "The used command is not allowed because the MariaDB server or client has disabled the local infile capability" }, { "ER_NO_SECURE_TRANSPORTS_CONFIGURED", 4167, "No secure transports are configured, unable to set --require_secure_transport=ON" }, { "ER_SLAVE_IGNORED_SHARED_TABLE", 4168, "Slave SQL thread ignored the \'%s\' because table is shared" }, { "ER_NO_AUTOINCREMENT_WITH_UNIQUE", 4169, "AUTO_INCREMENT column %`s cannot be used in the UNIQUE index %`s" }, { "ER_KEY_CONTAINS_PERIOD_FIELDS", 4170, "Key %`s cannot explicitly include column %`s" }, { "ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS", 4171, "Key %`s cannot have WITHOUT OVERLAPS" }, { "ER_NOT_ALLOWED_IN_THIS_CONTEXT", 4172, "\'%-.128s\' is not allowed in this context" }, { "ER_DATA_WAS_COMMITED_UNDER_ROLLBACK", 4173, "Engine %s does not support rollback. Changes were committed during rollback call" }, { "ER_PK_INDEX_CANT_BE_IGNORED", 4174, "A primary key cannot be marked as IGNORE" }, { "ER_BINLOG_UNSAFE_SKIP_LOCKED", 4175, "SKIP LOCKED makes this statement unsafe" }, { "ER_JSON_TABLE_ERROR_ON_FIELD", 4176, "Field \'%s\' can\'t be set for JSON_TABLE \'%s\'." }, { "ER_JSON_TABLE_ALIAS_REQUIRED", 4177, "Every table function must have an alias." }, { "ER_JSON_TABLE_SCALAR_EXPECTED", 4178, "Can\'t store an array or an object in the scalar column \'%s\' of JSON_TABLE \'%s\'." }, { "ER_JSON_TABLE_MULTIPLE_MATCHES", 4179, "Can\'t store multiple matches of the path in the column \'%s\' of JSON_TABLE \'%s\'." }, { "ER_WITH_TIES_NEEDS_ORDER", 4180, "FETCH ... WITH TIES requires ORDER BY clause to be present" }, { "ER_REMOVED_ORPHAN_TRIGGER", 4181, "Dropped orphan trigger \'%-.64s\', originally created for table: \'%-.192s\'" }, { "ER_STORAGE_ENGINE_DISABLED", 4182, "Storage engine %s is disabled" }, server/sslopt-case.h000064400000002776151031265050010472 0ustar00#ifndef SSLOPT_CASE_INCLUDED #define SSLOPT_CASE_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) case OPT_SSL_KEY: case OPT_SSL_CERT: case OPT_SSL_CA: case OPT_SSL_CAPATH: case OPT_SSL_CIPHER: case OPT_SSL_CRL: case OPT_SSL_CRLPATH: /* Enable use of SSL if we are using any ssl option One can disable SSL later by using --skip-ssl or --ssl=0 */ opt_use_ssl= 1; #if defined (HAVE_WOLFSSL) #if defined(MYSQL_SERVER) /* CRL does not work with WolfSSL (server) */ opt_ssl_crl= NULL; #endif #if !defined(_WIN32) || !defined(LIBMARIADB) /* CRL_PATH does not work with WolfSSL (server) and GnuTLS (client) */ opt_ssl_crlpath= NULL; #endif #endif break; #endif #endif /* SSLOPT_CASE_INCLUDED */ server/my_getopt.h000064400000012744151031265050010240 0ustar00/* Copyright (c) 2002, 2013, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_getopt_h #define _my_getopt_h #include "my_sys.h" /* loglevel */ /* my_getopt and my_default are almost always used together */ #include C_MODE_START #define GET_NO_ARG 1 #define GET_BOOL 2 #define GET_INT 3 #define GET_UINT 4 #define GET_LONG 5 #define GET_ULONG 6 #define GET_LL 7 #define GET_ULL 8 #define GET_STR 9 #define GET_STR_ALLOC 10 #define GET_DISABLED 11 #define GET_ENUM 12 #define GET_SET 13 #define GET_DOUBLE 14 #define GET_FLAGSET 15 #define GET_BIT 16 #define GET_ASK_ADDR 128 #define GET_AUTO 64 #define GET_TYPE_MASK 63 /** Enumeration of the my_option::arg_type attributes. It should be noted that for historical reasons variables with the combination arg_type=NO_ARG, my_option::var_type=GET_BOOL still accepts arguments. This is someone counter intuitive and care should be taken if the code is refactored. */ enum get_opt_arg_type { NO_ARG, OPT_ARG, REQUIRED_ARG }; struct st_typelib; struct my_option { const char *name; /**< Name of the option. name=NULL marks the end of the my_option[] array. */ int id; /**< For 0255 no short option is created, but a long option still can be identified uniquely in the my_get_one_option() callback. If an opton needs neither special treatment in the my_get_one_option() nor one-letter short equivalent use id=0 */ const char *comment; /**< option comment, for autom. --help. if it's NULL the option is not visible in --help. */ void *value; /**< A pointer to the variable value */ void *u_max_value; /**< The user def. max variable value */ struct st_typelib *typelib; /**< Pointer to possible values */ ulong var_type; /**< GET_BOOL, GET_ULL, etc */ enum get_opt_arg_type arg_type; /**< e.g. REQUIRED_ARG or OPT_ARG */ longlong def_value; /**< Default value */ longlong min_value; /**< Min allowed value (for numbers) */ ulonglong max_value; /**< Max allowed value (for numbers) */ longlong sub_size; /**< Unused */ long block_size; /**< Value should be a mult. of this (for numbers) */ void *app_type; /**< To be used by an application */ }; typedef my_bool (*my_get_one_option)(const struct my_option *, const char *, const char *); /** Used to retrieve a reference to the object (variable) that holds the value for the given option. For example, if var_type is GET_UINT, the function must return a pointer to a variable of type uint. A argument is stored in the location pointed to by the returned pointer. */ typedef void *(*my_getopt_value)(const char *, uint, const struct my_option *, int *); extern char *disabled_my_option; extern char *autoset_my_option; extern my_bool my_getopt_print_errors; extern my_bool my_getopt_skip_unknown; extern my_bool my_getopt_prefix_matching; extern my_bool my_handle_options_init_variables; extern my_error_reporter my_getopt_error_reporter; extern my_getopt_value my_getopt_get_addr; extern int handle_options (int *argc, char ***argv, const struct my_option *longopts, my_get_one_option) __attribute__((nonnull)); extern void my_cleanup_options(const struct my_option *options); extern void my_print_help(const struct my_option *options); extern void my_print_variables(const struct my_option *options); ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp, my_bool *fix); longlong getopt_ll_limit_value(longlong, const struct my_option *, my_bool *fix); double getopt_double_limit_value(double num, const struct my_option *optp, my_bool *fix); ulonglong getopt_double2ulonglong(double); double getopt_ulonglong2double(ulonglong); C_MODE_END #endif /* _my_getopt_h */ server/my_byteorder.h000064400000004005151031265050010724 0ustar00#ifndef MY_BYTEORDER_INCLUDED #define MY_BYTEORDER_INCLUDED /* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Macro for reading 32-bit integer from network byte order (big-endian) from an unaligned memory location. */ #define int4net(A) (int32) (((uint32) ((uchar) (A)[3])) | \ (((uint32) ((uchar) (A)[2])) << 8) | \ (((uint32) ((uchar) (A)[1])) << 16) | \ (((uint32) ((uchar) (A)[0])) << 24)) /* Function-like macros for reading and storing in machine independent format (low byte first). There are 'korr' (assume 'corrector') variants for integer types, but 'get' (assume 'getter') for floating point types. */ #if (defined(__i386__) || defined(_M_IX86)) && !defined(WITH_UBSAN) #define MY_BYTE_ORDER_ARCH_OPTIMIZED #include "byte_order_generic_x86.h" #elif (defined(__x86_64__) || defined (_M_X64)) && !defined(WITH_UBSAN) #include "byte_order_generic_x86_64.h" #else #include "byte_order_generic.h" #endif /* Function-like macros for reading and storing in machine format from/to short/long to/from some place in memory V should be a variable (not on a register) and M a pointer to byte. */ #ifdef WORDS_BIGENDIAN #include "big_endian.h" #else #include "little_endian.h" #endif #endif /* MY_BYTEORDER_INCLUDED */ server/my_xml.h000064400000005420151031265050007527 0ustar00/* Copyright (c) 2000, 2002, 2003, 2005, 2007 MySQL AB Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _my_xml_h #define _my_xml_h #ifdef __cplusplus extern "C" { #endif #define MY_XML_OK 0 #define MY_XML_ERROR 1 /* A flag whether to use absolute tag names in call-back functions, like "a", "a.b" and "a.b.c" (used in character set file parser), or relative names like "a", "b" and "c". */ #define MY_XML_FLAG_RELATIVE_NAMES 1 /* A flag whether to skip normilization of text values before calling call-back functions: i.e. skip leading/trailing spaces, \r, \n, \t characters. */ #define MY_XML_FLAG_SKIP_TEXT_NORMALIZATION 2 enum my_xml_node_type { MY_XML_NODE_TAG, /* can have TAG, ATTR and TEXT children */ MY_XML_NODE_ATTR, /* can have TEXT children */ MY_XML_NODE_TEXT /* cannot have children */ }; typedef struct xml_stack_st { int flags; enum my_xml_node_type current_node_type; char errstr[128]; struct { char static_buffer[128]; char *buffer; size_t buffer_size; char *start; char *end; } attr; const char *beg; const char *cur; const char *end; void *user_data; int (*enter)(struct xml_stack_st *st,const char *val, size_t len); int (*value)(struct xml_stack_st *st,const char *val, size_t len); int (*leave_xml)(struct xml_stack_st *st,const char *val, size_t len); } MY_XML_PARSER; void my_xml_parser_create(MY_XML_PARSER *st); void my_xml_parser_free(MY_XML_PARSER *st); int my_xml_parse(MY_XML_PARSER *st,const char *str, size_t len); void my_xml_set_value_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, const char *, size_t len)); void my_xml_set_enter_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, const char *, size_t len)); void my_xml_set_leave_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, const char *, size_t len)); void my_xml_set_user_data(MY_XML_PARSER *st, void *); size_t my_xml_error_pos(MY_XML_PARSER *st); uint my_xml_error_lineno(MY_XML_PARSER *st); const char *my_xml_error_string(MY_XML_PARSER *st); #ifdef __cplusplus } #endif #endif /* _my_xml_h */ server/little_endian.h000064400000006764151031265050011051 0ustar00/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /* Data in little-endian format. */ #ifndef MY_BYTE_ORDER_ARCH_OPTIMIZED #define float4get(V,M) memcpy(&V, (M), sizeof(float)) #define float4store(V,M) memcpy(V, (&M), sizeof(float)) #define float8get(V,M) doubleget((V),(M)) #define float8store(V,M) doublestore((V),(M)) /* Bi-endian hardware.... */ #if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) #define doublestore(T,V) do { *(((char*)T)+0)=(char) ((uchar *) &V)[4];\ *(((char*)T)+1)=(char) ((uchar *) &V)[5];\ *(((char*)T)+2)=(char) ((uchar *) &V)[6];\ *(((char*)T)+3)=(char) ((uchar *) &V)[7];\ *(((char*)T)+4)=(char) ((uchar *) &V)[0];\ *(((char*)T)+5)=(char) ((uchar *) &V)[1];\ *(((char*)T)+6)=(char) ((uchar *) &V)[2];\ *(((char*)T)+7)=(char) ((uchar *) &V)[3]; }\ while(0) #define doubleget(V,M) do { double def_temp;\ ((uchar*) &def_temp)[0]=(M)[4];\ ((uchar*) &def_temp)[1]=(M)[5];\ ((uchar*) &def_temp)[2]=(M)[6];\ ((uchar*) &def_temp)[3]=(M)[7];\ ((uchar*) &def_temp)[4]=(M)[0];\ ((uchar*) &def_temp)[5]=(M)[1];\ ((uchar*) &def_temp)[6]=(M)[2];\ ((uchar*) &def_temp)[7]=(M)[3];\ (V) = def_temp; } while(0) #else /* Bi-endian hardware.... */ /* Cast away type qualifiers (necessary as macro takes argument by value). */ #define doublestore(T,V) memcpy((T), (void*) &V, sizeof(double)) #define doubleget(V,M) memcpy(&V, (M), sizeof(double)) #endif /* Bi-endian hardware.... */ #endif /* !MY_BYTE_ORDER_ARCH_OPTIMIZED */ #define ushortget(V,M) do { uchar *pM= (uchar*)(M);V = uint2korr(pM);} while(0) #define shortget(V,M) do { uchar *pM= (uchar*)(M);V = sint2korr(pM);} while(0) #define longget(V,M) do { uchar *pM= (uchar*)(M);V = sint4korr(pM);} while(0) #define ulongget(V,M) do { uchar *pM= (uchar*)(M);V = uint4korr(pM);} while(0) #define shortstore(T,V) int2store(T,V) #define longstore(T,V) int4store(T,V) #ifndef floatstore /* Cast away type qualifiers (necessary as macro takes argument by value). */ #define floatstore(T,V) memcpy((T), (void*) (&V), sizeof(float)) #define floatget(V,M) memcpy(&V, (M), sizeof(float)) #endif #ifndef doubleget #define doubleget(V,M) memcpy(&V, (M), sizeof(double)) #define doublestore(T,V) memcpy((T), (void *) &V, sizeof(double)) #endif /* doubleget */ #define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong)) #define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong)) server/mysql_time.h000064400000004564151031265050010415 0ustar00/* Copyright (c) 2004, 2006 MySQL AB Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _mysql_time_h_ #define _mysql_time_h_ /* Portable time_t replacement. Should be signed and hold seconds for 1902 -- 2038-01-19 range i.e at least a 32bit variable Using the system built in time_t is not an option as we rely on the above requirements in the time functions */ typedef long my_time_t; /* Time declarations shared between the server and client API: you should not add anything to this header unless it's used (and hence should be visible) in mysql.h. If you're looking for a place to add new time-related declaration, it's most likely my_time.h. See also "C API Handling of Date and Time Values" chapter in documentation. */ enum enum_mysql_timestamp_type { MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1, MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2 }; /* Structure which is used to represent datetime values inside MySQL. We assume that values in this structure are normalized, i.e. year <= 9999, month <= 12, day <= 31, hour <= 23, hour <= 59, hour <= 59. Many functions in server such as my_system_gmt_sec() or make_time() family of functions rely on this (actually now usage of make_*() family relies on a bit weaker restriction). Also functions that produce MYSQL_TIME as result ensure this. There is one exception to this rule though if this structure holds time value (time_type == MYSQL_TIMESTAMP_TIME) days and hour member can hold bigger values. */ typedef struct st_mysql_time { unsigned int year, month, day, hour, minute, second; unsigned long second_part; my_bool neg; enum enum_mysql_timestamp_type time_type; } MYSQL_TIME; #endif /* _mysql_time_h_ */ server/decimal.h000064400000011471151031265050007623 0ustar00/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #ifndef _decimal_h #define _decimal_h #ifdef __cplusplus extern "C" { #endif typedef enum {TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} decimal_round_mode; typedef int32 decimal_digit_t; /** intg is the number of *decimal* digits (NOT number of decimal_digit_t's !) before the point frac is the number of decimal digits after the point len is the length of buf (length of allocated space) in decimal_digit_t's, not in bytes sign false means positive, true means negative buf is an array of decimal_digit_t's */ typedef struct st_decimal_t { int intg, frac, len; my_bool sign; decimal_digit_t *buf; } decimal_t; int internal_str2dec(const char *from, decimal_t *to, char **end, my_bool fixed); int decimal2string(const decimal_t *from, char *to, int *to_len, decimal_digits_t fixed_precision, decimal_digits_t fixed_decimals, char filler); int decimal2ulonglong(const decimal_t *from, ulonglong *to); int ulonglong2decimal(ulonglong from, decimal_t *to); int decimal2longlong(const decimal_t *from, longlong *to); int longlong2decimal(longlong from, decimal_t *to); int decimal2double(const decimal_t *from, double *to); int double2decimal(double from, decimal_t *to); decimal_digits_t decimal_actual_fraction(const decimal_t *from); int decimal2bin(const decimal_t *from, uchar *to, decimal_digits_t precision, decimal_digits_t scale); int bin2decimal(const uchar *from, decimal_t *to, decimal_digits_t precision, decimal_digits_t scale); uint decimal_size(decimal_digits_t precision, decimal_digits_t scale); uint decimal_bin_size(decimal_digits_t precision, decimal_digits_t scale); uint decimal_result_size(decimal_t *from1, decimal_t *from2, char op, int param); decimal_digits_t decimal_intg(const decimal_t *from); int decimal_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to); int decimal_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to); int decimal_cmp(const decimal_t *from1, const decimal_t *from2); int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to); int decimal_div(const decimal_t *from1, const decimal_t *from2, decimal_t *to, int scale_incr); int decimal_mod(const decimal_t *from1, const decimal_t *from2, decimal_t *to); int decimal_round(const decimal_t *from, decimal_t *to, int new_scale, decimal_round_mode mode); int decimal_is_zero(const decimal_t *from); void max_decimal(decimal_digits_t precision, decimal_digits_t frac, decimal_t *to); #define string2decimal(A,B,C) internal_str2dec((A), (B), (C), 0) #define string2decimal_fixed(A,B,C) internal_str2dec((A), (B), (C), 1) /* set a decimal_t to zero */ #define decimal_make_zero(dec) do { \ (dec)->buf[0]=0; \ (dec)->intg=1; \ (dec)->frac=0; \ (dec)->sign=0; \ } while(0) /* returns the length of the buffer to hold string representation of the decimal (including decimal dot, possible sign and \0) */ #define decimal_string_size(dec) (((dec)->intg ? (dec)->intg : 1) + \ (dec)->frac + ((dec)->frac > 0) + 2) /* negate a decimal */ #define decimal_neg(dec) do { (dec)->sign^=1; } while(0) /* conventions: decimal_smth() == 0 -- everything's ok decimal_smth() <= 1 -- result is usable, but precision loss is possible decimal_smth() <= 2 -- result can be unusable, most significant digits could've been lost decimal_smth() > 2 -- no result was generated */ #define E_DEC_OK 0 #define E_DEC_TRUNCATED 1 #define E_DEC_OVERFLOW 2 #define E_DEC_DIV_ZERO 4 #define E_DEC_BAD_NUM 8 #define E_DEC_OOM 16 #define E_DEC_ERROR 31 #define E_DEC_FATAL_ERROR 30 #ifdef __cplusplus } #endif #endif mariadb_rpl.h000064400000045667151031265050007211 0ustar00/* Copyright (C) 2018-2022 MariaDB Corporation AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA */ #ifndef _mariadb_rpl_h_ #define _mariadb_rpl_h_ #ifdef __cplusplus extern "C" { #endif #include #include #define MARIADB_RPL_VERSION 0x0002 #define MARIADB_RPL_REQUIRED_VERSION 0x0002 #define RPL_BINLOG_MAGIC (const uchar*) "\xFE\x62\x69\x6E" #define RPL_BINLOG_MAGIC_SIZE 4 /* Protocol flags */ #define MARIADB_RPL_BINLOG_DUMP_NON_BLOCK 1 #define MARIADB_RPL_BINLOG_SEND_ANNOTATE_ROWS 2 #define MARIADB_RPL_IGNORE_HEARTBEAT (1 << 17) #define EVENT_HEADER_OFS 20 #define FL_STMT_END 1 /* GTID flags */ /* FL_STANDALONE is set in case there is no terminating COMMIT event. */ #define FL_STANDALONE 0x01 /* FL_GROUP_COMMIT_ID is set when event group is part of a group commit */ #define FL_GROUP_COMMIT_ID 0x02 /* FL_TRANSACTIONAL is set for an event group that can be safely rolled back (no MyISAM, eg.). */ #define FL_TRANSACTIONAL 0x04 /* FL_ALLOW_PARALLEL reflects the (negation of the) value of @@SESSION.skip_parallel_replication at the time of commit. */ #define FL_ALLOW_PARALLEL 0x08; /* FL_WAITED is set if a row lock wait (or other wait) is detected during the execution of the transaction. */ #define FL_WAITED 0x10 /* FL_DDL is set for event group containing DDL. */ #define FL_DDL 0x20 /* FL_PREPARED_XA is set for XA transaction. */ #define FL_PREPARED_XA 0x40 /* FL_"COMMITTED or ROLLED-BACK"_XA is set for XA transaction. */ #define FL_COMPLETED_XA 0x80 /* SEMI SYNCHRONOUS REPLICATION */ #define SEMI_SYNC_INDICATOR 0xEF #define SEMI_SYNC_ACK_REQ 0x01 /* Options */ enum mariadb_rpl_option { MARIADB_RPL_FILENAME, /* Filename and length */ MARIADB_RPL_START, /* Start position */ MARIADB_RPL_SERVER_ID, /* Server ID */ MARIADB_RPL_FLAGS, /* Protocol flags */ MARIADB_RPL_GTID_CALLBACK, /* GTID callback function */ MARIADB_RPL_GTID_DATA, /* GTID data */ MARIADB_RPL_BUFFER, MARIADB_RPL_VERIFY_CHECKSUM, MARIADB_RPL_UNCOMPRESS, MARIADB_RPL_HOST, MARIADB_RPL_PORT, MARIADB_RPL_EXTRACT_VALUES, MARIADB_RPL_SEMI_SYNC, }; /* Event types: From MariaDB Server sql/log_event.h */ enum mariadb_rpl_event { UNKNOWN_EVENT= 0, START_EVENT_V3= 1, QUERY_EVENT= 2, STOP_EVENT= 3, ROTATE_EVENT= 4, INTVAR_EVENT= 5, LOAD_EVENT= 6, SLAVE_EVENT= 7, CREATE_FILE_EVENT= 8, APPEND_BLOCK_EVENT= 9, EXEC_LOAD_EVENT= 10, DELETE_FILE_EVENT= 11, NEW_LOAD_EVENT= 12, RAND_EVENT= 13, USER_VAR_EVENT= 14, FORMAT_DESCRIPTION_EVENT= 15, XID_EVENT= 16, BEGIN_LOAD_QUERY_EVENT= 17, EXECUTE_LOAD_QUERY_EVENT= 18, TABLE_MAP_EVENT = 19, PRE_GA_WRITE_ROWS_EVENT = 20, /* deprecated */ PRE_GA_UPDATE_ROWS_EVENT = 21, /* deprecated */ PRE_GA_DELETE_ROWS_EVENT = 22, /* deprecated */ WRITE_ROWS_EVENT_V1 = 23, UPDATE_ROWS_EVENT_V1 = 24, DELETE_ROWS_EVENT_V1 = 25, INCIDENT_EVENT= 26, HEARTBEAT_LOG_EVENT= 27, IGNORABLE_LOG_EVENT= 28, ROWS_QUERY_LOG_EVENT= 29, WRITE_ROWS_EVENT = 30, UPDATE_ROWS_EVENT = 31, DELETE_ROWS_EVENT = 32, GTID_LOG_EVENT= 33, ANONYMOUS_GTID_LOG_EVENT= 34, PREVIOUS_GTIDS_LOG_EVENT= 35, TRANSACTION_CONTEXT_EVENT= 36, VIEW_CHANGE_EVENT= 37, XA_PREPARE_LOG_EVENT= 38, PARTIAL_UPDATE_ROWS_EVENT = 39, /* Add new events here - right above this comment! Existing events (except ENUM_END_EVENT) should never change their numbers */ /* New MySQL events are to be added right above this comment */ MYSQL_EVENTS_END, MARIA_EVENTS_BEGIN= 160, ANNOTATE_ROWS_EVENT= 160, BINLOG_CHECKPOINT_EVENT= 161, GTID_EVENT= 162, GTID_LIST_EVENT= 163, START_ENCRYPTION_EVENT= 164, QUERY_COMPRESSED_EVENT = 165, WRITE_ROWS_COMPRESSED_EVENT_V1 = 166, UPDATE_ROWS_COMPRESSED_EVENT_V1 = 167, DELETE_ROWS_COMPRESSED_EVENT_V1 = 168, WRITE_ROWS_COMPRESSED_EVENT = 169, UPDATE_ROWS_COMPRESSED_EVENT = 170, DELETE_ROWS_COMPRESSED_EVENT = 171, /* Add new MariaDB events here - right above this comment! */ ENUM_END_EVENT /* end marker */ }; /* ROWS_EVENT flags */ #define STMT_END_F 0x01 #define NO_FOREIGN_KEY_CHECKS_F 0x02 #define RELAXED_UNIQUE_KEY_CHECKS_F 0x04 #define COMPLETE_ROWS_F 0x08 #define NO_CHECK_CONSTRAINT_CHECKS_F 0x80 enum mariadb_rpl_status_code { Q_FLAGS2_CODE= 0x00, Q_SQL_MODE_CODE= 0x01, Q_CATALOG_CODE= 0x02, Q_AUTO_INCREMENT_CODE= 0x03, Q_CHARSET_CODE= 0x04, Q_TIMEZONE_CODE= 0x05, Q_CATALOG_NZ_CODE= 0x06, Q_LC_TIME_NAMES_CODE= 0x07, Q_CHARSET_DATABASE_CODE= 0x08, Q_TABLE_MAP_FOR_UPDATE_CODE= 0x09, Q_MASTER_DATA_WRITTEN_CODE= 0x0A, Q_INVOKERS_CODE= 0x0B, Q_UPDATED_DB_NAMES_CODE= 0x0C, Q_MICROSECONDS_CODE= 0x0D, Q_COMMIT_TS_CODE= 0x0E, /* unused */ Q_COMMIT_TS2_CODE= 0x0F, /* unused */ Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP_CODE= 0x10, Q_DDL_LOGGED_WITH_XID_CODE= 0x11, Q_DEFAULT_COLLATION_FOR_UTF8_CODE= 0x12, Q_SQL_REQUIRE_PRIMARY_KEY_CODE= 0x13, Q_DEFAULT_TABLE_ENCRYPTION_CODE= 0x14, Q_HRNOW= 128, /* second part: 3 bytes */ Q_XID= 129 /* xid: 8 bytes */ }; #ifdef DEFAULT_CHARSET #undef DEFAULT_CHARSET #endif enum opt_metadata_field_type { SIGNEDNESS = 1, DEFAULT_CHARSET, COLUMN_CHARSET, COLUMN_NAME, SET_STR_VALUE, ENUM_STR_VALUE, GEOMETRY_TYPE, SIMPLE_PRIMARY_KEY, PRIMARY_KEY_WITH_PREFIX, ENUM_AND_SET_DEFAULT_CHARSET, ENUM_AND_SET_COLUMN_CHARSET }; /* QFLAGS2 codes */ #define OPTION_AUTO_IS_NULL 0x00040000 #define OPTION_NOT_AUTOCOMMIT 0x00080000 #define OPTION_NO_FOREIGN_KEY_CHECKS 0x04000000 #define OPTION_RELAXED_UNIQUE_CHECKS 0x08000000 /* SQL modes */ #define MODE_REAL_AS_FLOAT 0x00000001 #define MODE_PIPES_AS_CONCAT 0x00000002 #define MODE_ANSI_QUOTES 0x00000004 #define MODE_IGNORE_SPACE 0x00000008 #define MODE_NOT_USED 0x00000010 #define MODE_ONLY_FULL_GROUP_BY 0x00000020 #define MODE_NO_UNSIGNED_SUBTRACTION 0x00000040 #define MODE_NO_DIR_IN_CREATE 0x00000080 #define MODE_POSTGRESQL 0x00000100 #define MODE_ORACLE 0x00000200 #define MODE_MSSQL 0x00000400 #define MODE_DB2 0x00000800 #define MODE_MAXDB 0x00001000 #define MODE_NO_KEY_OPTIONS 0x00002000 #define MODE_NO_TABLE_OPTIONS 0x00004000 #define MODE_NO_FIELD_OPTIONS 0x00008000 #define MODE_MYSQL323 0x00010000 #define MODE_MYSQL40 0x00020000 #define MODE_ANSI 0x00040000 #define MODE_NO_AUTO_VALUE_ON_ZERO 0x00080000 #define MODE_NO_BACKSLASH_ESCAPES 0x00100000 #define MODE_STRICT_TRANS_TABLES 0x00200000 #define MODE_STRICT_ALL_TABLES 0x00400000 #define MODE_NO_ZERO_IN_DATE 0x00800000 #define MODE_NO_ZERO_DATE 0x01000000 #define MODE_INVALID_DATES 0x02000000 #define MODE_ERROR_FOR_DIVISION_BY_ZERO 0x04000000 #define MODE_TRADITIONAL 0x08000000 #define MODE_NO_AUTO_CREATE_USER 0x10000000 #define MODE_HIGH_NOT_PRECEDENCE 0x20000000 #define MODE_NO_ENGINE_SUBSTITUTION 0x40000000 #define MODE_PAD_CHAR_TO_FULL_LENGTH 0x80000000 /* Log Event flags */ /* used in FOMRAT_DESCRIPTION_EVENT. Indicates if it is the active binary log. Note: When reading data via COM_BINLOG_DUMP this flag is never set. */ #define LOG_EVENT_BINLOG_IN_USE_F 0x0001 /* Looks like this flag is no longer in use */ #define LOG_EVENT_FORCED_ROTATE_F 0x0002 /* Log entry depends on thread, e.g. when using user variables or temporary tables */ #define LOG_EVENT_THREAD_SPECIFIC_F 0x0004 /* Indicates that the USE command can be suppressed before executing a statement: e.g. DRIP SCHEMA */ #define LOG_EVENT_SUPPRESS_USE_F 0x0008 /* ??? */ #define LOG_EVENT_UPDATE_TABLE_MAP_F 0x0010 /* Artifical event */ #define LOG_EVENT_ARTIFICIAL_F 0x0020 /* ??? */ #define LOG_EVENT_RELAY_LOG_F 0x0040 /* If an event is not supported, and LOG_EVENT_IGNORABLE_F was not set, an error will be reported. */ #define LOG_EVENT_IGNORABLE_F 0x0080 /* ??? */ #define LOG_EVENT_NO_FILTER_F 0x0100 /* ?? */ #define LOG_EVENT_MTS_ISOLATE_F 0x0200 /* if session variable @@skip_repliation was set, this flag will be reported for events which should be skipped. */ #define LOG_EVENT_SKIP_REPLICATION_F 0x8000 typedef struct { char *str; size_t length; } MARIADB_STRING; enum mariadb_row_event_type { WRITE_ROWS= 0, UPDATE_ROWS= 1, DELETE_ROWS= 2 }; /* Global transaction id */ typedef struct st_mariadb_gtid { unsigned int domain_id; unsigned int server_id; unsigned long long sequence_nr; } MARIADB_GTID; /* Generic replication handle */ typedef struct st_mariadb_rpl { unsigned int version; MYSQL *mysql; char *filename; uint32_t filename_length; uint32_t server_id; unsigned long start_position; uint16_t flags; uint8_t fd_header_len; /* header len from last format description event */ uint8_t use_checksum; uint8_t artificial_checksum; uint8_t verify_checksum; uint8_t post_header_len[ENUM_END_EVENT]; MA_FILE *fp; uint32_t error_no; char error_msg[MYSQL_ERRMSG_SIZE]; uint8_t uncompress; char *host; uint32_t port; uint8_t extract_values; char nonce[12]; uint8_t encrypted; uint8_t is_semi_sync; }MARIADB_RPL; typedef struct st_mariadb_rpl_value { enum enum_field_types field_type; uint8_t is_null; uint8_t is_signed; union { int64_t ll; uint64_t ull; float f; double d; MYSQL_TIME tm; MARIADB_STRING str; } val; } MARIADB_RPL_VALUE; typedef struct st_rpl_mariadb_row { uint32_t column_count; MARIADB_RPL_VALUE *columns; struct st_rpl_mariadb_row *next; } MARIADB_RPL_ROW; /* Event header */ struct st_mariadb_rpl_rotate_event { unsigned long long position; MARIADB_STRING filename; }; struct st_mariadb_rpl_query_event { uint32_t thread_id; uint32_t seconds; MARIADB_STRING database; uint32_t errornr; MARIADB_STRING status; MARIADB_STRING statement; }; struct st_mariadb_rpl_previous_gtid_event { MARIADB_CONST_DATA content; }; struct st_mariadb_rpl_gtid_list_event { uint32_t gtid_cnt; MARIADB_GTID *gtid; }; struct st_mariadb_rpl_format_description_event { uint16_t format; char *server_version; uint32_t timestamp; uint8_t header_len; MARIADB_STRING post_header_lengths; }; struct st_mariadb_rpl_checkpoint_event { MARIADB_STRING filename; }; struct st_mariadb_rpl_xid_event { uint64_t transaction_nr; }; struct st_mariadb_rpl_gtid_event { uint64_t sequence_nr; uint32_t domain_id; uint8_t flags; uint64_t commit_id; uint32_t format_id; uint8_t gtrid_len; uint8_t bqual_len; MARIADB_STRING xid; }; struct st_mariadb_rpl_annotate_rows_event { MARIADB_STRING statement; }; struct st_mariadb_rpl_table_map_event { unsigned long long table_id; MARIADB_STRING database; MARIADB_STRING table; uint32_t column_count; MARIADB_STRING column_types; MARIADB_STRING metadata; unsigned char *null_indicator; unsigned char *signed_indicator; MARIADB_CONST_DATA column_names; MARIADB_CONST_DATA geometry_types; uint32_t default_charset; MARIADB_CONST_DATA column_charsets; MARIADB_CONST_DATA simple_primary_keys; MARIADB_CONST_DATA prefixed_primary_keys; MARIADB_CONST_DATA set_values; MARIADB_CONST_DATA enum_values; uint8_t enum_set_default_charset; MARIADB_CONST_DATA enum_set_column_charsets; }; struct st_mariadb_rpl_rand_event { unsigned long long first_seed; unsigned long long second_seed; }; struct st_mariadb_rpl_intvar_event { unsigned long long value; uint8_t type; }; struct st_mariadb_begin_load_query_event { uint32_t file_id; unsigned char *data; }; struct st_mariadb_start_encryption_event { uint8_t scheme; uint32_t key_version; char nonce[12]; }; struct st_mariadb_execute_load_query_event { uint32_t thread_id; uint32_t execution_time; MARIADB_STRING schema; uint16_t error_code; uint32_t file_id; uint32_t ofs1; uint32_t ofs2; uint8_t duplicate_flag; MARIADB_STRING status_vars; MARIADB_STRING statement; }; struct st_mariadb_rpl_uservar_event { MARIADB_STRING name; uint8_t is_null; uint8_t type; uint32_t charset_nr; MARIADB_STRING value; uint8_t flags; }; struct st_mariadb_rpl_rows_event { enum mariadb_row_event_type type; uint64_t table_id; uint16_t flags; uint32_t column_count; unsigned char *column_bitmap; unsigned char *column_update_bitmap; unsigned char *null_bitmap; size_t row_data_size; void *row_data; size_t extra_data_size; void *extra_data; uint8_t compressed; uint32_t row_count; }; struct st_mariadb_rpl_heartbeat_event { uint32_t timestamp; uint32_t next_position; uint8_t type; uint16_t flags; }; struct st_mariadb_rpl_xa_prepare_log_event { uint8_t one_phase; uint32_t format_id; uint32_t gtrid_len; uint32_t bqual_len; MARIADB_STRING xid; }; struct st_mariadb_gtid_log_event { uint8_t commit_flag; char source_id[16]; uint64_t sequence_nr; }; typedef struct st_mariadb_rpl_event { /* common header */ MA_MEM_ROOT memroot; unsigned char *raw_data; size_t raw_data_size; size_t raw_data_ofs; unsigned int checksum; char ok; enum mariadb_rpl_event event_type; unsigned int timestamp; unsigned int server_id; unsigned int event_length; unsigned int next_event_pos; unsigned short flags; /****************/ union { struct st_mariadb_rpl_rotate_event rotate; struct st_mariadb_rpl_query_event query; struct st_mariadb_rpl_format_description_event format_description; struct st_mariadb_rpl_gtid_list_event gtid_list; struct st_mariadb_rpl_checkpoint_event checkpoint; struct st_mariadb_rpl_xid_event xid; struct st_mariadb_rpl_gtid_event gtid; struct st_mariadb_rpl_annotate_rows_event annotate_rows; struct st_mariadb_rpl_table_map_event table_map; struct st_mariadb_rpl_rand_event rand; struct st_mariadb_rpl_intvar_event intvar; struct st_mariadb_rpl_uservar_event uservar; struct st_mariadb_rpl_rows_event rows; struct st_mariadb_rpl_heartbeat_event heartbeat; struct st_mariadb_rpl_xa_prepare_log_event xa_prepare_log; struct st_mariadb_begin_load_query_event begin_load_query; struct st_mariadb_execute_load_query_event execute_load_query; struct st_mariadb_gtid_log_event gtid_log; struct st_mariadb_start_encryption_event start_encryption; struct st_mariadb_rpl_previous_gtid_event previous_gtid; } event; /* Added in C/C 3.3.0 */ uint8_t is_semi_sync; uint8_t semi_sync_flags; /* Added in C/C 3.3.5 */ MARIADB_RPL *rpl; } MARIADB_RPL_EVENT; /* compression uses myisampack format */ #define myisam_uint1korr(B) ((uint8_t)(*B)) #define myisam_sint1korr(B) ((int8_t)(*B)) #define myisam_uint2korr(B)\ ((uint16_t)(((uint16_t)(((const uchar*)(B))[1])) | ((uint16_t) (((const uchar*) (B))[0]) << 8))) #define myisam_sint2korr(B)\ ((int16_t)(((int16_t)(((const uchar*)(B))[1])) | ((int16_t) (((const uchar*) (B))[0]) << 8))) #define myisam_uint3korr(B)\ ((uint32_t)(((uint32_t)(((const uchar*)(B))[2])) |\ (((uint32_t)(((const uchar*)(B))[1])) << 8) |\ (((uint32_t)(((const uchar*)(B))[0])) << 16))) #define myisam_sint3korr(B)\ ((int32_t)(((int32_t)(((const uchar*)(B))[2])) |\ (((int32_t)(((const uchar*)(B))[1])) << 8) |\ (((int32_t)(((const uchar*)(B))[0])) << 16))) #define myisam_uint4korr(B)\ ((uint32_t)(((uint32_t)(((const uchar*)(B))[3])) |\ (((uint32_t)(((const uchar*)(B))[2])) << 8) |\ (((uint32_t)(((const uchar*) (B))[1])) << 16) |\ (((uint32_t)(((const uchar*) (B))[0])) << 24))) #define myisam_sint4korr(B)\ ((int32_t)(((int32_t)(((const uchar*)(B))[3])) |\ (((int32_t)(((const uchar*)(B))[2])) << 8) |\ (((int32_t)(((const uchar*) (B))[1])) << 16) |\ (((int32_t)(((const uchar*) (B))[0])) << 24))) #define mi_uint5korr(B)\ ((uint64_t)(((uint32_t) (((const uchar*) (B))[4])) |\ (((uint32_t) (((const uchar*) (B))[3])) << 8) |\ (((uint32_t) (((const uchar*) (B))[2])) << 16) |\ (((uint32_t) (((const uchar*) (B))[1])) << 24)) |\ (((uint64_t) (((const uchar*) (B))[0])) << 32)) #define RPL_SAFEGUARD(rpl, event, condition) \ if (!(condition))\ {\ my_set_error((rpl)->mysql, CR_BINLOG_ERROR, SQLSTATE_UNKNOWN, 0,\ (rpl)->filename_length, (rpl)->filename,\ (rpl)->start_position,\ "Packet corrupted");\ mariadb_free_rpl_event((event));\ return 0;\ } #define mariadb_rpl_init(a) mariadb_rpl_init_ex((a), MARIADB_RPL_VERSION) #define rpl_clear_error(rpl)\ (rpl)->error_no= (rpl)->error_msg[0]= 0 #define IS_ROW_VERSION2(a)\ ((a) == WRITE_ROWS_EVENT || (a) == UPDATE_ROWS_EVENT || \ (a) == DELETE_ROWS_EVENT || (a) == WRITE_ROWS_COMPRESSED_EVENT ||\ (a) == UPDATE_ROWS_COMPRESSED_EVENT || (a) == DELETE_ROWS_COMPRESSED_EVENT) #define IS_ROW_EVENT(a)\ ((a)->event_type == WRITE_ROWS_COMPRESSED_EVENT_V1 ||\ (a)->event_type == UPDATE_ROWS_COMPRESSED_EVENT_V1 ||\ (a)->event_type == DELETE_ROWS_COMPRESSED_EVENT_V1 ||\ (a)->event_type == WRITE_ROWS_EVENT_V1 ||\ (a)->event_type == UPDATE_ROWS_EVENT_V1 ||\ (a)->event_type == DELETE_ROWS_EVENT_V1 ||\ (a)->event_type == WRITE_ROWS_EVENT ||\ (a)->event_type == UPDATE_ROWS_EVENT ||\ (a)->event_type == DELETE_ROWS_EVENT) /* Function prototypes */ MARIADB_RPL * STDCALL mariadb_rpl_init_ex(MYSQL *mysql, unsigned int version); const char * STDCALL mariadb_rpl_error(MARIADB_RPL *rpl); uint32_t STDCALL mariadb_rpl_errno(MARIADB_RPL *rpl); int STDCALL mariadb_rpl_optionsv(MARIADB_RPL *rpl, enum mariadb_rpl_option, ...); int STDCALL mariadb_rpl_get_optionsv(MARIADB_RPL *rpl, enum mariadb_rpl_option, ...); int STDCALL mariadb_rpl_open(MARIADB_RPL *rpl); void STDCALL mariadb_rpl_close(MARIADB_RPL *rpl); MARIADB_RPL_EVENT * STDCALL mariadb_rpl_fetch(MARIADB_RPL *rpl, MARIADB_RPL_EVENT *event); void STDCALL mariadb_free_rpl_event(MARIADB_RPL_EVENT *event); MARIADB_RPL_ROW * STDCALL mariadb_rpl_extract_rows(MARIADB_RPL *rpl, MARIADB_RPL_EVENT *tm_event, MARIADB_RPL_EVENT *row_event); #ifdef __cplusplus } #endif #endif ma_tls.h000064400000010371151031265050006174 0ustar00#ifndef _ma_tls_h_ #define _ma_tls_h_ enum enum_pvio_tls_type { SSL_TYPE_DEFAULT=0, #ifdef _WIN32 SSL_TYPE_SCHANNEL, #endif SSL_TYPE_OPENSSL, SSL_TYPE_GNUTLS }; #define PROTOCOL_SSLV3 0 #define PROTOCOL_TLS_1_0 1 #define PROTOCOL_TLS_1_1 2 #define PROTOCOL_TLS_1_2 3 #define PROTOCOL_TLS_1_3 4 #define PROTOCOL_UNKNOWN 5 #define PROTOCOL_MAX PROTOCOL_TLS_1_3 #define TLS_VERSION_LENGTH 64 extern char tls_library_version[TLS_VERSION_LENGTH]; typedef struct st_ma_pvio_tls { void *data; MARIADB_PVIO *pvio; void *ssl; } MARIADB_TLS; /* Function prototypes */ /* ma_tls_start initializes the ssl library Parameter: errmsg pointer to error message buffer errmsg_len length of error message buffer Returns: 0 success 1 if an error occurred Notes: On success the global variable ma_tls_initialized will be set to 1 */ int ma_tls_start(char *errmsg, size_t errmsg_len); /* ma_tls_end unloads/deinitializes ssl library and unsets global variable ma_tls_initialized */ void ma_tls_end(void); /* ma_tls_init creates a new SSL structure for a SSL connection and loads client certificates Parameters: MYSQL a mysql structure Returns: void * a pointer to internal SSL structure */ void * ma_tls_init(MYSQL *mysql); /* ma_tls_connect performs SSL handshake Parameters: MARIADB_TLS MariaDB SSL container Returns: 0 success 1 error */ my_bool ma_tls_connect(MARIADB_TLS *ctls); /* ma_tls_read reads up to length bytes from socket Parameters: ctls MariaDB SSL container buffer read buffer length buffer length Returns: 0-n bytes read -1 if an error occurred */ ssize_t ma_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length); /* ma_tls_write write buffer to socket Parameters: ctls MariaDB SSL container buffer write buffer length buffer length Returns: 0-n bytes written -1 if an error occurred */ ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length); /* ma_tls_close closes SSL connection and frees SSL structure which was previously created by ma_tls_init call Parameters: MARIADB_TLS MariaDB SSL container Returns: 0 success 1 error */ my_bool ma_tls_close(MARIADB_TLS *ctls); /* ma_tls_verify_server_cert validation check of server certificate Parameter: MARIADB_TLS MariaDB SSL container Returns: ß success 1 error */ int ma_tls_verify_server_cert(MARIADB_TLS *ctls); /* ma_tls_get_cipher returns cipher for current ssl connection Parameter: MARIADB_TLS MariaDB SSL container Returns: cipher in use or NULL on error */ const char *ma_tls_get_cipher(MARIADB_TLS *ssl); /* ma_tls_get_finger_print returns SHA1 finger print of server certificate Parameter: MARIADB_TLS MariaDB SSL container fp buffer for fingerprint fp_len buffer length Returns: actual size of finger print */ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int fp_len); /* ma_tls_get_protocol_version returns protocol version number in use Parameter: MARIADB_TLS MariaDB SSL container Returns: protocol number */ int ma_tls_get_protocol_version(MARIADB_TLS *ctls); const char *ma_pvio_tls_get_protocol_version(MARIADB_TLS *ctls); int ma_pvio_tls_get_protocol_version_id(MARIADB_TLS *ctls); void ma_tls_set_connection(MYSQL *mysql); /* Function prototypes */ MARIADB_TLS *ma_pvio_tls_init(MYSQL *mysql); my_bool ma_pvio_tls_connect(MARIADB_TLS *ctls); ssize_t ma_pvio_tls_read(MARIADB_TLS *ctls, const uchar *buffer, size_t length); ssize_t ma_pvio_tls_write(MARIADB_TLS *ctls, const uchar *buffer, size_t length); my_bool ma_pvio_tls_close(MARIADB_TLS *ctls); int ma_pvio_tls_verify_server_cert(MARIADB_TLS *ctls); const char *ma_pvio_tls_cipher(MARIADB_TLS *ctls); my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_list); my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio); void ma_pvio_tls_set_connection(MYSQL *mysql); void ma_pvio_tls_end(); #endif /* _ma_tls_h_ */