Commit 7cbbce05 authored by unknown's avatar unknown

Merge acurtis@bk-internal.mysql.com:/home/bk/mysql-5.0

into  ppcg5.local:/private/Network/Servers/anubis.xiphis.org/home/antony/work/mysql-5.0-engines.merge
parents 0e0b20da 8d8ca72d
...@@ -168,7 +168,12 @@ enum ha_extra_function { ...@@ -168,7 +168,12 @@ enum ha_extra_function {
These flags are reset by the handler::extra(HA_EXTRA_RESET) call. These flags are reset by the handler::extra(HA_EXTRA_RESET) call.
*/ */
HA_EXTRA_DELETE_CANNOT_BATCH, HA_EXTRA_DELETE_CANNOT_BATCH,
HA_EXTRA_UPDATE_CANNOT_BATCH HA_EXTRA_UPDATE_CANNOT_BATCH,
/*
Inform handler that an "INSERT...ON DUPLICATE KEY UPDATE" will be
executed. This condition is unset by HA_EXTRA_NO_IGNORE_DUP_KEY.
*/
HA_EXTRA_INSERT_WITH_UPDATE
}; };
/* The following is parameter to ha_panic() */ /* The following is parameter to ha_panic() */
......
...@@ -111,7 +111,7 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, ...@@ -111,7 +111,7 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
while (doc<end) while (doc<end)
{ {
for (;doc<end;doc++) for (; doc < end; doc+= mbl)
{ {
if (true_word_char(cs,*doc)) break; if (true_word_char(cs,*doc)) break;
if (*doc == FTB_RQUOT && param->quot) if (*doc == FTB_RQUOT && param->quot)
...@@ -120,6 +120,7 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, ...@@ -120,6 +120,7 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
*start=doc+1; *start=doc+1;
return 3; /* FTB_RBR */ return 3; /* FTB_RBR */
} }
mbl= my_mbcharlen(cs, *(uchar *)doc);
if (!param->quot) if (!param->quot)
{ {
if (*doc == FTB_LBR || *doc == FTB_RBR || *doc == FTB_LQUOT) if (*doc == FTB_LBR || *doc == FTB_RBR || *doc == FTB_LQUOT)
...@@ -187,10 +188,11 @@ byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, const byte *end, ...@@ -187,10 +188,11 @@ byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, const byte *end,
do do
{ {
for (;; doc++) for (;; doc+= mbl)
{ {
if (doc >= end) DBUG_RETURN(0); if (doc >= end) DBUG_RETURN(0);
if (true_word_char(cs, *doc)) break; if (true_word_char(cs, *doc)) break;
mbl= my_mbcharlen(cs, *(uchar *)doc);
} }
mwc= length= 0; mwc= length= 0;
......
CREATE TABLE t1(a BLOB) ENGINE=ARCHIVE;
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;
INSERT INTO t1 SELECT * FROM t1;
DROP TABLE t1;
...@@ -12364,3 +12364,10 @@ select * from t1; ...@@ -12364,3 +12364,10 @@ select * from t1;
i i
1 1
drop table t1; drop table t1;
create table t1(a longblob) engine=archive;
insert into t1 set a='';
insert into t1 set a='a';
check table t1 extended;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
...@@ -1843,6 +1843,45 @@ C3A4C3B6C3BCC39F ...@@ -1843,6 +1843,45 @@ C3A4C3B6C3BCC39F
D18DD184D184D0B5D0BAD182D0B8D0B2D0BDD183D18E D18DD184D184D0B5D0BAD182D0B8D0B2D0BDD183D18E
drop table federated.t1; drop table federated.t1;
drop table federated.t1; drop table federated.t1;
create table federated.t1 (a int primary key, b varchar(64))
DEFAULT CHARSET=utf8;
create table federated.t1 (a int primary key, b varchar(64))
ENGINE=FEDERATED
connection='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'
DEFAULT CHARSET=utf8;
insert ignore into federated.t1 values (1,"Larry"), (2,"Curly"), (1,"Moe");
select * from federated.t1;
a b
1 Larry
2 Curly
truncate federated.t1;
replace into federated.t1 values (1,"Larry"), (2,"Curly"), (1,"Moe");
select * from federated.t1;
a b
1 Moe
2 Curly
update ignore federated.t1 set a=a+1;
select * from federated.t1;
a b
1 Moe
3 Curly
drop table federated.t1;
drop table federated.t1;
create table federated.t1 (a int primary key, b varchar(64))
DEFAULT CHARSET=utf8;
create table federated.t1 (a int primary key, b varchar(64))
ENGINE=FEDERATED
connection='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'
DEFAULT CHARSET=utf8;
insert into federated.t1 values (1,"Larry"), (2,"Curly"), (1,"Moe")
on duplicate key update a=a+100;
ERROR 23000: Can't write; duplicate key in table 't1'
select * from federated.t1;
a b
1 Larry
2 Curly
drop table federated.t1;
drop table federated.t1;
DROP TABLE IF EXISTS federated.t1; DROP TABLE IF EXISTS federated.t1;
DROP DATABASE IF EXISTS federated; DROP DATABASE IF EXISTS federated;
DROP TABLE IF EXISTS federated.t1; DROP TABLE IF EXISTS federated.t1;
......
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
stop slave;
DROP DATABASE IF EXISTS federated;
CREATE DATABASE federated;
DROP DATABASE IF EXISTS federated;
CREATE DATABASE federated;
create table federated.t1 (a int primary key, b varchar(64))
engine=myisam;
create table federated.t1 (a int primary key, b varchar(64))
engine=federated
connection='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
insert into federated.t1 values (1,"Larry"), (2,"Curly"), (1,"Moe");
ERROR 23000: Can't write; duplicate key in table 't1'
select * from federated.t1;
a b
1 Larry
2 Curly
truncate federated.t1;
alter table federated.t1 engine=innodb;
insert into federated.t1 values (1,"Larry"), (2,"Curly"), (1,"Moe");
ERROR 23000: Can't write; duplicate key in table 't1'
select * from federated.t1;
a b
drop table federated.t1;
drop table federated.t1;
DROP TABLE IF EXISTS federated.t1;
DROP DATABASE IF EXISTS federated;
DROP TABLE IF EXISTS federated.t1;
DROP DATABASE IF EXISTS federated;
DROP TABLE IF EXISTS t1;
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);
HEX(a)
BEF361616197C22061616161
DELETE FROM t1 LIMIT 1;
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
SET NAMES latin1;
DROP TABLE t1;
--source include/big_test.inc
--source include/have_archive.inc
CREATE TABLE t1(a BLOB) ENGINE=ARCHIVE;
--disable_query_log
INSERT INTO t1 VALUES('<W*a8,mnd-Kt35R&Z\"-ZgzY-iUPm^o:j5\\W\'PFM6_bRV:Z@ixJCQOw8GANFVahj^wcjnm^k(wOa\"uX9LXZ@hv>gt:Y;V(Wh/DM;z\'@Scyb^2u*b:8GBTan./A;D(7x(PB98IL%ipw0x=^H,>8=i%m\'heEdN:pR*o%Ywtf&x]H2[]Ex\\Bn1>\'EhfGmw56OpkO(n$VpXE2d.M#Z*XevKM$`Er;euB&2e3d-HdFlw;RobzhxMQ3EFn&aCf`5y79V/\"UmMt-t36S(aAY&Ekt.w@m4Q!G,@@]?\\<Pazh\"\\79X7D3m[\\@gnt\'RPzBq@&6y5.)z`POzG+>:D.R;j1Kj[j*&\"n8cq6Me>@fgW_Wx$821=#0fAM@75D7\'Wi2T8W32B96C2kQ5MiO2C>NP-(!fms!;I?Biu7F?G*6o[Z54D?LCJ/H\\#+M,-;$?Rd\'-Ii`+GfW_\\5-zRc\'.M%dV`dYpOv2,\"`L;\"3u(Xk9pU8Ry79Z?fo\"K=-b7#FxX0!OS6Oma\"uZ@m1C?Q]c\\*P=z\")Hq/(xSsrd\"j&n(m{J9x#4y:KM%cSV7LZft=gzUtse$tM`#zsV35Oqsrf,=0u-q#H-@=Qc(1\\ddM6`gke>>^F{fmt(Zuey[9G=;O_tRx1zH2[Z9E5rjDL8j<)RIVX<\\Bq@\'<<X-nqmT:`_@Y*Yl<yz#/a*@I1S9[G/S9``Chja*E]-]va`Eq8V34J]wg\"c[{&=CuT!?[4+u@uX;U$H),@@bRS11DGt@wfvJF`7-u7KSFBVmMostran-)\'(0YW/x@m3Kd<;Pc-ImokLw>cbFq2;qS+q*lprp_gnv/t0$`Ep4HP>$4w-iWW35Lc7{8<bcK0GWbl\"R_l(r:_Y$:<^NH]&;:Pe7trbsD5v%Fr<es:]MIgRD=E\',EZxtcp3D=F-Ii\\pFHvH@DrA(@I5h:z,]u]Sh9vvs_`I.CK4[Uy.iUMb-N)uH?Bl)tA#$*Ea@UmO#WscxX0zH4d,AEvRo`tOf;/r&Ve{c^1po]da=G1[_LA@\\629duIFa?Sd&\'1^p>zxpK`+KyLKs.{Si>3#PR.,.@>Uqd%zj(wRpe,@Cm)q4D<>caAZ+[qQy9HCT_e_3sy0qw,b6#Fz`QT7Qv+a4v\'N;xxudtC+FcJ%p9``Cjt0)vJKt7JO5T10<\"-\\qK_#&2iIke<7?tY@m4Os$H((0TC/[did@K<)TU0)vJJq(eO;uj6aq>u_Z*Yi+1S6Pqo`qA*Fg\\u`_ChmkXU&SU8Pod.M{Q[[:LR=rR&\\)L.;\"1l\\i\"Z0u1)s;a_>Q^k&js+lkYY7B*FbEkr&U`hljR9cp01GUYAtRw/qz8>m:k=)M3Oy>`OMr\"Bju6A\'<:LUKWV.yJ>9Axft@va`Be\\#,RC5#EwV)]&<@gr-zQavV-ox56L_!wh&uM\\k,0Ia7\'YrYI?>W&N<{)L*).JmlZ]H0S9[I9!5)i`,N.7d\"m/:r\\UutlDH#hp!F#rIO4Q&\\*TNiO-0GWeyY/v59``ChiYbf]#,O6W<ccK/A?W\"73:g%tIIs5C3pg9y*TPv-lf><QhAEtHCXq[SjG_/_\"ym<wpP{F%ygwI@EvPg>8Ayk1EN;xwpQ$Vi9unNu-q#I1Q/1HZoHRGL+,<-gL\'p1;pQ\"MERQ#OO{J<-fFh^%2kP08h2T:\\LDQNpty*V\\NO(lu1(o+xMS=qMhL\"Y\'K-9tlDJ,8q`it4:g%q=sW8KWU,mng:)Yl=#3sz3\"MFWexSpauQod-G_4z;KL{Sg4c$xb`B`Dp6OpnZU$Er;er8T(^.`(:/u33ECbL5`hq%S[TsmLmkUGARYNXV*b>I:#<I;,c>G.Ii\\rPs\"<KJp\"G)1XNa#xi\'vRn[\\AjzQ]efVZD%&/Y[An5Orx-fGkme6qd&%&0\\fny=[<TtupU8T(^0fAL>0omXQkN&gb8+i[n@.`\'5qjERPy<W\'RPx:O`zm7^\\79X9LUL[gwKLwBw]LFVbn+yUx\'I\"bUcvN_tT%QS/++2[\\@ebAZ)QEFlt-p\"G(.Jmnc+?BjxG1XQn\\bYxvj6d$sJQ;oIZj1HYl;xvl?.b3mVHGfV\\NR6NjS@&7&QOw7@yn?-]sU-t7JO4Q$Td{fkmd0Z\\E\"o;mB;Bv\\E(.P2A2t#?Vw$:<[?bZz#0f>>Y.oty.iSD;:M[ccM6`kyI8z.gIq,vAv[Cx`Y!-\\oEDeV`dXk:uj8lFTX@qGJzW#;D(7x)UX?m2FM6][4.*%tJR@+O5T0.5_e`81./?4%Ywtcp6NjUIK\"\\512I[qOrw\'N9oOyAk%gb;:PiF]*M-3XJJp&Yxvl=&B\\0qtx(K)&#tU*hX`]4(eRHTQv,fK%l$]6/*!bYwqU5A.[j++4d*:\'OA7.yMMyI8x%>LG]\'ASczfo!G*8x&CcRPw44D>J=0s\'Wh0H`2n`uSz8@v^Sd%{n<ueyX-ka(:-mjS=qPv.pw/r$L<\'I!_G%ydfYh($tQsvx!+SGK\'vN]m7\\UqbuPiIliQ8]TmQ-%l%cN=&AVsf,=1y@flmb\'1azk.9r_d[{%8/zMMv:Rsqd%{n:j8i:wy\"+Q@-X]MIcBY#6,r,u:Y8E7$Fy[<Uz2x9JL%dYoIZm>\'AWupW@v`\\/jWRv)WexSrjCK1LosuwvpS-zRf3^hu:X309h1O#WrcxX0yG0S:bf\\zyucn(jmiKs1/4YLP/4W@wcheFid=Ak&hiZft?qIRD=Cxa[*SJ[k3S.&n+zVz1t)]\'ATe(.Kq$QQ)n#PS5GJzW$Be[vi2R-$ggUS$NFPGO<yxrV7KWX6A(<8E7{89W32>(Eg]#)BVmKfK#cUajs+kfBRZO[aZ$95?yqPu)\\#/`%)@G*7rh6h7oU;`]611A71-/CGwQjIj`)=>\\=X-j^tW4:euD-O1A6*h[m<z#0e9)ZrV7KUNf=<Pd-GcFlv33C=F-GcDcM8lDK-9wy$4y7;`Z\'I{^Cn1;r[Qd*:)Xg&wW/v;W.u34IXabL3WE1_uV0%bN?/hL{ToWF7\">UsmKjZdmw9KQ9aggO7_`G!fjfFcGtAzoD>I9z0ne5mR3A2og<0v6=pIVX=_QU<fuB%)@I2WJL{Sh;\'M4WB\"yn>\'D`A^=P`rGEdO>(HvE1_sL]pD?OR3?)IvC&.R>xm?.c4n]c_5\'[%81)t@ym<vl@3y=V\"<KJnt\"?Wz0nf<1zF*8w%AX#:?l.4YMUIKzQc\'-Hi_&2g>9C(9)[woJ_%1e5mT=m;rZJCPMornXKP3IXdp.(wTv#:?l.4\\Z2&cL0I_+N.8k@738`cRP{G+<0t+i\\oB7,r+mt&M=)N4V<cg\\xqOrw(PEFm\"OO&bI($tOjN\'kr&UcvM[baCf`1hHi_&5srf/Kmm`w\\G0T<l6_d]\'C[-_)?G,AEuKQ:exTttmJb:308g,;\'L/CH\"fjc7$FxW)[yxpNpn^hu=b`?TnR2<tahiYcg`1e:-k_\"yl6_d[\",UNhGeQC96@#(=>^H+:&J)\'\'-N&inm\\dfV]Re+>7;`Y#7-xH:(RPu.q\"DsC1f;-j[j-5`m-+/JlfAJ6h6kESR(fUU23FJ%m)tA#%.VMa*@F&#w_Xxz$5z9C+E\\*REB\\.fGjhM(vMWQpjCL9r`ggVW7GCXsctG@I2ZW)[uez]Cn1?*M1EL1I`.Zdls%PJb7&QOx:Oa$%*D\\)L.;{,YfvG<3*s8S\"Co4HTNjR<oJ\\rS\'^3x69Z@k\'r=k1HXfyZ3)o(eUZF-Kt5?zubjq\"Ey]DyaXsdy[;O`w`WrcvRpc%%(7!:D)<68S%RXE0[`VlCGwPb%(5rnS3?%91*xRkLs-s10=#4x3,zUvwwr]W#<H9%FuH@F\'\',HgW\\NO\'kqx0u2+#gi]xi+0Mv7D3oax`XxxtdvN[ceTR$R[RjF[xrU5C5y4-%jr)bAX{/fANGWeyX+dDbGxUx)QHSK]t[I:\'N:scsB*Gg[pLb3jKs/%f`3pjFXk<$:;V(ZwmDCdU[MO,$l%dTYE/R8]TkDOB;Bw_Tg1T;es9Y>eh_)CWqZP_rGFjiVPna{l2HXdr8U-w@m5S,vAtS#I-BG$o8_\\63;mA6)dK+,>4)lptvwxwoLgIq-zP^hvAw^Q[Y0zH4c&&,Jt6GCZ#3w1#Ui;&Em{J;&I&vSv&GyY0xAm.5]\\<Qe0VHD[%<Ap=t]Wy)QDBZ&Em#Sd$w\\E&(6rkERR&Z$7,r+mry3$Ug0Mv7F?G*5jFXl>-]wh)%xb_;D&*?CrB,N-1Kka*@F#o;j6am)uB&0[fo&^5&XpU7Nd6w\'I%r?zu^Y\'M6`jwAp?&8*b@R`l+\"da;=_NG[vh+3\\_I3YRmVE7#Ciq&Xr]Z0u1(lx=^I1S9^TkGXi0I`2lYW,i[j-7h7oV>n=yyueyW(Xi2R-#dYqW?n8cr>pHSK[l7cuLUHK\"\\9B#{u]Q^gnv1$[*SNkY[BsIO2EJ*)1XRpd+;.nlYU$FzbYvoNqw,a5w*]{{{\"$-WT%RS/-0JhTMb/XT#Fy[;QiEVez`OKiVRx1{I8vulDFs>qK^{vbgb<<Y2*uC\'5tsi8q_d_3v*_-VQt\"9=ceUYD(7v\"6*khM(s>qJX^Sg3_j!Vsh3[Y0w;Sv&GxQiBJ3WF7z63;nFN7csC-SC5x1x<Y3-)%tM`#!vbf^)FfZl:pU5GFha2jKt36V5C2kQ6Qy9H?Co7V39blyF+@Cl$^=NTA(=?aVg,:\"4%WnNt+fQ?)Gmv58X;W/xCx`Yz)N3Ov2-\'xZ6=j.<\'Gr5IQ={$2kTB+K\"]9Ayl5YIAI.DM=(L.<&DeXj6an-,3[X,fK$d\\$3pkLs.xF/P1<ws]W\"6-xH9&J+1R4EC`A_Bhj`\'5sqbuOf:(TYF/TD4tuvr][4-#cU^];IBL;\"2rw(QGN7cvN]n9f$p8^Y&H\"cZxwoJ`,O0>)L-7kA@Z-gM++3]edK,4^edJ$jyH7rh8raq:clw9M\\i&o.-5c!izRe0S<j0FSPy;RmWKO.3U<fvD.R<m@1oiCOFRMjUIM*\'{i#`I-=0pstq^bT_aNB>QavV*eK%n+{]@aQR*q,xH<2#Te)2\\aUd#o:h,4`p<oIXdo+u?qIRFGmy?c]0iO-0GZoHSOqpd)3d+<4-\"`H((1YW+fN5WAv]NN\"Sd$uU*dGr3=wl>(J%m)q4D=E&*<3-#d[z\")Hp+r13LhN+($uT%OH\\vf\"bXoP#QXICUf((2`vW0#Z+[rT*mqssj>/l`{qISJWY@l-2Q+u>l4S.%hi\\pHQA2pkMx@m3J`,O2DCeYoIZk6_cYqU7M_{rQu)[uduHBQT4C:47W7HFeUV6F@LCJ.?60/7g.BH&x]F*7rj=/mc/TC2kQ4K_#(==Y1\"R_k\"X$?Q_n2B::Su#>P\\_NGXg\'!i\"[0t,nsw\'J*,=4*q,wF1^o:j3R01EI%o4IXbgc@NKj^yk3Ow7B*GgYg#hp#L?5+q,vC\"wdks([z#/_yl6][64@*L*\'$yen\"MFTXC%\'6uz,^\"{yoHRHQC95;h\'zaWq[TqbwX1&eXg%sHGkjY^QYNZ_QWF8$FuKO/6_d_1kVL[guAxeo)knkS=qNl^rIRB5#G&#v\\J=0qx0s&T\\TnVC.UJQ;pPv2)r6KZg{Z1\"OQ,#aPMnjLv<]I7mO\"QYN[dg]ysYC\"tS%S[Qd-HfO:oMnkQ1<woNomXPiG_4x55FFifGlpqkIfM/;z*N4T4@(BUi8oT7NgDWlA<H7tp\\W\'OB=I:(PEI#hmpnZX/w:Sw)Wbhi[k2KfGkmg>=TrkFWcq8V2/7ctG@J7oWF8\">Vx\'Fp/.9oS/-2Q,ySlO&fZnDB_?X(O@3u*`1jO,)(*:*]$1gBL:y(Gp,wIAI0KorsnP)lu/xArFBVmKgM,/GYm@3w0yF*8y-d>DwW-r(^/gDZy\"*L+*0P+yUw%AY%Cf]%6\"Bjt38\\NR6R!Co3FJ%o2@.^zqMfBRZO[aYz%:7D4qlMt/\"Wwy\".`&3jIke=<Tv$=KDSYH;0v46R\"H-ABfeK(zb\\(Gp-\"[5.)z^G*4d,AG$sKWW32>(Go(g]\"$-TJRD;<[<Tw\'L/CDku46T*lmb\'/WQm\\b\\,[k5XE1_tOkR;i-;\"2rw(N8j8pV?qHN2KgJyP]eia1b*@G(+>:E2b(4kN{OS6Pt#AaOCDks(^/e<7>n@-Ydkr\"Bir+ox6:]PYQh?=TpasE;8D0`yh{[50/;z\'DaGwQg<0v3/2KhP6ZKF]+P<uf%rB.WV/\"TkDN?.a.UKVQu&K1Kkb-O,+2YRlR6Onf6qe+;-fHo\"MGYnDB`Dn*vF3iDPKgJwG7w\'H!_I0Mw=_PS18bn,#eb?NMu47W:V-nrv!2t%L7i:wvpQ#QYKN(r8W5<nA4!Bl\'lw;Tz75GFifIt:X7A\'9,kc2d.O,\'y_MEROu.s-t37W:U)^/b-Q6S+q,s5A.X]J</mg><RlN!OU?tZE)6rh6lJgQ@*N0>.fBR[Trh8rcwU%L7j>0olVGAONw;V(YnEK+.DPI]{yt\\P[Z7>oC:8IL\'o,$gja*FbCbL3XG:+eGp(ha0a(7x,a0c-Jt39cp16]X%GwQiDT]X&H!aTal%`AaM<&@UmMr$J3YO_sMa(9+dFhc<;SrlLoqpbzdh`-R@)Ho$VlCFtD0_sOjQ5Nnf8z2zCsGD^3x56OkXV+fO7aip\"Ex\\Bm-.>1t(Wg(%zl1FN9oNrz:E0[aWr`hkhIoz?`NFSPw56PplQ05WB!sU-u8Og?@d^0iM\'n&cL2P$Wsf\'&\'1^n6XByk/>/iP3IZk3T4C91*zW&M9oQ)jhQ;l?-^zsU.#]8;]KAAcWh.@;G6ri;%@UpZRjHa80&f\\z{\"(BTd\"j&m$[,_(<8F:-ortrd\"l+(\'\'0Z[=Z67R!Bit6C2iJnsy0t)_/b-N+%rB-R@*K#aK6d#qC7&SXB\"wclv6?vbhfM/;z)K&p4HSIVW48[I=4+u?m6[Qax^ONw;V(Zvj6`l\'ku0%dU^Z.jY`Z&B^;F2c\'0ZZ;Ttwy#0f@EzaZ{*N6ZJCRT5EAR\\]@bUcuIGh]xj2Nu/{OS9[H4e.Lv<]I6jBFvMWQqlN#UnP\'eTT/\'o,#cXmEL1Jb9.s/%bN@4\"G)0T>u_\\3&\\*RFJ#bUbn-)&\"p?\'@OP)q/,/FV`dZt`f_1jR:fyUy0omZY406ZNWOb*?@d_3v+b;:PiEXmEJ(\"k(uJIq(dL.=-b5v&GuG=;MXU\'Xk=\'Ejmg@F$rFATe(,DVdz^H-BH\'&&+CUf)/N%cOC?R`q?yu__?Z/prqbwW.t22A3u\'RQ$R[W\'PDEm#R_k$^=Rd,@Biq%UcuJL\"[0t+gSIRFFkoqnVB(;42?\'@PWF8&OB;C\"v\\LFWg+5d)1\\bZ#5&Vg.CI+5e.HdEf\\xqPu-nof6nU>qJX`[,`,O2EGuE1^qD9/\"Vq_gljR;l=$7,nt%I)*8z2v.t1+$m*wNXRstnO!LETW?n8bl$[-c9,liM&kt0&hgN3LgKzRe.Kpy;LS>ucn(knlWN^tU+i^\"\"!!!\"$/^rMd8%L5]_F$rGFjgM)z^I.H`3u$BbRP\"J8sh6g4`q?!#)EbGwO`w\\G0R8W9PlTA&5u#=NQ2?,X_Wsh2T9]NN{NMu5=qMgJt8Ne7x*Xcm\"OS4D<BsIP8bkw>caA\\3#NH\\yvexTtvtg+5g6lKmiM$_Cinqqg3_m0;xwnIYh))/Q4HP>$5z:F4lR4GN3Q\'cK.<\'J%p7U0+&uM^qFDaCdYmDFo*u?n<tajq%SYLM!TjDL7i6g1R4ECaEp04U6IQ?\'@MH_/`&/XX44GJ&q9`^=MP..:z)N4T4@\'>DzhzRh;)TV5A+O3LhM*%rC3mZZ8E3lS8ZCygt>k.8nP\"PVA\"zqNma#zn>&>I9z.gGh_\':1%bK/CI*,ACl#Xz+UU0(r7Rz=Tri=-eD].d:.r(]+TNjQ8[MN$\\1t\'U_`H&{k,/CJ,7oWE4kO)q3@*K#`I,:#:?j\'tD2hDT^^Bgjc6w(PEGt=j*\'&\'1^p?$2lVJO2GRKa,KzSh;)SNng?>X+`0c1^l0?1ohADsD5u\"6-yNS9_[0omYU#Bgi]u]OUA\'6x.k`{rMe;2*vE1_sL^wes8T\'Zyxtaipx2&aCe[xrW<b]3!E#o<pOu*b;9LWU*dIzVx)P?-\\oA0hKu8OiImppc#uX6?xm=$6\'YrZKJox7<er5FFjk\\k-6d!ixI?>W%I&vV(Zvj5^bWk<%>MKnrrmLpy529h/EQMk\\i$hmne4i@>Usj@9>j(xTy0ptw$;BvY9LWU)b>K@>W%Fs?u]OT<i(#p=t^Y&I#is22DCcQLfHkmd0ZZ:LS?\"&8(\\&;9M[dg\\ubkv8IIr.#^>W#<I>8=h$hkf@I3]da@Ti<*XclzG.JnqrmNw;Sw\'N:r^_DsC/\\hxLLwAuT#G\'%$#!xj/BCdYpOt)\\\"+O4S+q,wC\'/XSy3&`?TkGZrV6HJyOXOe5nVE5soZRjF\\&:8GAOLorrh8tmJc>Dx`Tf,;*Zm=%<@n5QzAjzOVF:.q\"Ey`QU<gwLN&gc?K@<LKr,t6GD^5\'^2rtsh5d%ygxOYTz9>n9i1Lnof4d,CMA9<`VmH\\zyubhi[i&sC0]n:j4[V#=P\\bYws]Y*ZoIYg{]@cZxvi/CI(%yfq-#aNA98L\\k0A:=b_;C#yl4R)ls#FxY1$\\0qtx%?PWG?DxZ9KM)vIGeQD>LG^)JyQazi$feK&r=pHRGJ$ip#K7nP$Xx{)Ht=h\"`L9pYLP/7bsB*GjhN/8lDH\"da=H4g5kESV:V.u5?zvf\"d_4{?aPKgL(xUz613J_(=@eeO9l?1rv%En*s9U+h[k4WAwbbL6`l%dV_^>TqatKR?$0e9)Yl?.c3mWKQ7[NR4IVX9PjKr,p%Vi7kCH#j!Up\\Z54D;=]E\"o<s\\OZV\'U\\UslFSS*mrx,dAS`m,)(*:*]$1iHhZj/@74?#*Ir11A9:U$J1NzH2]ddJ)$tPn`sJRC8,ox7>n=!(EeUZF.N%dU]W!3{DwW/xAqB0c/TD7&PKeAR[V#?X&J(&$\"wep/+,:\"4\"I3ZV%K3XG=9E1c*;0v46S&WlDGuE5pd)4g7rf,?=Qe0S<j2Lj\\k.8nNv5:bhfL(y\\Ais1-,6h6kEST1/;uk>.b4pd,AEtHFfUW;W/{NO(kqy3*s6JTJVW34Lc5sq`m,\'y`Tap9]Q_j\"Y)SNl^sOiM$`G\"glnhCPLjX\\H2\\_K;%BaI*/Mw?i\"[2#R]aPNu1(n%]1s\"=Qb%\"wchc=An5Pw2*vD.S=sYC\"sOl\\fmw43D=G.Jnsy/l_yi&o2?+RFFjmg@Cn1<wrXAv_Ti;\'I%o3EEjld6uy(HwKL!UnR17]Z/on`vV.u8IM+))1[]E\"o;oIXdn(ieBWq]Z2&aDjr&T\\X\'O@3z=V\";H<0x<Y54FEheC\\,[pGN6^_EvN_sPnc(3g:%Fq6NjR9cm#Xvtf%vU&SW>j*\'$yh$eb<BrGEeUX>hyOYU%L8mH\\wi.@89S{>V{4)g\\t\\OXMZ_Tf,=4*p\'cJ*+7tmLnm[aZ!+UPqrjA@]:D*AK:xz&=F,BK4_iv?l1B>LJkd7#AaM>.e@K;%AZ-c8+hVX9Of:*^*K\"\\8;`Xy\'DdTT/)wO`xceUX?k,.?76E?J:$=KEXoNqtx&CaFvMWQph=2#S^edJ#d\\&;=\\Ahr,u:W1*xO[_ONx@j!Vvxz&:8JM)wN]k,+5e-DQOw9IGh\\rR#NEPGRGP=z\")EbFs>qK[m8h.AChlhKxF/Q4Ka/XY9JL$e[yxrV8Nb,Js0*{`NDH$n0;vl?1okN#Z*UY@n7[LMzLHcAWrcvRn\\aWmGWcm$Y$=H8x(K-7kAA^>W#=LKs0(r:_Xx$833HQD@R`n0;uk;x{\'ATe)2[^K:!1ppc%{pB7(_2pmT;g\"bUais-v=caA]:D*=;NZ^K>3#PT7NiLzOU@!xm?,Ydo(jiSE?LCI+5h9y)O:oLiVQrtp[Sqd%!qGJ\"`H*0R6R$NFSQz@fi`*EbDe[xqT-yNT>rS%Vg.CI((-HgW\\NN\"R`m.2Nu/zMIiZg\"`J3ZSqh9wz&?OP+zW$A_BggSHP<ueyY2)mx>`QS28bl\"RasHEcHyW(TZH<2$Y\"3x7<h$jv=`Uf+7p]_L<(K)\'%$#$*DZ$7*i^\"\"\"#\'<9KO0:pU6IQ@-VU-s.{TlJhWV2.2Nt*fP>\",UOl[`Td{ejiQ8afa6&RV=fs7L\\pEATi:z,Ydq15W>l1EL/DH#l&jqz;NWNb*><Sqe,>:F4lR3EBZ&En$Y!/e>@c\\)IzVy,_)BVi:wwtctD2f:)Yk6an/3Q(fZnA7/%bOCCbM9oT2:i/CH$o5Q!F\'(3e/R7U.\"Y(QFL,3ZRnZX.s)cDeV_]89W34GL.;#6)fUS&WoNs(Zvh/DK1Mt.t4<oEHvF5o]eeRGO9g-<+]!#\'<:MYY9LSC6{<MQ6U1-0FSQ{E{hu>j)z_K9uqZP^m/:r\\W%H\"glmb(7x,a2kQ3D@R_k$`Er;fxNZ]G-BJ/Ib931:nJb8+gTMc6uw\"1ne4h<.lc1_rHJyP_p<qPu+eK%n*ySmR2?)Hs7OiL!Ti?8:X5;fz[79Z@m3IYh)(-F[\"-ZchfHnzCtLY_R_k#Z)SQy9IDYul?/jTD9.w=b]/hJu;Z>_K;$>MLt0)tB%-R>xnB:=_PQ+wKHgW]Q[X.s)a<ArFARZTsp]^DsB,O2GSOojIi_\"ypJ]u^Up[Ux)RJ[oC>K@?\\:D,KxF1YX2+xNWOc.R8]Sf2ZV$FwQkP+!^Co4IUU,r-xF1[aVlBBdXl=\'Eg`2kS>sW;Y6<h\'wSw\'N=$7-v<\\E\"p@\'>D{k*&ycbFr7Pruy(J#d^0iM$`Do1;pR(fXdr9[G1ZW-ot{5.#_Dn-)%vX6=m:qU5FBWr^bVdwQjLu7E9/w?j$dXlA7/&jr(^0jP1=%<?i{Vuq]\\;JImpnZX0zI9\"85C2jLxG3aw]LAAbOHW`aK0KiY_Xwxui4[Uvz-_$-Q9co,#fcAWvr\\W\"8:V,kfCTbq:cm\"NLs+i`(==X+a8-t20;tg*/MzMKpz:JJq\'_70*yY.pu\'N>+TQu\'SR)kk[emx:N^o?&8,mpmT?wetB%,N--<*V[I;+b6#EvQmXPe7tsf*3_m/8kA;D*;1zH2ZW)^+N3Mlc-Jr-xF/TA*GjfHlrz8;a\\.d;417bn*wLQ5NkYZ>aTcvOb)9\'ST.$e](ATf+;*Xg&vT\"?X)Xi-:z*SK]sU.\"Y%Elw;Su{2u+dC[-_\':0zK@=Rg7re)0WKQ;mA5%T`jt4<m=$6\'XoMprqarC3oc&\'0Y[>_MA=MQ07`hov+cAS`l(o,#dZxrZJDUakyE)5o]aTam*xPb%$$)?Ezfp(dO?*P=!&:6?vbild6trd$vX44JYgzX(SR%YvqW?pD;=\\@dbC`BcU__Dn.-9r`ju7GCZ#4z;O`w\\F*:\'O?0jTE=An3FL/A>P\\`PNx>aXr]Z.nlWN_wbaFtE3hCNCCfa90%bN<\"-]tV34K`+Jv?o>z{#+K$cWf\'\"o:i1KhSHO4S.%fb?LCL5`n/3P#Saq<nD@Tg4c#rGGkptv{,[m9l@4&Xs_d[{%4v(UZKEYs]X%Fq6L`)?F%ydifFha1f=7<dks%PMnkQ5OojHfQA2og:&K0H^\';7D1a%*@I3ZW)]$1iHjb2iGa949`aH&x^MDM;xz%92,&uKP8^Y)UX<aZ\"3u)[xqPx9IGg[n?-\\oD?NP)n%]2v.q#H*2]gq*lnf:)ZrU23GQC;?izP^j#`G{c\\+SIRD=F+=7;_VpXF7!8:Y9M\\j&o/3Ov2*vIAL=,_(?E#sKXZBsKVRv)Xh,8tk@711A70*yV{60,-=0omWM\\k-4[Uv\"4$PNt.v<^MEPHXdq3?(BY{-[n@-ZgzW%H$m.1I_,Q=vh+1T<h&tF=<Uz5+t9V,mne1\\egYi,6g0R2=zz#+O6W<a]3y>[:JJp&[\'CaGwRlP,$ir(bC`Be])Hr4B2m[`Uf,<,b6z8>k0B@X%B`Ckw<[?bZy{&8.xD%\'0\\hvC&-M%dVco17cq:_[.iUKVRx1zG-EVdyZ9D2d.N\'m$Y\"3x7>oD=D#tS!AgliQ8]TjEQKb3n_m2CAZ,_)D\\*SLc4nZW*_.\\n=\")FjiSFD^85@%1gBNCCgc@Q[W*]&8+gRFGr3?&;7D3lVF<7@xi*)0Q3D@Sd$vZ?gp&Z\"-]sT*je>?bYtg)-DSYI?Ae`81*z\\>Y.pty,^#)AQVA$&4n]flojKt23HUU.yLHdHuC*?Cp:fyW&L6e$uT%OGV_\\4)ieAOP%[*UV4:euE3jIi[j0A<I>;IDVg,9{0nhBL:y%95;h\'yaWpV>j+*2YSqh:$>P\\aVh4^efQB7,nt%H\'!k){aRXIAI/Ha945Le==X,gO7^\\513LjVPm^j\'p3A3v*\\yt]Up]`PLk^sRz>[67OjQ7X@qFDbHz^Cr?yrR#MEM:th0Ib<@j!Wy+Xclx@k(r8V33HSK^xl6^aNDH!bVg+7re\'\'-Jp%Vi7j=-b3n^i!Vx#70(s;dm{I7rd\"k(tC-R>xnB<C!o?%7([yxqQ\"H0Q-)&{l.8nLjZep+s5D90%aI*.Hb?K@=OYV*a91,\'xX0{LG](C\\-b3lS=oDB]4)ib4qlKnnc)8\"9>j(xW(YnEK**3_l.1Nu0&eWcp03P!J9wxz&<=^J5e*8w\"3v-j_yn>\'@R_it5>wh*-AEr=m>&>H3_l*$m--;\"3x8B%.UL[gvG:*^)D_9;X44GM0A=LIhYdo*q-zSjDQNpro[W(TYG5o[Y0w=^I3[Z53?(BXx\"-\\pFFkqw,d?J;\'L0EN;wtajv8HHnzBp8^Y\'I&vStw!/gGeQFGq/.5`m*{]>Z1zI5g4d*:\'M6cvQjMyG3ayfp(g\\vfz[8@wep/-2Q,zX&H$n/5][53=yvi0FTW>gu=gu>m6YF3f4f2[^G+8x(M2Mprqf,@?Z3&aCdVbn+!]?[7<ep+s6IN/=(K)\'\'+BM?3\"K:!0mb)9\'RNqu{3zBo7YAtS\"Bir)eN5ZMQ4IVV5=qQy>\\<RjJjb/XU(ZwpNry0u/w?iyMO+zZ1zH4d)2ayfq0.7h1S6Mc3jIgTLa*DZ\"0jQ4MjTGFha3mZ[>\\=Uy.jXZ<[;Ob%&0Z_PR18csA$*CYy$5#H)0T@zu]UmP\'g\\zvg&uOf=65HN4Q#RYO]i#^@`H*3]egXabM:tg+4d(0VIIs5C5{=RiBFxV%J,:#97JP7]UtoS14S-zTnWG<8@zpJXa`AaK4ZSnZW*a90%aGyZ7<eo*p+s7L\\m6]Z.mf>:JJq*mrx/oph;)V_\\4)ha2hDWk<&CbL6cwT{:F5o_k&jr\'XpR)jhO2HVZE,CPNs(Ztcq7R{@ecDf[t`bN@6.{SjAAcVbo/1FRKb3lR7U/#_?Z0u/xBtPoe/P-+-BFwTy/oph</opg9y)QFHwJE[%::PjKt5>u`aK1NzG/O(m#Tg0O&dTV8OiJr+p\']/gFbEilf@F$sL]pEB[-`,M*$m.1JeFifFh_\'<:O`xbbH#jzLKow/s(^0iN+\'y^J8rbuOd3f7usd#m.4WA!u[I<0v32={\'?MGZucp18g)+:(RNqroZUz2\"J:z+VZE)6rh:z.c6z63<pOs%L7h6f0Q..:x!+P<t`cVbm(lt+hZg\"aOGUYD&.Q5Px8B(<:KO0;wqU4?\"\'>DzhwG7x(N7e\"ixG7trbsE7#EsD2f9#>Sh=1u-pz<Qe1YTx-gL$fb>J=0s&RS.\'sA#&6y2\"K>4)h_)D\\-_%-TGGls#Fz_MCI&ya[&AWwwuh.BDl\"Sc\"n5S*mt\'U`ghURx52=wl?0jR<m@1pkMxArHL(wStvvqZNTB,P8__Er=oEDeV__Cjr+kjSC2jM\"TmMt.yG1ZZ7@xk4T28bn)p,xKJp$QR/+)*7utj=+XbheHp*p(fUV4;j1JfK$fcBXy\'B[+Zl:pR(fXbjqz:ICRU;^PT:a_=OWM[fo&]/iQ:h)(,BJ3XLTD5w+_*Hp(fUW9PjN\'n%^84>zvg%sF>DwZ;SrlLot#@[4)lr\"Bgi[k0CCe[yxoIYh&vPiHeL+/GZs^Y)SR$RXG9)[xrX>gu?pC946T*jd;7>oB7-s.{TkG[wnDB_AaM=)PA1m`vY:Rn^k)xRmUA#(<:MWQqkIfO6YG9&K0Ic?K>4)kk]m6\\SkJhUQw.orrh9vuj:xyz\"*JwI>=V\":@qGJyRiABe^.\\oB6%SYKKv<^NKj]qJYer4B3qnYRnYSsp[V%FxTttnQ\'bFs?tW8LY\\F)5kIdDcK0EPGSLb1e3f4d)7uwwr[Qc&*?@d^1m^m2FM6][79X8IIq*lrx-iTIRA0f@DvSuy,^#)ANH^+M,-?612EGt@yk3Q\'bGuD/Y[Al*zZ53>$2n^n7\\Rd)6p_j!UpZRjG`3sw%CcODGuF8%J/GXg(\'*:+c?H2YTw\'J*.EVdxV#AcTZKGa:9MZbaEm%`@Y(QHRIW]OR4GJ\"_FxZ8D2e6p_iwBw`Y$98M^sOlZ^J:$>MN$\\0qw*Yl:q[P^j&js-u8M\\i&o2@-[m9i1P)o\'aDgb<=]G)1[^K<*Xet@xg\"`MA<J@Bjv<]I3_k\'p/-7h3[W)Zt`dXmC?Rbw[Bo9adXj4[Ux(O=%92-,3[X.px2&bI%q?{yrT-v@pA.]sS&Udy[<Uz3%WnNv32?+SJVW6A*Gh_*E`>LIgTLb.SA+N.6dzefW`]:AuY;V&PKd?G*8z/jXX6<l7cwRo`tLZa]5*nv0zH5kG^)Hq.%ju5=rS)eN8h2S3>%7)a;<Z8F9,iX_WuoR,zSjCK3WF6u{0ojIgTMgCWlB>QawZ>_L@;D\'1_rIO5U6GGkniGcDdSPy=Y1#Sd&#v^Tf/IhX^Ti=.gIs6IM-2T8V/#\\2yAixE-HgXadRQ{F%{n:j7g.DPJb5v(PC@UnR.)#k%gc@PVB(:-pw.mjN\'kv6>uadVcp4GK(xZ7<j,2T8V33GL0CCdWeyY1$[,\\sV5?\"\'9/xBuSy52:mA7/&imjQ7YBw`[)P>(Gq0/<$834JZl7dxY54GJ\"`K4_iu8Nc/VKTGGlqv\'OA6,p$RYMR9af`3rtpZO]hu>j(xW*^,SEAUkDL5^aRT27__BghZh%m*yW$BdZt`dYqT26U25R\'^2v,gO8aipw2%^6,u=dhc90!PXLTE;9HD\\+SMc5uw#4z>Y.ot{4)h^$-VOjP2A6(`82/3T4@,UMd8%K4ZSmU?t[KCL9q]Z1!K?:D)9*a5x1\"PT9\\I:&Hz\\=Uy0omYU$FwQkO\'iiWV/#[,b3oc&);2%^5,s39blyCxb_;C$\"xj-7i;#86B.[guAw`\\.iR=t]Wx$:=^NH_/^u[H6p^efQA3w.opkLr&Vi5_gmrw\'K-;%>NO\'ij]pC8/!Sg4bycaA[.gL\'q6Pt\"<LJp$NEPCA[0r!=SmR2={&:44IW\\J?:F3g=2\"OO%^9;Z;Uz629g&y_NKle:+b<@ht5B0d6ttj>1t)_0e9(V`e^*K#`K4\\\\<RjFZueyY2(kprqe(/O+#ea>J>63:k:ulB=I>8=i%l&dU[OYStuulBB`FyZ7?sS\'[#1lYY8F<9F7\"@[5/.5an/3P\"LBFvKQ9adYpNon_o:g%sF>DwX46OoiF]*L)$sGBWr^^Bhow1$Y\"3w2)myBo9cp16[Qaxa\\.d=>^H-CL:umFQFJ\'y^I3^gnv1$Y%?PXN^qFBY{,Zh#fdJ$jv:RrmS8U.zP[\\?bUe#l-/DI))0S=oDB[-b6!=P^n4Ou-nnb\'1[b_98M\\l3LiVPog8w#5%RV=gvG:+`2lXSuz.d;56Prv#9:W-r)eM4S00>*SMgFa@UpYLP3GO<xtaipy:IBQS01DFq5HN3Ns$H),@Ck\"Ti;$?Sh:{/jTGC\\.d:/w>eh\\wg\"d]+SJVU.!Sg3]dbDeXg)(-Jp!DvStw\"3v,fK$hnruy(K(y^K9x#5&Ubo3EDcM9mI^&7%NCBaJ/GYnFN7csB)?F&%\'4n[]Ezfmu-py:G<67PplQ04U6GHq/)!d_5$OI_+L)y\\@bXoOx=Y2)p+u?o=wmA70+&tJN/9mH\\yqS(aAZ(N9lA<H8!5-xI<3(igL\'o04T4A/`$%/Y[CtOe8#@Z.la):.q\"ExZ7>pHQA2qo^iu<^OP%_=KF\\\'@R_jyH9!5)jfD\\,Yckqy4-$ggRC947U1/6bsD5v$?Ww\"3u\'SV9U(\\$4w.oqlNzLFWg((.Kt22C?PYQh@Cm)r7Qv+c?K@?X\'L3S01FM7dy^H,>63>!&90$[-b3lVJM\'p4EC]3!G,?<LM$aH$o4MkYZ<W+c>I7rf-BFwU!:E.Q8\\OXPe4iDOEJ*,>5/+*.HcDbI\'\"k)xUx,_+L%iow.noe0S:dq3?\'@QZUy.gK#^@_EwSu\"5+o#PP%\\/hM\'q6Oog;+^&8+gUS%RWAzqJYfuE0[b]/iO.4[SlO&bK1Nw8G@H/MxBw\\E$ygyRg7sj@;D+BMBA`EuJL#^>Vy*VX>fp(ePC;>c_:;[@jzNT>qMfCUg/H_.]rNgGfSLa+JwD\'1`yi$e`7*fRHQ@-[j-7i8q\\Z3*s5GFhb7(Ys^Z0u/xBvW/\"WvulCEn(jk_yi*),@Bhmm^pA,TISHM-5_hp\"H,<.iVRw/qy67OiM%eZs]UtmLle9&K0JeFh`0b+BOJeEdQGP>&<BrD9-s+ox9E4lT<l7csD3mYV%M;x!*L*&x`VlFST-{Urd%w^PU<gxO]hxH<2%Z\'FmzG-DQP!H2[Z9E4mVGAOKhTK[l5W?pE@OQ,$fgRFIwJGa?NP*t?sQv,fL\'r>qNjTD91&f\\zxqR$QU<er3<rX@sQtz2y?`QR,xNT@%1e5nVE6w(QGQEEhfJyRg6lLq{>Y-jZchdAQVB(8(YqT0-.>4\'_71-/B@[0r$H)/N#Wwy$7*dJ$is,t4<nEI!^Fzb\\*P?*L(xY2*r5D:58\\LIgTL`(;404S0.5^bWi5_jxF/P1<z#0f=8@wfvICQT3>!&;8G?E\"o<sYF0WLY]LDOB?Se.G`5#I/G]\'AR\\\\;O]j&lzK?<KIlma!rOkWOg?AgkfDZz\'B[+W^Wwy$6\'ZwoJ`,N.5`jyI9$BbPHYg%rB.XY;Tw)U[KG^-ZfwLM$^<LMzKDPJ`/^tU-s1.1I_-TKYbcPC@Vrd%w\\G,BI.DN>*SLc4n]c^1ne5jG^-WX7F>Am,+0P+ySnVE7!;I>=TsoVA{tY>dh_)BUe).Lt5<oGN6_aNDFq4GIvD.Q7[I=65GHq.%ggTNiN,(\"m0<\".a-N,))2]eh`*D\\-^ztY@m5U38`bOEJ\'y`Tbr@$,M+(\'+@ExZ:LQ9ahgQ?)GnzDx\\F&(2b%&.TF@NLpv*^)EbI#jxG1ZX2)q/-1Mt,moh@Ad^,VV0)vH?Bm)wMTD7&RQ&^4$RYMUE9-nsx*XfxRlO&dUYF0YX1\'hc<>`PR-\"^BffP=!\'?K>2\"NJfM/:wtcs@ypJZk5YIBOH[t]TlLr&Ubq:aaGy[8B&3iEYqV:Z=[>]Cq>wi,5c{izTnWF8$EuHCUf)0S;fwMVM[gvE0YZ<V%H\'!l/<\"0hHlmc,HhZj/@712EI$iu9Od2b$#zqMfCWpT15V9Ru\":@qEBXwxxs[P^l-/A?X\'K-<\'J(!hvB\"tW6C2hCOJb8)_1m]gu<a\\-_&6z5.\'q7U-xD(5n[Y0yF*9#@[1w6?vclw;Sv%Dikc1a!rKZg{Z3\'fXexSpbzfmw44GL-6e\'(4iCN?3zAit5>wh*.Hb?KACiq#H+9y(K*)0T>t\\MN\"Tj@<I??^BjxC\"qISFGn#R[W%FwSqh;\'I$l(r9X9LVRu#<JDSZMR:do+vG6v{/fCTdzaYvoMnkR6Qw1&aEn(n\"LAChmkVJQ<qS)jeBS`k$]74?\"(ARZSo_m.3U:[CvY:QjIkfCUe&yejiUM`%-O0;xwpPy>`PMpw,eEaDjoqo[X.r$M>0ojJlkWSy2%Z%@Th8qap8YC#xgyRjG^+RD=D#uY<Z8B(<6<i*+7p]`NEPC=I9\":@o>\"*Is5E@NMv7C.WT&RV<digO2I[oFK+,=2zBqA*Is4A+O6XAxfuAyl6^_G\"k%gfM-5^edGr7NhGgVX<^MEQKeCXscvOc-Ill^o>zxrV5C3roZV$Eq6Om_rGGn#S^aRU8Sz=Vy.fGic:0!OT:^Vq^cYs`gfN3P#OO\"NMw<\\@gozBn09j<#7.xF/S>sYBzk.:wsakyF+@BkzMMzJ>9@rMe=:KM\'o-%kyH8vy&?MHa:6?zubij^u\\J?<LP/3R+s5C5y7:ZAn7[OVE9,hVW36Qx8@zrR\"F&\"pD<>bZ!+RFDbGxTv$>P[Z69ZD\"qHM/=\'Df^(?J:$>P\\`S[SlO&dSPw6:`^:@pB2n`tRtz2w42=z$2nb\"rMc2d-Ks1,,4^fi^\"\"%2hCPKfKzUslGXj4WD/WQoaxa]3{Cq?{xoGP@-\\qIVU.xG4iCK4\\[:G<3-&p6Rz=X,iVU,nv.ou&L6bsD4pg6mR05U6GIu?qHP;nI\\vco+vC)=<RjHdFkon_p=s\\Rd(2]i\"Z,c;7A$+KzRe,BJ3XLR;i0EPEGuD/WRtz2x9G?Bn2B835Qx7>pFIxP_o:h+4_m-.=-c8\'Vbm\'jmf?Bl\'ks*gVV0)t?tV37YC$!uZD%%\'6x.jWV/!RarE<<U!:E/UHFfW_\\5+t;Z@iwC#{rPs\";E/TB/]o@-X]PU@wg$iu9Og@F\"j%geGp+u?n<uf#ht39co,$fdGr5E>G0S;fxP`vZ?egZm;ug((.M$]8;\\G,@AcZxrZKF_1m_tPod/O)t@v_Y&Df`2lVLVRw,dATf-@@_FxZ9F7#BfdDcPCAY\'K+.DQNr{:G7w\'L1Lk]pEAUj>1t)[{$/`%,L#^=Qaxb_<I;*^%4ty+XbhgN1CCf`2lWNa$#%,N.3S29g*1T=l7bq;fxPc*=8>m8bq6Rz@c[$4y9D-N)vKL#^=NVIK{VuumFRKa0a$#\"ztZH5mQ/2KgN/:sdxY2)q14Nr\">X&I\'\"o<rXAw_Wti7j=+ZnB821=#3rsp[V#>Rg5jESS-yMQ08g+5i<*Yi+2WHBQS3@*M.9oS3;pOv1$[-a1c.O.1H\\wk8h4]aSZPb#uZ@m2DDf^)EeTT/&kv9MZccM8h0Lq\"Cn1;r[Rh;+\\vewN]hxKJnrttoS/-4[W\'OB>MMxCzh![4,yRf1YV\'U]W\"6/\'p18dwSpf1T?xm<y{%6%NEK,8oV?tY=aXtg.A@[4*n{G,?=To]c[$6\'[#/c1`vZ>c`=G1\\b\\*P>\'?NMu6?xnB821?-\\qK_#\'7%NA86C1g@DtJM*%rB,O4Ml^sOjO/7ctGAPQ,zTp]bYtdwTy/prqc!k(uF;2(lt-p{Aiv;Y6;fvH>>Y1#R^fgW\\KEU^[4,wI>=TrjBDn,\"_G$sKVQt#=NT>rR%S[RkJkc2c.LzMN%aEr:^RbwZ<V&PJ_(?H.F\\%6%OGUX?n8bl\"R`o4JZl7ak{OT;cika(8&OC@X\"4%Uf+6lJhUOjR;j3U8T&S[Qc(0YX2)q03KfEbEn&aFt@zsV36U11?-]u^TlH_-X[E\'.O--7lH]%6\"@_H+7qbvStuumHZoHRIVV1-/A=MP/5YKJp$QQ*r3:i/DN=&@Se,?=Qc&(6v!1rw(PB<Cyeo%Xti3[Uz4\'_99Oe7x,^#*Hp\'`<G1[^K<+Yj3Q)n\"K=-fHo\"I5d(/S=oDAWvuj7i7nR,\"\\:G9%I\'$w`WulDI%p8\\NP+ySo^fi_$,M(vJL\"Z+[t]Vsi:{-]wes<fwIAJ5atIM)yY3-&p5K\\sT(cEijZft>l2Jb7$J/FV`cU_`H\'$xdlu/zLHa:6A)BR[Uv#84=t\\NS9[J?<P^m/:tg*0S8W7E;9G@J8sh2U?v`]87M_xgxQd.Lw>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%5y8<gwKKu9PlXQmXOe5o\\`NHZoHUU/&kv6?zwi-:y\'DdRNprmP*r5GJySmQ,$iq%S]\\8=j*)-F\\%:5:dp16ZKIll[eknkR9^Wwxz%90\'lx?ddK+1P*uB#$)BS\\X+c=@ht8PjP1<z$1jM&hhSGJ#aOHXg&sHE`=J?=SmS7T*gYdn\'fZnEFo*s8S!@_H+8tmIb7\'Wk:umHWaeYoJ^\"$+K\"[1x;Sqh9z,\\tX>dh^$,O2FL1KiUOkUGD\\+VX:Sv\'M7cxX/x@n3LeBTd#qC3od-Ij`(==Z3-\'tF:/w>c_71-0EM9nMopf6nV@yl6_e^-Zg{Z2&_<I;.mgBNEM9pS.%kv:Stx\'HxRkLu47X=a[\'DdU]VtmKj[gzVy+[qPt$H%sFAOP(kqz77PqmU@yoC<Ap?%2mYV(XmB>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<i+.DPGSNng>: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]aRV<eq0.6d%vX6<l8e%wX44HP?*O7_`K3VB(9*b:6A%2iIjc7$Gz]F\"n4Nqu\"73:evLTB-TGHr15S,u;]I7oYPb$#zsU.\"X#;AsMc4mU@ypIXckq{=Vy-eBRYLR9bikc1`xbaFq7Qt$Dl$Z\'GvG:+c?LESS.$dWi2P(hb8)`4y66KZeo*r3:j4XH?Bn/5[To[[;N[cdN8i4[W\'RNrz63=vh-9vsbp4FIxO\\ekl_xdlu1*uE1_tQtz3\"J7oU=j,1R/.7j=,]xk4W@v]Q[Z6:_Y$=JAEwSrmQ+wH<65IRFDaFtC,L#];IAH+9x&B_@[3%[)O;qV:Z@j$aJ/FTYG8y.fEbCeYpMjUJSEAUlH[vh)(+@Dq=pKa-R<qQ#L@;D(5rlJhVRy7;a`Be[wl=\'DcPFN:oOv1&dTV9U\'Vdy]DtJP5T/)wPf7uvsctHCUh1P)r4?\'=Ao8^[/niJp#MDI\'zccJ&tHGg[pIW\\NQ/0BA^?Z1zDx`TcwX/yE(4iADn,&sD3lR8[H8x(L1H[rS+q+p(dN8i4]aQQ(id>E$yh{X)V__@^Ae^._zrNl]k)\"fib1c,E\\&<Am3IYevH@ExZ;Sqg7oWF8%J-;(O?,X^UkFV`bPI]\"#(ANLorrjAAbOFQGP>$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?&<<Z6<fwKInu*a7)a;=`R\\X*^*JzSlLq#H)0UC0^rIQ?)FihP9g%uN`{qL_#$,O1@1ojIhX^R_j!Vrf.DQMooayceTS(eN9k=+V[I9#=LKq&WmI\\wh)*5lLpx2\'eSQz@d`;=^K>3%Yws^^BghW[F-Jns\">Rh;*[rU0*!bWlDHz\\=V!87KYa`BaL7g0O%_?UqasF@J7mP(knkS:dr6Me=<Qg=3&_<E-Hi`)?G+:%FuHAK9unLk\\m8bn-(!fkl]n;qT.#aI,:#<E+BM@86GC\\/gGgXbf]#+N2HV]Q`p<m?-^xi+/G^*L)\"hs38__Dn+!]@`K6h8q]\\<RlP)q01B>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%ChgP<s]Usi:y(Ht@wbf\\zxoIV[I:(SS(dL0EN=&=G1XPiEYqW@qHO6ZKHgUS$NEOA70(s>oD=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><RiAFwSrmQ-(xV$H&y`VmH\\wj2Nt,mpkN\"Sf.F\\#.ZfvF7x*VZH9$ChhWW5<m?,VW5=rR&Ywuf%sFAPR.++4auPlWN`!sS&XoNr#Cn,#hnrw&En(ihSE>I5f3`p<nB837X<`Td$sJUNe;0w=\\CtLVSy4.\'tC/[bbFr9X:Tz9@uX;V\'TZMR9`aGz]DtIK{Urg3\\]Afja0]l0?.e>?_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+</r#Fy\\@da?Q\\`OI`1f>=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<gzV!739bkv6@$,N0>*Q@/d5soYO`xdhd>E%\"tS#J3[W)Xl;y{&:45OohAH\'\'+CPMr{=SlP*vH><Qh>9AzoA0hGcGt@va_?UtnP&bGvKN*yY0w<X.t1,&tIIs4>ys[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<eo(fXcn\'hb8,ja-O0:r\\V{3zBn08h2U?rQv.r$J3YQg:\'O>,XaaEr<fxNYY6;fwKN&jpy517]Y+]\"&7(ZvmA6-wBxeo\'bI#hp\"F#rIP7_`I+7p\\Z2$Z%=F.M#Y(M4YH@DuOb(6tsg1R2>&=CxaZ$95=sX=aYxyz$0e:-j^uZAo=s\\Si=0ry5/,.BDkxBw[Ap;m@0jSA,R>\"(APT:]NP)p-#cWh,9wz)M0B=LIhYes<dijY`[+[oD?PZStsi7mKhSHN3LjWV.xE\'1\\ekk^rK[j,1R03Nqu\"61/7f()6qd\'(3e2_n7ZI<1!LBEq9]OT<j0BA^>Vw#95A)BUh2XJL!UoXJHia.WU&T[RiBG\"iyMMyF,BNDK-;%CbK2Q+wG8z2!H.G`5{?\\<O_qB3qkJiZep+vE/S>vevLP4J[oEEjnlYY42>$4w-j\\m7_cXj8nNt-p!Cp8[J@Ae`6\'Ys__G\"ixH;-hQ=xpLfDZ\".`\'4oavX59^VunOw9JL\"Z-gL\'q7U/%eZqR%VmHYj5[UuupV<chd@K>60.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<m>(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<yyxoKb4srf/Kmm_tRx3+t=en$WoS28cp1:mFM5[RjDRQ%WoR,wI?@cWk;z*P=yvk8k?3y>\\?_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`<G1[^LBCghVV22A3v+dBXy$6\'Yvk;{*Q?*L)$o8]Sf3^iwByi&q:dn&_;Av[BuU&SZMR9]Sh8re)2\\bYwr\\Uurao4GM0DGvJKyJ??\\<NXRroZUx*Yh\'x]E$vY:Pe7ux!+SK\\pGL-7i:x{*N5XC&0Z^MESS-!X#;Aw]OO&dRMjVOgAL;!0jTGCZ$81+\"c\\%:7D3kP/1KgK$fa8-q\'^2qpc\"n:i2S2;nHTT-wD\'/UJO4Nry0v2-)$uQqjG_0f@G)0T?xk5\\W%Eo03P\"K>2y=Z7=m:nHZk7cvQkQ2?*P;qT0/7g/JiZgzY,gM-1Mt,p\"G\'*9%Er<g!^DsE9-ot$FuF;43A/c4nYU{9>l2I\\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<U#@_EuJKxJAH*4e/MyH5lN{MJi\\n=z#,RA-WZ?flon[^K9wws`ghWZBw]I8sk@:?l/9sbp7U1-,4^hq\'`;@o;nFL1Jc<<W)\\!%7&T[O[^I1VG>?`MCFr:a_=OYV(YnGRJYes<dlw9IGia1b,E]-]tW8JO2FM2Nw6?vadU[LLwBuV.v:Ty5/*#l*\"d_2sw(QEFlx<X1&bK0FU\\P]daAX\"4#MDM9mI`0b,Ilnf9#=NS9_[.hO1CAY\'K.<&DhhSHO5XC%*BRYLM&gdD`>Q^hr-zP^hs1/7g/IeGo%[(J#fgSK\\oC948]Q`o7X>gvC%*BS[Vz0qv%Em%_<JBJ4\\\\<Qf8x&DhfL(wRo]gnw56PqrjCG\"hp%Vi6f.FZtbku7D3lVIK{Ure)0UB,M){`NGXf\"d_3t$Eq6Pt#?X(SOs%I,:\"4%WoOzDx]I3`qA)CZ$81-+/Lq#G\'%\"wabI&wY6>pGO7cr=l7dy\\@ecEheGmw7@ynA4z<Pa\"uX8IJxJCNDHz\\>Y-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\\<RkKq#L:z*P>%:5:et?qK^wfvIDVi7i;#6+ox9F9(YpMme5p`p:g$n1<xug)*7rf-BJ1Nx?efW]Sg7nU<eo(jk\\l1EL1Ib8,ljR=sZH;+^\';8F9,hURw1!LCK1O$Y\"2u(Wf#l+#hnt&OFM3T6JUOm^n7]Uq`m,*,;(QJ[nA3v,gN2I]{zwj1LnlXRph;\'M5[Tp`q>xoIW_Y$<E)9%FuIE\\*RGJ#bT]X&I\'zfo#QV>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-ow0yAp<qQ\"I1VC.TF@LAAbQNr\"?\\7<bdQHSMhM&ilgBOJeGjk^sOm_qD;9JM\'p1:mC@X#:<]J:#:<_QU>oC95>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>\"\'<<Y3,\"_G&ydha3ph;)UYAuW46T+ms\"=Re0S9^VuoS16YE,Ins!;G8!8:Y;Ty1y?c],Yep//;y$5$OGTV6FAQZPc*<3*q0/;xxvl=\'DeWco,{Z2$Uj=-b3lTA&3mYV&N@710<z%6\'Yuf\'{i$dXmC?Sh9wy&=CydigN.5]]>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(+><Pazi&q8Y=caB^>SjERR\'cH{^Co3DBZ)TPv-oqqd\'(5pby`WpV<fs7OkUE:2)s:]LET[NWKSA.[fu?oB4x2\'f[t]Sf0Q07akyI9!4$QU<eo)n{H/Lv9Oc.R9_^<LM\"UoVB\'5rlKnna{m8aiq$L<&Elw9LUIP8bl{NLs,q(bAX#723GQC=D$xgxOYY44HP;r[MP-**2]fje@MCGxW(V`cU^^Ad])Hq14Q#MEOA7.zRc$yi&q:cild3jG`7,mpo]fjd<9IE^1qpd)5mR19i1P%]3!F$uSx2&`>QauSy4,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<s]UtpWA\"yl6^_F!fkiQ8af`4w,fJyQb\"rKY`Z\'GuC)?F$tOgCS[Rh<0t)_0gCS[Tp^gox8A$*FfUU0(s@wdp,\"_Dp5K`(:.r)dJ&p7V36U4:g\'{gr/)wPc*=9C)=9HCT_cYqXB#zpGN6^^AfcAXwvpS-#_Ck!R^iu9Ru!5-xKEZug+2YSsp]aS[Qd,DRV=guB##$)?F%zj++4c\"pB4u$ChhW[D\"tT&UcsB)?H0O(n&bGwPa\"rNiL{Sf0R4EFlt.t21>*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;\\Dzgt<aZ\'I!^FzbZ\".^xi)&#w_WuoQ%Yxz#.\\m8dxW+cBVpZPaxa]2v1#VpYMUF<<X,fN3MnkS:do*q12I\\t[I<1zG-G_3sy/k\\k/:tg,=.k]pC6(\\%80$_A`I+5h9y)M3Ov58Y>ejgJv@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:6<k4U7Pnaxdg_*GkolWKTE<<V\'RR(cK+.G[xt_^<NXPhCQNu0$[,]xoEHwJF`7/$_BcU_aM<%>LFXmC@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/+),=63<rYF0WNa&0Y[?fh^#)ANIdAScxZ9JIq)jeBRXIE]._\"!yrT-wE*?Aea=F.Lv;Y6>sT-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_qB2kS<l;voMme9$Bfa80&g`1iImpo]flniHfQD<ArE>G+>8?sQw/t0$]9<b^86FAPS5GHt;a^6-wD)8%I),@?Y-hRC6$L<&Eikb,Inv.r%SXD,Hjc9+eIvD.P3GO<y!&8+jb/Y[Am1>*P=z#,UM`%.ULZb`@W!4$RXG:,gP<t_^=Qe/P,%m+\"bWj:wtdz^F$tNd4kO&eWduHDWnMqv\'N:sdwRpf0Q/4V;a\\1s$H$sGD]/gHkl_wa_>P]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/0A<F2_p@\'>Dydg]ypKa.XY8E6y2\"MFXh-:\"4\"F$uV-r)cGr4C90\'ij^u\\LDRR\'cL0FQJ\\rS&Z!+RC;:Pf:)ZoI[pK^\"zvdq5GHs:[D{k.6cy`TcwW,kb.R<qPu+eHq12FL/BCfb>H1VF>?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<h&r?xk5\\V\"88PlYX1\'g_*K#_EvMZa[(K*(*9\":B{qJX`]76FAR^bVf&!l1C@Wy(I\"cWk;{,Ydn$UlFQLe?F%\"qJUOnc*>: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%*CVh2T<es9Y=`QU<er5EAVoU<cheFg^%2kP07e#l,))0VF<:LTD6{<Pb\"tS\"Dq<l;s`fdGo&]1ry3&\\-_\'6{9?pC935Ld:0{LFYqU4@(AR[X-j\\l3Nptx(L-8q[Uv!0m_uU,moh?>V!74>xoHUU.{Sg6lIb:48ZE+AI/H`3rqd)1XRpg6kGZucq5HO9j7i8p[TtrbtIHmu-ml\\dg[rR%WoOzCsJQ;l>+US%S\\Y/pt{4(fVZF/P1<xvj4[W&M7h2T<fxNXQobzi#`I.A?Z0t+fP;s^]<O]flokO)s;`Y#96C0c1\\eib6y4-\"Z1w9IGfVY@n9g&x\\CuOd5pbvV*eK)!fmqtvxyyz!$1g@DrB,P5S,v?k.6bvPjKq(`;@k*%sFAONyE%%\'3iDU`fb>J<,c9/xC!o?%5z<NYY56MgGgYh%q<k5[Qc(1[`TbsD5w(RMk\\j&p4ISISJYdm{I6mO\"SasHEa@Wvuk<%>LH`6(\\&<Ao9cp2<vj6aq<k6^`J1Q.)%uQod+@Aea:8HFdN8f(*8w$=H6qbvSx1w7A%-TIM,-<)QGM3P\"K?9@sPqpd&$\"u\\KCK3WF7y/opf3avW2*xQg;)V\\Rb\"o;l>)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<difIr00<z\'@R]bUf\'$zk.8mKiXZ@m.6am,%n..>.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<Czj+)+;-iTK[h#fcC^86F@MGYoJ^$*Ho!H0Q07`e`7*eM/?4#ONt.xE(3h=2\"LBDl\"UlIb8+i_!ym>(Ht?oA/b/Y[@j{TmP&`BbNA:>hxIAH+9z.d<8E6u{0nhCPJa4suupS0/<!,VV0(p18cq6OojHcAVran./B?Urf+8vvsbn-\'x[;N\\hvD(8\"<JBNDH#jzMLt0&ika\'7z4(fV\\NP+zY/qy79W5=nC=G1ZY3-(y]Ezfn{F&\'/S?zwh+1R3@+TJX]NLu47W;W1&dUYE.Q5Qx55JYckq!@_EwTx-fIu=ft:Z?eic:2,#cZvmC@X$=I<2$Uj=+[qOpmWLVM_zn?*O9h-<(PB80(o+yTp`p8^W{0k[dg[sZH6qf-AFxZ69ZArIN2HV[MLs/&gb91(n%]2x8B\'7$G{da=F.M#\\3#NJfM-4[W&M:uj9pYIAK:y$7+mpmVE7$H%sJR?#+O4R)h`,P8`cU`e^+O8bl$\\/k\\j*$p=t[MMzJ?=SkIeJ{Z.ooe/P/4V=h!\\:G:+a7\'Zvj5^d\\&<@l*$o3HSK^zu]Se*7usf+6mQ.)#o7W<aYz\'DbI($vZ@j$bQKeAPQ,#cXlA86D90!Q\\]Bk!TkH_-WV1)s:_Xy(Ht>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)/Q1<xvh.?8;]I5g6nQ-&r>t[I:%GwNYZ<U\">Vy-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*><TrjBDo/2KfIu?o@,SGGo&^722DB\\2y@fh^zrT+mqrmNzJ:&HyX,eIt;^NN\"QXNZ_OP&`?Vutg/Ha5\"Co1;sal{OQ/1FO?+UU,p#J7oWC)=;N\\hyP_n3IXdr8U-u:T\"?Z/s(Zuh+4bzdha3mXRqg9x&A[-d?H.FZwpQ{E{hxLLxF/S;h&vQlS<k2OyBq>zveuF8%I*/MxCzi$fc@Sc!k)xTx*Xcm%^:>fr27[MN\'ij]sS$NDK0H]#,R@,RA/a\'6x-gK!Y*Yj2Q*s7OhFa<D%%*@J5c!l,.A?X&I(#rIM.7j;$:<\\DycaCcQMk]m4R)jfGh`,O1B=G3b$zo@,VT&Wk=)O;r[OXPg><Qe2`qC2lVKUJTJTMb.TF?J;&En&cOA4#J5czejhM*#k#\\4\'cI%r?ypKa-Q9aikd7!9@qGIwIAI0Mw;W+eHq01A;?l.6d\"m1C?Q_j#]9>j*\'%#zoC<BtQpg9\"87JSE>E\'*>=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<U!8:Y8HE^4#MCH$o5Qz>^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<!)IyRh=0s&PKd?I5e*8y,\\t[JBH*2ZX.s*fP?+Q>!&;7D3jKp#L<)O=#2oh?;JDUcvN`xcfZpMkY]LCJ/ERNqw*\\vg%o6R%UcvRrlNyE\'-LxE+??_H,;*[rS(a@Vsf,<-eEcI%q<m>\'C`A\\76GGlrz9C(:-nm^o=ubjr%SZLM$_Be]\'@OO%\\0qssj?3$Tao5MfDXui3ZPd-Kr*jgGic:2,$is-v>fnx<W+b;;Su\"5)fUU1-,6g4c$uW1(o)mv2.,3WH?CsF?G+=4+u>i\'r=n>(Hs:[F)6smKkb-M%dXi1NxAl.1Ms&Ucs@#%0^tT)b@R^fh^ztYAuU*dHt<dmzE%{n<vh-:#98Nd1`uW2-,3YN[`WpV=j*(+;*]!\"(?H2XOb\'3e3b$xdkr{<P`vW0#Xy\'CbL4ZRkMw?hxI>:F6v#725Q\"J5d(/Q5MiO2C?OUA$)AOLqy529g)+:&J)(,BNCFq6NiN,(\"n5S*ny<W(U^]9@rOjSA)CYz\'AUmKj^uZCzl0>,[oFHvF8!9?pC934J\\pGO8f((1YU&OGRMgJs4@%5y64D:48X=ca@VrczdfTT*lmd3d+=7<dkpv(RNqsp^fi_%/Y]I8tlDJ-9vvqV<a^6.#_Ckx@o9dtC,M\'p2<vmA85@\':45La+Hnu.r\'Zws]Vusf).Lt36U23J]xm?-]sS\'^1ma#yk2I]\"&6\"AcUbq8[G0VHFcI$k{R`p;j4V>n>%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/A<JAG%vX2./?5(dL1Ja5w-j[gyQc&(4kLt0\'n\'dSR&[\'Ega6\"AfeM0A<F1\\dcJ)(*9%G{aQT6KX^Q]`POx<X-ot\":D\'3iEWi5_fi]vaaH%sIK{Wy,\\sU23GM4W?pEBXy\'C_>SjDM;z(Flr%M?2w419i5^bVf\'$yfs6IQ>!\'=CtM_ym8dyZ9E6v$?Si>3&[(J#d^/e>>\\<Qd/Q4J\\pHP?*L,.BDm&dRNolS;g$jv<]G-BK3XKM&kv8HD\\-_$)BUg1P+ySlMu6@#)CXsdxW*b=CwZ<X-kd7z614Pz@gp#K9x!-ZfvIAL;$;?i\"]=Rh=3\'dQFHxPc\'.P2B:<]H1S8W6@\':1\'jle;1#UkDJ,8p[V{739co/1GSOqux\'Gr6Ne<68W5;i-7lGZpLfD\\*SIUQx3-\'tG>CrB+L&o.-4[Y2%^9:X45JZi(y_NGZrW<b]4#NFTV8OgCRU:Y<Z7>rR\"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/0CFs<fuC);3+yQe/O(q3=woJ_\'8+eJ$feJ\"`M=*VX>gq-\"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$OJc<?c^1ne2^l,*-CL;y$5\"Co3D?OS8W5@$/[gwJDVg,8vwtdxU{8<cdQJ[n?-[i+->3&\\,]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<ep-\"]<OYX2+yQg7tpYJHjc8%K3WD.R:f\"fjb2hCPKhP9f#k$bPFPB;=_NH_,UMd6ttnNv6?xm>%:8KP7[OXQjJpy;Pb#zm;qW?m5U6F@OO%\\/k\\j(wPg</s\'XpPzAm-,5f.IfN5V9T$M>0mc/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,ySlMxAo<oJ_)@I5f0R3C<Cw^OQ+yTrh7mLnn_sKVT&T^_G%vU%NBA^=P]hwC#ym9j7h5bwX1%bK0GWez[9D/WQn^n4Nppg7qbuOf;,fK\"^@_H((/Q5Pw1\"R]_L=*V\\OWHDZz%;:Od1]i#_Ad\\%:47V5>xnB:;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<wqS+s3:i.?4)jgJv?m6ZKHfQB7-u7HGklb(7z2zE#rJTL^wes9Z@l,-9wy#2plR2>$2pkJiZh#ea<Cx_Ui8rcvRobzhxLO)vH?@da;=_PR.\'vN]m3Mmd4iAEvM[b_:>fq/(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;42<woI\\u`aH#k&kt-u7GBTcxY6<j,4]_I/Lpz>Y-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&L8kA<G5kMu6@\"$,N/8k?3y?_L>1u-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<er4A-ZdmzD{k+*0R5Md8(Vbl!PU?tZE)7x)QEHuC(7\"=Rg9!4&\\+US&WnJb7%OEL1JeD]3y<Uz4)h^#+It:W2..:vsctF<7?wdn\'g]zxpNl]n:l>*P>$3rpbx]G.G])Gn\"ONw=^I1T<g{]@`NA>P\\_L?88PkT@%/^uW35MiR>vg&uOe9%H\"fi_%/\\k,->2\"L@=P_m2FN8e#o7X@n;mA6,r/\'n*r4B3sw$<D\'0[_OO#SbuPiIke@G)2\\ddL/?5,t7HK#bPKeD^4$QS2:k8j=*V[J>9C&1c);.px3(ha1e9&M:r_bQPzF(.M#\\5+q-yOZW*`3pkKpz<Pb%&-P4K_(<9JKyMO*wMUHEaCdTZH<2&bGwPc(4iCL9q[TsnQ*s8Rw/t.t23FIzZ2\'eU[JBI,9y(M1I_)CZ$7.yJ?>Y+_,Q<qS)ic:0\"Tf/KnpmVF<8A#%/\\hyRh=2\"LCH&yccI\"cZz#-WW34J]u^Up[Ux+\\wh*,?9@sOkUIJwG6snQ,\"^AcZue\"hs38\\Q_n3GN9mDH\"edHt>oA0e=9G<69Y<[<W+b92/3S0.7h3[W*^+M,/H\\\"\'<<V%L6cwW+hUQv*`1gCT_cYpR\'bFr9Y=^LBBcWg\'$w\\I9w\"3w3*r5D91(q2;oJ`.VPnb#wbdTW=ceUV8LY_VoS16XC$$)?EzdgYi.?4&\\+TOog:\'PDDheIt<djiWU(])Hr3=vi.>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\"<LM#[-b6z9@uY>deSOpn[[<Uw(N9oMpsslFV`dYoLfEa?Sg3]c[\'B\\/k\\j)\"ixH:&L4ZO]k*#iwArKY`Z(K)\'&)9\'RQ#NH]%4v\'M6btGBTap7W8M_zm8f&ydg]yrS*ic6{9@rNhHh]xj0DI(\')6spYMTA(>CsHGkk\\l3Mmg>;MS?!\"&7\'Xk<\"1kXV)]*M/;y&<ArE=Bq?$-UMc2e3c(1^m3HW^X\"4&Xsajv<Z9HDXtg)/Ls.!TjCH&x_QV@wchdD^6.$`FwRmXQkN&dUZG8x*W`_AbSV9U\'XnJ_*Hms%M>.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;
...@@ -1374,3 +1374,12 @@ insert into t1 values (1); ...@@ -1374,3 +1374,12 @@ insert into t1 values (1);
repair table t1 use_frm; repair table t1 use_frm;
select * from t1; select * from t1;
drop table 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;
...@@ -1576,4 +1576,57 @@ connection slave; ...@@ -1576,4 +1576,57 @@ connection slave;
drop table federated.t1; 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; source include/federated_cleanup.inc;
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;
--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
...@@ -570,6 +570,25 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length) ...@@ -570,6 +570,25 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
previous->next=pos->next; /* unlink pos */ previous->next=pos->next; /* unlink pos */
/* Move data to correct position */ /* 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; pos=data+new_index;
new_pos_index=hash_rec_mask(hash,pos,blength,records); new_pos_index=hash_rec_mask(hash,pos,blength,records);
if (new_index != new_pos_index) if (new_index != new_pos_index)
......
...@@ -205,7 +205,7 @@ bool archive_db_init() ...@@ -205,7 +205,7 @@ bool archive_db_init()
else else
{ {
zoffset_size= 2 << ((zlibCompileFlags() >> 6) & 3); zoffset_size= 2 << ((zlibCompileFlags() >> 6) & 3);
switch (sizeof(z_off_t)) { switch (zoffset_size) {
case 2: case 2:
max_zfile_size= INT_MAX16; max_zfile_size= INT_MAX16;
break; break;
...@@ -676,6 +676,7 @@ int ha_archive::real_write_row(byte *buf, gzFile writer) ...@@ -676,6 +676,7 @@ int ha_archive::real_write_row(byte *buf, gzFile writer)
total_row_length+= ((Field_blob*) table->field[*ptr])->get_length(); total_row_length+= ((Field_blob*) table->field[*ptr])->get_length();
if (share->approx_file_size > max_zfile_size - total_row_length) if (share->approx_file_size > max_zfile_size - total_row_length)
{ {
gzflush(writer, Z_SYNC_FLUSH);
info(HA_STATUS_TIME); info(HA_STATUS_TIME);
share->approx_file_size= (ulong) data_file_length; share->approx_file_size= (ulong) data_file_length;
if (share->approx_file_size > max_zfile_size - total_row_length) if (share->approx_file_size > max_zfile_size - total_row_length)
...@@ -1204,7 +1205,6 @@ bool ha_archive::is_crashed() const ...@@ -1204,7 +1205,6 @@ bool ha_archive::is_crashed() const
int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt)
{ {
int rc= 0; int rc= 0;
byte *buf;
const char *old_proc_info=thd->proc_info; const char *old_proc_info=thd->proc_info;
ha_rows count= share->rows_recorded; ha_rows count= share->rows_recorded;
DBUG_ENTER("ha_archive::check"); DBUG_ENTER("ha_archive::check");
...@@ -1213,26 +1213,14 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1213,26 +1213,14 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt)
/* Flush any waiting data */ /* Flush any waiting data */
gzflush(share->archive_write, Z_SYNC_FLUSH); gzflush(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= (byte*) 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 Now we will rewind the archive file so that we are positioned at the
start of the file. start of the file.
*/ */
if (!rc)
read_data_header(archive); read_data_header(archive);
while (!(rc= get_row(archive, table->record[0])))
if (!rc)
while (!(rc= get_row(archive, buf)))
count--; count--;
my_free((char*)buf, MYF(0));
thd->proc_info= old_proc_info; thd->proc_info= old_proc_info;
if ((rc && rc != HA_ERR_END_OF_FILE) || count) if ((rc && rc != HA_ERR_END_OF_FILE) || count)
......
...@@ -348,6 +348,11 @@ pthread_mutex_t federated_mutex; // This is the mutex we use to ...@@ -348,6 +348,11 @@ pthread_mutex_t federated_mutex; // This is the mutex we use to
// init the hash // init the hash
static int federated_init= FALSE; // Variable for checking the static int federated_init= FALSE; // Variable for checking the
// init state of hash // init state of 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
/* Federated storage engine handlerton */ /* Federated storage engine handlerton */
...@@ -440,6 +445,58 @@ bool federated_db_end() ...@@ -440,6 +445,58 @@ bool federated_db_end()
return FALSE; return FALSE;
} }
/**
@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(&quote_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(&quote_char, 1, system_charset_info)))
goto err;
if ((result= string->append(name, clen, string->charset())))
goto err;
}
result= string->append(&quote_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 Check (in create) whether the tables exists, and that it can be connected to
...@@ -458,7 +515,6 @@ bool federated_db_end() ...@@ -458,7 +515,6 @@ bool federated_db_end()
static int check_foreign_data_source(FEDERATED_SHARE *share, static int check_foreign_data_source(FEDERATED_SHARE *share,
bool table_create_flag) bool table_create_flag)
{ {
char escaped_table_name[NAME_LEN*2];
char query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char query_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
uint error_code; uint error_code;
...@@ -499,7 +555,6 @@ static int check_foreign_data_source(FEDERATED_SHARE *share, ...@@ -499,7 +555,6 @@ static int check_foreign_data_source(FEDERATED_SHARE *share,
} }
else else
{ {
int escaped_table_name_length= 0;
/* /*
Since we do not support transactions at this version, we can let the Since we do not support transactions at this version, we can let the
client API silently reconnect. For future versions, we will need more client API silently reconnect. For future versions, we will need more
...@@ -517,14 +572,8 @@ static int check_foreign_data_source(FEDERATED_SHARE *share, ...@@ -517,14 +572,8 @@ static int check_foreign_data_source(FEDERATED_SHARE *share,
query.append(FEDERATED_SELECT); query.append(FEDERATED_SELECT);
query.append(FEDERATED_STAR); query.append(FEDERATED_STAR);
query.append(FEDERATED_FROM); query.append(FEDERATED_FROM);
query.append(FEDERATED_BTICK); append_ident(&query, share->table_name, share->table_name_length,
escaped_table_name_length= ident_quote_char);
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(FEDERATED_BTICK);
query.append(FEDERATED_WHERE); query.append(FEDERATED_WHERE);
query.append(FEDERATED_FALSE); query.append(FEDERATED_FALSE);
...@@ -725,7 +774,9 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, ...@@ -725,7 +774,9 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table,
ha_federated::ha_federated(TABLE *table_arg) ha_federated::ha_federated(TABLE *table_arg)
:handler(&federated_hton, table_arg), :handler(&federated_hton, table_arg),
mysql(0), stored_result(0) mysql(0), stored_result(0)
{} {
bzero(&bulk_insert, sizeof(bulk_insert));
}
/* /*
...@@ -784,9 +835,8 @@ uint ha_federated::convert_row_to_internal_format(byte *record, ...@@ -784,9 +835,8 @@ uint ha_federated::convert_row_to_internal_format(byte *record,
static bool emit_key_part_name(String *to, KEY_PART_INFO *part) static bool emit_key_part_name(String *to, KEY_PART_INFO *part)
{ {
DBUG_ENTER("emit_key_part_name"); DBUG_ENTER("emit_key_part_name");
if (to->append(FEDERATED_BTICK) || if (append_ident(to, part->field->field_name,
to->append(part->field->field_name) || strlen(part->field->field_name), ident_quote_char))
to->append(FEDERATED_BTICK))
DBUG_RETURN(1); // Out of memory DBUG_RETURN(1); // Out of memory
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -1309,31 +1359,28 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) ...@@ -1309,31 +1359,28 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
query.append(FEDERATED_SELECT); query.append(FEDERATED_SELECT);
for (field= table->field; *field; field++) for (field= table->field; *field; field++)
{ {
query.append(FEDERATED_BTICK); append_ident(&query, (*field)->field_name,
query.append((*field)->field_name); strlen((*field)->field_name), ident_quote_char);
query.append(FEDERATED_BTICK);
query.append(FEDERATED_COMMA); query.append(FEDERATED_COMMA);
} }
query.length(query.length()- strlen(FEDERATED_COMMA)); query.length(query.length()- strlen(FEDERATED_COMMA));
query.append(FEDERATED_FROM); query.append(FEDERATED_FROM);
query.append(FEDERATED_BTICK);
tmp_share.table_name_length= strlen(tmp_share.table_name);
append_ident(&query, tmp_share.table_name,
tmp_share.table_name_length, ident_quote_char);
if (!(share= (FEDERATED_SHARE *) if (!(share= (FEDERATED_SHARE *)
my_multi_malloc(MYF(MY_WME), my_multi_malloc(MYF(MY_WME),
&share, sizeof(*share), &share, sizeof(*share),
&select_query, &select_query, query.length()+1,
query.length()+table->s->connect_string.length+1,
NullS))) NullS)))
goto error; goto error;
memcpy(share, &tmp_share, sizeof(tmp_share)); memcpy(share, &tmp_share, sizeof(tmp_share));
memcpy(select_query, query.ptr(), query.length()+1);
share->table_name_length= strlen(share->table_name);
/* TODO: share->table_name to LEX_STRING object */
query.append(share->table_name, share->table_name_length);
query.append(FEDERATED_BTICK);
share->select_query= select_query; share->select_query= select_query;
strmov(share->select_query, query.ptr());
share->use_count= 0; share->use_count= 0;
DBUG_PRINT("info", DBUG_PRINT("info",
("share->select_query %s", share->select_query)); ("share->select_query %s", share->select_query));
...@@ -1467,6 +1514,8 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) ...@@ -1467,6 +1514,8 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
table->s->reclength); table->s->reclength);
DBUG_PRINT("info", ("ref_length: %u", ref_length)); DBUG_PRINT("info", ("ref_length: %u", ref_length));
reset();
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -1538,6 +1587,83 @@ inline uint field_in_record_is_null(TABLE *table, ...@@ -1538,6 +1587,83 @@ inline uint field_in_record_is_null(TABLE *table,
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/**
@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;
/* 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);
insert_string.append(FEDERATED_OPENPAREN);
tmp_length= insert_string.length() - strlen(FEDERATED_COMMA);
/*
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++)
{
/* 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 because we may not append
if the next field doesn't match the condition:
(((*field)->query_id && (*field)->query_id == current_query_id)
*/
insert_string.append(FEDERATED_COMMA);
}
/*
remove trailing comma
*/
insert_string.length(insert_string.length() - strlen(FEDERATED_COMMA));
/*
if there were no fields, we don't want to add a closing paren
AND, we don't want to chop off the last char '('
insert will be "INSERT INTO t1 VALUES ();"
*/
if (insert_string.length() > tmp_length)
{
insert_string.append(FEDERATED_CLOSEPAREN);
}
insert_string.append(FEDERATED_VALUES);
DBUG_RETURN(query->append(insert_string));
}
/* /*
write_row() inserts a row. No extra() hint is given currently if a bulk load 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 is happeneding. buf() is a byte array of data. You can use the field
...@@ -1554,13 +1680,14 @@ inline uint field_in_record_is_null(TABLE *table, ...@@ -1554,13 +1680,14 @@ inline uint field_in_record_is_null(TABLE *table,
int ha_federated::write_row(byte *buf) int ha_federated::write_row(byte *buf)
{ {
char insert_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char values_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char values_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char insert_field_value_buffer[STRING_BUFFER_USUAL_SIZE]; char insert_field_value_buffer[STRING_BUFFER_USUAL_SIZE];
Field **field; 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 */ /* The string containing the values to be added to the insert */
String values_string(values_buffer, sizeof(values_buffer), &my_charset_bin); String values_string(values_buffer, sizeof(values_buffer), &my_charset_bin);
/* The actual value of the field, to be added to the values_string */ /* The actual value of the field, to be added to the values_string */
...@@ -1568,7 +1695,6 @@ int ha_federated::write_row(byte *buf) ...@@ -1568,7 +1695,6 @@ int ha_federated::write_row(byte *buf)
sizeof(insert_field_value_buffer), sizeof(insert_field_value_buffer),
&my_charset_bin); &my_charset_bin);
values_string.length(0); values_string.length(0);
insert_string.length(0);
insert_field_value_string.length(0); insert_field_value_string.length(0);
DBUG_ENTER("ha_federated::write_row"); DBUG_ENTER("ha_federated::write_row");
...@@ -1578,15 +1704,19 @@ int ha_federated::write_row(byte *buf) ...@@ -1578,15 +1704,19 @@ int ha_federated::write_row(byte *buf)
/* /*
start both our field and field values strings 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(FEDERATED_INSERT); if (!(use_bulk_insert= bulk_insert.str &&
insert_string.append(FEDERATED_BTICK); (!insert_dup_update || replace_duplicates)))
insert_string.append(share->table_name, share->table_name_length); append_stmt_insert(&values_string);
insert_string.append(FEDERATED_BTICK);
insert_string.append(FEDERATED_OPENPAREN);
values_string.append(FEDERATED_VALUES);
values_string.append(FEDERATED_OPENPAREN); values_string.append(FEDERATED_OPENPAREN);
tmp_length= values_string.length();
/* /*
loop through the field pointer array, add any fields to both the values loop through the field pointer array, add any fields to both the values
...@@ -1599,14 +1729,12 @@ int ha_federated::write_row(byte *buf) ...@@ -1599,14 +1729,12 @@ int ha_federated::write_row(byte *buf)
else else
{ {
(*field)->val_str(&insert_field_value_string); (*field)->val_str(&insert_field_value_string);
values_string.append('\''); values_string.append(value_quote_char);
insert_field_value_string.print(&values_string); insert_field_value_string.print(&values_string);
values_string.append('\''); values_string.append(value_quote_char);
insert_field_value_string.length(0); insert_field_value_string.length(0);
} }
/* append the field name */
insert_string.append((*field)->field_name);
/* append the value */ /* append the value */
values_string.append(insert_field_value_string); values_string.append(insert_field_value_string);
...@@ -1620,32 +1748,61 @@ int ha_federated::write_row(byte *buf) ...@@ -1620,32 +1748,61 @@ int ha_federated::write_row(byte *buf)
if the next field doesn't match the condition: if the next field doesn't match the condition:
(((*field)->query_id && (*field)->query_id == current_query_id) (((*field)->query_id && (*field)->query_id == current_query_id)
*/ */
insert_string.append(FEDERATED_COMMA);
values_string.append(FEDERATED_COMMA); values_string.append(FEDERATED_COMMA);
} }
/*
remove trailing comma
*/
insert_string.length(insert_string.length() - strlen(FEDERATED_COMMA));
/* /*
if there were no fields, we don't want to add a closing paren if there were no fields, we don't want to add a closing paren
AND, we don't want to chop off the last char '(' AND, we don't want to chop off the last char '('
insert will be "INSERT INTO t1 VALUES ();" insert will be "INSERT INTO t1 VALUES ();"
*/ */
if (table->s->fields) if (values_string.length() > tmp_length)
{ {
/* chops off leading commas */ /* chops off leading commas */
values_string.length(values_string.length() - strlen(FEDERATED_COMMA)); values_string.length(values_string.length() - strlen(FEDERATED_COMMA));
insert_string.append(FEDERATED_CLOSEPAREN);
} }
/* we always want to append this, even if there aren't any fields */ /* we always want to append this, even if there aren't any fields */
values_string.append(FEDERATED_CLOSEPAREN); values_string.append(FEDERATED_CLOSEPAREN);
/* add the values */ if (use_bulk_insert)
insert_string.append(values_string); {
/*
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 (mysql_real_query(mysql, insert_string.ptr(), insert_string.length())) 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);
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()); DBUG_RETURN(stash_remote_error());
} }
...@@ -1653,12 +1810,79 @@ int ha_federated::write_row(byte *buf) ...@@ -1653,12 +1810,79 @@ int ha_federated::write_row(byte *buf)
If the table we've just written a record to contains an auto_increment 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 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(); update_auto_increment();
DBUG_RETURN(0); 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 ha_federated::update_auto_increment
...@@ -1688,9 +1912,8 @@ int ha_federated::optimize(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1688,9 +1912,8 @@ int ha_federated::optimize(THD* thd, HA_CHECK_OPT* check_opt)
query.set_charset(system_charset_info); query.set_charset(system_charset_info);
query.append(FEDERATED_OPTIMIZE); query.append(FEDERATED_OPTIMIZE);
query.append(FEDERATED_BTICK); append_ident(&query, share->table_name, share->table_name_length,
query.append(share->table_name, share->table_name_length); ident_quote_char);
query.append(FEDERATED_BTICK);
if (mysql_real_query(mysql, query.ptr(), query.length())) if (mysql_real_query(mysql, query.ptr(), query.length()))
{ {
...@@ -1711,9 +1934,8 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1711,9 +1934,8 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt)
query.set_charset(system_charset_info); query.set_charset(system_charset_info);
query.append(FEDERATED_REPAIR); query.append(FEDERATED_REPAIR);
query.append(FEDERATED_BTICK); append_ident(&query, share->table_name, share->table_name_length,
query.append(share->table_name, share->table_name_length); ident_quote_char);
query.append(FEDERATED_BTICK);
if (check_opt->flags & T_QUICK) if (check_opt->flags & T_QUICK)
query.append(FEDERATED_QUICK); query.append(FEDERATED_QUICK);
if (check_opt->flags & T_EXTEND) if (check_opt->flags & T_EXTEND)
...@@ -1788,10 +2010,12 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) ...@@ -1788,10 +2010,12 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
update_string.length(0); update_string.length(0);
where_string.length(0); where_string.length(0);
update_string.append(FEDERATED_UPDATE); if (ignore_duplicates)
update_string.append(FEDERATED_BTICK); update_string.append(STRING_WITH_LEN("UPDATE IGNORE "));
update_string.append(share->table_name); else
update_string.append(FEDERATED_BTICK); update_string.append(STRING_WITH_LEN("UPDATE "));
append_ident(&update_string, share->table_name,
share->table_name_length, ident_quote_char);
update_string.append(FEDERATED_SET); update_string.append(FEDERATED_SET);
/* /*
...@@ -1806,8 +2030,11 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) ...@@ -1806,8 +2030,11 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
for (Field **field= table->field; *field; field++) for (Field **field= table->field; *field; field++)
{ {
where_string.append((*field)->field_name); uint field_name_length= strlen((*field)->field_name);
update_string.append((*field)->field_name); append_ident(&where_string, (*field)->field_name, field_name_length,
ident_quote_char);
append_ident(&update_string, (*field)->field_name, field_name_length,
ident_quote_char);
update_string.append(FEDERATED_EQ); update_string.append(FEDERATED_EQ);
if ((*field)->is_null()) if ((*field)->is_null())
...@@ -1816,9 +2043,9 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) ...@@ -1816,9 +2043,9 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
{ {
/* otherwise = */ /* otherwise = */
(*field)->val_str(&field_value); (*field)->val_str(&field_value);
update_string.append('\''); update_string.append(value_quote_char);
field_value.print(&update_string); field_value.print(&update_string);
update_string.append('\''); update_string.append(value_quote_char);
field_value.length(0); field_value.length(0);
} }
...@@ -1829,9 +2056,9 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) ...@@ -1829,9 +2056,9 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
where_string.append(FEDERATED_EQ); where_string.append(FEDERATED_EQ);
(*field)->val_str(&field_value, (*field)->val_str(&field_value,
(char*) (old_data + (*field)->offset())); (char*) (old_data + (*field)->offset()));
where_string.append('\''); where_string.append(value_quote_char);
field_value.print(&where_string); field_value.print(&where_string);
where_string.append('\''); where_string.append(value_quote_char);
field_value.length(0); field_value.length(0);
} }
...@@ -1888,16 +2115,16 @@ int ha_federated::delete_row(const byte *buf) ...@@ -1888,16 +2115,16 @@ int ha_federated::delete_row(const byte *buf)
delete_string.length(0); delete_string.length(0);
delete_string.append(FEDERATED_DELETE); delete_string.append(FEDERATED_DELETE);
delete_string.append(FEDERATED_FROM); delete_string.append(FEDERATED_FROM);
delete_string.append(FEDERATED_BTICK); append_ident(&delete_string, share->table_name,
delete_string.append(share->table_name); share->table_name_length, ident_quote_char);
delete_string.append(FEDERATED_BTICK);
delete_string.append(FEDERATED_WHERE); delete_string.append(FEDERATED_WHERE);
for (Field **field= table->field; *field; field++) for (Field **field= table->field; *field; field++)
{ {
Field *cur_field= *field; Field *cur_field= *field;
data_string.length(0); data_string.length(0);
delete_string.append(cur_field->field_name); append_ident(&delete_string, (*field)->field_name,
strlen((*field)->field_name), ident_quote_char);
if (cur_field->is_null()) if (cur_field->is_null())
{ {
...@@ -1907,9 +2134,9 @@ int ha_federated::delete_row(const byte *buf) ...@@ -1907,9 +2134,9 @@ int ha_federated::delete_row(const byte *buf)
{ {
delete_string.append(FEDERATED_EQ); delete_string.append(FEDERATED_EQ);
cur_field->val_str(&data_string); cur_field->val_str(&data_string);
delete_string.append('\''); delete_string.append(value_quote_char);
data_string.print(&delete_string); data_string.print(&delete_string);
delete_string.append('\''); delete_string.append(value_quote_char);
} }
delete_string.append(FEDERATED_AND); delete_string.append(FEDERATED_AND);
...@@ -2397,7 +2624,6 @@ int ha_federated::info(uint flag) ...@@ -2397,7 +2624,6 @@ int ha_federated::info(uint flag)
{ {
char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char status_buf[FEDERATED_QUERY_BUFFER_SIZE]; char status_buf[FEDERATED_QUERY_BUFFER_SIZE];
char escaped_table_name[FEDERATED_QUERY_BUFFER_SIZE];
int error; int error;
uint error_code; uint error_code;
MYSQL_RES *result= 0; MYSQL_RES *result= 0;
...@@ -2411,14 +2637,8 @@ int ha_federated::info(uint flag) ...@@ -2411,14 +2637,8 @@ int ha_federated::info(uint flag)
{ {
status_query_string.length(0); status_query_string.length(0);
status_query_string.append(FEDERATED_INFO); status_query_string.append(FEDERATED_INFO);
status_query_string.append(FEDERATED_SQUOTE); append_ident(&status_query_string, share->table_name,
share->table_name_length, value_quote_char);
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(FEDERATED_SQUOTE);
if (mysql_real_query(mysql, status_query_string.ptr(), if (mysql_real_query(mysql, status_query_string.ptr(),
status_query_string.length())) status_query_string.length()))
...@@ -2484,6 +2704,51 @@ int ha_federated::info(uint flag) ...@@ -2484,6 +2704,51 @@ int ha_federated::info(uint flag)
} }
/**
@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;
case HA_EXTRA_RESET:
insert_dup_update= FALSE;
ignore_duplicates= FALSE;
replace_duplicates= FALSE;
break;
default:
/* do nothing */
DBUG_PRINT("info",("unhandled operation: %d", (uint) operation));
}
DBUG_RETURN(0);
}
/* /*
Used to delete all rows in a table. Both for cases of truncate and 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 for cases where the optimizer realizes that all rows will be
...@@ -2506,9 +2771,8 @@ int ha_federated::delete_all_rows() ...@@ -2506,9 +2771,8 @@ int ha_federated::delete_all_rows()
query.set_charset(system_charset_info); query.set_charset(system_charset_info);
query.append(FEDERATED_TRUNCATE); query.append(FEDERATED_TRUNCATE);
query.append(FEDERATED_BTICK); append_ident(&query, share->table_name, share->table_name_length,
query.append(share->table_name); ident_quote_char);
query.append(FEDERATED_BTICK);
/* /*
TRUNCATE won't return anything in mysql_affected_rows TRUNCATE won't return anything in mysql_affected_rows
...@@ -2616,6 +2880,9 @@ int ha_federated::stash_remote_error() ...@@ -2616,6 +2880,9 @@ int ha_federated::stash_remote_error()
DBUG_ENTER("ha_federated::stash_remote_error()"); DBUG_ENTER("ha_federated::stash_remote_error()");
remote_error_number= mysql_errno(mysql); remote_error_number= mysql_errno(mysql);
strmake(remote_error_buf, mysql_error(mysql), sizeof(remote_error_buf)-1); 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); DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM);
} }
......
...@@ -157,6 +157,9 @@ class ha_federated: public handler ...@@ -157,6 +157,9 @@ class ha_federated: public handler
MYSQL_ROW_OFFSET current_position; // Current position used by ::position() MYSQL_ROW_OFFSET current_position; // Current position used by ::position()
int remote_error_number; int remote_error_number;
char remote_error_buf[FEDERATED_QUERY_BUFFER_SIZE]; char remote_error_buf[FEDERATED_QUERY_BUFFER_SIZE];
bool ignore_duplicates, replace_duplicates;
bool insert_dup_update;
DYNAMIC_STRING bulk_insert;
private: private:
/* /*
...@@ -171,6 +174,14 @@ class ha_federated: public handler ...@@ -171,6 +174,14 @@ class ha_federated: public handler
bool records_in_range); bool records_in_range);
int stash_remote_error(); int stash_remote_error();
bool append_stmt_insert(String *query);
int read_next(byte *buf, MYSQL_RES *result);
int index_read_idx_with_result_set(byte *buf, uint index,
const byte *key,
uint key_len,
ha_rkey_function find_flag,
MYSQL_RES **result);
public: public:
ha_federated(TABLE *table_arg); ha_federated(TABLE *table_arg);
~ha_federated() ~ha_federated()
...@@ -256,6 +267,8 @@ class ha_federated: public handler ...@@ -256,6 +267,8 @@ class ha_federated: public handler
int open(const char *name, int mode, uint test_if_locked); // required int open(const char *name, int mode, uint test_if_locked); // required
int close(void); // required int close(void); // required
void start_bulk_insert(ha_rows rows);
int end_bulk_insert();
int write_row(byte *buf); int write_row(byte *buf);
int update_row(const byte *old_data, byte *new_data); int update_row(const byte *old_data, byte *new_data);
int delete_row(const byte *buf); int delete_row(const byte *buf);
...@@ -284,6 +297,7 @@ class ha_federated: public handler ...@@ -284,6 +297,7 @@ class ha_federated: public handler
int rnd_pos(byte *buf, byte *pos); //required int rnd_pos(byte *buf, byte *pos); //required
void position(const byte *record); //required void position(const byte *record); //required
int info(uint); //required int info(uint); //required
int extra(ha_extra_function operation);
void update_auto_increment(void); void update_auto_increment(void);
int repair(THD* thd, HA_CHECK_OPT* check_opt); int repair(THD* thd, HA_CHECK_OPT* check_opt);
...@@ -298,14 +312,7 @@ class ha_federated: public handler ...@@ -298,14 +312,7 @@ class ha_federated: public handler
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type); //required 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 read_next(byte *buf, MYSQL_RES *result);
int index_read_idx_with_result_set(byte *buf, uint index,
const byte *key,
uint key_len,
ha_rkey_function find_flag,
MYSQL_RES **result);
}; };
bool federated_db_init(void); bool federated_db_init(void);
......
...@@ -715,6 +715,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ...@@ -715,6 +715,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
*/ */
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
} }
if (duplic == DUP_UPDATE)
table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
/* /*
let's *try* to start bulk inserts. It won't necessary let's *try* to start bulk inserts. It won't necessary
start them as values_list.elements should be greater than start them as values_list.elements should be greater than
...@@ -2434,6 +2436,8 @@ bool Delayed_insert::handle_inserts(void) ...@@ -2434,6 +2436,8 @@ bool Delayed_insert::handle_inserts(void)
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
using_opt_replace= 1; 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 thd.clear_error(); // reset error for binlog
if (write_record(&thd, table, &info)) if (write_record(&thd, table, &info))
{ {
...@@ -2761,6 +2765,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -2761,6 +2765,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
} }
if (info.handle_duplicates == DUP_UPDATE)
table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
thd->no_trans_update.stmt= FALSE; thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= (!info.ignore && thd->abort_on_warning= (!info.ignore &&
(thd->variables.sql_mode & (thd->variables.sql_mode &
...@@ -3226,6 +3232,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -3226,6 +3232,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
} }
if (info.handle_duplicates == DUP_UPDATE)
table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
if (!thd->prelocked_mode) if (!thd->prelocked_mode)
table->file->start_bulk_insert((ha_rows) 0); table->file->start_bulk_insert((ha_rows) 0);
thd->no_trans_update.stmt= FALSE; thd->no_trans_update.stmt= FALSE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment