l2Jb7$J/FV`cU_`H\'$xdlu/zLHa:6A)BR[Uv#84=t\\NS9[J?elr!=Qe/N&e[t`dXj7i6i<(L1GXi.?4&[(K\'vN`zo@,TMd6tusbsA\'8(Zt`bPIZnC@RbyaXtg+4d\'+AK6i;$>LHdGq.(vMXX5:``Cjt1,\'y^I4bzgs4?$0b*AL?5,u=dg^$-THM,0JfM-5`m,(\"l+(%yenzDydg[sYBw^R_k#\\5+s6E=BrD5y64D931:oOt,i]u\\LFXnHUX<\\F(-Jq%T_ggWZCxcdO@3v/r\'[z%5y8dh^$,O2FL1KiUOkUGD\\+VX:Sv\'M7cxX/x@n3LeBTd#qC3od-Ij`(==Z3-\'tF:/w>c_71-0EM9nMopf6nV@yl6_e^-Zg{Z2&_MMyG1ZY6;er4D:7C/[gt:Y;Ty1x=[;Qg;+a3ob\"rMb-O1?-\\rOoh??[7:ZBrHIt:Y9MY[@k&ku48[I<1zE&(6uvwtcr=nA4y69X7D6{;H??^EwSuz1pqh=/niIi^ypHRFI{[50/<#2sz2!H.JljS>vf#hq&Z\".a)=;N\\gv@tS%PLld6uuq\\Y+_-VQt{4(dN9j;\"2sy/lb*?Cq=rU0+$l&geFieBVkA>SjDNA:?izUuse\'&)9\'RPx7B\'7#CkzMKov)[wmA5$POyCx_QYMWQpe1ZW)])Fhb5w-iUPm_p>yvg\'zfms#EvPe6qbyb^6+p$S\\X+`/_wchdC\\-a.WSz8=i)\"k&inplQ05XC&-O-0I_-UPn_sMa);402I^&5x1w8G?F$w\\F*:(UYB{pD;>aVkA:@o>\"\'=An5Pw3..7kBA_Er:G:,fJ!Z.k_zoC948ZF-Ks.\"X\"722B;@n7[LLw@n7[NS;h(#qB/^tU,p%T_ffN7_bQPzF&$###%/]m5W?m5T0-1NyBrE=@j!Vvxy!(C]4&[\'C`A_Dq8ZBvX7E8&RR)kl^sPqpbw[>^J5f-CL7i:z,Zg#ea=F.Ks0(r7Qt!76IP;oKd;6>pGK*\'#w^PWIE_4\"Ezb\\+TPqsp]aRVE$yh{X)V__@^Ae^._zrNl]k)\"fib1c,E\\&$5{=V#?X\'M9mFO@1ma!rL`\'7#BgfO7^^AcXmFN;tez`RV?tU,q\'_4#I2VE4n\\_LA=MP-*,;*Yi0EPEJ(\"m/9mH[t_]:B#!vadWco//@5*kjUJQ?&<3%Yws^^BghW[F-Jns\">Rh;*[rU0*!bWlDHz\\=V!87KYa`BaL7g0O%_?UqasF@J7mP(knkS:dr6Me=NO*uB##%/Y]LCK4YNZ]F\')8{5.#`I-=/ngAI.CL7g.FWe!c^1nc,GcC_>TmQ,$iox54B5#H*3`rD9-s,ox7>qL`(9+eJ\"^Cm*yUx+\\sZE)8#?X%ChgPoD=D\"tQu&M;xvmB?Se+<0u1)tA{sU/#[0ry4-\"];JGbAX\"2sz5,xLKr)dJ%l(n&aCfb:6?wj/@:@pA0e;1#Scyb[\'Gp/-2P)mw9HCXr^aM?4\'].d:-lhHjfDYxwnI[pLd:.s,p{Bl&josw$>OVD1d/TB.XZ>c_97F?I5e-DT\\Uvy$81*yV\";H9#@Y*Yl9oOy@gp&\\)L,1R05U6GHs7KX\\G1XOd2b#xcga4stram,\'vQlUD2g>I5f3`p?_L?3\"L@;F1[`R\\X+b;;Sv#99T#Dp7U0)xRlP+zW%Fs?sV21?+VW8IJvD\'3f9\"9=elt+hYdo(jk^sOnb&*@H-AEtHCVj;!/d:-osv\"5(dJ%n09mGV\\OUC.UM_xh\"bRV=i%m)s:]LFWg*1S:beWeyW(Wf#k%cPI]yrS*ic7\"AbU^^AfdGq/-1NyD#w`Xy%:9Pg@Cn-)(*:*]$.X\\H4d+=Vz2x;QkN%bM7e\'&*>;NXSw+]$0c0\\ddPB;>dgZl:nMniJq%Vh0Ls)bBZ(L.=,]xn@/f@H-DQLiVPlYX1$]4(fUU23IYer7Rw0x>bXuj7g2YPd.N(n(lt+iZi)&!m4R)id=@eeM5WB#$)ANFU\\Rg6kFXj6cxZ:LQ8^Y(QHVW9Nb,HkiO1A70\'n(koob%%(8$G{c],ZfxNZ\\Dx^OLqz:IDWnKeCXvr\\W{2x8E6y1w7@!xl;tdxUz75C5y52:k:r_d]\'BXwxxug(\'+@Cn-,4^gmpn]c`97GCZ%>LEWf&zdg[rU36S*lme5lP,\"bVcuKR>yt^Wx&AXy\'Gq16W@rJTNf?ExY7@xl8h/ETYE-Kt38_]8:X7D2iIkhKv?m5T0.6ao3C;@l,,8tmJdAPR.*&{k*$o5Qz>^F#n6U4>wj4WC(:0x@k\'p19i1O\"OS6L`&0`yj-3ZSo]dbCcQKb6y4*o$Ui9uoR,yQd+<2$Yy$5$NEO@2sy/la\'1_rIP8dwQkM{PVE7!:E-N\'n\'hc;9JKzRc&);-lgBOIa5z7;`[+[oDCaEr;fuE0Z_QU>oD?LDNA;AsNgDYte!eeP?*O9j6d{fo{E#rFD`?Re.HdEf\\xoHVYBvX47V6B0b+F_4y;MXSu$A_Ciou&K3U*Q@/d5soYO`xdhd>E%\"tS#J3[W)Xl;y{&:45OohAH\'\'+CPMr{=SlP*vH>9AzoA0hGcGt@va_?UtnP&bGvKN*yY0wys[MO)q3@,UNf>=W(SV7JTL^wbf^\'<;Rpb\"o>ywj5^aPMprrf/Ls.yKCOFPEGq15XAv_UlH[uexSpc&%(6w%DhiZgzX*[wj2P%[+Xdp//;z&@PUA\"zrQx6;bdU\\Q^l)yW)Xj3U,XaaEr&=CxaZ$95=sX=aYxyz$0e:-j^uZAo=s\\Si=0ry5/,.BDkxBw[Ap;m@0jSA,R>\"(APT:]NP)p-#cWh,9wz)M0B=LIhYesVw#95A)BUh2XJL!UoXJHia.WU&T[RiBG\"iyMMyF,BNDK-;%CbK2Q+wG8z2!H.G`5{?\\vevLP4J[oEEjnlYY42>$4w-j\\m7_cXj8nNt-p!Cp8[J@Ae`6\'Ys__G\"ixH;-hQ=xpLfDZ\".`\'4oavX59^VunOw9JL\"Z-gL\'q7U/%eZqR%VmHYj5[UuupV60.6ap7U1-/CFuHCT`ir)dM1GWblxBrF?I7qbsF?I2WJIr.$bQKc;45K]tY?izUre+8utlB>P\\bZ#1na{n;pQ$S_hov.r(],X_Y%@WvvpT4B0d6v\"4\"I0O&eU[NR4HREC^;D&.P3IW\\OS7S&Vi6f.G\\{%7&T]X(ROt\'SU5C3ro[Z69[G0VGANI`1hGeM2KgKzUrf/Mv;U$H((/S(Eg^\'=An3GQEEf^%6\"@`J0Nx@l.5]\\9E1a#xgxMS=qPv.q!Ahpz@ea>I:%FtB(:/v7D3n_qA+N.4\\[9D.Q9``H$q@%2hEZyyuez_I0Mv8HFdL2MoqnXMWQpg9y(K+/JgRB5\"Bl&f]#.Y_WrcuKP7[MQ1:qV9S\"Co09lCDgeHq12FN9k?2t\'V`e`4u&N;y#/d7x,b7\'T[NVKQ:h*-BJ2R04S.%ggSHO7__EvOb\'2d-IlkZ_R^bT^`L;z)L*)/O)r8S$NFSS(aA[0psslH[uduG<55IQC7,ov.r$M@85B0a\'4nZX0\"QZRn\\`OLlb,KxI=5/.7i7mKkb,Jq+nv/u48\\MN$]738af`4w-ka\'2g>:E3f6p^gox56La+GfTQv/u1+{^Dq=oEGq01DGtB(;2)p+vE-LxH9\"8:V*fO9i3U;dkr$J3[W(TV;Z?dbB_AaL8oS2;pOrz500@4\"H/IdGn{G.G`7,nv,iZgwKJr+q(dK-7mKk_yl8ez`QS02Ja3mXQn]gp$S\\W\'PEHzY.oqo\\`OIa6#G\"j#^?Z1w:Pf8y,`,Q;k7h1O\'eWdq5K]u[G1[\\Bn0:pU9T&T]X)U[LKr+mrx.iSB2oc\'-Kv?l/;xxs^\\9@uX:T{9A{rPt#@[2\"LABdXmEJ($sM_{sS\'Zz$5y8?qL^{t[H6rf-BH\'$v[E%$$&1a%(7\"?Z-gO3Mk[ft9W31\\?_G\'&\'0Z_PT9X9MZb_;C%&-P4Kc7$FvPd1]hu>h![50/9pWAxh&q:adTX?n9f&wX305XC(7y/mg?@aPKgM-1KmiJp#L=-c7%K4[V$Cjt/%cROs&PKeE`2y=Z7=m:nHZk7cvQkQ2?*P;qT0/7g/JiZgzY,gM-1Mt,p\"G\'*9%Erl2I\\ubkt.v=aXsctHCXuj:uk?2v/u5;g\"cYs^]:F3h>77OkUGCYz)J{Z1x>aVj<&A[.hM)yY3+yP_rHK#aK6f-CN@4%TcuM[djk[gvE1\\fp)kmc0XU$I.ABe])Fkoph=1x=\\=Y.pv(ST/\'q6Mc4mVD5ssj?4(eRIW^Wvuj9q]\\8?tU,ox8C*CUf,;)TT,t6GFg[tZH:&I%sE:2-)#o8``Gy\\AgkjTE;7B)?F%zl4Px;Pe4g7tmKka&1`xdmw7@#\'8*dFigO2HV\\NP,&tHDZ#3w/s([#0f@F\"k(vMYZ?`MCFr:a_=OYV(YnGRJYesQ^hr-zP^hs1/7g/IeGo%[(J#fgSK\\oC948]Q`o7X>gvC%*BS[Vz0qv%Em%_pGO7cr=l7dy\\@ecEheGmw7@ynA4zY-iYbbI%rC1c/VM[emv2*vH=8B%-Q7ZH8x*UW8Nb+E^1plR4ISL`&4n^izP\\aTbtHFfUV4=sW;Z>^H/Lt1+\"d^/d9*^)EdO=$4y9B&2f8{5*kjVOiLwC#wa^9=dieCWq\\Y+b92*ySpasGCZ%=F.Ks.\"Z*ZmA3w2)mv46Prv$>OUD1b(6v!1rx-eEbDgeGls&RQ\'cJ(%yceTR\'].b3iFZyvk7f+7q`m,(\"l/8j=)P?,VU.wAsL]rPpmWKR>wl9nKeEa@Wy)M1HZpNomVG@K:\"6,s23GQDB[+Yh\'xZ8C,L$dXi2S18e{aSZPaxaZ\'Fp-%m\'jopjFZug\'#rGGknkR9acSR)ia1f;.oro]da=F,DSYH;1zH2]efVYBuV/!Sd(0UC2gAF!hv?n:i1Lpu%G{`NEO?0l\\fp\'`=I:(QKb2iHeN6ZNXPf<4,xMP07ctGBRXIDXr\\TnWG?DuM^rNf>>\\=W$Dku5>sW;[?c^0iN*z\\%:5:et?qK^wfvIDVi7i;#6+ox9F9(YpMme5p`p:g$n1xoIW_Y$n=\")EfYi.=-c9+fO9i0Kle;2\'dQIYg#feN7am\'jmf?Bjw@p?#+M*$n4K`)?G,ADp4IVY?hxJBL:y$820:r\\Uvwxvl>-_%/\\h\"\\:D.R=rU38^Y&I&wX/yH3aycdQFI\"`K7j>2x8D1a\"uX:QmYW+eK$iq$QQ(g\\xl:r]X&L3T7OlXRrqbwV*b;=`RYNYW-ow0yApoC95>sYAuX5:es;bfZqPw303P#PQ)o(ha1c0XSy2!K>600=%;=_QXG;2)o&]2t&M<$:9Of;.mjM%dVahke<7?rPqrmO{KADo..;z)N5ZKImpo^hr0,,4bwW-q&XoNr\"@aPKhR>\"\'<X+`2m]hvAuX8GAOOzG,BI-AAbTYJCRS16XBzn={&:59_X!2w1$[*TQw418csB\'7$I-=/la&/XT!>X)YnEHyW$Er;bg`1f<52;qS,u>hyQax`Wr_gi\\pGM/?1s#Ckw?i!X$>OVF:0\"Q[[9E4o`q?#+KzSjCJ.BEs@\"zt[I:)Wcn(lw7B*CWnLla&/VNa&1`xbbK-8sf+6lLpx2$Z$;@n7ZI?@cXpQ%WqZP_rGHo$Te(+>SjERR\'cH{^Co3DBZ)TPv-oqqd\'(5pby`WpVQauSy4,xJF_2pkMxBsMa(9(Xi1Mu0%dU[LIja-P3Ka0^tS\"Bl(o)o(fYg%sD3oc%$%,Js1/6bq=oGP=#1hHjc6z4,vB\"u\\I;,b7([{%7)^0e>>Y2$Z(L0DK.=-eBRZPazj+*2[[;NZ^NIb9/\"Vsg/G^+P*N2KgN/;y#0gBNDK0FUZH9&L3S3>{#.Zeo%Z%>KDRQ$Td{flon^j#_Dm\'igO7[Q`uRt{4(dL.=*VX>gq.%fcAWr`hnrv!2v1#Wsg.FYnGQEDdSQ\"I1UC+Jt8PlWOf:,c?I4b{k*#l,\'{gp\'a@VtnMqx1zH0P-)%yen\"LBEr;chfIwH<3+uB{sS#K9tj<%AZ)QDB[.hN.4[SnWIE`:<^L@=OYTz64@*IwH;-j^tV34IW^TkGXk9nKeFha1gAH,=0t)`7*hYfuE2e5kHc?MIfM/<&C`Cjq%PMqx2#QYO`xa[)RGM1HYj1KhQ;pQzDvSv%Dku49_\\2zBn2D@WuqZLP1?-]sT,q\'^2t%K1NzF*7w%@Wur`is0\'lx>dcHzY.oqnWJJu;\\DzgtejgJv@rL]qJYdn$Z$96D7\'Ve#k&iorqe+9$CgeGp*ny>^F$w\\F)3f4c(/S>vds?rOojKox3*s6HM+,;&I\"d`7/#[.gL\'r;fxNZ\\CvSy2$XuoNt+fN2Lk\\k/<$7.xG5kIdC_=KF\\&<=_L?75D:6LFXmC@Wy&B_>P^k\'q7R{@aQP{I4c#rIP8dtD0_tRx4.(y\\@ecFlw;Tz4)mt)](Fhc;5;clx?eh]zwg\"d]*Q?&=BtOg?BjwAtRu%Eq5HQC:6A&5x/nkQ3GL.;$96A+M*\"goy=Z4.+-=.k\\k-3WC,LzRc&&+CVi4^fgX_Z(L1KhRA-XZ@l.3WB$&1d0VLXZ>_NJc?J<+]zveuD/Z]I6lMr&Wi5bwU$I+7nU>pEEg^%5z78Rw0x@iyLLw@n6V7JRC7*gVW6C3n]gq+r/)yZ52;pPw7B\'7$GzbWpS/+),=63sT-u9PjO,)).Ks-u:U(Zuh/CFvNZ`Uh4^fgXclw9KP6T0,-9wxz#-X[F+?@cXmDHyV!9?l1FN:r\\SmR19h0Lnm^l,,8tlGWae](D`@Z,a0c1]i\"[2{G-F\\$2lWPkO)s:]NMv;U\"?Y-gM++3_n3FK($rD8*dHt;`Y{-_$,M)yX-j\\n={&8-s.zOT>sU.\"Y%ElzG1VIGjeAQWC)@G\'(4iDRS.&n*t=h!\\;JE]+SISKZi)#m0:scr>t\\LF\\$5z:F6tvtg,:#;D\'/WRro\\_I1Q.**1UB)@J7mMt.w>dg]{yrU37YD&+DWoOv59[F0T>uadWg))1YV(ZueyX+dEdPC@Vsi8q\\Y-hSEBVpYLN(q6KZh&rA%/Z`XvpT3=wnFL1I^(@K>5+t:Y:QlR6Pt&PFM3S16XB{pEBY%?Rby`Ui8q\\Z4-%ju7GD\\*RFGr7M`&1b(3g:(SQ\"J7oWD/VM_v_X!1ng=529exV$G\"hq)h^!ztZG3b!n8`fa:5;h)(,AI.DOEL1Llc1_qB2kSG+>8?sQw/t0$]9*P=z#,UM`%.ULZb`@W!4$RXG:,gPP]dbDe[tae[vi2O\"PS4FFkqw-iWW1,\'xZ;Ob\'/TA*FgZm@0hIp%XsdwRmWJN,+3[[9D0^p?&:6@!ypHTQw0w;Tx/njO*zZ4-#cWj7h3ZSrjCI)-EU`fdEeV]Vur_cWk:wui3XHBNGXg&wX3/0ADydg]ypKa.XY8E6y2\"MFXh-:\"4\"F$uV-r)cGr4C90\'ij^u\\LDRR\'cL0FQJ\\rS&Z!+RC;:Pf:)ZoI[pK^\"zvdq5GHs:[D{k.6cy`TcwW,kb.RH1VF>?cZy\"*JyO\\b\\*REB[*W^UmNzI7sj?5-xH9$Ciml[aYxz&;9KSB1f?AffQC;<[>\\@cZz$2lYU&QNqx/nmZZ:LUHIt;\\H4d*:)V]TnT7Ry7;dkorri=-eD\\+XbeYk8h4\\^H+7rf,=3(h_\':1&f[vg&vRqlKnog8z.eBQXF7y2x;Sqg4e+;*]\")CY!.`(;69ZBw]MG]%4suwy{\'@PS5KZgzX)Xf#j{Q`o9co-%kzLEVbl$]727YD&.S@\':3..8pZNVLXX6@#(>CuPkR6T*jfE_70(s:JHh]wi+/IdFiiTHM/:ti7j>1t)\\%5z:H@EzdeRK`+Jv?m3Noo`sHK#bRT01@4{Cq;i,3[Z53>$3rrjBEo..:unLjWX5:cjq\"Co2>\'C_;E.O-.=-a.VPn`uU*dFjnm\\cbElzF+>9C*@F$vZ=]CsHIq+s4?#,P7\\Si>4,vC%*CVh2TV!74>xoHUU.{Sg6lIb:48ZE+AI/H`3rqd)1XRpg6kGZucq5HO9j7i8p[TtrbtIHmu-ml\\dg[rR%WoOzCsJQ;l>+US%S\\Y/pt{4(fVZF/P1J<,c9/xC!o?%5zLH`6(\\&)L.;!.c4pe/N&eZoIZk6^bQQ&]0kWT#H\'&(3g=4,yRg6lMu33DAY%@WvvqW>k/>-^\"!ysV7IO2EJ&rB.WV+ja.UL[fs9W2/5XF6tuoR+u?n:l>*SLa*Ea?Q\\^H+:\'N;vlA86B1e8#>TmQ.-5_hp\"H,>8.gK!W{2v-nrsnP\'eV\\P[]E!k(vLUHGjhQ;oJ^#\':3-*\'&(3g9#?TmNzH4g5f3`p;j1Kj\\k/;!.a*E].c4pd*8y+Zj2Nt,mm^pA/`$\'7!;JDUdxX/t/$]77M_zrMgHkiR>yt^Z,b5v&H#hp$PQ*s7OhHh[pGL-7j>1v1%`BdZrZJBNB?TmNyE(/R;h*-ACm&dRPv1\'jk]rK]rOnc)9$Es>rPu\'SR*knhBK7i9wxwoLhN,,8re%w[Cx]J:\"5\'^1nc,GdIzV{5*nzCrE:2*uD/WOf;0x>`PP$VoS3@)It9V.u8JO2FK-9sh2U@zrOqqg4d(1ZY6=n?+SHO8bp3A4w-le;0xAn4Ld==Y2&bHz^Ezca@UnS5HO7__Fzb[&>I:&GwQg=63=xoK`-Q:h),<0s(\\$4x0w8E9*cATf,<.mhEYuf&y`Ui:x\"-[m:oNs%N@4$QR/-5_it24LfE_6,r/(s@yl8e!fkhL&kw;X/w>b]0l[ccK,3\\^F#n8^X$>QawY6>pK^yoC(Ht?oA/b/Y[@j{TmP&`BbNA:>hxIAH+9z.d<8E6u{0nhCPJa4suupS0/l2KgM*&yaYy\",UOjQ4LeAPP&`A\\63:k8i6e\'+>:H>?`L<%@Vrcy`QV=l3Ox9KR=rU4;i0I`2m]fmu+fN4T0/8kA:BxbbJ+2XMVOiHi^zrR!E{hwC\'0\\emt)`4x3(koqjEU^^AaQNqy4*p(eTQ{Cp7X?k)\"iu:T$I+8tnO{I4d*6rf.HcC`?Uqczb[\'EijZdkqv(TW;\\Cw[Aj$`FvLS@%4stq_fgUS#J6j?5+s6FC]0l]n7^\\514Nqty+Zi,5czejfGid>Ak$_A_F{ddJ(zc^2rw&Eo-%k{NQ/2Moph=0r\"AcVe$o7X>fq,vB#zpFFks\'Vf$rD8)`7)dI{[528ahiZep/,->5-yOYTy2zCvU\'Wg(*6nUA\"#\':1\'jmf>;N[`S]_I0N\"Sc!j$dYqS,wD)9\'SS+o$Uf)/Q1t[I:%GwNYZVy-a.Y]LCH\'#sKX^PVD/WSx2#SbtLVQrpatJO4Orz63>zyucn(iiVS{=Uv!1nf;+`/]n=xs[OVIIq-zQbzhxLLyJ@?Z0s*cDdRMl`zn;s\\Rd*8\"86HK$fcC_;C#!u[F,EZuj6br@%2hF[#2m^m3IYfzY.mjO.0FRNmc,HfTOpmWKO.4WB$(;3-(zaXpV=fr5FEeSPx9H@I1S6Psx+]\"$+N-2P$Y\"1oiDRT13I[pIX`_A^AaOFQIYevG;3,\"_DsC1b*>zveuF8%I*/MxCzi$fc@Sc!k)xTx*Xcm%^:>fr27[MN\'ij]sS$NDK0H]#,R@,RA/a\'6x-gK!Y*Yj2Q*s7OhFaj*\'%#zoCE\'*>=Uux#6\'Z{(BY$::Sv\'L2R-%js+lmb(6soWF7x,b8(YpQ%Z\"-^xh(zdcGuE3iF]\'?LBH$q>vewN[b^7.#_@_Fy^I4_l+%p8[KCOFPDB^:C#yn?(D`@W!3y^Ex[?aRU;a]6-yMN&dUZJCOFPEI\"bT][4+t<`Z%@UoXICS][4-$geL-4[W%J,9y(IyTrh7pZSo\\^H+:\'O?-^xk1KfJxKIll^pB3str`l(q3>$2m]hwH8#=MQ1=#1jQ6V4:h+0MxC!n8dtF9,kb0[cdO!&;7D3jKp#L<)O=#2oh?;JDUcvN`xcfZpMkY]LCJ/ERNqw*\\vg%o6R%UcvRrlNyE\'-LxE+??_H,;*[rS(a@Vsf,<-eEcI%q\'C`A\\76GGlrz9C(:-nm^o=ubjr%SZLM$_Be]\'@OO%\\0qssj?3$Tao5MfDXui3ZPd-Kr*jgGic:2,$is-v>fnxi\'r=n>(Hs:[F)6smKkb-M%dXi1NxAl.1Ms&Ucs@#%0^tT)b@R^fh^ztYAuU*dHt:F6v#725Q\"J5d(/Q5MiO2C?OUA$)AOLqy529g)+:&J)(,BNCFq6NiN,(\"n5S*ny,[oFHvF8!9?pC934J\\pGO8f((1YU&OGRMgJs4@%5y64D:48X=ca@VrczdfTT*lmd3d+=7n>%8,ll]l0A7/%geIt>j+*3]b[&?MIcC]2x:LR=sZH;*]$0`%*AK;&Fq3?(AUlEM9pS26ZH:)YnDB`CgdGmzF)2]iyMR4IUS%RU9Y:Su\"88Ne7v#723HRISMd8\'SW<`Yz*P>#0d6w%B_AbSU6JSHK%l$]611C>OU?u^VtlFQHSMiN-0EQLeCVj>-d:2,$jv=`WnOzG,AH\'$zm6YH<4//<$95>u``G{aVj8pWC(7#BgfM.8mLmiKt24Lc7$I,;\'K/ASjDM;z(Flr%M?2w419i5^bVf\'$yfs6IQ>!\'=CtM_ym8dyZ9E6v$?Si>3&[(J#d^/e>>\\CrB+L&o.-4[Y2%^9:X45JZi(y_NGZrWrR\"F$tNc1_rHK#cU`e]\'@Q[W\'SS,wE-Jp%WlEM7cwStvxz%6\'[\"*M.8lFQIZm;tf%sIN-1Nv6@\"!zveuE3jHfO9g+6jBEs?vclv6=oEGq2;pNpssi<)RHSJZi*()3e0UE7#EsC.XX32>\'AUlGWds>pISITNjR9co,#d[\"+N3Ml_xdkr$K5asGBUg/Hc@R]aS[SmT=m=!(C\\,^zvdo-(xW,hWY=`R\\Y/q{=SlP+zVy-eAPQ*q00?/gIq)g\\sW:T\"Ad]*L(z_NEPCB]9=eo$Tf+7rh4^fkjTF@ONyD{l0A99Rsurcy\\Aj\"Vsg1T;dlx@iyKEYqV9T$I.ESU3:i0FU^X&Fr9[H6nU=j-4_jxD(4lO(n&aBbNA71-,7nS3?(EeTU25Py;Pf8y-c8)^*J\"^@aPKd@NJgRA0d4lQ1:nI^%3m[^I3\\_MBA_Cl#Wvuk?2v0\"Q]`NGV_];G7w&Dga6#EvPhBM>0ng=4-&o/0CFsgq-\"Z,b6\"Ae^/e;1#Te*7uth2T:_Xx\"1l\\dg\\veuC-O.3U;baFuF;2\'eXh))2]gp%Vi8oV>m7bo/1FO?+UT)bB\\1r{;H>;KM$`FwRmVD4ob#tT%OGUYC%(9\'TZLJnqsq_jwByfq.&o19i2R2:l=\'Eij]qJWY>b^4$OJc3&\\,]u^Vsh4aq=sX=a\\.b4n]ca?Q^fkjWT$I,<,b7\'XlA71.2Q*s6HM.7g2VB\'5v&FtD/XX45JZi+/H`3qnVF:0yF-HdFmx?ddL-7kEN<\"/c4n\\_NFTW;\\F(.P0;tdxTy0ptvz(Ht%:8KP7[OXQjJpy;Pb#zm;qW?m5U6F@OO%\\/k\\j(wPg0mc/R:cm#WrcvPe7uumKfJzTqasHIp*lomXPiF[z%5y4-&o1:nHV^X\"6.zP]efTR{Cp8[I>9@v^Q]d_7,q&\\\'DeXh*.Hb>I7rf-ADq9]Q\\_MBA^@`G&zfp*p)kl^qGIvC);3,{Z1{J9z,\\rPu+fK&n..:wvoKfGlrx0u/zMKot{5.$dZtafb>F+=3+t=ep)ifHo%Ywtey\\Aiu:W.v:RsskEPEI$l(o,ySlMxAoxnB:;V+gTLb/XU\'VctD2hCNA=NS8X<_ONx@k)wPb\'/TC1f:,fK$ggTOnd-ImokO(n&bGwQg:\'M8lCDlyF-F](Go(fYh*,<,d?I5g4e*9!5)jgIp(bGr9[F,EWj:umHXf#gkfD[%;?izSjDN@7/\'p18bn,&sB,N,+4`p=pNl]k-3XJInw43C8.v>gs6HJzUrg0Q19k:uk>0md2azj*\'\"qD<=]G(/O)s=j*(*:&K1JfL&o1$2pkJiZh#eafq/(uG=:KO0:sbq:acQKa2hCQS.&m\'ijZfr6HL+*2[]Cp;h)\'&(5pbx]F*7skCFwPd.M$`DkxBvY;Tw\'N:pS12GRIX_[0ppe0Q3C:9M^qIQ>\"+O6ZKIhYfuD.R=qPt(Wi0Kk`&/Z]J:$>PZV%I,7oYLR;i/DJ*.HdEf[uae\\{#*JyP\\b].a+Io\"J9uq\\Y+_,THL+*1VF;42Y-iVRx3*s5FBXxxyvj5]`J3\\[8?rMe;42;r[OYW+dEg^\'=@gmt&ODDks)a97D5w*ZoGO;saiq&UcuLVNd4mU?wh(#n4LhN,+2XMXW.w>caAZ,b5w,eC[&CaH\"glmb):+b90&e[tagdBZ(L.:y$6\'\\(DdTU4>xqOqtuulCEp02Kd>E#tPlXRpg6nU>qMf@J5e,ACk!R_k$`Dm&cN<#3t{60/;ws^]=Pb\"rMa,Jt5A*Ho$S]^Bl(n(h`0a%(:/t/\"X\"4$PP%]2u+fK&p3EEf]\"(@LAA`H%w\\E$w_VoT7Pnc\'1\\ca?Si<*V\\Q^jzQ^j\"Y\'M7ctIJt7KXZ>aXsdwRpb!l1DGuF8&L8kA1u-ov,eEdQHTQz=W&N=\'C`BdWg+2ZW*b:59^X\"5)eQDAXy\'Fm\"NLpx4-$hjb1b)9\'PEJ&vRpg5h;)TU37YD&+F_6,p&Yws^[2!J:%@Y\'L/CEo/2I^$-THJzVy.d=?aUd!fid;419i2U*P>$3rpbx]G.G])Gn\"ONw=^I1TP\\_L?88PkT@%/^uW35MiR>vg&uOe9%H\"fi_%/\\k,->2\"L@=P_m2FN8e#o7X@n;mA6,r/\'n*r4B3sw$9C&1c);.px3(ha1e9&M:r_bQPzF(.M#\\5+q-yOZW*`3pkKpzY+_,QoA0e=9G<69Y<[0omWM[dkmd4kKq#H,=2\"LA@];IBL:x\"/b.TFAS`l(o*s8Qsw#838^Z,b6!>UsnP&bJ*+9#:>hyO[\\CuOe9%FwQiEUaip\"DtJM(wO_rHM/=(HvH@G&$\"wabJ+1U@{u``EtB*FcHxP`w\\H3bx`Wsbq:bf_-UPog:\'M8kA:AtS#I.FXk8j=,`*D]1ppb!m5S*nw6=oC<@l-1Lnm[^J:{0kYY9LVNb,Jq(a>KCL9se&zhwH;0x>c_6*jfBS_hov,hUQt\"deSOpn[[CsHGkk\\l3Mmg>;MS?!\"&7\'Xk<\"1kXV)]*M/;y&.e@I1UA$)APP&');
+--enable_query_log
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+--error 0,1114
+INSERT INTO t1 SELECT * FROM t1;
+DROP TABLE t1;
diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test
index b5ace75dbc4..23c591856a7 100644
--- a/mysql-test/t/archive.test
+++ b/mysql-test/t/archive.test
@@ -1550,3 +1550,12 @@ insert into t1 values (1);
repair table t1 use_frm;
select * from t1;
drop table t1;
+
+#
+# BUG#29207 - archive table reported as corrupt by check table
+#
+create table t1(a longblob) engine=archive;
+insert into t1 set a='';
+insert into t1 set a='a';
+check table t1 extended;
+drop table t1;
diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test
index 9b4fc3f39b0..da10f4efa61 100644
--- a/mysql-test/t/bigint.test
+++ b/mysql-test/t/bigint.test
@@ -307,7 +307,7 @@ select -(9223372036854775808);
select -((9223372036854775808));
select -(-(9223372036854775808));
--disable_metadata
---endble_ps_protocol
+--enable_ps_protocol
select --9223372036854775808, ---9223372036854775808, ----9223372036854775808;
select -(-9223372036854775808), -(-(-9223372036854775808));
diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test
index 26051da24aa..4aff4b27976 100644
--- a/mysql-test/t/csv.test
+++ b/mysql-test/t/csv.test
@@ -1675,6 +1675,17 @@ insert into bug21328 values (1,NULL,NULL);
alter table bug21328 engine=myisam;
drop table bug21328;
+#
+# BUG#28971 - ALTER TABLE followed by UPDATE for a CSV table make server
+# crash
+#
+create table t1(a blob, b int) engine=csv;
+insert into t1 values('a', 1);
+flush tables;
+update t1 set b=2;
+select * from t1;
+drop table t1;
+
#
# Bug #29353: negative values
#
diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
index 88af556725e..9d2b4abc929 100644
--- a/mysql-test/t/disabled.def
+++ b/mysql-test/t/disabled.def
@@ -24,3 +24,4 @@ ctype_big5 : BUG#26711 2007-06-21 Lars Test has never worked on Do
mysql_upgrade : Bug#28560 test links to /usr/local/mysql/lib libraries, causes non-determinism and failures on ABI breakage
+federated_innodb : Bug#29522 failed assertion in binlog_close_connection()
diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test
index 0eaead8011e..fa65568e9cc 100644
--- a/mysql-test/t/federated.test
+++ b/mysql-test/t/federated.test
@@ -1630,4 +1630,57 @@ connection slave;
drop table federated.t1;
+#
+# BUG#21019 Federated Engine does not support REPLACE/INSERT IGNORE/UPDATE IGNORE
+#
+connection slave;
+create table federated.t1 (a int primary key, b varchar(64))
+ DEFAULT CHARSET=utf8;
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval create table federated.t1 (a int primary key, b varchar(64))
+ ENGINE=FEDERATED
+ connection='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'
+ DEFAULT CHARSET=utf8;
+
+insert ignore into federated.t1 values (1,"Larry"), (2,"Curly"), (1,"Moe");
+select * from federated.t1;
+
+truncate federated.t1;
+replace into federated.t1 values (1,"Larry"), (2,"Curly"), (1,"Moe");
+select * from federated.t1;
+
+update ignore federated.t1 set a=a+1;
+select * from federated.t1;
+
+drop table federated.t1;
+connection slave;
+drop table federated.t1;
+
+#
+# BUG#25511 Federated Insert failures.
+#
+# When the user performs a INSERT...ON DUPLICATE KEY UPDATE, we want
+# it to fail if a duplicate key exists instead of ignoring it.
+#
+connection slave;
+create table federated.t1 (a int primary key, b varchar(64))
+ DEFAULT CHARSET=utf8;
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval create table federated.t1 (a int primary key, b varchar(64))
+ ENGINE=FEDERATED
+ connection='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'
+ DEFAULT CHARSET=utf8;
+
+--error ER_DUP_KEY
+insert into federated.t1 values (1,"Larry"), (2,"Curly"), (1,"Moe")
+on duplicate key update a=a+100;
+select * from federated.t1;
+
+drop table federated.t1;
+connection slave;
+drop table federated.t1;
+
+
source include/federated_cleanup.inc;
diff --git a/mysql-test/t/federated_innodb-slave.opt b/mysql-test/t/federated_innodb-slave.opt
new file mode 100644
index 00000000000..627becdbfb5
--- /dev/null
+++ b/mysql-test/t/federated_innodb-slave.opt
@@ -0,0 +1 @@
+--innodb
diff --git a/mysql-test/t/federated_innodb.test b/mysql-test/t/federated_innodb.test
new file mode 100644
index 00000000000..772e37a2929
--- /dev/null
+++ b/mysql-test/t/federated_innodb.test
@@ -0,0 +1,34 @@
+source include/federated.inc;
+source include/have_innodb.inc;
+
+#
+# Bug#25513 Federated transaction failures
+#
+connection slave;
+create table federated.t1 (a int primary key, b varchar(64))
+ engine=myisam;
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval create table federated.t1 (a int primary key, b varchar(64))
+ engine=federated
+ connection='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+--error ER_DUP_KEY
+insert into federated.t1 values (1,"Larry"), (2,"Curly"), (1,"Moe");
+select * from federated.t1;
+
+connection slave;
+truncate federated.t1;
+alter table federated.t1 engine=innodb;
+connection master;
+
+--error ER_DUP_KEY
+insert into federated.t1 values (1,"Larry"), (2,"Curly"), (1,"Moe");
+select * from federated.t1;
+
+drop table federated.t1;
+connection slave;
+drop table federated.t1;
+
+
+source include/federated_cleanup.inc;
diff --git a/mysql-test/t/fulltext3.test b/mysql-test/t/fulltext3.test
new file mode 100644
index 00000000000..a57fd48daaa
--- /dev/null
+++ b/mysql-test/t/fulltext3.test
@@ -0,0 +1,24 @@
+--source include/have_gbk.inc
+#
+# test of new fulltext search features
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+
+#
+# BUG#29299 - repeatable myisam fulltext index corruption
+#
+CREATE TABLE t1(a VARCHAR(255) CHARACTER SET gbk, FULLTEXT(a));
+SET NAMES utf8;
+INSERT INTO t1 VALUES(0xF043616161),(0xBEF361616197C22061616161);
+SELECT HEX(a) FROM t1 WHERE MATCH(a) AGAINST(0x97C22061616161 IN BOOLEAN MODE);
+DELETE FROM t1 LIMIT 1;
+CHECK TABLE t1;
+SET NAMES latin1;
+DROP TABLE t1;
+
+# End of 5.0 tests
+
diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test
index 426eec4be6d..d7182e36e3a 100644
--- a/mysql-test/t/gis.test
+++ b/mysql-test/t/gis.test
@@ -571,6 +571,26 @@ create table t2 as select f2 as a from t1 union select f3 from t1;
desc t2;
select AsText(a) from t2;
drop table t1, t2;
+
+#
+# Bug #29166: MYsql crash when query is run
+#
+
+# The test query itself is not logged : too large output.
+# The real test is the second query : see if the first hasn't crashed the
+# server
+--disable_query_log
+--disable_result_log
+SELECT AsText(GeometryFromText(CONCAT(
+ 'MULTIPOLYGON(((',
+ REPEAT ('-0.00000000001234567890123456789012 -0.123456789012345678,', 1000),
+ '-0.00000000001234567890123456789012 -0.123456789012345678',
+ ')))'
+))) AS a;
+--enable_result_log
+--enable_query_log
+SELECT 1;
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test
index 17c5f1bbe8f..e33712e1ebf 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -1271,6 +1271,6 @@ grant select on test.* to юзер_юзер@localhost;
--exec $MYSQL --default-character-set=utf8 --user=юзер_юзер -e "select user()"
revoke all on test.* from юзер_юзер@localhost;
drop user юзер_юзер@localhost;
---error 1573
+--error ER_WRONG_STRING_LENGTH
grant select on test.* to очень_длинный_юзер@localhost;
set names default;
diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test
index 51f5e5135e6..4a4f667d3ea 100644
--- a/mysql-test/t/loaddata.test
+++ b/mysql-test/t/loaddata.test
@@ -67,6 +67,41 @@ load data infile '../std_data_ln/loaddata_dq.dat' into table t1 fields terminate
select * from t1;
drop table t1;
+#
+# Bug #29294 SELECT INTO OUTFILE/LOAD DATA INFILE with special
+# characters in the FIELDS ENCLOSED BY clause
+#
+
+CREATE TABLE t1 (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ c1 VARCHAR(255)
+);
+
+CREATE TABLE t2 (
+ id INT,
+ c2 VARCHAR(255)
+);
+
+INSERT INTO t1 (c1) VALUES
+ ('r'), ('rr'), ('rrr'), ('rrrr'),
+ ('.r'), ('.rr'), ('.rrr'), ('.rrrr'),
+ ('r.'), ('rr.'), ('rrr.'), ('rrrr.'),
+ ('.r.'), ('.rr.'), ('.rrr.'), ('.rrrr.');
+SELECT * FROM t1;
+
+--exec rm -f $MYSQLTEST_VARDIR/tmp/t1
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval SELECT * INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/t1' FIELDS ENCLOSED BY 'r' FROM t1;
+--exec cat $MYSQLTEST_VARDIR/tmp/t1
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/t1' INTO TABLE t2 FIELDS ENCLOSED BY 'r';
+SELECT t1.id, c1, c2 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE c1 != c2;
+SELECT t1.id, c1, c2 FROM t1 RIGHT JOIN t2 ON t1.id=t2.id WHERE c1 != c2;
+
+--exec rm $MYSQLTEST_VARDIR/tmp/t1
+DROP TABLE t1,t2;
+
# End of 4.1 tests
#
@@ -182,6 +217,31 @@ select f1 from t1 where f2 <> '0000-00-00 00:00:00' order by f1;
--exec rm $MYSQLTEST_VARDIR/tmp/t2
drop table t1,t2;
+#
+# Bug#29442: SELECT INTO OUTFILE FIELDS ENCLOSED BY digit, minus sign etc
+# corrupts non-string fields containing this character.
+#
+
+CREATE TABLE t1 (c1 INT, c2 TIMESTAMP, c3 REAL, c4 DOUBLE);
+
+INSERT INTO t1 (c1, c2, c3, c4) VALUES (10, '1970-02-01 01:02:03', 1.1E-100, 1.1E+100);
+SELECT * FROM t1;
+
+--exec rm -f $MYSQLTEST_VARDIR/tmp/t1
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval SELECT * INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/t1' FIELDS ENCLOSED BY '-' FROM t1;
+--exec cat $MYSQLTEST_VARDIR/tmp/t1
+--exec echo EOF
+
+TRUNCATE t1;
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/t1' INTO TABLE t1 FIELDS ENCLOSED BY '-';
+SELECT * FROM t1;
+
+--exec rm $MYSQLTEST_VARDIR/tmp/t1
+DROP TABLE t1;
+
# End of 5.0 tests
diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test
index 1374c049431..42db23dadef 100644
--- a/mysql-test/t/partition.test
+++ b/mysql-test/t/partition.test
@@ -1496,17 +1496,7 @@ SET GLOBAL general_log = default;
#
# Bug #27084 partitioning by list seems failing when using case
+# BUG #18198: Case no longer supported, test case removed
#
-CREATE TABLE `t1` ( `a` varchar(1)) ENGINE=MyISAM
- PARTITION BY LIST (CASE a WHEN 'a' THEN 1
- WHEN 'b' THEN 2
- WHEN 'c' THEN 3
- END) (
- PARTITION a VALUES IN (1),
- PARTITION b VALUES IN (2),
- PARTITION c VALUES IN (3)
-);
-
-DROP TABLE t1;
--echo End of 5.1 tests
diff --git a/mysql-test/t/partition_bug18198.test b/mysql-test/t/partition_bug18198.test
new file mode 100644
index 00000000000..7f071c6ec9e
--- /dev/null
+++ b/mysql-test/t/partition_bug18198.test
@@ -0,0 +1,219 @@
+-- source include/have_partition.inc
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (col1 datetime)
+partition by range(datediff(col1,col1))
+(partition p0 values less than (10), partition p1 values less than (30));
+drop table t1;
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(greatest(col1,10))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(isnull(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(least(col1,12))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(case when col1>0 then 10 else 20 end)
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(ifnull(col1,5))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(nullif(col1,5))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(bit_length(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 char(5))
+partition by range(bit_length(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(char_length(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 char(5))
+partition by range(char_length(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 char(5))
+partition by range(character_length(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(find_in_set(col1,1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 char(5))
+partition by range(find_in_set(col1,'1'))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(instr(col1,3))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 char(5))
+partition by range(instr(col1,'3'))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 char(5))
+partition by range(length(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 char(5))
+partition by range(locate(1,col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(locate(1,col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 char(5))
+partition by range(octet_length(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 char(5))
+partition by range(position(1 in col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(position(1 in col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 char(5))
+partition by range(strcmp(col1,2))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(strcmp(col1,2))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(crc32(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(round(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(sign(col1))
+(partition p0 values less than (2), partition p1 values less than (6));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 datetime)
+partition by range(period_add(col1,5))
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 datetime, col2 datetime)
+partition by range(period_diff(col1,col2))
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int, col2 int)
+partition by range(period_diff(col1,col2))
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 datetime)
+partition by range(timestampdiff(day,5,col1))
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 date)
+partition by range(unix_timestamp(col1))
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 datetime)
+partition by range(week(col1))
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 varchar(25))
+partition by range(cast(col1 as signed))
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 varchar(25))
+partition by range(convert(col1,unsigned))
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(col1 | 20)
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(col1 & 20)
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(col1 ^ 20)
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(col1 << 20)
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(col1 >> 20)
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(~col1)
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(bit_count(col1))
+(partition p0 values less than (10), partition p1 values less than (30));
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (col1 int)
+partition by range(inet_aton(col1))
+(partition p0 values less than (10), partition p1 values less than (30));
diff --git a/mysql-test/t/partition_charset.test b/mysql-test/t/partition_charset.test
index 27d0dc87b89..6842e5268fa 100644
--- a/mysql-test/t/partition_charset.test
+++ b/mysql-test/t/partition_charset.test
@@ -19,3 +19,11 @@ flush tables;
set names latin1;
select * from t1;
drop table t1;
+
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (a varchar(1), primary key (a))
+partition by list (ascii(a))
+(partition p1 values in (65));
+#insert into t1 values ('A');
+#replace into t1 values ('A');
+#drop table t1;
diff --git a/mysql-test/t/partition_error.test b/mysql-test/t/partition_error.test
index 20703b979f1..5fc2097cc52 100644
--- a/mysql-test/t/partition_error.test
+++ b/mysql-test/t/partition_error.test
@@ -33,7 +33,7 @@ partitions 2;
#
# Partition by key list, wrong result type
#
---error ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
+--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
CREATE TABLE t1 (
a int not null,
b int not null,
@@ -109,7 +109,7 @@ partitions 3
#
# Partition by hash, invalid result type
#
---error ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
+--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
CREATE TABLE t1 (
a int not null,
b int not null,
@@ -533,7 +533,7 @@ partitions 2
#
# Partition by range, wrong result type of partition function
#
---error ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
+--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
CREATE TABLE t1 (
a int not null,
b int not null,
@@ -769,10 +769,11 @@ partition by range (a)
#
# Bug 18198 Partitions: Verify that erroneus partition functions doesn't work
#
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
create table t1 (v varchar(12))
partition by range (ascii(v))
(partition p0 values less than (10));
-drop table t1;
+#drop table t1;
-- error 1064
create table t1 (a int)
@@ -790,7 +791,7 @@ partition by hash (extract(hour from convert_tz(a, '+00:00', '+00:00')));
create table t1 (a int)
partition by range (a + (select count(*) from t1))
(partition p1 values less than (1));
--- error ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
+-- error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
create table t1 (a char(10))
partition by hash (extractvalue(a,'a'));
diff --git a/mysql-test/t/partition_grant.test b/mysql-test/t/partition_grant.test
index 0d30ad01c7a..cf944e507fd 100644
--- a/mysql-test/t/partition_grant.test
+++ b/mysql-test/t/partition_grant.test
@@ -63,13 +63,13 @@ insert into t1 values (1);
grant alter on mysqltest_1.* to mysqltest_1@localhost;
connect (conn4,localhost,mysqltest_1,,mysqltest_1);
connection conn4;
---error 1514
+--error ER_NO_PARTITION_FOR_GIVEN_VALUE
alter table t1 partition by list (s1) (partition p1 values in (2));
connection default;
grant select, alter on mysqltest_1.* to mysqltest_1@localhost;
disconnect conn4;
connect (conn5,localhost,mysqltest_1,,mysqltest_1);
---error 1514
+--error ER_NO_PARTITION_FOR_GIVEN_VALUE
alter table t1 partition by list (s1) (partition p1 values in (2));
disconnect conn5;
connection default;
diff --git a/mysql-test/t/partition_hash.test b/mysql-test/t/partition_hash.test
index ca7972cc01c..98add060a76 100644
--- a/mysql-test/t/partition_hash.test
+++ b/mysql-test/t/partition_hash.test
@@ -9,18 +9,6 @@
drop table if exists t1;
--enable_warnings
-#
-# BUG 18198: Partition functions handling
-#
-create table t1 (a varchar(10) charset latin1 collate latin1_bin)
-partition by hash(length(a))
-partitions 10;
-insert into t1 values (''),(' '),('a'),('a '),('a ');
-explain partitions select * from t1 where a='a ';
-explain partitions select * from t1 where a='a';
-explain partitions select * from t1 where a='a ' OR a='a';
-drop table t1;
-
#
# More partition pruning tests, especially on interval walking
#
diff --git a/mysql-test/t/partition_list.test b/mysql-test/t/partition_list.test
index 1e420cfe6ed..1c76de9d55a 100644
--- a/mysql-test/t/partition_list.test
+++ b/mysql-test/t/partition_list.test
@@ -179,4 +179,8 @@ insert into t1 values (null);
select * from t1;
drop table t1;
+--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
+create table t1 (a char(1))
+partition by list (ascii(ucase(a)))
+(partition p1 values in (2));
diff --git a/mysql-test/t/partition_mgm.test b/mysql-test/t/partition_mgm.test
index 8458d47d634..a06f8d1aee5 100644
--- a/mysql-test/t/partition_mgm.test
+++ b/mysql-test/t/partition_mgm.test
@@ -20,7 +20,7 @@ subpartition sp01, subpartition sp02));
drop table t1;
CREATE TABLE t1 (f_date DATE, f_varchar VARCHAR(30))
-PARTITION BY HASH(CAST(YEAR(f_date) AS SIGNED INTEGER)) PARTITIONS 2;
+PARTITION BY HASH(YEAR(f_date)) PARTITIONS 2;
SHOW CREATE TABLE t1;
--replace_result $MYSQLTEST_VARDIR "hello"
diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test
index a60846f18ff..12951c9232a 100644
--- a/mysql-test/t/partition_pruning.test
+++ b/mysql-test/t/partition_pruning.test
@@ -538,18 +538,17 @@ select * from t1 where f_int1 between 5 and 15 order by f_int1;
drop table t1;
# part2: bug in pruning code
-create table t1 (a char(10) binary)
-partition by list(length(a))
- (partition p1 values in (1),
- partition p2 values in (2),
- partition p3 values in (3),
- partition p4 values in (4),
- partition p5 values in (5)
-);
-insert into t1 values ('a'),('bb'),('ccc'),('dddd'),('eeEee');
-select * from t1 where a>='a' and a <= 'dddd';
-explain partitions select * from t1 where a>='a' and a <= 'dddd';
-drop table t1;
+#create table t1 (a char(10) binary)
+#partition by list(ascii(a))
+# (partition p1 values in (ascii('a')),
+# partition p2 values in (ascii('b')),
+# partition p3 values in (ascii('c')),
+# partition p4 values in (ascii('d')),
+# partition p5 values in (ascii('e')));
+#insert into t1 values ('a'),('bb'),('ccc'),('dddd'),('eeEee');
+#select * from t1 where a>='a' and a <= 'dddd';
+#explain partitions select * from t1 where a>='a' and a <= 'dddd';
+#drop table t1;
# BUG#18659: Assertion failure when subpartitioning is used and partition is
# "IS NULL"
@@ -692,20 +691,47 @@ explain partitions select * from t1 where a = 18446744073709551000;
explain partitions select * from t1 where a = 18446744073709551613;
explain partitions select * from t1 where a = 18446744073709551614;
drop table t1;
-
-create table t1 (a int)
- partition by range((a & 0xFF) << 56) (
- partition p0 values less than (0x40 << 56),
- partition p1 values less than (0x80 << 56),
- partition p2 values less than (0xFF << 56)
+#
+# Test all variants of usage for interval_via_mapping
+# and interval_via_walking
+#
+# t1 will use interval_via_mapping since it uses a
+# monotonic function, whereas t2 will use
+# interval_via_walking since the intervals are short
+# and the function isn't monotonic (it is, but it isn't
+# discovered in this version).
+#
+ create table t1 (a int)
+ partition by range(a) (
+ partition p0 values less than (64),
+ partition p1 values less than (128),
+ partition p2 values less than (255)
);
-insert into t1 values (0x20), (0x20), (0x41), (0x41), (0xFE), (0xFE);
+create table t2 (a int)
+ partition by range(a+0) (
+ partition p0 values less than (64),
+ partition p1 values less than (128),
+ partition p2 values less than (255)
+);
+
+insert into t1 values (0x20), (0x20), (0x41), (0x41), (0xFE), (0xFE);
+insert into t2 values (0x20), (0x20), (0x41), (0x41), (0xFE), (0xFE);
explain partitions select * from t1 where a=0;
+explain partitions select * from t2 where a=0;
explain partitions select * from t1 where a=0xFE;
-explain partitions select * from t1 where a>0xFE and a<= 0xFF;
+explain partitions select * from t2 where a=0xFE;
+explain partitions select * from t1 where a > 0xFE AND a <= 0xFF;
+explain partitions select * from t2 where a > 0xFE AND a <= 0xFF;
+explain partitions select * from t1 where a >= 0xFE AND a <= 0xFF;
+explain partitions select * from t2 where a >= 0xFE AND a <= 0xFF;
+explain partitions select * from t1 where a < 64 AND a >= 63;
+explain partitions select * from t2 where a < 64 AND a >= 63;
+explain partitions select * from t1 where a <= 64 AND a >= 63;
+explain partitions select * from t2 where a <= 64 AND a >= 63;
drop table t1;
-
+drop table t2;
+
create table t1(a bigint unsigned not null) partition by range(a+0) (
partition p1 values less than (10),
partition p2 values less than (20),
diff --git a/mysql-test/t/partition_range.test b/mysql-test/t/partition_range.test
index 84f67febe8b..50d850913bc 100644
--- a/mysql-test/t/partition_range.test
+++ b/mysql-test/t/partition_range.test
@@ -12,45 +12,45 @@ drop table if exists t1;
#
# BUG 18198: Various tests for partition functions
#
-create table t1 (a varchar(10) charset latin1 collate latin1_bin, b int)
-partition by range (length(a) * b)
-(partition p0 values less than (2), partition p1 values less than (400));
-insert into t1 values ('a ', 2),('a',3);
-drop table t1;
+#create table t1 (a varchar(10) charset latin1 collate latin1_bin, b int)
+#partition by range (ascii(a) * b)
+#(partition p0 values less than (2), partition p1 values less than (4000));
+#insert into t1 values ('a ', 2),('a',3);
+#drop table t1;
-create table t1 (a varchar(10) charset latin1 collate latin1_bin, b int)
-partition by range (b* length(a) * b)
-(partition p0 values less than (2), partition p1 values less than (400));
-insert into t1 values ('a ', 2),('a',3);
-drop table t1;
+#create table t1 (a varchar(10) charset latin1 collate latin1_bin, b int)
+#partition by range (b* ascii(a) * b)
+#(partition p0 values less than (2), partition p1 values less than (4000));
+#insert into t1 values ('a ', 2),('a',3);
+#drop table t1;
-create table t1 (a varchar(10) charset latin1 collate latin1_bin,
- b varchar(10) charset latin1 collate latin1_bin)
-partition by range (length(b) * length(a))
-(partition p0 values less than (2), partition p1 values less than (400));
-insert into t1 values ('a ', 'b '),('a','b');
-drop table t1;
+#create table t1 (a varchar(10) charset latin1 collate latin1_bin,
+# b varchar(10) charset latin1 collate latin1_bin)
+#partition by range (ascii(b) * ascii(a))
+#(partition p0 values less than (2), partition p1 values less than (40000));
+#insert into t1 values ('a ', 'b '),('a','b');
+#drop table t1;
-create table t1 (a varchar(10) charset latin1 collate latin1_bin,
- b varchar(10) charset latin1 collate latin1_bin)
-partition by range (length(a) * length(b))
-(partition p0 values less than (2), partition p1 values less than (400));
-insert into t1 values ('a ', 'b '),('a','b');
-drop table t1;
+#create table t1 (a varchar(10) charset latin1 collate latin1_bin,
+# b varchar(10) charset latin1 collate latin1_bin)
+#partition by range (ascii(a) * ascii(b))
+#(partition p0 values less than (2), partition p1 values less than (40000));
+#insert into t1 values ('a ', 'b '),('a','b');
+#drop table t1;
-create table t1 (a varchar(10) charset latin1 collate latin1_bin,
- b varchar(10) charset latin1 collate latin1_bin, c int)
-partition by range (length(a) * c)
-(partition p0 values less than (2), partition p1 values less than (400));
-insert into t1 values ('a ', 'b ', 2),('a','b', 3);
-drop table t1;
+#create table t1 (a varchar(10) charset latin1 collate latin1_bin,
+# b varchar(10) charset latin1 collate latin1_bin, c int)
+#partition by range (ascii(a) * c)
+#(partition p0 values less than (2), partition p1 values less than (4000));
+#insert into t1 values ('a ', 'b ', 2),('a','b', 3);
+#drop table t1;
-create table t1 (a varchar(10) charset latin1 collate latin1_bin,
- b varchar(10) charset latin1 collate latin1_bin, c int)
-partition by range (c * length(a))
-(partition p0 values less than (2), partition p1 values less than (400));
-insert into t1 values ('a ', 'b ', 2),('a','b', 3);
-drop table t1;
+#create table t1 (a varchar(10) charset latin1 collate latin1_bin,
+# b varchar(10) charset latin1 collate latin1_bin, c int)
+#partition by range (c * ascii(a))
+#(partition p0 values less than (2), partition p1 values less than (4000));
+#insert into t1 values ('a ', 'b ', 2),('a','b', 3);
+#drop table t1;
#
# More checks for partition pruning
@@ -733,29 +733,27 @@ DROP TABLE t1;
#
# Bug 18198: Try with a couple of cases using VARCHAR fields in
# partition function.
-create table t1 (a varchar(20))
-partition by range (crc32(md5(a)))
-(partition p0 values less than (100),
- partition p1 values less than maxvalue);
+#create table t1 (a varchar(20))
+#partition by range (ascii(a))
+#(partition p0 values less than (100),
+# partition p1 values less than maxvalue);
-insert into t1 values ("12345678901234567890");
-insert into t1 values ("A2345678901234567890");
-insert into t1 values ("B2345678901234567890");
-insert into t1 values ("1234567890123456789");
-insert into t1 values ("1234567890123456");
-select * from t1;
-explain partitions select * from t1 where a = "12345678901234567890";
-explain partitions select * from t1 where a = "12345678901234567890" OR
- a = "A2345678901234567890" OR
- a = "B2345678901234567890" OR
- a = "C2345678901234567890";
-explain partitions select * from t1 where a = "01234567890123456";
-select * from t1 where a = "01234567890123456";
-select * from t1 where a = "12345678901234567890" OR
- a = "A2345678901234567890" OR
- a = "B2345678901234567890" OR
- a = "C2345678901234567890";
-select * from t1 where a = "12345678901234567890";
-
-
-drop table t1;
+#insert into t1 values ("12345678901234567890");
+#insert into t1 values ("A2345678901234567890");
+#insert into t1 values ("B2345678901234567890");
+#insert into t1 values ("1234567890123456789");
+#insert into t1 values ("1234567890123456");
+#select * from t1;
+#explain partitions select * from t1 where a = "12345678901234567890";
+#explain partitions select * from t1 where a = "12345678901234567890" OR
+# a = "A2345678901234567890" OR
+# a = "B2345678901234567890" OR
+# a = "C2345678901234567890";
+#explain partitions select * from t1 where a = "01234567890123456";
+#select * from t1 where a = "01234567890123456";
+#select * from t1 where a = "12345678901234567890" OR
+# a = "A2345678901234567890" OR
+# a = "B2345678901234567890" OR
+# a = "C2345678901234567890";
+#select * from t1 where a = "12345678901234567890";
+#drop table t1;
diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
index e052ecfa82b..b1776d09744 100644
--- a/mysql-test/t/type_newdecimal.test
+++ b/mysql-test/t/type_newdecimal.test
@@ -1172,6 +1172,39 @@ drop table t1;
#
SELECT 1.000000000000 * 99.999999999998 / 100 a,1.000000000000 * (99.999999999998 / 100) b;
+
+#
+# Bug #29415: CAST AS DECIMAL(P,S) with too big precision/scale
+#
+
+SELECT CAST(1 AS decimal(65,10));
+--error ER_TOO_BIG_PRECISION
+SELECT CAST(1 AS decimal(66,10));
+
+SELECT CAST(1 AS decimal(65,30));
+--error ER_TOO_BIG_SCALE
+SELECT CAST(1 AS decimal(65,31));
+
+CREATE TABLE t1 (a int DEFAULT NULL, b int DEFAULT NULL);
+INSERT INTO t1 VALUES (3,30), (1,10), (2,10);
+SELECT a+CAST(1 AS decimal(65,30)) AS aa, SUM(b) FROM t1 GROUP BY aa;
+--error ER_TOO_BIG_SCALE
+SELECT a+CAST(1 AS decimal(65,31)) AS aa, SUM(b) FROM t1 GROUP BY aa;
+
+DROP TABLE t1;
+
+#
+# Bug #29417: assertion abort for a grouping query with decimal user variable
+#
+
+CREATE TABLE t1 (a int DEFAULT NULL, b int DEFAULT NULL);
+INSERT INTO t1 VALUES (3,30), (1,10), (2,10);
+
+SET @a= CAST(1 AS decimal);
+SELECT 1 FROM t1 GROUP BY @b := @a, @b;
+
+DROP TABLE t1;
+
--echo End of 5.0 tests
#
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index ee807a1ae25..68b2a38aa27 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -3348,6 +3348,60 @@ EXPLAIN SELECT a, SUM(b) FROM v1 WHERE a=1 GROUP BY a;
DROP VIEW v1;
DROP TABLE t1;
+#
+# Bug #29392: SELECT over a multi-table view with ORDER BY
+# selecting the same view column with two different aliases
+#
+
+CREATE TABLE t1 (
+ person_id int NOT NULL PRIMARY KEY,
+ username varchar(40) default NULL,
+ status_flg char(1) NOT NULL default 'A'
+);
+
+CREATE TABLE t2 (
+ person_role_id int NOT NULL auto_increment PRIMARY KEY,
+ role_id int NOT NULL,
+ person_id int NOT NULL,
+ INDEX idx_person_id (person_id),
+ INDEX idx_role_id (role_id)
+);
+
+CREATE TABLE t3 (
+ role_id int NOT NULL auto_increment PRIMARY KEY,
+ role_name varchar(100) default NULL,
+ app_name varchar(40) NOT NULL,
+ INDEX idx_app_name(app_name)
+);
+
+CREATE VIEW v1 AS
+SELECT profile.person_id AS person_id
+ FROM t1 profile, t2 userrole, t3 role
+ WHERE userrole.person_id = profile.person_id AND
+ role.role_id = userrole.role_id AND
+ profile.status_flg = 'A'
+ ORDER BY profile.person_id,role.app_name,role.role_name;
+
+INSERT INTO t1 VALUES
+ (6,'Sw','A'), (-1136332546,'ols','e'), (0,' *\n','0'),
+ (-717462680,'ENTS Ta','0'), (-904346964,'ndard SQL\n','0');
+
+INSERT INTO t2 VALUES
+ (1,3,6),(2,4,7),(3,5,8),(4,6,9),(5,1,6),(6,1,7),(7,1,8),(8,1,9),(9,1,10);
+
+INSERT INTO t3 VALUES
+ (1,'NUCANS_APP_USER','NUCANSAPP'),(2,'NUCANS_TRGAPP_USER','NUCANSAPP'),
+ (3,'IA_INTAKE_COORDINATOR','IACANS'),(4,'IA_SCREENER','IACANS'),
+ (5,'IA_SUPERVISOR','IACANS'),(6,'IA_READONLY','IACANS'),
+ (7,'SOC_USER','SOCCANS'),(8,'CAYIT_USER','CAYITCANS'),
+ (9,'RTOS_DCFSPOS_SUPERVISOR','RTOS');
+
+EXPLAIN SELECT t.person_id AS a, t.person_id AS b FROM v1 t WHERE t.person_id=6;
+SELECT t.person_id AS a, t.person_id AS b FROM v1 t WHERE t.person_id=6;
+
+DROP VIEW v1;
+DROP TABLE t1,t2,t3;
+
--echo End of 5.0 tests.
#
diff --git a/mysys/hash.c b/mysys/hash.c
index d8c914d13dd..47ddc5aa97d 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -593,6 +593,25 @@ my_bool hash_update(HASH *hash, uchar *record, uchar *old_key,
previous->next=pos->next; /* unlink pos */
/* Move data to correct position */
+ if (new_index == empty)
+ {
+ /*
+ At this point record is unlinked from the old chain, thus it holds
+ random position. By the chance this position is equal to position
+ for the first element in the new chain. That means updated record
+ is the only record in the new chain.
+ */
+ if (empty != idx)
+ {
+ /*
+ Record was moved while unlinking it from the old chain.
+ Copy data to a new position.
+ */
+ data[empty]= org_link;
+ }
+ data[empty].next= NO_RECORD;
+ DBUG_RETURN(0);
+ }
pos=data+new_index;
new_pos_index=hash_rec_mask(hash,pos,blength,records);
if (new_index != new_pos_index)
diff --git a/sql/field.cc b/sql/field.cc
index 332a654c89f..2cd81afca49 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2328,6 +2328,7 @@ Field_new_decimal::Field_new_decimal(uchar *ptr_arg,
unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg)
{
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
+ set_if_smaller(precision, DECIMAL_MAX_PRECISION);
DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
(dec <= DECIMAL_MAX_SCALE));
bin_size= my_decimal_get_binary_size(precision, dec);
@@ -2344,6 +2345,7 @@ Field_new_decimal::Field_new_decimal(uint32 len_arg,
NONE, name, dec_arg, 0, unsigned_arg)
{
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
+ set_if_smaller(precision, DECIMAL_MAX_PRECISION);
DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
(dec <= DECIMAL_MAX_SCALE));
bin_size= my_decimal_get_binary_size(precision, dec);
@@ -6469,6 +6471,7 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
is 2.
****************************************************************************/
+const uint Field_varstring::MAX_SIZE= UINT_MAX16;
int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
diff --git a/sql/field.h b/sql/field.h
index ef76cb47d36..8bf087c7ebd 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1185,7 +1185,7 @@ public:
The maximum space available in a Field_varstring, in bytes. See
length_bytes.
*/
- static const uint MAX_SIZE= UINT_MAX16;
+ static const uint MAX_SIZE;
/* Store number of bytes used to store length (1 or 2) */
uint32 length_bytes;
Field_varstring(uchar *ptr_arg,
diff --git a/sql/filesort.cc b/sql/filesort.cc
index b1dfb4d5e71..e547940797b 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1128,6 +1128,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
BUFFPEK *buffpek;
QUEUE queue;
qsort2_cmp cmp;
+ void *first_cmp_arg;
volatile THD::killed_state *killed= ¤t_thd->killed;
THD::killed_state not_killable;
DBUG_ENTER("merge_buffers");
@@ -1152,9 +1153,18 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
/* The following will fire if there is not enough space in sort_buffer */
DBUG_ASSERT(maxcount!=0);
+ if (param->unique_buff)
+ {
+ cmp= param->compare;
+ first_cmp_arg= (void *) ¶m->cmp_context;
+ }
+ else
+ {
+ cmp= get_ptr_compare(sort_length);
+ first_cmp_arg= (void*) &sort_length;
+ }
if (init_queue(&queue, (uint) (Tb-Fb)+1, offsetof(BUFFPEK,key), 0,
- (queue_compare) (cmp= get_ptr_compare(sort_length)),
- (void*) &sort_length))
+ (queue_compare) cmp, first_cmp_arg))
DBUG_RETURN(1); /* purecov: inspected */
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
{
@@ -1207,7 +1217,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
buffpek= (BUFFPEK*) queue_top(&queue);
if (cmp) // Remove duplicates
{
- if (!(*cmp)(&sort_length, &(param->unique_buff),
+ if (!(*cmp)(first_cmp_arg, &(param->unique_buff),
(uchar**) &buffpek->key))
goto skip_duplicate;
memcpy(param->unique_buff, (uchar*) buffpek->key, rec_length);
@@ -1259,7 +1269,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
*/
if (cmp)
{
- if (!(*cmp)(&sort_length, &(param->unique_buff), (uchar**) &buffpek->key))
+ if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (uchar**) &buffpek->key))
{
buffpek->key+= rec_length; // Remove duplicate
--buffpek->mem_count;
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index d874525c4ad..e4924e8e8f2 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -2961,8 +2961,34 @@ int ha_partition::rnd_init(bool scan)
uint32 part_id;
DBUG_ENTER("ha_partition::rnd_init");
- include_partition_fields_in_used_fields();
-
+ /*
+ For operations that may need to change data, we may need to extend
+ read_set.
+ */
+ if (m_lock_type == F_WRLCK)
+ {
+ /*
+ If write_set contains any of the fields used in partition and
+ subpartition expression, we need to set all bits in read_set because
+ the row may need to be inserted in a different [sub]partition. In
+ other words update_row() can be converted into write_row(), which
+ requires a complete record.
+ */
+ if (bitmap_is_overlapping(&m_part_info->full_part_field_set,
+ table->write_set))
+ bitmap_set_all(table->read_set);
+ else
+ {
+ /*
+ Some handlers only read fields as specified by the bitmap for the
+ read set. For partitioned handlers we always require that the
+ fields of the partition functions are read such that we can
+ calculate the partition id to place updated and deleted records.
+ */
+ bitmap_union(table->read_set, &m_part_info->full_part_field_set);
+ }
+ }
+
/* Now we see what the index of our first important partition is */
DBUG_PRINT("info", ("m_part_info->used_partitions: 0x%lx",
(long) m_part_info->used_partitions.bitmap));
@@ -3118,7 +3144,7 @@ int ha_partition::rnd_next(uchar *buf)
continue; // Probably MyISAM
if (result != HA_ERR_END_OF_FILE)
- break; // Return error
+ goto end_dont_reset_start_part; // Return error
/* End current partition */
late_extra_no_cache(part_id);
@@ -3144,6 +3170,7 @@ int ha_partition::rnd_next(uchar *buf)
end:
m_part_spec.start_part= NO_CURRENT_PART_ID;
+end_dont_reset_start_part:
table->status= STATUS_NOT_FOUND;
DBUG_RETURN(result);
}
@@ -3275,7 +3302,15 @@ int ha_partition::index_init(uint inx, bool sorted)
m_start_key.length= 0;
m_ordered= sorted;
m_curr_key_info= table->key_info+inx;
- include_partition_fields_in_used_fields();
+ /*
+ Some handlers only read fields as specified by the bitmap for the
+ read set. For partitioned handlers we always require that the
+ fields of the partition functions are read such that we can
+ calculate the partition id to place updated and deleted records.
+ But this is required for operations that may need to change data only.
+ */
+ if (m_lock_type == F_WRLCK)
+ bitmap_union(table->read_set, &m_part_info->full_part_field_set);
file= m_file;
do
{
@@ -4144,35 +4179,6 @@ int ha_partition::handle_ordered_prev(uchar *buf)
}
-/*
- Set fields in partition functions in read set for underlying handlers
-
- SYNOPSIS
- include_partition_fields_in_used_fields()
-
- RETURN VALUE
- NONE
-
- DESCRIPTION
- Some handlers only read fields as specified by the bitmap for the
- read set. For partitioned handlers we always require that the
- fields of the partition functions are read such that we can
- calculate the partition id to place updated and deleted records.
-*/
-
-void ha_partition::include_partition_fields_in_used_fields()
-{
- Field **ptr= m_part_field_array;
- DBUG_ENTER("ha_partition::include_partition_fields_in_used_fields");
-
- do
- {
- bitmap_set_bit(table->read_set, (*ptr)->field_index);
- } while (*(++ptr));
- DBUG_VOID_RETURN;
-}
-
-
/****************************************************************************
MODULE information calls
****************************************************************************/
@@ -4714,6 +4720,12 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
HA_EXTRA_KEY_CACHE:
HA_EXTRA_NO_KEY_CACHE:
This parameters are no longer used and could be removed.
+
+ 7) Parameters only used by federated tables for query processing
+ ----------------------------------------------------------------
+ HA_EXTRA_INSERT_WITH_UPDATE:
+ Inform handler that an "INSERT...ON DUPLICATE KEY UPDATE" will be
+ executed. This condition is unset by HA_EXTRA_NO_IGNORE_DUP_KEY.
*/
int ha_partition::extra(enum ha_extra_function operation)
@@ -4795,6 +4807,9 @@ int ha_partition::extra(enum ha_extra_function operation)
*/
break;
}
+ /* Category 7), used by federated handlers */
+ case HA_EXTRA_INSERT_WITH_UPDATE:
+ DBUG_RETURN(loop_extra(operation));
default:
{
/* Temporary crash to discover what is wrong */
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index a168007ea04..895f001fa6a 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -449,7 +449,6 @@ private:
int handle_ordered_next(uchar * buf, bool next_same);
int handle_ordered_prev(uchar * buf);
void return_top_record(uchar * buf);
- void include_partition_fields_in_used_fields();
public:
/*
-------------------------------------------------------------------------
diff --git a/sql/item.h b/sql/item.h
index 6df85476f03..6d993d72821 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -843,8 +843,7 @@ public:
german character for double s is equal to 2 s.
The default is that an item is not allowed
- in a partition function. However all mathematical functions, string
- manipulation functions, date functions are allowed. Allowed functions
+ 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
@@ -1633,6 +1632,7 @@ public:
uint decimal_precision() const
{ return (uint)(max_length - test(value < 0)); }
bool eq(const Item *, bool binary_cmp) const;
+ bool check_partition_func_processor(uchar *bool_arg) { return FALSE;}
};
@@ -1650,6 +1650,7 @@ public:
void print(String *str);
Item_num *neg ();
uint decimal_precision() const { return max_length; }
+ bool check_partition_func_processor(uchar *bool_arg) { return FALSE;}
};
@@ -1692,6 +1693,7 @@ public:
uint decimal_precision() const { return decimal_value.precision(); }
bool eq(const Item *, bool binary_cmp) const;
void set_decimal_value(my_decimal *value_par);
+ bool check_partition_func_processor(uchar *bool_arg) { return FALSE;}
};
@@ -1752,7 +1754,6 @@ public:
{}
void print(String *str) { str->append(func_name); }
Item *safe_charset_converter(CHARSET_INFO *tocs);
- bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
@@ -1861,7 +1862,6 @@ public:
CHARSET_INFO *cs= NULL):
Item_string(name, length, cs)
{}
- bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
@@ -1915,7 +1915,6 @@ public:
unsigned_flag=1;
}
enum_field_types field_type() const { return int_field_type; }
- bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
@@ -2116,6 +2115,12 @@ public:
bool fix_fields(THD *, Item **);
bool eq(const Item *item, bool binary_cmp) const;
+ Item *get_tmp_table_item(THD *thd)
+ {
+ Item *item= Item_ref::get_tmp_table_item(thd);
+ item->name= name;
+ return item;
+ }
virtual Ref_Type ref_type() { return VIEW_REF; }
};
@@ -2237,7 +2242,6 @@ public:
}
Item *clone_item();
virtual Item *real_item() { return ref; }
- bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
#ifdef MYSQL_SERVER
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 1bc52ea093c..ee36aca069d 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -355,7 +355,6 @@ public:
}
Item *neg_transformer(THD *thd);
virtual Item *negated_item();
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool subst_argument_checker(uchar **arg) { return TRUE; }
};
@@ -367,7 +366,6 @@ public:
enum Functype functype() const { return NOT_FUNC; }
const char *func_name() const { return "not"; }
Item *neg_transformer(THD *thd);
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
void print(String *str);
};
@@ -598,7 +596,6 @@ public:
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
uint decimal_precision() const { return 1; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -610,7 +607,6 @@ public:
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "strcmp"; }
void print(String *str) { Item_func::print(str); }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -673,7 +669,6 @@ public:
const char *func_name() const { return "ifnull"; }
Field *tmp_table_field(TABLE *table);
uint decimal_precision() const;
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -714,7 +709,6 @@ public:
void print(String *str) { Item_func::print(str); }
table_map not_null_tables() const { return 0; }
bool is_null();
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
/* Functions to handle the optimized IN */
@@ -1141,7 +1135,6 @@ public:
void print(String *str);
Item *find_item(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
- bool check_partition_func_processor(uchar *bool_arg) { return FALSE;}
void cleanup();
};
@@ -1211,7 +1204,6 @@ public:
bool nulls_in_row();
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class cmp_item_row :public cmp_item
@@ -1283,7 +1275,6 @@ public:
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
Item *neg_transformer(THD *thd);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
/* Functions used by HAVING for rewriting IN subquery */
@@ -1310,7 +1301,6 @@ public:
*/
table_map used_tables() const
{ return used_tables_cache | RAND_TABLE_BIT; }
- bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
@@ -1333,7 +1323,6 @@ public:
void print(String *str);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
void top_level_item() { abort_on_null=1; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -1372,7 +1361,6 @@ public:
const char *func_name() const { return "like"; }
bool fix_fields(THD *thd, Item **ref);
void cleanup();
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
#ifdef USE_REGEX
@@ -1395,7 +1383,6 @@ public:
const char *func_name() const { return "regexp"; }
void print(String *str) { print_op(str); }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
#else
@@ -1452,7 +1439,6 @@ public:
Item *transform(Item_transformer transformer, uchar *arg);
void traverse_cond(Cond_traverser, void *arg, traverse_order order);
void neg_arguments(THD *thd);
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool subst_argument_checker(uchar **arg) { return TRUE; }
Item *compile(Item_analyzer analyzer, uchar **arg_p,
Item_transformer transformer, uchar *arg_t);
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 20041b1176a..e20926c564f 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -5039,6 +5039,18 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
my_error(ER_M_BIGGER_THAN_D, MYF(0), "");
return 0;
}
+ if (len > DECIMAL_MAX_PRECISION)
+ {
+ my_error(ER_TOO_BIG_PRECISION, MYF(0), len, a->name,
+ DECIMAL_MAX_PRECISION);
+ return 0;
+ }
+ if (dec > DECIMAL_MAX_SCALE)
+ {
+ my_error(ER_TOO_BIG_SCALE, MYF(0), dec, a->name,
+ DECIMAL_MAX_SCALE);
+ return 0;
+ }
res= new (thd->mem_root) Item_decimal_typecast(a, len, dec);
break;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 8fc68f93e12..568effb2f63 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -253,7 +253,6 @@ public:
void fix_num_length_and_dec();
void find_num_type();
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -311,7 +310,6 @@ public:
{ max_length=args[0]->max_length; unsigned_flag=0; }
void print(String *str);
uint decimal_precision() const { return args[0]->decimal_precision(); }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -345,7 +343,6 @@ public:
void fix_length_and_dec() {};
const char *func_name() const { return "decimal_typecast"; }
void print(String *);
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -442,6 +439,7 @@ public:
void fix_length_and_dec();
void fix_num_length_and_dec();
uint decimal_precision() const { return args[0]->decimal_precision(); }
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -454,6 +452,7 @@ public:
my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "abs"; }
void fix_length_and_dec();
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
// A class to handle logarithmic and trigonometric functions
@@ -488,7 +487,6 @@ public:
Item_func_exp(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "exp"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -498,7 +496,6 @@ public:
Item_func_ln(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "ln"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -509,7 +506,6 @@ public:
Item_func_log(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
const char *func_name() const { return "log"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -519,7 +515,6 @@ public:
Item_func_log2(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "log2"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -529,7 +524,6 @@ public:
Item_func_log10(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "log10"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -539,7 +533,6 @@ public:
Item_func_sqrt(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "sqrt"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -549,7 +542,6 @@ public:
Item_func_pow(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
const char *func_name() const { return "pow"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -559,7 +551,6 @@ public:
Item_func_acos(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "acos"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_asin :public Item_dec_func
@@ -568,7 +559,6 @@ public:
Item_func_asin(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "asin"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_atan :public Item_dec_func
@@ -578,7 +568,6 @@ public:
Item_func_atan(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
const char *func_name() const { return "atan"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_cos :public Item_dec_func
@@ -587,7 +576,6 @@ public:
Item_func_cos(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "cos"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_sin :public Item_dec_func
@@ -596,7 +584,6 @@ public:
Item_func_sin(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "sin"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_tan :public Item_dec_func
@@ -605,7 +592,6 @@ public:
Item_func_tan(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "tan"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_integer :public Item_int_func
@@ -633,6 +619,7 @@ public:
longlong int_op();
double real_op();
my_decimal *decimal_op(my_decimal *);
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -644,6 +631,7 @@ public:
longlong int_op();
double real_op();
my_decimal *decimal_op(my_decimal *);
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
/* This handles round and truncate */
@@ -684,7 +672,6 @@ public:
Item_func_sign(Item *a) :Item_int_func(a) {}
const char *func_name() const { return "sign"; }
longlong val_int();
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -699,7 +686,6 @@ public:
const char *func_name() const { return name; }
void fix_length_and_dec()
{ decimals= NOT_FIXED_DEC; max_length= float_length(decimals); }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -725,7 +711,6 @@ public:
void fix_length_and_dec();
enum Item_result result_type () const { return cmp_type; }
bool result_as_longlong() { return compare_as_dates; };
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
uint cmp_datetimes(ulonglong *value);
};
@@ -781,7 +766,6 @@ public:
longlong val_int();
const char *func_name() const { return "length"; }
void fix_length_and_dec() { max_length=10; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_bit_length :public Item_func_length
@@ -801,7 +785,6 @@ public:
longlong val_int();
const char *func_name() const { return "char_length"; }
void fix_length_and_dec() { max_length=10; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_coercibility :public Item_int_func
@@ -825,7 +808,6 @@ public:
longlong val_int();
void fix_length_and_dec();
void print(String *str);
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -850,7 +832,6 @@ public:
longlong val_int();
const char *func_name() const { return "ascii"; }
void fix_length_and_dec() { max_length=3; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_ord :public Item_int_func
@@ -860,7 +841,6 @@ public:
Item_func_ord(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "ord"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_find_in_set :public Item_int_func
@@ -874,7 +854,6 @@ public:
longlong val_int();
const char *func_name() const { return "find_in_set"; }
void fix_length_and_dec();
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
/* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */
@@ -886,7 +865,6 @@ public:
Item_func_bit(Item *a) :Item_int_func(a) {}
void fix_length_and_dec() { unsigned_flag= 1; }
void print(String *str) { print_op(str); }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_bit_or :public Item_func_bit
@@ -912,7 +890,6 @@ public:
longlong val_int();
const char *func_name() const { return "bit_count"; }
void fix_length_and_dec() { max_length=2; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_shift_left :public Item_func_bit
@@ -1363,7 +1340,6 @@ public:
longlong val_int();
const char *func_name() const { return "inet_aton"; }
void fix_length_and_dec() { decimals= 0; max_length= 21; maybe_null= 1; unsigned_flag= 1;}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index c036ec490db..6d2d9c199c9 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -50,7 +50,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "md5"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -94,7 +93,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "concat"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_concat_ws :public Item_str_func
@@ -116,7 +114,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "reverse"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -154,7 +151,6 @@ protected:
public:
Item_str_conv(Item *item) :Item_str_func(item) {}
String *val_str(String *);
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -455,7 +451,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "soundex"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -549,7 +544,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "rpad"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -562,7 +556,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "lpad"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -577,7 +570,6 @@ public:
collation.set(default_charset());
max_length= 64;
}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -594,7 +586,6 @@ public:
decimals=0;
max_length=args[0]->max_length*2*collation.collation->mbmaxlen;
}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_unhex :public Item_str_func
@@ -614,7 +605,6 @@ public:
decimals=0;
max_length=(1+args[0]->max_length)/2;
}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -638,7 +628,6 @@ public:
}
void print(String *str);
const char *func_name() const { return "cast_as_binary"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -678,7 +667,6 @@ public:
String* val_str(String* str);
const char *func_name() const { return "inet_ntoa"; }
void fix_length_and_dec() { decimals = 0; max_length=3*8+7; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_quote :public Item_str_func
@@ -693,7 +681,6 @@ public:
collation.set(args[0]->collation);
max_length= args[0]->max_length * 2 + 2;
}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_conv_charset :public Item_str_func
@@ -794,7 +781,6 @@ public:
const char *func_name() const { return "crc32"; }
void fix_length_and_dec() { max_length=10; }
longlong val_int();
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_uncompressed_length : public Item_int_func
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index bd0954e6bdb..32f5bcf8e52 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -38,7 +38,6 @@ public:
{
max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -53,7 +52,6 @@ public:
decimals=0;
max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -129,6 +127,7 @@ public:
max_length=10*my_charset_bin.mbmaxlen;
maybe_null=1;
}
+ bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
@@ -224,7 +223,6 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_yearweek :public Item_int_func
@@ -303,6 +301,7 @@ class Item_func_dayname :public Item_func_weekday
max_length=9*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
+ bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
@@ -319,7 +318,6 @@ public:
decimals=0;
max_length=10*MY_CHARSET_BIN_MB_MAXLEN;
}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -603,7 +601,6 @@ public:
void fix_length_and_dec();
uint format_length(const String *format);
bool eq(const Item *item, bool binary_cmp) const;
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -617,7 +614,6 @@ class Item_func_from_unixtime :public Item_date_func
const char *func_name() const { return "from_unixtime"; }
void fix_length_and_dec();
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -676,7 +672,6 @@ public:
}
const char *func_name() const { return "sec_to_time"; }
bool result_as_longlong() { return TRUE; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -698,7 +693,6 @@ public:
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
bool eq(const Item *item, bool binary_cmp) const;
void print(String *str);
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -753,7 +747,6 @@ public:
max_length=args[0]->max_length;
maybe_null= 1;
}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -773,7 +766,6 @@ public:
String *val_str(String *a);
void fix_length_and_dec();
void print(String *str);
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -884,7 +876,6 @@ public:
max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
longlong val_int();
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -907,7 +898,6 @@ public:
}
void print(String *str);
const char *func_name() const { return "add_time"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
double val_real() { return val_real_from_decimal(); }
my_decimal *val_decimal(my_decimal *decimal_value)
{
@@ -949,7 +939,6 @@ public:
:Item_str_timefunc(a, b ,c) {}
String *val_str(String *str);
const char *func_name() const { return "maketime"; }
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_microsecond :public Item_int_func
@@ -981,7 +970,6 @@ public:
maybe_null=1;
}
void print(String *str);
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -1028,7 +1016,6 @@ public:
{
return tmp_table_field_from_field_type(table, 1);
}
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h
index 650893fa7bd..278c98baf7c 100644
--- a/sql/item_xmlfunc.h
+++ b/sql/item_xmlfunc.h
@@ -41,7 +41,6 @@ public:
Item_func_xml_extractvalue(Item *a,Item *b) :Item_xml_str_func(a,b) {}
const char *func_name() const { return "extractvalue"; }
String *val_str(String *);
- bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
diff --git a/sql/log.cc b/sql/log.cc
index 8ad290fdefc..cd1acb35ece 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1445,7 +1445,7 @@ static int binlog_close_connection(handlerton *hton, THD *thd)
{
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd->ha_data[binlog_hton->slot];
- DBUG_ASSERT(mysql_bin_log.is_open() && trx_data->empty());
+ DBUG_ASSERT(trx_data->empty());
thd->ha_data[binlog_hton->slot]= 0;
trx_data->~binlog_trx_data();
my_free((uchar*)trx_data, MYF(0));
@@ -1570,7 +1570,6 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
DBUG_ENTER("binlog_commit");
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd->ha_data[binlog_hton->slot];
- DBUG_ASSERT(mysql_bin_log.is_open());
if (trx_data->empty())
{
@@ -1598,7 +1597,6 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
int error=0;
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd->ha_data[binlog_hton->slot];
- DBUG_ASSERT(mysql_bin_log.is_open());
if (trx_data->empty()) {
trx_data->reset();
@@ -1659,7 +1657,6 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
{
DBUG_ENTER("binlog_savepoint_rollback");
- DBUG_ASSERT(mysql_bin_log.is_open());
/*
Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index d18dc9b90e9..29b51b9d17a 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -98,7 +98,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) > 0); \
if (((uchar*)Thd) != NULL) \
push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \
- ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), \
+ ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX_WITH_VER), \
(Old), (Ver), (New)); \
else \
sql_print_warning("The syntax '%s' is deprecated and will be removed " \
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 23bc3c96e8f..308b96d84f8 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -905,7 +905,6 @@ bool partition_info::set_up_charset_field_preps()
Field *field, **ptr;
uchar **char_ptrs;
unsigned i;
- bool found;
size_t size;
uint tot_fields= 0;
uint tot_part_fields= 0;
@@ -918,7 +917,6 @@ bool partition_info::set_up_charset_field_preps()
{
ptr= part_field_array;
/* Set up arrays and buffers for those fields */
- i= 0;
while ((field= *(ptr++)))
{
if (field_is_partition_charset(field))
@@ -954,7 +952,7 @@ bool partition_info::set_up_charset_field_preps()
}
part_charset_field_array[i]= NULL;
}
- if (is_sub_partitioned() && list_of_subpart_fields &&
+ if (is_sub_partitioned() && !list_of_subpart_fields &&
check_part_func_fields(subpart_field_array, FALSE))
{
/* Set up arrays and buffers for those fields */
@@ -962,7 +960,10 @@ bool partition_info::set_up_charset_field_preps()
while ((field= *(ptr++)))
{
if (field_is_partition_charset(field))
+ {
tot_subpart_fields++;
+ tot_fields++;
+ }
}
size= tot_subpart_fields * sizeof(char*);
if (!(char_ptrs= (uchar**) sql_calloc(size)))
@@ -975,10 +976,10 @@ bool partition_info::set_up_charset_field_preps()
if (!(char_ptrs= (uchar**) sql_alloc(size)))
goto error;
subpart_charset_field_array= (Field**)char_ptrs;
+ ptr= subpart_field_array;
i= 0;
while ((field= *(ptr++)))
{
- unsigned j= 0;
CHARSET_INFO *cs;
uchar *field_buf;
LINT_INIT(field_buf);
@@ -987,28 +988,16 @@ bool partition_info::set_up_charset_field_preps()
continue;
cs= ((Field_str*)field)->charset();
size= field->pack_length();
- found= FALSE;
- for (j= 0; j < tot_part_fields; j++)
- {
- if (field == part_charset_field_array[i])
- found= TRUE;
- }
- if (!found)
- {
- tot_fields++;
- if (!(field_buf= (uchar*) sql_calloc(size)))
- goto error;
- }
+ if (!(field_buf= (uchar*) sql_calloc(size)))
+ goto error;
+ subpart_charset_field_array[i]= field;
subpart_field_buffers[i++]= field_buf;
}
- if (!(char_ptrs= (uchar**) sql_calloc(size)))
- goto error;
- restore_subpart_field_ptrs= char_ptrs;
+ subpart_charset_field_array[i]= NULL;
}
if (tot_fields)
{
- uint j,k,l;
-
+ uint k;
size= tot_fields*sizeof(char**);
if (!(char_ptrs= (uchar**)sql_calloc(size)))
goto error;
@@ -1026,11 +1015,12 @@ bool partition_info::set_up_charset_field_preps()
full_part_field_buffers[i]= part_field_buffers[i];
}
k= tot_part_fields;
- l= 0;
for (i= 0; i < tot_subpart_fields; i++)
{
+ uint j;
+ bool found= FALSE;
field= subpart_charset_field_array[i];
- found= FALSE;
+
for (j= 0; j < tot_part_fields; j++)
{
if (field == part_charset_field_array[i])
@@ -1038,12 +1028,12 @@ bool partition_info::set_up_charset_field_preps()
}
if (!found)
{
- full_part_charset_field_array[l]= subpart_charset_field_array[k];
- full_part_field_buffers[l]= subpart_field_buffers[k];
- k++; l++;
+ full_part_charset_field_array[k]= subpart_charset_field_array[i];
+ full_part_field_buffers[k]= subpart_field_buffers[i];
+ k++;
}
}
- full_part_charset_field_array[tot_fields]= NULL;
+ full_part_charset_field_array[k]= NULL;
}
DBUG_RETURN(FALSE);
error:
diff --git a/sql/partition_info.h b/sql/partition_info.h
index ce2f2a7b358..10edea074c0 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -81,6 +81,13 @@ public:
*/
Field **full_part_field_array;
Field **full_part_charset_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
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 0e3544415d1..c899d7424e2 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -1478,6 +1478,8 @@ ER_DUP_KEYNAME 42000 S1009
spa "Nombre de clave duplicado '%-.192s'"
swe "Nyckelnamn '%-.192s' finns flera gånger"
ukr "äÕÂÌÀÀÞÅ ¦Í'Ñ ËÌÀÞÁ '%-.192s'"
+# When using this error code, please use ER(ER_DUP_ENTRY_WITH_KEY_NAME)
+# for the message string. See, for example, code in handler.cc.
ER_DUP_ENTRY 23000 S1009
cze "Zdvojen-Bý klíè '%-.192s' (èíslo klíèe %d)"
dan "Ens værdier '%-.192s' for indeks %d"
@@ -5022,7 +5024,9 @@ ER_UNKNOWN_STORAGE_ENGINE 42000
ger "Unbekannte Speicher-Engine '%s'"
por "Motor de tabela desconhecido '%s'"
spa "Desconocido motor de tabla '%s'"
-ER_UNUSED_1
+# When using this error code, use ER(ER_WARN_DEPRECATED_SYNTAX_WITH_VER)
+# for the message string. See, for example, code in mysql_priv.h.
+ER_WARN_DEPRECATED_SYNTAX
eng "'%s' is deprecated; use '%s' instead"
ger "'%s' ist veraltet. Bitte benutzen Sie '%s'"
por "'%s' é desatualizado. Use '%s' em seu lugar"
@@ -5606,8 +5610,6 @@ ER_SP_RECURSION_LIMIT
ER_SP_PROC_TABLE_CORRUPT
eng "Failed to load routine %-.192s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)"
ger "Routine %-.192s konnte nicht geladen werden. Die Tabelle mysql.proc fehlt, ist beschädigt, oder enthält fehlerhaften Daten (interner Code: %d)"
-ER_FOREIGN_SERVER_EXISTS
- eng "The foreign server, %s, you are trying to create already exists."
ER_SP_WRONG_NAME 42000
eng "Incorrect routine name '%-.192s'"
ger "Ungültiger Routinenname '%-.192s'"
@@ -5629,6 +5631,34 @@ ER_NON_GROUPING_FIELD_USED 42000
ER_TABLE_CANT_HANDLE_SPKEYS
eng "The used table type doesn't support SPATIAL indexes"
ger "Der verwendete Tabellentyp unterstützt keine SPATIAL-Indizes"
+ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
+ eng "Triggers can not be created on system tables"
+ ger "Trigger können nicht auf Systemtabellen erzeugt werden"
+ER_REMOVED_SPACES
+ eng "Leading spaces are removed from name '%s'"
+ ger "Führende Leerzeichen werden aus dem Namen '%s' entfernt"
+ER_AUTOINC_READ_FAILED
+ eng "Failed to read auto-increment value from storage engine"
+ ger "Lesen des Autoincrement-Werts von der Speicher-Engine fehlgeschlagen"
+ER_USERNAME
+ eng "user name"
+ ger "Benutzername"
+ER_HOSTNAME
+ eng "host name"
+ ger "Hostname"
+ER_WRONG_STRING_LENGTH
+ eng "String '%-.70s' is too long for %s (should be no longer than %d)"
+ ger "String '%-.70s' ist zu lang für %s (sollte nicht länger sein als %d)"
+ER_NON_INSERTABLE_TABLE
+ eng "The target table %-.100s of the %s is not insertable-into"
+ ger "Die Zieltabelle %-.100s von %s ist nicht einfügbar"
+ER_ADMIN_WRONG_MRG_TABLE
+ eng "Table '%-.64s' is differently defined or of non-MyISAM type or doesn't exist"
+ER_FOREIGN_SERVER_EXISTS
+ eng "The foreign server, %s, you are trying to create already exists."
+ER_FOREIGN_SERVER_DOESNT_EXIST
+ eng "The foreign server name you are trying to reference does not exist. Data source error: %-.64s"
+ ger "Die externe Verbindung, auf die Sie zugreifen wollen, existiert nicht. Datenquellenfehlermeldung: %-.64s"
ER_ILLEGAL_HA_CREATE_OPTION
eng "Table storage engine '%-.64s' does not support the create option '%.64s'"
ger "Speicher-Engine '%-.64s' der Tabelle unterstützt die Option '%.64s' nicht"
@@ -5848,9 +5878,6 @@ ER_BINLOG_ROW_WRONG_TABLE_DEF
ER_BINLOG_ROW_RBR_TO_SBR
eng "Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events"
ger "Slave, die mit --log-slave-updates laufen, müssen zeilenbasiertes Loggen verwenden, um zeilenbasierte Binärlog-Ereignisse loggen zu können"
-ER_FOREIGN_SERVER_DOESNT_EXIST
- eng "The foreign server name you are trying to reference does not exist. Data source error: %-.64s"
- ger "Die externe Verbindung, auf die Sie zugreifen wollen, existiert nicht. Datenquellenfehlermeldung: %-.64s"
ER_EVENT_ALREADY_EXISTS
eng "Event '%-.192s' already exists"
ger "Event '%-.192s' existiert bereits"
@@ -5901,7 +5928,9 @@ ER_EVENT_DATA_TOO_LONG
ER_DROP_INDEX_FK
eng "Cannot drop index '%-.192s': needed in a foreign key constraint"
ger "Kann Index '%-.192s' nicht löschen: wird für einen Fremdschlüssel benötigt"
-ER_WARN_DEPRECATED_SYNTAX
+# When using this error message, use the ER_WARN_DEPRECATED_SYNTAX error
+# code. See, for example, code in mysql_priv.h.
+ER_WARN_DEPRECATED_SYNTAX_WITH_VER
eng "The syntax '%s' is deprecated and will be removed in MySQL %s. Please use %s instead"
ger "Die Syntax '%s' ist veraltet und wird in MySQL %s entfernt. Bitte benutzen Sie statt dessen %s"
ER_CANT_WRITE_LOCK_LOG_TABLE
@@ -5916,9 +5945,6 @@ ER_FOREIGN_DUPLICATE_KEY 23000 S1009
ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE
eng "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use mysql_upgrade to fix this error."
ger "Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d erhalten. Erzeugt mit MySQL %d, jetzt unter %d. Bitte benutzen Sie mysql_upgrade, um den Fehler zu beheben"
-ER_REMOVED_SPACES
- eng "Leading spaces are removed from name '%s'"
- ger "Führende Leerzeichen werden aus dem Namen '%s' entfernt"
ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR
eng "Cannot switch out of the row-based binary log format when the session has open temporary tables"
ger "Kann nicht aus dem zeilenbasierten Binärlog-Format herauswechseln, wenn die Sitzung offene temporäre Tabellen hat"
@@ -5975,9 +6001,6 @@ ER_BASE64_DECODE_ERROR
eng "Decoding of base64 string failed"
swe "Avkodning av base64 sträng misslyckades"
ger "Der Server hat keine zeilenbasierte Replikation"
-ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
- eng "Triggers can not be created on system tables"
- ger "Trigger können nicht auf Systemtabellen erzeugt werden"
ER_EVENT_RECURSION_FORBIDDEN
eng "Recursion of EVENT DDL statements is forbidden when body is present"
ger "Rekursivität von EVENT-DDL-Anweisungen ist unzulässig wenn ein Hauptteil (Body) existiert"
@@ -5987,27 +6010,12 @@ ER_EVENTS_DB_ERROR
ER_ONLY_INTEGERS_ALLOWED
eng "Only integers allowed as number here"
ger "An dieser Stelle sind nur Ganzzahlen zulässig"
-ER_AUTOINC_READ_FAILED
- eng "Failed to read auto-increment value from storage engine"
- ger "Lesen des Autoincrement-Werts von der Speicher-Engine fehlgeschlagen"
-ER_USERNAME
- eng "user name"
- ger "Benutzername"
-ER_HOSTNAME
- eng "host name"
- ger "Hostname"
-ER_WRONG_STRING_LENGTH
- eng "String '%-.70s' is too long for %s (should be no longer than %d)"
- ger "String '%-.70s' ist zu lang für %s (sollte nicht länger sein als %d)"
ER_UNSUPORTED_LOG_ENGINE
eng "This storage engine cannot be used for log tables""
ger "Diese Speicher-Engine kann für Logtabellen nicht verwendet werden"
ER_BAD_LOG_STATEMENT
eng "You cannot '%s' a log table if logging is enabled"
ger "Sie können eine Logtabelle nicht '%s', wenn Loggen angeschaltet ist"
-ER_NON_INSERTABLE_TABLE
- eng "The target table %-.100s of the %s is not insertable-into"
- ger "Die Zieltabelle %-.100s von %s ist nicht einfügbar"
ER_CANT_RENAME_LOG_TABLE
eng "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'"
ger "Kann '%s' nicht umbenennen. Wenn Loggen angeschaltet ist, müssen beim Umbenennen zu/von einer Logtabelle zwei Tabellen angegeben werden: die Logtabelle zu einer Archivtabelle und eine weitere Tabelle zurück zu '%s'"
@@ -6023,6 +6031,8 @@ ER_WRONG_PARAMETERS_TO_STORED_FCT 42000
ER_NATIVE_FCT_NAME_COLLISION
eng "This function '%-.192s' has the same name as a native function"
ger "Die Funktion '%-.192s' hat denselben Namen wie eine native Funktion"
+# When using this error message, use the ER_DUP_ENTRY error code. See, for
+# example, code in handler.cc.
ER_DUP_ENTRY_WITH_KEY_NAME 23000 S1009
cze "Zvojen-Bý klíè '%-.64s' (èíslo klíèe '%-.192s')"
dan "Ens værdier '%-.64s' for indeks '%-.192s'"
@@ -6059,8 +6069,6 @@ ER_SLAVE_INCIDENT
eng "The incident %s occured on the master. Message: %-.64s"
ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT
eng "Table has no partition for some existing values"
-ER_ADMIN_WRONG_MRG_TABLE
- eng "Table '%-.64s' is differently defined or of non-MyISAM type or doesn't exist"
ER_BINLOG_UNSAFE_STATEMENT
eng "Statement is not safe to log in statement format."
swe "Detta är inte säkert att logga i statement-format."
diff --git a/sql/spatial.cc b/sql/spatial.cc
index e0680ed182c..97e5fcfa27a 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -17,7 +17,28 @@
#ifdef HAVE_SPATIAL
-#define MAX_DIGITS_IN_DOUBLE 16
+/*
+ exponential notation :
+ 1 sign
+ 1 number before the decimal point
+ 1 decimal point
+ 14 number of significant digits (see String::qs_append(double))
+ 1 'e' sign
+ 1 exponent sign
+ 3 exponent digits
+ ==
+ 22
+
+ "f" notation :
+ 1 optional 0
+ 1 sign
+ 14 number significant digits (see String::qs_append(double) )
+ 1 decimal point
+ ==
+ 17
+*/
+
+#define MAX_DIGITS_IN_DOUBLE 22
/***************************** Gis_class_info *******************************/
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 337bd4e6cc1..4945b805578 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1542,6 +1542,8 @@ select_export::prepare(List- &list, SELECT_LEX_UNIT *u)
field_sep_char= (exchange->enclosed->length() ? (*exchange->enclosed)[0] :
field_term_length ? (*exchange->field_term)[0] : INT_MAX);
escape_char= (exchange->escaped->length() ? (*exchange->escaped)[0] : -1);
+ is_ambiguous_field_sep= test(strchr(ESCAPE_CHARS, field_sep_char));
+ is_unsafe_field_sep= test(strchr(NUMERIC_CHARS, field_sep_char));
line_sep_char= (exchange->line_term->length() ?
(*exchange->line_term)[0] : INT_MAX);
if (!field_term_length)
@@ -1616,7 +1618,8 @@ bool select_export::send_data(List
- &items)
used_length=min(res->length(),item->max_length);
else
used_length=res->length();
- if (result_type == STRING_RESULT && escape_char != -1)
+ if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
+ escape_char != -1)
{
char *pos, *start, *end;
CHARSET_INFO *res_charset= res->charset();
@@ -1682,7 +1685,9 @@ bool select_export::send_data(List
- &items)
NEED_ESCAPING(pos[1])))
{
char tmp_buff[2];
- tmp_buff[0]= escape_char;
+ tmp_buff[0]= ((int) *pos == field_sep_char &&
+ is_ambiguous_field_sep) ?
+ field_sep_char : escape_char;
tmp_buff[1]= *pos ? *pos : '0';
if (my_b_write(&cache,(uchar*) start,(uint) (pos-start)) ||
my_b_write(&cache,(uchar*) tmp_buff,2))
diff --git a/sql/sql_class.h b/sql/sql_class.h
index a35cdbbec2a..004c4aa4f5a 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1944,9 +1944,30 @@ public:
};
+#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;
+ /*
+ 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_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;
public:
select_export(sql_exchange *ex) :select_to_file(ex) {}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index eeac5e7c4fe..11db88d8f5e 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -695,6 +695,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (duplic == DUP_REPLACE &&
(!table->triggers || !table->triggers->has_delete_triggers()))
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
+ if (duplic == DUP_UPDATE)
+ table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
/*
let's *try* to start bulk inserts. It won't necessary
start them as values_list.elements should be greater than
@@ -2546,6 +2548,8 @@ bool Delayed_insert::handle_inserts(void)
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
using_opt_replace= 1;
}
+ if (info.handle_duplicates == DUP_UPDATE)
+ table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
thd.clear_error(); // reset error for binlog
if (write_record(&thd, table, &info))
{
@@ -2890,6 +2894,8 @@ select_insert::prepare(List
- &values, SELECT_LEX_UNIT *u)
if (info.handle_duplicates == DUP_REPLACE &&
(!table->triggers || !table->triggers->has_delete_triggers()))
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
+ if (info.handle_duplicates == DUP_UPDATE)
+ table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= (!info.ignore &&
(thd->variables.sql_mode &
@@ -3481,6 +3487,8 @@ select_create::prepare(List
- &values, SELECT_LEX_UNIT *u)
if (info.handle_duplicates == DUP_REPLACE &&
(!table->triggers || !table->triggers->has_delete_triggers()))
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
+ if (info.handle_duplicates == DUP_UPDATE)
+ table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
if (!thd->prelocked_mode)
table->file->ha_start_bulk_insert((ha_rows) 0);
thd->no_trans_update.stmt= FALSE;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 0138030487b..3ffbdf83815 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -851,6 +851,7 @@ continue_loop:;
char
READ_INFO::unescape(char chr)
{
+ /* keep this switch synchornous with the ESCAPE_CHARS macro */
switch(chr) {
case 'n': return '\n';
case 't': return '\t';
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index f3253e5b086..0584bb12b9e 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -523,6 +523,7 @@ static bool set_up_field_array(TABLE *table,
SYNOPSIS
create_full_part_field_array()
+ thd Thread handle
table TABLE object for which partition fields are set-up
part_info Reference to partitioning data structure
@@ -537,11 +538,12 @@ static bool set_up_field_array(TABLE *table,
This function is called from fix_partition_func
*/
-static bool create_full_part_field_array(TABLE *table,
+static bool create_full_part_field_array(THD *thd, TABLE *table,
partition_info *part_info)
{
bool result= FALSE;
Field **ptr;
+ my_bitmap_map *bitmap_buf;
DBUG_ENTER("create_full_part_field_array");
if (!part_info->is_sub_partitioned())
@@ -578,6 +580,35 @@ static bool create_full_part_field_array(TABLE *table,
part_info->full_part_field_array= field_array;
part_info->no_full_part_fields= no_part_fields;
}
+
+ /*
+ Initialize the 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.
+ */
+ if (!(bitmap_buf= (my_bitmap_map*)
+ thd->alloc(bitmap_buffer_size(table->s->fields))))
+ {
+ mem_alloc_error(bitmap_buffer_size(table->s->fields));
+ result= TRUE;
+ goto end;
+ }
+ if (bitmap_init(&part_info->full_part_field_set, bitmap_buf,
+ table->s->fields, FALSE))
+ {
+ mem_alloc_error(table->s->fields);
+ result= TRUE;
+ goto end;
+ }
+ /*
+ full_part_field_array may be NULL if storage engine supports native
+ partitioning.
+ */
+ if ((ptr= part_info->full_part_field_array))
+ for (; *ptr; ptr++)
+ bitmap_set_bit(&part_info->full_part_field_set, (*ptr)->field_index);
+
end:
DBUG_RETURN(result);
}
@@ -1636,7 +1667,7 @@ bool fix_partition_func(THD *thd, TABLE *table,
my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
goto end;
}
- if (unlikely(create_full_part_field_array(table, part_info)))
+ if (unlikely(create_full_part_field_array(thd, table, part_info)))
goto end;
if (unlikely(check_primary_key(table)))
goto end;
@@ -2869,6 +2900,8 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
}
if (unsigned_flag)
part_func_value-= 0x8000000000000000ULL;
+ if (left_endpoint && !include_endpoint)
+ part_func_value++;
while (max_part_id > min_part_id)
{
loc_part_id= (max_part_id + min_part_id + 1) >> 1;
@@ -3294,7 +3327,9 @@ static uint32 get_sub_part_id_from_key(const TABLE *table,uchar *buf,
key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
if (likely(rec0 == buf))
+ {
part_id= part_info->get_subpartition_id(part_info);
+ }
else
{
Field **part_field_array= part_info->subpart_field_array;
@@ -3337,8 +3372,10 @@ bool get_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info,
key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
if (likely(rec0 == buf))
+ {
result= part_info->get_part_partition_id(part_info, part_id,
&func_value);
+ }
else
{
Field **part_field_array= part_info->part_field_array;
@@ -3384,8 +3421,10 @@ void get_full_part_id_from_key(const TABLE *table, uchar *buf,
key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
if (likely(rec0 == buf))
+ {
result= part_info->get_partition_id(part_info, &part_spec->start_part,
&func_value);
+ }
else
{
Field **part_field_array= part_info->full_part_field_array;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index e74f09362e3..593e0f74596 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2259,11 +2259,9 @@ bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
if (item->type() == Item::FUNC_ITEM)
{
Item_func *item_func= (Item_func*)item;
- Item **child;
- Item **item_end= (item_func->arguments()) + item_func->argument_count();
- for (child= item_func->arguments(); child != item_end; child++)
+ for (uint i=0; iargument_count(); i++)
{
- if (!uses_only_table_name_fields(*child, table))
+ if (!uses_only_table_name_fields(item_func->arguments()[i], table))
return 0;
}
}
diff --git a/sql/sql_sort.h b/sql/sql_sort.h
index da28ca07e2c..1e9322f7f5b 100644
--- a/sql/sql_sort.h
+++ b/sql/sql_sort.h
@@ -50,6 +50,12 @@ typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
ulong max_keys; /* Max keys in buffert */
} BUFFPEK;
+struct BUFFPEK_COMPARE_CONTEXT
+{
+ qsort_cmp2 key_compare;
+ void *key_compare_arg;
+};
+
typedef struct st_sort_param {
uint rec_length; /* Length of sorted records */
uint sort_length; /* Length of sorted columns */
@@ -65,6 +71,9 @@ typedef struct st_sort_param {
uchar *unique_buff;
bool not_killable;
char* tmp_buffer;
+ /* The fields below are used only by Unique class */
+ qsort2_cmp compare;
+ BUFFPEK_COMPARE_CONTEXT cmp_context;
} SORTPARAM;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 3bd930f6041..df83e1d2e25 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4107,8 +4107,7 @@ part_bit_expr:
}
Lex->part_info->curr_part_elem->has_null_value= TRUE;
}
- else if (part_expr->result_type() != INT_RESULT &&
- !part_expr->null_value)
+ else if (part_expr->result_type() != INT_RESULT)
{
my_parse_error(ER(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR));
MYSQL_YYABORT;
diff --git a/sql/stacktrace.c b/sql/stacktrace.c
index 40507907120..b1267e20774 100644
--- a/sql/stacktrace.c
+++ b/sql/stacktrace.c
@@ -228,6 +228,15 @@ void write_core(int sig)
void write_core(int sig)
{
signal(sig, SIG_DFL);
+#ifdef HAVE_gcov
+ /*
+ For GCOV build, crashing will prevent the writing of code coverage
+ information from this process, causing gcov output to be incomplete.
+ So we force the writing of coverage information here before terminating.
+ */
+ extern void __gcov_flush(void);
+ __gcov_flush();
+#endif
pthread_kill(pthread_self(), sig);
#if defined(P_MYID) && !defined(SCO)
/* On Solaris, the above kill is not enough */
diff --git a/sql/uniques.cc b/sql/uniques.cc
index 7a05ceaddfc..0394eee9c6d 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -360,17 +360,12 @@ Unique::reset()
}
/*
- The comparison function, passed to queue_init() in merge_walk() must
+ The comparison function, passed to queue_init() in merge_walk() and in
+ merge_buffers() when the latter is called from Uniques::get() must
use comparison function of Uniques::tree, but compare members of struct
BUFFPEK.
*/
-struct BUFFPEK_COMPARE_CONTEXT
-{
- qsort_cmp2 key_compare;
- void *key_compare_arg;
-};
-
C_MODE_START
static int buffpek_compare(void *arg, uchar *key_ptr1, uchar *key_ptr2)
@@ -629,6 +624,10 @@ bool Unique::get(TABLE *table)
sort_param.unique_buff= sort_buffer+(sort_param.keys*
sort_param.sort_length);
+ sort_param.compare= (qsort2_cmp) buffpek_compare;
+ sort_param.cmp_context.key_compare= tree.compare;
+ sort_param.cmp_context.key_compare_arg= tree.custom_arg;
+
/* Merge the buffers to one file, removing duplicates */
if (merge_many_buff(&sort_param,sort_buffer,file_ptr,&maxbuffer,&file))
goto err;
diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc
index d1482de18ec..bdc59cbe795 100644
--- a/storage/archive/ha_archive.cc
+++ b/storage/archive/ha_archive.cc
@@ -1548,7 +1548,6 @@ bool ha_archive::is_crashed() const
int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt)
{
int rc= 0;
- uchar *buf;
const char *old_proc_info;
ha_rows count= share->rows_recorded;
DBUG_ENTER("ha_archive::check");
@@ -1557,27 +1556,14 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt)
/* Flush any waiting data */
azflush(&(share->archive_write), Z_SYNC_FLUSH);
- /*
- First we create a buffer that we can use for reading rows, and can pass
- to get_row().
- */
- if (!(buf= (uchar*) my_malloc(table->s->reclength, MYF(MY_WME))))
- rc= HA_ERR_OUT_OF_MEM;
-
/*
Now we will rewind the archive file so that we are positioned at the
start of the file.
*/
init_archive_reader();
-
- if (!rc)
- read_data_header(&archive);
-
- if (!rc)
- while (!(rc= get_row(&archive, buf)))
- count--;
-
- my_free((char*)buf, MYF(0));
+ read_data_header(&archive);
+ while (!(rc= get_row(&archive, table->record[0])))
+ count--;
thd_proc_info(thd, old_proc_info);
diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc
index c6cbcbd422f..8b0359fdc21 100644
--- a/storage/csv/ha_tina.cc
+++ b/storage/csv/ha_tina.cc
@@ -589,6 +589,7 @@ int ha_tina::find_current_row(uchar *buf)
int eoln_len;
my_bitmap_map *org_bitmap;
int error;
+ bool read_all;
DBUG_ENTER("ha_tina::find_current_row");
/*
@@ -600,6 +601,8 @@ int ha_tina::find_current_row(uchar *buf)
local_saved_data_file_length, &eoln_len)) == 0)
DBUG_RETURN(HA_ERR_END_OF_FILE);
+ /* We must read all columns in case a table is opened for update */
+ read_all= !bitmap_is_clear_all(table->write_set);
/* Avoid asserts in ::store() for columns that are not going to be updated */
org_bitmap= dbug_tmp_use_all_columns(table, table->write_set);
error= HA_ERR_CRASHED_ON_USAGE;
@@ -671,7 +674,7 @@ int ha_tina::find_current_row(uchar *buf)
}
}
- if (bitmap_is_set(table->read_set, (*field)->field_index))
+ if (read_all || bitmap_is_set(table->read_set, (*field)->field_index))
{
if ((*field)->store(buffer.ptr(), buffer.length(), buffer.charset(),
CHECK_FIELD_WARN))
diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc
index 96ce0013587..635a6fa79e0 100644
--- a/storage/federated/ha_federated.cc
+++ b/storage/federated/ha_federated.cc
@@ -388,6 +388,11 @@
/* Variables for federated share methods */
static HASH federated_open_tables; // To track open tables
pthread_mutex_t federated_mutex; // To init the hash
+static char ident_quote_char= '`'; // Character for quoting
+ // identifiers
+static char value_quote_char= '\''; // Character for quoting
+ // literals
+static const int bulk_padding= 64; // bytes "overhead" in packet
/* Variables used when chopping off trailing characters */
static const uint sizeof_trailing_comma= sizeof(", ") - 1;
@@ -415,7 +420,7 @@ static handler *federated_create_handler(handlerton *hton,
/* Function we use in the creation of our hash to get key */
static uchar *federated_get_key(FEDERATED_SHARE *share, size_t *length,
- my_bool not_used __attribute__ ((unused)))
+ my_bool not_used __attribute__ ((unused)))
{
*length= share->share_key_length;
return (uchar*) share->share_key;
@@ -477,6 +482,57 @@ int federated_done(void *p)
}
+/**
+ @brief Append identifiers to the string.
+
+ @param[in,out] string The target string.
+ @param[in] name Identifier name
+ @param[in] length Length of identifier name in bytes
+ @param[in] quote_char Quote char to use for quoting identifier.
+
+ @return Operation Status
+ @retval FALSE OK
+ @retval TRUE There was an error appending to the string.
+
+ @note This function is based upon the append_identifier() function
+ in sql_show.cc except that quoting always occurs.
+*/
+
+static bool append_ident(String *string, const char *name, uint length,
+ const char quote_char)
+{
+ bool result;
+ uint clen;
+ const char *name_end;
+ DBUG_ENTER("append_ident");
+
+ if (quote_char)
+ {
+ string->reserve(length * 2 + 2);
+ if ((result= string->append("e_char, 1, system_charset_info)))
+ goto err;
+
+ for (name_end= name+length; name < name_end; name+= clen)
+ {
+ uchar c= *(uchar *) name;
+ if (!(clen= my_mbcharlen(system_charset_info, c)))
+ clen= 1;
+ if (clen == 1 && c == (uchar) quote_char &&
+ (result= string->append("e_char, 1, system_charset_info)))
+ goto err;
+ if ((result= string->append(name, clen, string->charset())))
+ goto err;
+ }
+ result= string->append("e_char, 1, system_charset_info);
+ }
+ else
+ result= string->append(name, length, system_charset_info);
+
+err:
+ DBUG_RETURN(result);
+}
+
+
/*
Check (in create) whether the tables exists, and that it can be connected to
@@ -495,7 +551,6 @@ int federated_done(void *p)
static int check_foreign_data_source(FEDERATED_SHARE *share,
bool table_create_flag)
{
- char escaped_table_name[NAME_LEN*2];
char query_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
uint error_code;
@@ -536,7 +591,6 @@ static int check_foreign_data_source(FEDERATED_SHARE *share,
}
else
{
- int escaped_table_name_length= 0;
/*
Since we do not support transactions at this version, we can let the
client API silently reconnect. For future versions, we will need more
@@ -551,14 +605,10 @@ static int check_foreign_data_source(FEDERATED_SHARE *share,
the query will be: SELECT * FROM `tablename` WHERE 1=0
*/
- query.append(STRING_WITH_LEN("SELECT * FROM `"));
- escaped_table_name_length=
- escape_string_for_mysql(&my_charset_bin, (char*)escaped_table_name,
- sizeof(escaped_table_name),
- share->table_name,
- share->table_name_length);
- query.append(escaped_table_name, escaped_table_name_length);
- query.append(STRING_WITH_LEN("` WHERE 1=0"));
+ query.append(STRING_WITH_LEN("SELECT * FROM "));
+ append_ident(&query, share->table_name, share->table_name_length,
+ ident_quote_char);
+ query.append(STRING_WITH_LEN(" WHERE 1=0"));
if (mysql_real_query(mysql, query.ptr(), query.length()))
{
@@ -907,6 +957,7 @@ ha_federated::ha_federated(handlerton *hton,
mysql(0), stored_result(0)
{
trx_next= 0;
+ bzero(&bulk_insert, sizeof(bulk_insert));
}
@@ -969,9 +1020,8 @@ uint ha_federated::convert_row_to_internal_format(uchar *record,
static bool emit_key_part_name(String *to, KEY_PART_INFO *part)
{
DBUG_ENTER("emit_key_part_name");
- if (to->append(STRING_WITH_LEN("`")) ||
- to->append(part->field->field_name) ||
- to->append(STRING_WITH_LEN("`")))
+ if (append_ident(to, part->field->field_name,
+ strlen(part->field->field_name), ident_quote_char))
DBUG_RETURN(1); // Out of memory
DBUG_RETURN(0);
}
@@ -1515,20 +1565,20 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
query.append(STRING_WITH_LEN("SELECT "));
for (field= table->field; *field; field++)
{
- query.append(STRING_WITH_LEN("`"));
- query.append((*field)->field_name);
- query.append(STRING_WITH_LEN("`, "));
+ append_ident(&query, (*field)->field_name,
+ strlen((*field)->field_name), ident_quote_char);
+ query.append(STRING_WITH_LEN(", "));
}
/* chops off trailing comma */
query.length(query.length() - sizeof_trailing_comma);
- query.append(STRING_WITH_LEN(" FROM `"));
- query.append(tmp_share.table_name, tmp_share.table_name_length);
- query.append(STRING_WITH_LEN("`"));
- DBUG_PRINT("info", ("calling alloc_root"));
+ query.append(STRING_WITH_LEN(" FROM "));
+
+ append_ident(&query, tmp_share.table_name,
+ tmp_share.table_name_length, ident_quote_char);
if (!(share= (FEDERATED_SHARE *) memdup_root(&mem_root, (char*)&tmp_share, sizeof(*share))) ||
- !(share->select_query= (char*) strmake_root(&mem_root, query.ptr(), query.length())))
+ !(share->select_query= (char*) strmake_root(&mem_root, query.ptr(), query.length() + 1)))
goto error;
share->use_count= 0;
@@ -1669,6 +1719,8 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
table->s->reclength);
DBUG_PRINT("info", ("ref_length: %u", ref_length));
+ reset();
+
DBUG_RETURN(0);
}
@@ -1741,6 +1793,82 @@ static inline uint field_in_record_is_null(TABLE *table,
}
+/**
+ @brief Construct the INSERT statement.
+
+ @details This method will construct the INSERT statement and appends it to
+ the supplied query string buffer.
+
+ @return
+ @retval FALSE No error
+ @retval TRUE Failure
+*/
+
+bool ha_federated::append_stmt_insert(String *query)
+{
+ char insert_buffer[FEDERATED_QUERY_BUFFER_SIZE];
+ Field **field;
+ uint tmp_length;
+ bool added_field= FALSE;
+
+ /* The main insert query string */
+ String insert_string(insert_buffer, sizeof(insert_buffer), &my_charset_bin);
+ DBUG_ENTER("ha_federated::append_stmt_insert");
+
+ insert_string.length(0);
+
+ if (replace_duplicates)
+ insert_string.append(STRING_WITH_LEN("REPLACE INTO "));
+ else if (ignore_duplicates && !insert_dup_update)
+ insert_string.append(STRING_WITH_LEN("INSERT IGNORE INTO "));
+ else
+ insert_string.append(STRING_WITH_LEN("INSERT INTO "));
+ append_ident(&insert_string, share->table_name, share->table_name_length,
+ ident_quote_char);
+ tmp_length= insert_string.length();
+ insert_string.append(STRING_WITH_LEN(" ("));
+
+ /*
+ loop through the field pointer array, add any fields to both the values
+ list and the fields list that match the current query id
+ */
+ for (field= table->field; *field; field++)
+ {
+ if (bitmap_is_set(table->write_set, (*field)->field_index))
+ {
+ /* append the field name */
+ append_ident(&insert_string, (*field)->field_name,
+ strlen((*field)->field_name), ident_quote_char);
+
+ /* append commas between both fields and fieldnames */
+ /*
+ unfortunately, we can't use the logic if *(fields + 1) to
+ make the following appends conditional as we don't know if the
+ next field is in the write set
+ */
+ insert_string.append(STRING_WITH_LEN(", "));
+ added_field= TRUE;
+ }
+ }
+
+ if (added_field)
+ {
+ /* Remove trailing comma. */
+ insert_string.length(insert_string.length() - sizeof_trailing_comma);
+ insert_string.append(STRING_WITH_LEN(") "));
+ }
+ else
+ {
+ /* If there were no fields, we don't want to add a closing paren. */
+ insert_string.length(tmp_length);
+ }
+
+ insert_string.append(STRING_WITH_LEN(" VALUES "));
+
+ DBUG_RETURN(query->append(insert_string));
+}
+
+
/*
write_row() inserts a row. No extra() hint is given currently if a bulk load
is happeneding. buf() is a byte array of data. You can use the field
@@ -1757,69 +1885,14 @@ static inline uint field_in_record_is_null(TABLE *table,
int ha_federated::write_row(uchar *buf)
{
- /*
- I need a bool again, in 5.0, I used table->s->fields to accomplish this.
- This worked as a flag that says there are fields with values or not.
- In 5.1, this value doesn't work the same, and I end up with the code
- truncating open parenthesis:
-
- the statement "INSERT INTO t1 VALUES ()" ends up being first built
- in two strings
- "INSERT INTO t1 ("
- and
- " VALUES ("
-
- If there are fields with values, they get appended, with commas, and
- the last loop, a trailing comma is there
-
- "INSERT INTO t1 ( col1, col2, colN, "
-
- " VALUES ( 'val1', 'val2', 'valN', "
-
- Then, if there are fields, it should decrement the string by ", " length.
-
- "INSERT INTO t1 ( col1, col2, colN"
- " VALUES ( 'val1', 'val2', 'valN'"
-
- Then it adds a close paren to both - if there are fields
-
- "INSERT INTO t1 ( col1, col2, colN)"
- " VALUES ( 'val1', 'val2', 'valN')"
-
- Then appends both together
- "INSERT INTO t1 ( col1, col2, colN) VALUES ( 'val1', 'val2', 'valN')"
-
- So... the problem, is if you have the original statement:
-
- "INSERT INTO t1 VALUES ()"
-
- Which is legitimate, but if the code thinks there are fields
-
- "INSERT INTO t1 ("
- " VALUES ( "
-
- If the field flag is set, but there are no commas, reduces the
- string by strlen(", ")
-
- "INSERT INTO t1 "
- " VALUES "
-
- Then adds the close parenthesis
-
- "INSERT INTO t1 )"
- " VALUES )"
-
- So, I have to use a bool as before, set in the loop where fields and commas
- are appended to the string
- */
- my_bool commas_added= FALSE;
- char insert_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char values_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char insert_field_value_buffer[STRING_BUFFER_USUAL_SIZE];
Field **field;
+ uint tmp_length;
+ int error= 0;
+ bool use_bulk_insert;
+ bool auto_increment_update_required= (table->next_number_field != NULL);
- /* The main insert query string */
- String insert_string(insert_buffer, sizeof(insert_buffer), &my_charset_bin);
/* The string containing the values to be added to the insert */
String values_string(values_buffer, sizeof(values_buffer), &my_charset_bin);
/* The actual value of the field, to be added to the values_string */
@@ -1830,7 +1903,6 @@ int ha_federated::write_row(uchar *buf)
DBUG_ENTER("ha_federated::write_row");
values_string.length(0);
- insert_string.length(0);
insert_field_value_string.length(0);
ha_statistic_increment(&SSV::ha_write_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
@@ -1838,14 +1910,19 @@ int ha_federated::write_row(uchar *buf)
/*
start both our field and field values strings
+ We must disable multi-row insert for "INSERT...ON DUPLICATE KEY UPDATE"
+ Ignore duplicates is always true when insert_dup_update is true.
+ When replace_duplicates == TRUE, we can safely enable multi-row insert.
+ When performing multi-row insert, we only collect the columns values for
+ the row. The start of the statement is only created when the first
+ row is copied in to the bulk_insert string.
*/
- insert_string.append(STRING_WITH_LEN("INSERT INTO `"));
- insert_string.append(share->table_name, share->table_name_length);
- insert_string.append('`');
- insert_string.append(STRING_WITH_LEN(" ("));
+ if (!(use_bulk_insert= bulk_insert.str &&
+ (!insert_dup_update || replace_duplicates)))
+ append_stmt_insert(&values_string);
- values_string.append(STRING_WITH_LEN(" VALUES "));
values_string.append(STRING_WITH_LEN(" ("));
+ tmp_length= values_string.length();
/*
loop through the field pointer array, add any fields to both the values
@@ -1855,7 +1932,6 @@ int ha_federated::write_row(uchar *buf)
{
if (bitmap_is_set(table->write_set, (*field)->field_index))
{
- commas_added= TRUE;
if ((*field)->is_null())
values_string.append(STRING_WITH_LEN(" NULL "));
else
@@ -1863,15 +1939,13 @@ int ha_federated::write_row(uchar *buf)
bool needs_quote= (*field)->str_needs_quotes();
(*field)->val_str(&insert_field_value_string);
if (needs_quote)
- values_string.append('\'');
+ values_string.append(value_quote_char);
insert_field_value_string.print(&values_string);
if (needs_quote)
- values_string.append('\'');
+ values_string.append(value_quote_char);
insert_field_value_string.length(0);
}
- /* append the field name */
- insert_string.append((*field)->field_name);
/* append commas between both fields and fieldnames */
/*
@@ -1879,7 +1953,6 @@ int ha_federated::write_row(uchar *buf)
make the following appends conditional as we don't know if the
next field is in the write set
*/
- insert_string.append(STRING_WITH_LEN(", "));
values_string.append(STRING_WITH_LEN(", "));
}
}
@@ -1890,26 +1963,53 @@ int ha_federated::write_row(uchar *buf)
AND, we don't want to chop off the last char '('
insert will be "INSERT INTO t1 VALUES ();"
*/
- if (commas_added)
+ if (values_string.length() > tmp_length)
{
- insert_string.length(insert_string.length() - sizeof_trailing_comma);
- /* chops off leading commas */
+ /* chops off trailing comma */
values_string.length(values_string.length() - sizeof_trailing_comma);
- insert_string.append(STRING_WITH_LEN(") "));
}
- else
- {
- /* chops off trailing ) */
- insert_string.length(insert_string.length() - sizeof_trailing_closeparen);
- }
-
/* we always want to append this, even if there aren't any fields */
values_string.append(STRING_WITH_LEN(") "));
- /* add the values */
- insert_string.append(values_string);
+ if (use_bulk_insert)
+ {
+ /*
+ Send the current bulk insert out if appending the current row would
+ cause the statement to overflow the packet size, otherwise set
+ auto_increment_update_required to FALSE as no query was executed.
+ */
+ if (bulk_insert.length + values_string.length() + bulk_padding >
+ mysql->net.max_packet_size && bulk_insert.length)
+ {
+ error= mysql_real_query(mysql, bulk_insert.str, bulk_insert.length);
+ bulk_insert.length= 0;
+ }
+ else
+ auto_increment_update_required= FALSE;
+
+ if (bulk_insert.length == 0)
+ {
+ char insert_buffer[FEDERATED_QUERY_BUFFER_SIZE];
+ String insert_string(insert_buffer, sizeof(insert_buffer),
+ &my_charset_bin);
+ insert_string.length(0);
+ append_stmt_insert(&insert_string);
+ dynstr_append_mem(&bulk_insert, insert_string.ptr(),
+ insert_string.length());
+ }
+ else
+ dynstr_append_mem(&bulk_insert, ",", 1);
- if (mysql_real_query(mysql, insert_string.ptr(), insert_string.length()))
+ dynstr_append_mem(&bulk_insert, values_string.ptr(),
+ values_string.length());
+ }
+ else
+ {
+ error= mysql_real_query(mysql, values_string.ptr(),
+ values_string.length());
+ }
+
+ if (error)
{
DBUG_RETURN(stash_remote_error());
}
@@ -1917,12 +2017,79 @@ int ha_federated::write_row(uchar *buf)
If the table we've just written a record to contains an auto_increment
field, then store the last_insert_id() value from the foreign server
*/
- if (table->next_number_field)
+ if (auto_increment_update_required)
update_auto_increment();
DBUG_RETURN(0);
}
+
+/**
+ @brief Prepares the storage engine for bulk inserts.
+
+ @param[in] rows estimated number of rows in bulk insert
+ or 0 if unknown.
+
+ @details Initializes memory structures required for bulk insert.
+*/
+
+void ha_federated::start_bulk_insert(ha_rows rows)
+{
+ uint page_size;
+ DBUG_ENTER("ha_federated::start_bulk_insert");
+
+ dynstr_free(&bulk_insert);
+
+ /**
+ We don't bother with bulk-insert semantics when the estimated rows == 1
+ The rows value will be 0 if the server does not know how many rows
+ would be inserted. This can occur when performing INSERT...SELECT
+ */
+
+ if (rows == 1)
+ DBUG_VOID_RETURN;
+
+ page_size= (uint) my_getpagesize();
+
+ if (init_dynamic_string(&bulk_insert, NULL, page_size, page_size))
+ DBUG_VOID_RETURN;
+
+ bulk_insert.length= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief End bulk insert.
+
+ @details This method will send any remaining rows to the remote server.
+ Finally, it will deinitialize the bulk insert data structure.
+
+ @return Operation status
+ @retval 0 No error
+ @retval != 0 Error occured at remote server. Also sets my_errno.
+*/
+
+int ha_federated::end_bulk_insert()
+{
+ int error= 0;
+ DBUG_ENTER("ha_federated::end_bulk_insert");
+
+ if (bulk_insert.str && bulk_insert.length)
+ {
+ if (mysql_real_query(mysql, bulk_insert.str, bulk_insert.length))
+ error= stash_remote_error();
+ else
+ if (table->next_number_field)
+ update_auto_increment();
+ }
+
+ dynstr_free(&bulk_insert);
+
+ DBUG_RETURN(my_errno= error);
+}
+
+
/*
ha_federated::update_auto_increment
@@ -1952,9 +2119,9 @@ int ha_federated::optimize(THD* thd, HA_CHECK_OPT* check_opt)
query.length(0);
query.set_charset(system_charset_info);
- query.append(STRING_WITH_LEN("OPTIMIZE TABLE `"));
- query.append(share->table_name, share->table_name_length);
- query.append(STRING_WITH_LEN("`"));
+ query.append(STRING_WITH_LEN("OPTIMIZE TABLE "));
+ append_ident(&query, share->table_name, share->table_name_length,
+ ident_quote_char);
if (mysql_real_query(mysql, query.ptr(), query.length()))
{
@@ -1974,9 +2141,9 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt)
query.length(0);
query.set_charset(system_charset_info);
- query.append(STRING_WITH_LEN("REPAIR TABLE `"));
- query.append(share->table_name, share->table_name_length);
- query.append(STRING_WITH_LEN("`"));
+ query.append(STRING_WITH_LEN("REPAIR TABLE "));
+ append_ident(&query, share->table_name, share->table_name_length,
+ ident_quote_char);
if (check_opt->flags & T_QUICK)
query.append(STRING_WITH_LEN(" QUICK"));
if (check_opt->flags & T_EXTEND)
@@ -2053,9 +2220,13 @@ int ha_federated::update_row(const uchar *old_data, uchar *new_data)
update_string.length(0);
where_string.length(0);
- update_string.append(STRING_WITH_LEN("UPDATE `"));
- update_string.append(share->table_name);
- update_string.append(STRING_WITH_LEN("` SET "));
+ if (ignore_duplicates)
+ update_string.append(STRING_WITH_LEN("UPDATE IGNORE "));
+ else
+ update_string.append(STRING_WITH_LEN("UPDATE "));
+ append_ident(&update_string, share->table_name,
+ share->table_name_length, ident_quote_char);
+ update_string.append(STRING_WITH_LEN(" SET "));
/*
In this loop, we want to match column names to values being inserted
@@ -2071,7 +2242,9 @@ int ha_federated::update_row(const uchar *old_data, uchar *new_data)
{
if (bitmap_is_set(table->write_set, (*field)->field_index))
{
- update_string.append((*field)->field_name);
+ uint field_name_length= strlen((*field)->field_name);
+ append_ident(&update_string, (*field)->field_name, field_name_length,
+ ident_quote_char);
update_string.append(STRING_WITH_LEN(" = "));
if ((*field)->is_null())
@@ -2083,10 +2256,10 @@ int ha_federated::update_row(const uchar *old_data, uchar *new_data)
bool needs_quote= (*field)->str_needs_quotes();
(*field)->val_str(&field_value);
if (needs_quote)
- update_string.append('\'');
+ update_string.append(value_quote_char);
field_value.print(&update_string);
if (needs_quote)
- update_string.append('\'');
+ update_string.append(value_quote_char);
field_value.length(0);
tmp_restore_column_map(table->read_set, old_map);
}
@@ -2095,7 +2268,9 @@ int ha_federated::update_row(const uchar *old_data, uchar *new_data)
if (bitmap_is_set(table->read_set, (*field)->field_index))
{
- where_string.append((*field)->field_name);
+ uint field_name_length= strlen((*field)->field_name);
+ append_ident(&where_string, (*field)->field_name, field_name_length,
+ ident_quote_char);
if (field_in_record_is_null(table, *field, (char*) old_data))
where_string.append(STRING_WITH_LEN(" IS NULL "));
else
@@ -2105,10 +2280,10 @@ int ha_federated::update_row(const uchar *old_data, uchar *new_data)
(*field)->val_str(&field_value,
(old_data + (*field)->offset(record)));
if (needs_quote)
- where_string.append('\'');
+ where_string.append(value_quote_char);
field_value.print(&where_string);
if (needs_quote)
- where_string.append('\'');
+ where_string.append(value_quote_char);
field_value.length(0);
}
where_string.append(STRING_WITH_LEN(" AND "));
@@ -2165,9 +2340,10 @@ int ha_federated::delete_row(const uchar *buf)
DBUG_ENTER("ha_federated::delete_row");
delete_string.length(0);
- delete_string.append(STRING_WITH_LEN("DELETE FROM `"));
- delete_string.append(share->table_name);
- delete_string.append(STRING_WITH_LEN("` WHERE "));
+ delete_string.append(STRING_WITH_LEN("DELETE FROM "));
+ append_ident(&delete_string, share->table_name,
+ share->table_name_length, ident_quote_char);
+ delete_string.append(STRING_WITH_LEN(" WHERE "));
for (Field **field= table->field; *field; field++)
{
@@ -2175,8 +2351,9 @@ int ha_federated::delete_row(const uchar *buf)
found++;
if (bitmap_is_set(table->read_set, cur_field->field_index))
{
+ append_ident(&delete_string, (*field)->field_name,
+ strlen((*field)->field_name), ident_quote_char);
data_string.length(0);
- delete_string.append(cur_field->field_name);
if (cur_field->is_null())
{
delete_string.append(STRING_WITH_LEN(" IS NULL "));
@@ -2187,10 +2364,10 @@ int ha_federated::delete_row(const uchar *buf)
delete_string.append(STRING_WITH_LEN(" = "));
cur_field->val_str(&data_string);
if (needs_quote)
- delete_string.append('\'');
+ delete_string.append(value_quote_char);
data_string.print(&delete_string);
if (needs_quote)
- delete_string.append('\'');
+ delete_string.append(value_quote_char);
}
delete_string.append(STRING_WITH_LEN(" AND "));
}
@@ -2680,7 +2857,6 @@ int ha_federated::info(uint flag)
{
char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char status_buf[FEDERATED_QUERY_BUFFER_SIZE];
- char escaped_table_name[FEDERATED_QUERY_BUFFER_SIZE];
int error;
uint error_code;
MYSQL_RES *result= 0;
@@ -2693,13 +2869,9 @@ int ha_federated::info(uint flag)
if (flag & (HA_STATUS_VARIABLE | HA_STATUS_CONST))
{
status_query_string.length(0);
- status_query_string.append(STRING_WITH_LEN("SHOW TABLE STATUS LIKE '"));
- escape_string_for_mysql(&my_charset_bin, (char *)escaped_table_name,
- sizeof(escaped_table_name),
- share->table_name,
- share->table_name_length);
- status_query_string.append(escaped_table_name);
- status_query_string.append(STRING_WITH_LEN("'"));
+ status_query_string.append(STRING_WITH_LEN("SHOW TABLE STATUS LIKE "));
+ append_ident(&status_query_string, share->table_name,
+ share->table_name_length, value_quote_char);
if (mysql_real_query(mysql, status_query_string.ptr(),
status_query_string.length()))
@@ -2770,6 +2942,65 @@ error:
}
+/**
+ @brief Handles extra signals from MySQL server
+
+ @param[in] operation Hint for storage engine
+
+ @return Operation Status
+ @retval 0 OK
+ */
+int ha_federated::extra(ha_extra_function operation)
+{
+ DBUG_ENTER("ha_federated::extra");
+ switch (operation) {
+ case HA_EXTRA_IGNORE_DUP_KEY:
+ ignore_duplicates= TRUE;
+ break;
+ case HA_EXTRA_NO_IGNORE_DUP_KEY:
+ insert_dup_update= FALSE;
+ ignore_duplicates= FALSE;
+ break;
+ case HA_EXTRA_WRITE_CAN_REPLACE:
+ replace_duplicates= TRUE;
+ break;
+ case HA_EXTRA_WRITE_CANNOT_REPLACE:
+ /*
+ We use this flag to ensure that we do not create an "INSERT IGNORE"
+ statement when inserting new rows into the remote table.
+ */
+ replace_duplicates= FALSE;
+ break;
+ case HA_EXTRA_INSERT_WITH_UPDATE:
+ insert_dup_update= TRUE;
+ break;
+ default:
+ /* do nothing */
+ DBUG_PRINT("info",("unhandled operation: %d", (uint) operation));
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Reset state of file to after 'open'.
+
+ @detail This function is called after every statement for all tables
+ used by that statement.
+
+ @return Operation status
+ @retval 0 OK
+*/
+
+int ha_federated::reset(void)
+{
+ insert_dup_update= FALSE;
+ ignore_duplicates= FALSE;
+ replace_duplicates= FALSE;
+ return 0;
+}
+
+
/*
Used to delete all rows in a table. Both for cases of truncate and
for cases where the optimizer realizes that all rows will be
@@ -2791,9 +3022,9 @@ int ha_federated::delete_all_rows()
query.length(0);
query.set_charset(system_charset_info);
- query.append(STRING_WITH_LEN("TRUNCATE `"));
- query.append(share->table_name);
- query.append(STRING_WITH_LEN("`"));
+ query.append(STRING_WITH_LEN("TRUNCATE "));
+ append_ident(&query, share->table_name, share->table_name_length,
+ ident_quote_char);
/*
TRUNCATE won't return anything in mysql_affected_rows
@@ -2901,6 +3132,9 @@ int ha_federated::stash_remote_error()
DBUG_ENTER("ha_federated::stash_remote_error()");
remote_error_number= mysql_errno(mysql);
strmake(remote_error_buf, mysql_error(mysql), sizeof(remote_error_buf)-1);
+ if (remote_error_number == ER_DUP_ENTRY ||
+ remote_error_number == ER_DUP_KEY)
+ DBUG_RETURN(HA_ERR_FOUND_DUPP_KEY);
DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM);
}
diff --git a/storage/federated/ha_federated.h b/storage/federated/ha_federated.h
index 861f50fad06..3443194817b 100644
--- a/storage/federated/ha_federated.h
+++ b/storage/federated/ha_federated.h
@@ -88,6 +88,9 @@ class ha_federated: public handler
MYSQL_ROW_OFFSET current_position; // Current position used by ::position()
int remote_error_number;
char remote_error_buf[FEDERATED_QUERY_BUFFER_SIZE];
+ bool ignore_duplicates, replace_duplicates;
+ bool insert_dup_update;
+ DYNAMIC_STRING bulk_insert;
private:
/*
@@ -102,6 +105,14 @@ private:
bool records_in_range, bool eq_range);
int stash_remote_error();
+ bool append_stmt_insert(String *query);
+
+ int read_next(uchar *buf, MYSQL_RES *result);
+ int index_read_idx_with_result_set(uchar *buf, uint index,
+ const uchar *key,
+ uint key_len,
+ ha_rkey_function find_flag,
+ MYSQL_RES **result);
public:
ha_federated(handlerton *hton, TABLE_SHARE *table_arg);
~ha_federated() {}
@@ -189,6 +200,8 @@ public:
int open(const char *name, int mode, uint test_if_locked); // required
int close(void); // required
+ void start_bulk_insert(ha_rows rows);
+ int end_bulk_insert();
int write_row(uchar *buf);
int update_row(const uchar *old_data, uchar *new_data);
int delete_row(const uchar *buf);
@@ -217,6 +230,7 @@ public:
int rnd_pos(uchar *buf, uchar *pos); //required
void position(const uchar *record); //required
int info(uint); //required
+ int extra(ha_extra_function operation);
void update_auto_increment(void);
int repair(THD* thd, HA_CHECK_OPT* check_opt);
@@ -231,18 +245,12 @@ public:
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type); //required
- virtual bool get_error_message(int error, String *buf);
+ bool get_error_message(int error, String *buf);
int external_lock(THD *thd, int lock_type);
int connection_commit();
int connection_rollback();
int connection_autocommit(bool state);
int execute_simple_query(const char *query, int len);
-
- int read_next(uchar *buf, MYSQL_RES *result);
- int index_read_idx_with_result_set(uchar *buf, uint index,
- const uchar *key,
- uint key_len,
- ha_rkey_function find_flag,
- MYSQL_RES **result);
+ int reset(void);
};
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index e433298c96c..c6319d977f7 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -623,7 +623,7 @@ convert_error_code_to_mysql(
} else if (error == (int) DB_TABLE_NOT_FOUND) {
- return(HA_ERR_KEY_NOT_FOUND);
+ return(HA_ERR_NO_SUCH_TABLE);
} else if (error == (int) DB_TOO_BIG_RECORD) {