From 50f79f56a8783376a277ad840c78119bfcc4c328 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 20 Apr 2012 12:02:32 +0000 Subject: [PATCH 01/13] Remove obsolete art. FossilOrigin-Name: 372a90e2264a29ce543c093766cdec764d18b5a5 --- art/2005osaward.gif | Bin 3750 -> 0 bytes art/SQLite.eps | Bin 24155 -> 0 bytes art/SQLite.gif | Bin 3062 -> 0 bytes art/SQLiteLogo3.tiff | Bin 85156 -> 0 bytes art/SQLite_big.gif | Bin 7428 -> 0 bytes art/nocopy.gif | Bin 3449 -> 0 bytes art/powered_by_sqlite.gif | Bin 3391 -> 0 bytes art/src_logo.gif | Bin 3348 -> 0 bytes manifest | 18 +++++------------- manifest.uuid | 2 +- 10 files changed, 6 insertions(+), 14 deletions(-) delete mode 100644 art/2005osaward.gif delete mode 100644 art/SQLite.eps delete mode 100644 art/SQLite.gif delete mode 100644 art/SQLiteLogo3.tiff delete mode 100644 art/SQLite_big.gif delete mode 100644 art/nocopy.gif delete mode 100644 art/powered_by_sqlite.gif delete mode 100644 art/src_logo.gif diff --git a/art/2005osaward.gif b/art/2005osaward.gif deleted file mode 100644 index fa6d7d7c2761f603db7d88b16eb606cc7a29ff89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3750 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 QI-@jNqc$1?34s6rJAm}olmGw# diff --git a/art/SQLite.eps b/art/SQLite.eps deleted file mode 100644 index 1f334ecf7b49ee6e596802d5cf8e208caebb034f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24155 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 DOHLiR diff --git a/art/SQLite.gif b/art/SQLite.gif deleted file mode 100644 index 5ec05b0be2aded7c2f7aafd23ff53107d39e4362..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3062 zcmVgd_z;l$O@&)wPR@9lo1n3A%nwadh%z_;`E z_3rcW`1<+w`1k++|NZ^_EC2ui07n5~000F4(8)=wy*TU5yZ>M)j$~<`XsWJk>%MR- zn@>R?Nv}Ja7Zi~k4Q%VaWFWa(C7gnSR}95tajUa5E9X__<2YW7~Hga%}y4Y z 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 EI|CU?v;Y7A diff --git a/art/SQLiteLogo3.tiff b/art/SQLiteLogo3.tiff deleted file mode 100644 index 70b88e78057d7aa046d489e025273ba38d774c1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85156 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%0A2vxehzOjQ>q9f8Q0p_RnbfbgOQW+j z8|)9bf_LuEW_|0XmodQ@Ewh*$1JI4W3>XbY>LC=J&MJGD1IegtU3zPmv6F4_E#W|$ z(`8)Z8d4&P7u+NUrb;A*L%X{)h|#R%*Q=)W@Fwa{ES*!__0@glx5}jrmIJpo*%04f z@W*HDurG1Y91e-cV<@o@5AY8p&C3E{u5-3HA&2`oE4`onAd(w7T$D$&S)DF~Yj?3j z7%<9=!6fvnB~Z8%9KTn09N9!KjvmgmZgUw$rM)s*>Xs1frbz?>mF#084_7rh1%!YQ zj{_i-5y`YgKzEXV`w=xH%D)9Ik6Hz`BxgaQsDrkSI=s-JzGE5a0#2i5s2KTCOuUxW;6LgWi zfOwH%$q*v_-HVv@+*}KFviXmC;V{JmiuQ%#J^1>YM8Kn>_^B`+Ni%6MOGcO;G}`a2 zldwx9>W8b6Lvw3wwZ>~9{HnAjiQ8h!lT-0?8?FaMO|x7CIu_wTQVGThfXQJdk&mn+ zpIEm)H^B)opk-MlEmnR!WTotIy;e}_(=g6`tUR&vcJi_0`qOd8xWP0P9&nnVgvxQy zgAF-8IlSw>nfuUS(?$VOYt<$%<6q_R)8Vc>@b+!4>Jfo{AGZ3D_5V=gL;C1O(M}(gXqFc%si0>$;ogKh)Kxz}3BU#ifr&rTY~q5rz`Gw8>LXiEQe8p_gVnxw>C6@Gj|xZ zS(@?sfZ`ZBdB5Xs)itj9nJLdGMvMuBYVR?Jz6U(kw){mPKiZODcE~y3Y)d=F=$c?} zXC@7HwHmRjIB=+nE?F6Zw&BimJYmD;5G8+@7k2*4+WlJ_+I*p?O|kDoZbGZEBg9fx zayvh~+NEvRbWotBrv0~Bww}dXEd&SeHF&tWEc;^~6g4TVuEv|Kh8a8ckC4s9F!k8q zNR|b2hZQ@-#gElj?`N%>`mZT8Ri#h|C#ou7HzjC++O`-YH= zSh#w%rQ&Bc{*ef2TWz!z6WWzeeF}sTjIdy3G-qI}6hnRw6~VuUT_X|d_*u3Ml73PL znc<_gby0_SCRRRJVDYn@&RK>4ZJ3;-;1;8DRV; zqjqb9e>}T*(u91qL*{{veWSAomz0ip>;y=neWh6$wfEKMP0g?t|RLqgG*&4K4p7UE{Z$tuI=ca z8n>u@PHbu-I~)3rrEBaBy$q}^H1IL~97Z*=hk@AO`Y42jJj1zF)rC3aJKLRii(j~S z-_B>;H1Bx`8%2Bam14XEi44C-%EZlC)V}g}9sGVLThvyZ&W48|fAu>gxM&iO=gc9| z3yqk10UU@#hN3gZnG-CI5AZK*aG8DdQj3y{|EjF^$oG9Rist_PyFcH33KKEZYu`wM z$f}OBFoHA)rAMUwW;E$YFJa$oB+fsO6Qb}u_yY&xAQZJ62OmLnpPfX# zvx1TuVu9YplPw7<5!exnsna=)<9W681%+y+`bCLA%R;whaJA18x|M zh2|-^HJ2UZtvpb*D{$KnAM%;2PX-suLab+v7uP|NUo_eMfW`gg?$;;f}WD;V_?oUpfjgjNh ztIOAXp6~6(1&*=5y*Z%MWloHSP(xtQg*PoiK(}G}Lymw^MZdtsQzZckHJ6G6Lm4@E zAn~#V0U1o#3&r-DBc8?ulYdpf^d|Y&%%D4Ld4ENzwga@rMlzhC3Zc89tdSc8=eoxu zkR(%;(ZFut!tlGir$GCL18V-O4B+R$mBLTv4;UfAEFZDBI?IRCrS6c_KcB7EF@-hu zojzSCXu z_R*`JHcd@K)F)pKx~;G`hyV>!VO*qg=6cbeYdwCTU)#orA$N3*yAUD4SRjhx@bsCv znas!;7ugxt?K;?hVdqC+FBBtWa>R=KpM2?3rJOgR`0|4j@!(C6)=}G6hfDU?G@sU6 zKC{tY*}Ufg>usvFsbK=&99C@^H*#NnEcRdBY890BQoAjC?nUMjJ$G3?Kpdpcc_VWW zSuPKHFMpm>{{BkRU%kBEIX5e}yqNEwW~11Mi;!9I3LFwbJPzPWVoEiiU$(8fN)F_5 zytUqM?2kYRwMWPgsYsC-MAnV(lbh6Gf99HBshF9|8@oo z7+67x8bpA@@TdgOu=hM*YP599qs~n(B+oV6^yhj0Hxxvr-2)MPZkJDzj>PtE>+88s zJC9JP_fn?B4W5kKKR+d@5G{SsuQ?(_J(qt;$9(wUGC%$?@PbG4xaDgZU^r=tcyX$U zMUXUN@^&O~;!ytu?^N1oj~L{b0x_8TZo<}8PWn-FBD?N8sYClNyYUNrz@D9*#)D=l z7+_#wO2E<(#s4oh(ni3UIiY=%Zx4aI$8eNocla-)^YY7yjBCb!<=gy&FP~smh?Nur5R8XJ8u?z)I*Q!(;uc|8Ma*Zwmko?GC$DK?W ztNZW1(RJ-0DaAy1nPoK|As|zkhZ`f}5(WB%j{WWt8u?x8^KhbC?JvR`pMMT3H6W%dFWV5{0Gi>=H0fpbc zbr|Y+viIF(!HkeUoVQfcyj*VFIKy~O%7vGY{_Mf!?H9bsknXlP^v!BKT_yJfMB+>d z^FI92Nmlu+G8y-%?b_OV>Anu{_>wFGzV7P!@<1!8F&f9iHzWh@n05t5I5;JAyLtOY zh>Xi~CMK53-|PU5+wk#`9HJyDW}~TC?Y=>8LiVfNYELHdO^U@B?dWq$tS zXi5HSmd3y}F)zOfW>S42jkUU4&^Z59Hyu;B@X+DbiL|H^ALmai^e4_Uc17hm-`iJH zm|y3VYGp6(OS=C@H-*w=kD7KeV8R+*n1wjiX173lQqy-^wP zVNZdn1hA_a2}&M@cW=@S@myckrMg0l!srTkha)I)4JEWE2X{^dhBPh;33Jhf;v;&e zHmKi78)m>4>>C@HsFv*b`80e*BP}6ahI2EC2lv**vT{;^bH|BXxd9xK)$rcr_6J_4 z4)qER&*}hkbCC+qFfyDHYnu_5%i4s$(kQL;Hf?|AG$gzn$Q*qm;Wp? zwDW-TMA}Pc(2^J@#)%CZ-OWJt=U~=hQt{>KEzaljvWdx61N5*S;#b2tH@d_VXP0^A z*rN)?Mby5#6$#BPZ`y9n44VIux#&IO!cTL5KJ`Q$QPp^gOXdy-L$t^LowJFUf}Tmm ze-F~TMzQ|%cJ5pj*s;-(PCMIkfSQFnvsGSITLKa?svA5xCziKY_J}PWW}}*{AF716&4)pC{^4ChzG}3Vxx)%r#s(^bFkfEi#(N-ko`vs zxmngB)-oxKYq*6X9{VK>#j;vwPrF~lj-(3ww-BN4FGW7e8-@=)3()?|L3x3i9n<67 z?T~$V(Ux=nw+yqZEMMwp-BSk$LN|U74kl{}lOquf;sOASj)h6k%R1mc)mrBg@c%DT zG{ezaRa#b@^&~15`X=AdiSCb3OC1X3|7%4g1MP~^;Fk;AC7)Nq4DQ%3KG^xZssE*1 z_S4(DdhwA>p`*8c$W1EwkNBE^L6p!9Pcu2gA#)ew!_T+f2j|tETt2=5k1w6ondghF zs4;wZe}A&E>d38g(fXQ_DtR&Db*tNPq{wuPj>I=8wjBMdeZ>D4e)O;QaasJWv7^(s zmGp?e_;^CI$lF@s#>k;4yPLlGxx*+pN4gnY^`k@Ikuo};bGxx5{>VuAw*5|m>KFAO zgC8zp^Ni1p?H`T0C+4!W6Qlm?umN#&9eim}D zRIc2=ufK_!XWhChW2(0I+{lwSW61gDP?NnkXYDj+D|OFJuoV069`q4n{Uj@bybRnb zT5e-D6oV?cbMTn1f}9eksap@6rwJ(x4)yXTNGlE~umh{-hIa4M#o4L@=&HF%f^_{` zzF5E=EnmaLVAkTE_x|MIg!eRmKo}j@zPNYiWTvFeExj>VY)A9Mrq2JDPX60A0qG=L zI8C@Ncj&4*YPIL8X!GhDDMCD`MS~rP%fGU>DNfJW@}=wnvo&jglUvdcWP_!P@5LGQ z9zX=GvG-ljgb#C-Mi=;`oge?*shDA*NBgJjzp1WRm?|KYx(CpG0-5(o4HfgX_i;So6DRJsL%1M> ztm`avrJ$5OQd`BI#@$D_V$~z>6u%rB-lV$}F<883NbvKYw}1S7xgo;I)V)!5lD!97 zg?o4g5Pw@L4Ik@<8bWozo^IaY4ecBoinU?@v52YMlH6 z=z65l4f)K{=%xZ0a`FLpKF>#3nLp5tq|})X`x1)ULM2!eK>eJ{y<~rBHa6_P@jm&7 z>A1@Yb`y7yV1iUzKfbygmjt%~iN-QowZKe|)M0jKa zgQ~j|NA0rJcmSxbA`~~WD*?f#n!woOL*120ZRsc)&VYrBE|LW60`}R2R9az(W#vpn zAP2MCUxSU_(BCTg+ddcRB}j-Kn;*fjMDmzodazS%Ow_TtGI_Wr{p6fMy> zty@Pb)k2<$Lh;n1yw~jCE5B`g=<{YOt|JLn%WE_0Z+C9QNFV_zIOlz(Qs>23%8gCb zTF}JJ<#hp5$!xBOHA0=kWLbQ)Jy3-dW1QH6fO2?P%@nnmedtg7m;RQoc1Ag#T~R}B zpR)$4lY$hg2=ks*jqTmXjK^&b0akFx!-&aAR)GYI5cb}d7*4+gljU9mF_-mf4bo%# z{=K*L&f!NX?8{vsV zZRJf&8(mfPVk8@dhRl|ZL%|qz4vEE)gLq0D(){oHr?eWY^u>@LA%Dr2LSJ{6?`l0z zmICY}ON0cK3?8G*wjMW|L~y7POCnVjR%!YJ7^PL3fI5U~bG&a~2FKv)k0?v}?=SX$ zHe7QsV=FT1AgWlvyQ$j-3%EC&8?&-Z?_nb@wq^9leCM~AiII{ABH z_@S9hj#RDi6U+mL{_X+M57ZjWkQ;4N&c4AZe}jHIopwV}0YNsl9z;Py7)(5Gp};{Z z$rgj}6PL*Y@`)N#>2JLiQ}x%~!I;}PJ)eX%cJR0XT2nFwMv{_FoaoX?Isg0P_2%39 zTyLNC?|u1dd>DAeJyq@Pf977VYMigU_dPLzOQbsLf6d-_-rc`vPIF)G&>CXpOra_; zQTx1W#^rf`a|+IRT*(Uidb_fSRE=p8+A$Ki(3wN&V4ZBOq6UM*u+?8>EAr^N7Ka+Zm zKxjl$u`%ixn>%=Lf+_gZv*z`$Ln0%Nq7Slca=pK}(Y*7&+{3*5~ec559h#CAkOv~H@zrmXZ$xx`&X zCs|ttY?AERBw1N&X&5H`eqblcY?>?&nLuyM$c22lKZT-w6*KJuD#|5eOLPBM!CE7H zUmfbxerse;I49?ucO%c-E`KCdejdw6h)hnYQ)9J$Bd3^>>d{buV69@ zzs%VQJTMM;w1=R0t+03-EM2-vUP`nT zfm)t9nYnVps6~)O7jOis^;eMh092HnG+sr=r-Gfb%)MOrPMpr7YC%hH4;~dmkpcdp zuizq?5%Zoi%!e<`|2wF(kT}g-NmKyMa8Q16hHku2y)57dy^0e%&Ka=-0F^%Ohui#E zHlyUj1qbaMJUs)}H)zShMI+YD%0d9!Dt6}h7%=%Y0xW;rLMO$cXi$DtXgo}6px*oD zTAl^tJHFS-kE;DeDz{K*07IwGIFagcWetpRSpww%whR^yc!jJAOS-XrN=wX~7SyL7S29aMa<&U~{fgNKm%0BU)Sf1Kyr>#oZi^{nfW z|I6>D$-b(19%Mrq3V-lE*iESIFO;2bO8kildClU73nqq=Nh_7Cym}DbX|e#I46T2= zYnV^DFyA%*#^Y<|I@hKoGEAOt&XpJJ;0-n5;&GS^miO+>s|@`>n77{urC349H(31p1Rnxfe5bSn58vxrLdswB9kMZQ2*|>CBW_?5kyy14 zr+A(S4NvMnkTAkC@UG`cB*a6(nGCWHhBlPK#n5ZURvMet*4{in6fg4CDhrs*o??jP z0Q4bXaVshPX%H(zGx2yO@x9qvs)IMPAl$QT?DFdziR8oY(u+)0KWaXy*37cw8309% zDiGnJb(y7FtgU`LkgU=TD~?-z#ptpO`dOGfn5StXB7>RbZk68}qRHM29Uglc)zo*U zl2`7bl02+ykcGttsn$(AX4p<&WpekFO$3QCZ*9N>tKgNQED!15I2<)p8_ucKys^;G zY`SQHD}z&4IGUt7$W==q;DmM*wX(=g{J|@p9&Rq@wrwJlO6m4aLD`hqDHO|K`Zyd3 z?(xt?iqx8dVjG)ATi!^KllPdN`#1;foVSFL|7mB?2;%2=Tw)b^_R%cL6n}1$dq?D^6EHSr+VHd8F&7X*3%tNUHh@z$Z1U z@ky@%sTBiNS)h_E^ol#c;WZ{FN8e%mf%v7MNQN`EA#7UXAIuPVGXW5wRCp^H*i9C; z7Wxt>f9k~gCA{$!@0X_NZ&xl#HOwkbhZmW=R2t@a=jr3?jsj#VTUV>qnkvPl|e__89s1vC}m8 z#62a5ii}h%i;~t|%X&;ne3@wOU43QK`Cu_khn#BrEy_61Tt;F(JCi ztb&ygq|GsMU-9twgYfzmkKU2NG;)fII;bU`C40ayrBO0|AdPQwd1br&H8MGf5;)(W z4Ik*_Ny3LrHQ?U^b+Fr|lVCig6zP+)fkyVyJ{w!ut zHqZgm;tnuRGo7m=bvi8sHV#59q=VB>^y5#S*%_cIWD2bu*vp%adh(2}>N5#?1Y zyv_{YygD8kAIaV=#)CCc{bdD4FN3@NQ)K(j{yOWC;esu0&Fx9Xs%T2*1;HqTF?O1~ zVdwp*nT4TW+26ipx!b7OQ6MJ1R68mSjaW@H7J-AtYq1L#d_EbiPsVK@_TdR7%NrGz zd$s3+SYw({>+Q_lza}z8RIef5iO-j?Pu)q+Iin0R&A%0@6bWrdibgCK8;OPNR`KK0 z75K%@^F8CT1WGUE6}2^iMd~aCHYgf9xw_=SW8=t(+{ibPxSAShpq)rd8(T1O`W&t5 zK$S4244kAKORBQtcS-b>-~Ukb2^D1%aTnsPj;OIxZIouCdxi&Qy9F691@H-5KLc@$R_DJ0p9 zt@IC!b&~)b$Yg(^)EAJBmW;eCPC2KWLuPZnCqF`OaAQ4qd-=e($P8EzuXLTNaC3Lj?U-NZtc9Y^imQ`W2fG7L zFxn5G_Fb|`^i;A3v-1C>NB8{}KAL9i*1C5HEC~j1Q^aUH7l{5f)UXZ)!8;f!{&TBH zz5=nsAorxE+xIv4MPh_#7!uPsf<2Tq^Xk=W=Q%dERPk1P`Z0#V=U}hz1nMaAoYi+Y z3uY>E@EM%sx#1y>qtv25i|ISKPTdNj9hJ1)Dy!Pnj2fb1VL{NocT$d~GlG8eIp;9{ z>I7_50C+q696YWG{FXw3F?P(YU=4T1>;6171C;Fw_qK}Q#~@Wk@2&9XqKm^)yex30a&{z zTy)CJX_w9Tnz?5Ui+4c_2v(i95^zbPJKvf{Z%WqJ3S@NG`Ctkm7J_s7Bu(!h6r8q*K-Jd8Ko#`@m$WSVmOab=|ewhV9C>?Vb&} z&+Hq=&TI6#=g?FHjk!L)um6X=ZGlqD8cU~w1TY$$>^%TVOoY3@G$xPPAHF#5;nFC)m>FWm%)ixG5DAqQe(TUIpFNnRZWgsgBeqp>#?GdG|hD{ZS zev?8iI&Az_PH5=w6PLCQZel~79v1&QrvFP7XUBx|VCsGdX_KSqcdrya1|PwG^8pp`$-*C+-eWS!$Np z#odLWsc1HS;lK3eFf4C~fJAvW#PKmX9lFM)|2bYpVr=Ja2#au5zoZjvC)w~sp5^y| zClFUyMcT_*N5R-AH967$!_=8aL*2jsf5r?m82i4?jD63(rOep(DA`hG?0X2IWoGRA zPDqS3l0usljeSi-C8>LCp(I-x()hmJ_vd%c@2`%Nb2!I)nb&napN~hL1(|tzBlc9K zU9TrTaPGL7F<5s+@vtMo=GAzh*3Mt}i)<;^H?RYr$Miyr`&=<2$*3boV~_7}k-rgN z<5ln2n_cUG&&Fa|2fXlYgd49sHU&lbIe?WS{^z{?W)@0LH20sSser%qAnW_cmE{6c zdZt$ga?Q7C;gx5+oX_Tv#8dVoH$7DG4EnWr<(UN#B*NAGp-Q~1<{Mfc_j%|8=i2MH z*>9B&61HN2CfpBtuJ4O~R-gxKb?rTiZO{VjGTqnWp2tdmf*w7^qxWoxz@5++W6PJ< zBYsKV6!3R!hE}DAm8qJdD^dZxNX62ureHYEK?eG=h4yow+5u54s?HcVE;; z%x_;MsPfFC;y>*cqt^*lKfl4xqs{kSg;|Vod#Ad$mPBFkl%coP4fC`%P2?goxBb6u zs8bJP>41jk{#ok%yfnJ=le(TcLPB& zeq$P)YMQ3$?5yWK+;+1mDv!RVpIBNOr~lwN(DF!a`L|OA^gOx|s!`})vA#Z7$uX#dx-GWpvcqW4Tajy&j3BqCUE?*gR=U0-DYCi-T+l=^I}{8S&*;2- z?dzXcmk(i(?y&1X=?R3wfPm?^$T5;`n=5ASNUetV^6qWZuSZVpl|O&&RBMk!o6UyO zW|zx9g(QF}o7dSdo+z>LJ*QXuK18S7&hOmwrM(-5l^o2{-04yA?*bpXZ#!#-crRr& ziK;!Zj@PccJTR@iIve{!#7;*tp#F3A$WfbXvs1>Y`j0`+E)*!=-J$o2*v(X~eSdrN z)wNEUbt;wYu7)8&0CRn&4F7+3LIfB9UEcfW-|IEqQ_ti0PWb0;`={XFC9~P>N9P^? z*`>{H7aw_c)P%@O{%zmRs<2P3wTA;GqXj+pE?zMr_K# z*N)~18_^EUd9Zkr7u$kmAxnBk4W3HM#Oq~y-%75UxQ-M} z30R`~xNh7i5(f-cA;69xt)_B0yYMlO$t2w{5JqckTxcgd3NXo>%mjn8!yPZ&>fa-@ zE)DXJ5pIcC(yf1_&~~0xE<`WitNPDE1>CJnu@!$`-R;{tUx$3|J6v&R&N|Gq1R$>t zRxS~w2)Uw-be$a-?a}M1c+RAbNWs>lR8Mqnph!82dYUs2F2};UDVF2&aqrH*cC?!t24m+5`YEbxghecrQlD$HCuCcijBy&qJX?8WT9a z;q@3FlaW0x&PhT0LRV5XnNYL}5Obee^=Lb2{d8OJaP|gco0^$wyrtqChSzu`y>GtE ztJOV=fk06dQFh}74u%G=n1^DcY4c&rj4kgx6xRt4wrFKIu4^ZLt`dqQv=381ib;B* zqVgrGB;Q2ShNBmyf-MioH{8jhp?$oWVkP3pRQGUpNCs(PUKcp|ZK=e7A# zu(P3;zhS@bTQTE?QV@=l0b_BQtLOTep7|pIi`np`c;YKc0fYr7;ZF+Fe2y7-uQmAA zSF=Y;ons5CVn#V)z=d%#)Rv`^wx!v?%e>Vsw2brZ6b1j+!c`XA7Yf@>A~#zP<@2>A z8AnW0&pvRndP{_Y+C|t_?2jc`_xbXVkPAwlg_8W+@hW5hI%9$ANsQ|x+ycRcJeF$ zVl8kEn>nr5l{Msd^StljV#06tRQQLYr4OoW@%|UT_gSA%J2ILVK6I9ibVA%!ku_~U zV(L~^N^RWzLGTdsPAf)IY8umOPA=eE6dAuqUW%a5aC6zm# zXs=_gx-O;FSyAiQx7e?G#HAfF`aHMN@3V*wl9I~9Kr(l2#_F|DBiXa?J$kP@3njhE zW)0?pu!(n`JK=vhCx5zuQ{r<#UuEfT1s||>muQKg{Mkucp!c&s8atfrzFoY~9JSG{ z1tB*GX6D+l^?;7f-+QUeTx@#cD@*tt@6bH1)=JY9+6NEDb!XP_&@YwJA79ywK?cIO zIT;*GxFiytS>~_n43_NNsSQ7KdY*pB5+!$Ya%gX2XWHY9O=XT?Xi4!Bml}MQyAyIK z4|Cv_&bQ!Xp!jP8mmL=b9uBO8Owz%0v3^XS>B8atexGYLXKW&Ex5EDz{5pwP1HY8? z3aDTQubTDyzYz37NF>%T-~3DlgHUkjFqnpj*F6U$Do&;TVz2hrOm+BX3Nv4ptE&h& zFX`DGhMUjSOBvc{R8$g#IdFwKb$m?bsXu3Ub;p`h>qLp0vX$39)bI`ZYi?SRnH;qX zowz#eNX_=o4$BsTG#nwS^~dfkQZl*nHI4j@*%fyqgO;U6w9i(b_sI%r9`|Pf%7Rj2 zm}G(8SWd3${EBnSe{3hZGLvNMmCE)f%6;9UKR_pdRgk^B9odMr>X}e#m2uYASgAtf zBAY<`?#{VP4|$Vd?~m$cP7PGbwY#zb1uFv(aErNIyqY=(<=2_>C2hij>rE%Bjdge3 zziMq465dAX-fd`le+@$Cc6Oc(>F@ZGv3ob!XxP-ck}meHuA_7fGFmn)MV0K4u(iO4 z0n4=rUWv_P2&VL4;5D!fGVbne@^R)y=oa?^V|JED5G{KRP*Lqp(skpAM@TW-LKd`- z)BZP`4>${EM0mZnV^rIH#5z^os7w8isasQg&Qm>erRkm;G7}L1_}xBaVGna=oi9|+ zQQJKIA;%NBN2zzhbQ0;+Ee|x zlRf*KSs68~@Fn=z(as9$Lf{5K z)dB4gHNUI~tCp&hlXWt(SUESLN$qRdS&dXZuI8-pu}0Tn=f3U0~FFgpXYrC_+^E z^t7_sbc^OYFufql8M3U@)5lP%M84TATqKnRtG*5;I|8E&IIcvF*u{ohV#geE&8zdE z?F2~qLg-|X)PXJ|?SnkGu5fqcYB&?Hap-=@HyG=A# zpn2_hy!Md&`;So7yX;muQqmH`lM*EQ{)C+?XUot=$%WT2Dd<1*0Pc*1(#A?`2VhpMgTNTA>>mEhPSWb8+0X^qCZ;rQLG@ib ztdoWnusY`7O3`LT(_sU0|DxL*Ez#P%>nveytCF7fN>#4v_4;1a9~v^XfhiV`gRCBJ zXJ4b%vJ!g`==J7Q;b45DmZ#h^%p0wFI`cX2$P>=m)%-AD6w>zr6F5x_rGn5f*40ST zy^^L|19VFH!Q^0lVBCaDx1v%xEg#>`4@|Bb;kWs={|$3s55&r9MH^S&Y?(2Vy_5+Qv#N_=srB!zN zkkuvTu5vUDtdPHwSp07~y}ZAN7rBxcL%hcU7Si{2F&*Ka++{h+S4O6OKFOfn87wG? zPp{>4ME>}45cE}~MS5&_>BBMRX{-JK}S5s4xrK$Jk(T?1fB z9|)G?gFWTP7cpfPo$S5lc%oKlc-|U)0|$v+t4Z^}TnV2HYZvU= z*ndN^K}0E_mIX(ZAisgg_65w|6dPNaOQvfgJ-dY#Pm$YL(|m@w0ID!{7D=MP$f+qm zzJZD2-$@`|*=NuZBUhd^slf_6c@uN32b#O}TDz2tpPx+g&${!_EVyW~cMp33Ci$wZ zB;$_EIDDU@$W5jXQ6>doBKMFcixH(wz zqe;j2$|c023^Vz*Z?ZTNgcd^8>QQ7Eo|X$^pNDWjk{_D4UeApbU&%zyeSN9uobp};zN`-GSjdodRP%DSUJyfYb9SS+yOmnWj(P86#Xw4|H4Vq(N-!M(=H%(7r>$0} zdp_r4l$*Cgjr&k8Guy5wMyL{bN9uJ!B5=ET-uJfxuGuace6{mu1nLQs zW9L;S*M(@=i$!K$tl|8MkeZvQWa7w3O zo;++LQ9t4SNreBvOp=fCuy?c~*FeEZ%_oK3C8CzAQ1xl(_cl}+UYh-I{zU^j~Z6F+?>JC6BO0;$vvS|<5q~uxTAzWY)=Do8VZ}P{M`BG+x z*3ic=@_odE2r!DbQm5rShxcB=5EH(dX<$R_gOxbhcY`$kB#0N!x(Oy3@%a`ull}&u zVbsi~SvEOAsvbP~?iK9oD0Yx|5K8eM$n};n;fX8UCH}n#svk2qtwq<|;p@|*Br2)~HIfH`4*k0E z^g8cl+2$AEmXnMvfn(sW{A{|S$R!(7E||jGs|1(rYS|Sjb8_6d#lj*lvv{4@5=Y^7 z7je8UpG+YFGkt|Mmx&Tm_gm@MmPNH=!F3@hW1J+FU97iIynW|_PGO-}zG~}@gv&Q3 zx+JeIN(mj`ys2LB!Kdzf&YBQ@b#swj(4?JBwl-Q(To-)bgT>3^3gT1ieE)aorV{20xTz8 zw35Gs%Ym8>pb3p2Tty&egDZl>919$8n_^5RZ+j;o+l>vqd~QCX6WW`e|8O&#<$TLb za(nVmHlEI2Wh1B($ca@I-6{utuRf2`XGGyp2(>NT_|XY;LC#J`RVtu95Xsq1(E4($ zKFB#%9|&ig*R-~Oi<1D#7d7{8A);`L+0ApU??%h?+2GK4%zrc3GpoG9d{9AlSi)ef zr>hc`Xev<{^we6q{73dXulpm9{uZuhw|)+PFL_VDCvwn5`|2Nt>8?m~=j@no- zTz@{!+>xcfdZO4~fe(0ys|u$8G_X}H9#o_*Bf{~|(j$j0dZ4x9KP&GtPSGfp~cl;B5QZ~DBj_aLcGreh>%R0HhZt>%f-`D=mb5g>-cTrh~yjS+!_i_jT zw?3MXn>6{DkS}w^z~;93&V$^VjaKcP7yfHjmuu<*`d*%}_H1h|%iN-0EdBcNDKp^Y zR-l=Nd(HBvGPry(6Z{@)REYd3tnX}WzV9J!e1d1_oYBf*aCSkXk~C~MEVAsoC7W?O zq0r$)r~JS&wDydZ-B`(Y>&?X86E=3W0!$q$rJ_DfeGbW8xkB4wa=xWpS)78CVo7xf;W2fH^bs+4_(^P0Mbya8#Ua_tPTHP}Tt0c`oNrZoSh*$< zq?}n}KOI{M`}q6JyI-Uur+0%|frPT6p7%IG*uJ#~aw#O9kR6StE6l9Wj;BPcn(PTn zj8?|nCf%wxu}`w_+%-w(I|z9?V7k_vAFb*Na{hDijd)_as`~V^q{Y}v0TXmH?!>wl zLWRye{TG`ojX=WbiWT`X0iTOP5^$RsBT!cAi8#-gdc_P++JHuuSIpOwIbQorMioR9 z9Ko3k?jHIBj04J*XL`GZ!nv18bgY0(_mN8FvT+ZgSU#NITT?gt&7*nckIVzb!Gjh; znSUca$V6sxDf@O=D}A!2e#e4P;`_wRo^Sbi=&9WI@CPRlUV<)yO!yKL?!@`iCRIrn zVtkQ}MlSbM5xuH(3m&Oq6~`w&mN$Kcl8dYTHT(`9XTSFU)-j?!dv+{)^+4jAyG+Wy zFQu-fFIKd2+3p6qrcNqN61iD*B!}E~yrXWzgS_(T>czgYj2bCmuKhnrR9;n+Sx_vK z`)yg;l7qnA7H%femXj_NjPnoXPA0AG6eW>pK%d8GbB>Ua$fZiiN<6NKmB-0j&HYDR^*t@3_7t>T&xUUSp6s4K>Y-j4^$Q{k(hf|MigXHAal_4-G1;MbYK zCTBmF%%B*_)4}R3fO@ab9Ge|z=)}?S zxC*7YV3Lf#op$+`Y`)`ttJHNka(N;#AlIXyq6j@yuk$-k1;0$l|e*fb|)umZ) z4#f>m4CRBamvv*Nnlijo5bM1<3xDV@x1OEeI~1F`e$Sw--r4HWu!5Mh#9C=t^m ziuYClBt%Y#TO0ICn$b3yKW6IuuV+ig9G!yQ<5Hu-!9-ngD0v!~;ru&FVVppE2BN=zToWry?3}QXRB@WU!z-ww#8ikwo_a&XuwrZdlIL}mv;F&JGJh!Q zw;tJu1sg>>a7#|biT_~l*S@Q=S80+$lTL2g$E?Z}6<}FT*ii}mUKUB5gI^9U)Zk~* z_Azqk?J7)zb?y1+hdN%K!Tn(!f@&9o-^WdK5jW9LTo$m>3_X#webCHDj&TmBYX?nv z08^FDvd8Iirtl+9em*ayWM~+;K^JCx9||DWSPOv(mlV|#v2|ao>0Y@9022S48pm|}RKIZfZyc!`gJic^yTNU!fl7TvGq zMTDLoeSS-O#hoe)rL$X!mm*EqQhGryk zsvvCANpX(-(X73pN=}(DewAe67m*KN|K$8xotnFn+hr2%?QlzB>clmVT)F69n#t)l zcfhfd&&p0)2e^E*_@N#(^m*omPSBaP0js;Mk}@Yh#BXk=9&s zbb!x$DJvPne&$)xq&|N{o9S%|}kXIYqQ#BW*E^ zbk8^qzwA8rrLDcAX7Y{n$G30V&18Sa8eh$Sm*_vFv>@og zO{6If_#Yt_EY5Rm<_jB7yzwSN!L1YO@NSC+7|Bts>)EW~!hL5uXqfqPx$i9tLSj+- ztY(<{+@%y+yU0Uyv3NE#5f}Jr-FTC1*<I_p!cr;xt+femC12Wg5I+*+zM*`Da+>#p%J$y6((eM)&5dNF#-$nE^qH zc+l(H<*Wc-OANqqrIP3(eVgq+HW+N-~bB@XGjzUPMQud**5DiN+zDcy4NjGp~x zNeyD)O(YBx18ZD-g$l=5xg}jOC}uqgc??(5RY=+Q0fuLwZ%?5KE0m9XBvn3Am^@U~ z1ZqK0auI{!c)(}XYITvAB?0VpL2RZF7C4JFR1kqoCK3P0o~omGC4R^ddizu7FaxK$ z$YZrjFBBMZ&`9_<`?}Ta^8NAhSzKoRZ$#^;Xliq-KcR>E8oqv_UT;WmGf+6AQg1t} zERVDGx{8`LZ!hy*;VU1Gy&|L87b;7w$mJjp8n}f66%_G|eFq^Bn!5 z6Q12>{kBt5y6?KB*wl2jXH^Au8TRM>qt(sIsz2Hd=V6N)B#DPaA}eS@8%rfTXj_NT z6d>)uY*`apa{ftyn~{>OXmyo>lm+s8%kwb8-E=3TfQd|myjq80Ekda^W;}K6UI)Vw zEbMy9kR79iOH!(OLf{-2#08c*d)l9wNaZB?%RzFDQdNx-Kc3{|-qdz^RQ2-GV5ViK zZcf{6Z<7(Z&KN=h)rBdHkl=62NG9|^(Hyz#;Q3r)J10ri4m=~Dz}lDyx7Kez%eW8D zRdP??iRn~G&3j=|H+5a}wzXMg0BpGRwj#4A>Qo}e0!qZHme{m3_Ap}mnQ&e(h8L~Z z^;qWg)k^DhYfraMvbBD5(5p3iUOJ6lt3-cPJShx%vZc&DkzYDzZjvS=);L@G@#B-V z8ScCf&m~Lh(!`}HJqXWVWsXX%HhE=}4;hENnQ{Zbxgy{p(UQh|fNw)W0iJ_vV4_5P z{126-sL~d9rVc&CC;1n<9{DeBk);NeXJq3il(8+e)Ak66P*D!$ugdJk%c*fFZ_m(B z2D~p$=XQQR%c(N>MKN%l(IO9w=9ENhBp+}-a40CX`u<=@8A7w-X}M@4)oUI`=%0H# zt`uwa=pkpIe&X#eevo$tT03JkB{gHF^S1xflB86BolXiNLD0;QNaxs;f@mC&T4Wf8 z2qcsci5h!vLUF8?Cb+2y$vA+u-$+@Te}z7iQb>oi%-9;F8FCfl z+hh6g&SxgioSAQ8ddG4ChnI|TwI3oRF|xB;oK9FJ#20ZXzx{%Q-zJjf`Q&sGMtV{v zZl-K^D9waAlrugW!c4woR-S%Nnz>2@!q5JqXEH}X4M4(8%ODJ@7=>n@K{KdIF<=zp zhg2A-Hi>_JC+Rv3JReYct(@HI0F#SI35%tuUY!z*n^Jl5GEIagui}%j{fX}s83i>GTy!8|NCr4MUQBx0*3|K$8McH-1a|KBx>Ecsz;e2` z2c5b+eSBuvg69FB{|UDy);{ca8nhECi){rCv~t%7^|vqoKDhBh$w8+s-RZE^j#{ix zuHGM%?$Q!I%5P`s`8M^)?YU1zie_t+E#aZ)cK@Gh7fPYwj8-w9?=vM&{kqHxJoH|# zwl=Yd0qeGIAG~YuUXUXDs7up(=XZfww)7XTR03J!&ixHZsh?WZgSjg(ZmCfs-Uvv@|Ehg%cguO=}Nn1-) z)Fq|I_p08@cX?R(RsTJqG$qg_Kx_?vKSnxva;aG4fhGNNMH)UgL^K60VOLlu*QJq_ zfD09e&C{e<7|2civLkR#ea=J@imZb05@NEkkY+9nE0=~~EQPs%Gf#8h@e+H}fQPZW zCE<$Rvn#d8lXkXw0Pl00Cr!JX-Eo4DTlekKzjZz>?*7>SR`9^7%M~p*#XG{nlF%)L z`j>I6%&}BO*DLhdI%a^rhCbu|`ux|)@kUSgVhv`z`=ESAoQuEMWF(GIwu3(ss7tO( z4m7>{mso5n@54lBwl*>AJdw#z+@QLK_wDcfHS01YtCXQ|TYYR6&pLMgktuV}`R0Jw zH#)UjCojqFpJM)e_fXkgL#gzL9l2b1x<@+c+u;l87 zK}JadM~V6MJ!WGIpg4Q1YXc66+;};u#`0cv< z+{SZS@gyE-?`}b`sxEG);sv{O{zpa5Gr9CGDgekV6tmu>e!bPzKN_r4{`++PK;zcn zwx%@V7}H!%$X>>#oqH!so3rB|q>WkdiORFsRxXsRn<5unrcWb(F`DqDRO`{%ldx&| z3?z`C9?Z|zbcnK<_N`xX>^a9 zDf@T+RDLDw5>n&+Yk9L*vv?$k_8ff&G?WSRwcdIr;9U**=k_n&FrdO%qGZ^6U+5~@ zMm}dZ--KkZ!UW+28`%r~VzhsDvqb@#W8vGR zhXKe1D{YR=A0mUa3#?T!Hxn_r+$lI!V7=yhT=`9;Dl(y_RZNE2&`Tz1d1qD3EP$Q= zQbHUUr3p*ev|@YB>t{2z9Zr?P*ISxyjugF7;km-9X z(mwGq+uitZK=o|)vk`f7HAyYrD8b+b8?;3_znxI#cjDySXi){vNX+vT8Nr5A z&^Lr(b!b>Hg};pM363Qa1tG+~ymJ^i80pwMQ(_?Q*Rsbjag#fRW`@8|I;4UXs;B*r zj?)e~TX2nGvCCF_3M&ztp6m8KpR=#P)3 zi_7<8xgAOL3)Ws7ZcPq6x70Te-w%^6B=h5}`+L0V|1kI^er_uro_KNBjpwemdf%4| z!?CYB_Jb1+?W>~4-pKszDKq|?r0nf*Hu+xfz1p_6_c7Uwpj8Pj^Og)Q;)rCDh6`VU zJecgdb-H|1Ta)!KLdaO@4LB9cj8~bOp8zpoQ3`y6t@exu)|S1*N&(er_pB65%ekbl zcbO`FJ;giCvgme%_!Rm*{Yq^!*WD4vYsx2uJxoazWM?4a)G8=;>p*;Ps`UdOUuK_F%l_)>P$6}nUa63PMeP@M|R8e7zKb+@5V@IF(h){ zoiX_4Ko`|AyZcVnTYovkM$)AHj>r;sIteAE#uW2jcrss&qxrhwz(#j6`+e77ha<#i z)b$vSLwW3K96OeJN}Or~+>AZHKqbK8(>;it<=I2=Z>Qwqdm~)A#3dIa!&pz=CnU7Q zain~io}E>UyL@pS6Hjy;>T$HgSTyks+W!)x%{&G!(#t}q1cA`jp2Q>2`21O&=24W{n)U= zvosf9u)uy-qb({p)-!3dcG=JIZ^dXV#agWsgS(0wRJFXS((f~)e#$5O*8{S5T!vrI z+Zn>R)9WPVzXra)o3DR48Cw!TSKkopgo$kZ_U6$G4f26vJ?HLM2N-1|BxHmcaw9o= zA1a?D3POo3Zg3J&PxNpQE52@J*aQ5}{yFHqBu9%h38-AWO@L(S&pE%^bzj=qjcAqn z6#K(o=ej-0EtAN!@4v2x)V9^%FDh<%Z#4Lu{%66l%{Ax7X9E7WVEdo*kGt)Un(r1o zdUn;Yc`i39+sRyT=|V!8D)Z-CkI=wSq!RMgU}7JPGhk-;%ngLMMcFZZ5=jCPVu{ud zq9I3H>f82XIW3*RayZMlJtJ~yPeo}9yQ&xGZAOZ--OFF2PcJIIlukPE{n@aQ;{dVO zJ=oONww&>(A6rZ7x{aonj#jjf96lU5&4Q|qBk}`PEau)B81Wv$k0oryKFVf%)HrkZ zzJ$?bCqF6mo<$`_Tm&4GxMh)_AE2;Jq6f;qc8S!{nG!+L0pFnLJ1MBZ{*2^15sJGlCw{9E3l_u2a#7WlB z)rzk#gPG~_WI&o$e`M~-LZxwo>Bk)qEFFL%COkyIvmiW+GY}vYT^0E++t80W?>t{f z+b8cBF>gC*QYXL9VSH9$3?dVdpTb*X1;XRtlO%335e`0L#v}* zADC<(Gl2qOpfE8&bymwwUF8(pdWoEWA}Tw618pf5ZLfzcOIjS~H>Ko)j! zxCj_E8IGS5uiDmqz&;~!iEkTJ*A3@P5?^4KVZw!O+s^@Ed%g%U^pDMdFc1Dog$to8 zt^-azId^L7bCJBqSagAuWFgn6XNp{uP^h#}YTRcaI6HX{hMi$V0Ya;I2u2?=4*~(k zG?2Lj_YK)?lAL-H@ZpZ(!~%N@`4lml1=sWSI}S;G%UyMmlQVAga>szm!d=C8aAS<` z@Ai>TDlGF^ZfrJKpzM+BS0vaoJ>C8Vd+Dd%1h1_q!|ENfr7$UH5@IsLr558r0tqsKZnT9&KUYeQG?38=NzCal%Z~*BqMc@`)%W++$X9m-vSG>9h6=MH=TK z&P!_AhnEhpwqYTw>S%EW=2lSPgW6&aY7DV9$V{~xZEQmnWn)3{w$qk5eOQ#pN9~of| zbH;%5j%Gr!as+J^`p3KfTcdbX_5xt1*U-I@u7G=GEjG96 z;p;NcU-#vHB+3T9x3ZghoaH@o^j^XcKo0H|BB>NEu)#QG0?<}6qN3qdCd-^&OyT;- zW7*ta1@2nIB?e58LM7)D?g8>3l+J!;7@oooe+u0*5B+cFg3H%7rQX9L`4- zTolieONNc@WuqCmU)%Lt2R>avMPOSt_EZNFWkFsNw;FR59)?PjszU~3%&i`aE@fNF zqac9au=^Tb+E{)(qE2(R=-dT60o;Znn>SRZW%@I4dDC;&ArvPjYzYJTG?XM8PAz|& zw|q^|Bu{IP`N8QWlnIn#&l__tDg28d@m~wrj8}4~sz}2g3_X?H9+2#EEgAPOu#t+g z^amM$osvw?Uxc-b)5>Sq5(Qmq)#hE*(DLaEMqcWy=it|pwidT zpup(K>i*bg9>veRihp0cB`9E2ylrdp(WeS7fPIYIfx!Hn<1yuI^9=fnZODWnh>c$M z0`QDACQvR3@+Y4q-V(s|v192h&@Mcr?EGvZ!wD zdE(3H&FVnxkw$k`A}96BmMtG-22LG%ch@)i@zxo~xt0An?LEzx`ra+Yr=sF`s)VBI z52C!kbGFR#>naUg8K#*w%BD7C|3|1kRUFI~xwl!GiJa#=WJL!q(|W?v;*6Dkk=3DQ zTZIsc7X>F6Mh1FqVqTkum~Xs;Z_g)P43tc2aI!V*Q&~%kF1cK(dnVT$E`r zoimA$M)`%{(xi`18bssyg7|B8IsXKxQYP4#teB}4pPRoRW0td1bNHIuKlL0^`zW%0 z3;gPgsH_h~cCsnxDcQ5JkDVC)leF^TeXn7M#ISQApPZ6NTQ31o;I%R2yjrKMPYa$7 zKlwTD*TSs28xufs29KudCRb6#VV@dbz4-g;5KNJPF;fWs3fiZ7XP7`~&-|{(2*AR~ zU-a)|x)z+~M>(_>(5~=>Ft~ZcK#;4#w73zI+`B zGpUBj!U7<_0`i-B=4#qLGmmw$jg@Oug>JNN5PV$U-I2M+2QEpw{2u6Inmo31SeAHd z{I_}9tE~llZ#SeOLCFszJ{%}Xaj*g7@VLeIr^XH^KxJ&?BVWfu$sP>HQ+oG9bGR7h z5978+9+i;lv~wPBb+w7wT8t;U3waAV=?-T|P5W zD>fsE@iT+(1!W53kAqbR@|OfTE6^21%Ei@XPz4LMot3nN1n+J9ac*C-68v@{^LJQ! zY%0g!z>nGT$y8=GvP$aKck!(qWO#e}fhw|6~ zNeEm00lR^``0=G&59zyx(>f17?O7L};RVP)j`)v@bR%HC$S};hbQ3UGWUcOjYjJ+; z4`m1ObVg?ZL2?IMlkTGrIrmN(a6RgLAZvK1vwz|S$GRBj%d+?@^Qg*~iY0m}2JW`_ zN8Bu!Z(Q(b7V2v?$}IuRaj_k7Gd(t?90L4GRhRv}W|%5|*7(-5TG^_0%kagHyuNtK z=lKoGu6{+uYxRvEcl73?J@o3o41V8OyL`gJTv1N`Twm0RC+pRoT7co{BXhQ@w=A+3 zO@Y1p@bXQ(rewt|U~jRFZUp)|yT}9@fv6q5(|1bjyHP*qrH`;Yeb$Cs>=>Ten$PcV z1buRsjm4(RKlj%TGj3u6ttUr<$n0Pg&+5xyc6%}-?m9D!Cb3Q(zktMlyYQQIw0)yj zf46e99{OJ|@A(z1ph}6P^hapG3!sjY$z}HxrwX3u%(VcE<(MyV3-M-~F*7B?jj-gc z_2cR3_8Jjj#}W#&8&dX5Q4NGUh3h*1is5QX!=@j(ZUgc-YT-ea(H+Oe^MO%i{h<$? z&pg8c^HeVPg?MaL*oQx^^U%6|_1O_B9|cgKp)3DvMMM5t))8v7ICkor>E}Nf4%W=?&~%ZU)oL@6vCAMLQ1JWc z{(bJH^q*X~~B*i0-uuV!t>LZx-hCZ;7IPW_j8PSZmSDzj-vb(Fc_j!4Zgm4}g!AfVHQMacU^5O| zI>}+Y1wBT6N?EfKiE?akMl>n8R7Ut;SudWVKXH)9?v5)r2qi5`if+b zOO}bGhIG|KSKyhSI_I${A1V(!3?p{b&`soDOqw|HX%L>hh|Je2S&B?%kH%FkBAz zM_ab?WvJ0FY_A+}#|v3I)TSa=^XJ-;E8w*;p;0p3Bp*twP-Hcl0J>lJa@mR>nZfoD zP!FhBE?r7q{cO5JjFvfSN#xCSD;6$$1rWeHL`ffDcFoKzX8ME{U4oE;s=lyH5#;h@ z5<(DT*sm$+Ogc2o*=%I7M{5AQ%&Q6o0olCXt zlENTYul)E(#2Bi7=;PI&(8@wS|K=2$2j@c6i)Xp1z#Q|)EOmw}fipsnf?)-dXH9Ik z4Ir2jepc(Xo0fbQnb;CbmYPEefclu#o10{RPn3|HC#Ps@Un{V9cq)Cqq`RN;p|BS` zR2VPZ>SXZTlY7?Hem}@Wx{jx6IMPmcL6AI4H}m>C(y z>N&oIiR`S&p(D0xe>cVc>xO;)L+G2ps-e_fq;KVrUDN^g|@>ZB>O9T^YGSmy^q{siXr%Bt$~*_ zB0SzT#;Q^5_s;Qx1o0+cLb?L8xO*< zgQ*65U57%+sxLNK!2YUCpjq)gR3f(#*^L!T)EOjhUPxYLrA0P3?U-$L%Wg+vN~s)ZGr(_BXq4v{ET8x|nQWK6W_1cx{1 z)QFp)5)w2xwmiywH2qmipX$UX44i2FazzJCF@RBMn#mLYh%9bW#n*=g2Kf_^3y+Ll zz2dTa1-+2-8s_Fu)>?=1E8^txt&A2?C@9rpyzJ_kfWO#=DE=DbMCkt(jBKz(BfNbs z&P2|UD>LOX7}(GqrS~tM*g7U|%G^Hlb9-Az_ee{+=;uz`o#Z3KX5q`b#*BSO7LO`8 zcK>^6{;s|d!v^d?ukbsewv0o5@%)zm6X#$FhcebOxZX&!B%E<6-m+4}abco(Z% zTxEZ2EXr4Gw0eE>*4IBBKPwm4JpKNCuSqjI&{a51dN9C4CpBHJuw`s19u)E@EGuPU zVoKxne}O%~X4qgk5^XaK+dm0LE<;%yus}po`K)6VzlVtL+=}f~;rbF2;B9@JS{*X0 z@{cZq?vQ@v!W!Hb`QHl^&;ufu9FikU^CE^GSz0YIR85YE$y62PhSOc0Q}!dT$oZnD zt4aq0lY?aa_Uj`n23wM)nR}uP-acmIl@cmDuc4j+yqmfPTDN$}-%moey#4#R9O#y1 z=C!wRuQc6~?cb`N&jTtBuJj9{_k?0zRDK0d`Oo_8=SR!=hTJEVZa2~cRHEM-1%8t0 zYzwYX5PH0a+`n|bSVYL~La|6G{#mgPi+BX#tAe;?M#JUgFB10gkJR?(pEsV0cCqtc;C~}8YK~ldSV&0k z3ZNqo#0fR467(v%2n_x43wILQ)svA#^bh}VSb5_0&R--Das69)`SWi&GH2;62q(va zfS^&1=RaG_*s~i69>KcZH8?iQMf%`JtP7%c^=F-|Eo0SWJb_g7Qhkw0!<6{wU(xRA ztFXyF6pk}Zv>`FS;KR(MxYwci?~YqjEWk72Qui<8_Gc~($a{Jgsqs3P82#xnpsWRkNgry^O}40)>}MLU4?6?uOtsQ zCc-Uws<1nPT7sQuVZ3Bl2ix2I!2CL6xrb@UuBu}RRY-T;@he_3SvlT=2oTE)6 zMK7B!u_g&Nj@_?SZ4hzN%3!R~6A!vGHq^pvaG;g}j?wK?%jY!A)lcuB9J>albyQ*! zt7BPH&+dT;+GOE&9i+!D2r;LnMk`F=qbj|vDH(QQNRQGE80n&ejG%=YE@!EEo^W?Q zEf+B?AJMIFd8G*Agb8=cMdkSe8`4c#E#{x*3jCXPc%{bDfJr-XY1( z%lj}(E+$cPaQ1*6jFwM%Hv&SjK)^XmhtDDM$D*HzIl%TVkHXc@QUVaN%raIZ%cxi$ z@Ixt=Yy&lw%sxpqbDF}cyYj6ElIXdDRnE6h-Ec7a#uBu|=xN_oXZ>7#)oY@e+y1#~ zmqRW8?UslfCVrQ}awUWNqLfMa@3VoSPA`faQZhJHD|M$Y8*uIU4Np06`k3*wN^E>y zdUL)qWx%?dd(iXCC)-r*O~Mg>cL*j^^Re!L#hg4q?}l%ExI9QQdtz|F2Mv$ZK#Bf@ zZ1$YQv1|%{I2rJ8fbq%~VC&ujqu9-ePjQ_l+=)LD!;=;P??oibW;|nV)(4oMFk*KYm2PgH4jqkQRBOQ`XS(iI-F|cB^!;CnNOO8>9som%ad^sJ z%h{pP8*+w=__$`}y{YV=M<(+?6Nb+>hQhIW=#zv1R!Ft))wVXVbBw&3tyI7d_gqL% ziMndrOYO9#vSu&8yDQ4JQ8+WP*&9O6=Tu*@F1D*OT~)yD>2xl;GehEB-*rfxi0o&g z_nbEJ8Xpn-#N)_Vd%#0wUBga0%}s@@wEDurNV9XMCb$|&jU5l60kcSPR2T9k&5;Ya ztySpsoG{5O5Bb@hMH#@mrW#-t$yI8IhNOiqJ!`CPAEB9NEy|gR>V7Q4@KuSr&rvIW zN@Z52-#mhM?{h88T%C|HYTr|mFfU9Nf8MkIVYhToXjtx)Q{^^G=k8PP^`~e?u04gV z0V)gacZy~=q|o^pwzBUnt*0Lt_)s%SQ8ySgrkOwh3O-%XsB1HfWW(&m?|B3D`>x+- z|Iq@(X}`}F+VS{`pP$OC~4J7$2K`TA~Dx9Iu(OH z)%!0T1iu9Xmdvqs^f`?%FiM_B^E>7R2oNY>Jz}|u^kz-W7VHCXh-BUE^2sv9jy_KE zYl;HL3tOA^s|Ar?I}8eI4_sv5@`g8$I(d#5Bz^hW;5Yc&x_c^Y?EQ=TzaTgejmYf_ zyGIfYpxcRv?~90UGEx_24$p9K-Y!ND$VdhALh3pA1|IGVH6Lq7Rcr8jz7PyH>|2o) z+_L_a(5eMaqOPHEvY;grSd>BCG%Y~!%9gs?okwznjcCZJXBR4~BdC~$nDeKd4`&k= zdHiymPO%a(>-U5>_7q9~G+b>MbP_tN!8#|;o}eb+IVt#Dn`%Vsl21PG_;?}Ma6_1m zsfNPLGF$yUg=VGY3LzYZjuj%9P=o9^QOsbV%P+i*C4!EngNbFEl~su&dUG=a1f;_y zsHy{CH9Ifp1!zY_CcN~;g0|W$pRZScWXENEUEg2U|5;(;;zE>2v3UEt74-Wx+BgOK z`_A|$^RY1iML-s{YRB5srz^5Z$FiNmoy#}<6h&!PEMvb}_Kb(pD?vHb`)b&0D6c)) zo**X(LnB!rAKKYlZ)p1w8`e`O`azTxP+&ae|26)rEDI7vO$gx+^%M|MZKYpSGe|R} zS7ip%Y@o<=0bB{y$7X1at-Wiel&=?BQx^#eHz}HZgx_*E>zaBi(#I-{MVoQqi zTk+3v$S(<19wGrSAp}g@pnb+Hgk#DPkJo8_Ul;q$G9H_BZvEwtVU~MgW@lPvKSemC zgns@VspZ*e#1oMLU)`{UA_#hDhrZ`Fj9V^>%lw=hd?ETCzW zN!_rBZJmR#O&lq_5qOF0WfexPkG)oyeF#XAWu<-GxKPDxtfOoobxin!QT^BohoREa zv44cS=*RDvV+89bfm&R+3{W0?tswWEQ>3)uySr47H63~qjy)8V34$P%q19V2XopWW z=<-=U%#r$8rTn}p@}X3d&QCF}pVw25{PMm1(xf~a1rq>8)i~Nr*J~&S_^e5T)H9(Z zmE%ksP;kcfGE0`ih56J0Cg_fXrojWT`ir9LtCAtFIM*`j+2iZQ=(pSD4}$rmf*KLu zgb-U|2j7sMRuj&?<%bvE_Owkqw<7?nap!w_2G2PTF9bZ$$LY^eIDHHC>0NDAxO9=b zoWw%jADPiBd=YcALd4xq)00jYbJa^4QNRwv>Yc^2@foyrER<9Z1h zTyejTOveHek`*d#C|ZEN3_fx*npFmMAa+Nww#1}jT>=H5H&D&;A~2@c@OV}^iap{Qw5v?UCbxrGmvY{_*WM4VUbvXJ)ITqbIoBY@uw9`26B>txM{9Bu_sR7rbkv3Ed+&Gt> zT}!Pt8!>zAv{@4{4jXAiEX@!VsG|lxiY97JWGqC#SP~*qj>)XVBmRzOQNQe?LA94M z*^cc}O{lOXc5bsFblA>xsbU(bB9$MuFSxiptJ%QSNLusU3_v>p?Z>+`dE9vsJ+8R3 zae_7D15*Vq1|9f}iOM!|RF z!99|vH9zR$Gp#fFe8S`BtAWCxJz8=`)gXYZ0JiI&vG}DO1wM*g$J!&>PMlaVy_x472$RzvC~YDl|zPa1k?H)9eS{K(H$WxqV{*D>`LttY9IDv*Wcu0UaBP8K##c-P%vi#7y zon2i_0z?r*zt8_(MbD(b+~Om$(hl>SKW32<)#k&bb9rrw)a{EdI~TPioU7J<<7{eI zEQI*6q?1!hCgi@}ZhoDXAfeC{6g&cGQLM?gIV^=Z^3(*q?T|B~8gZ@~iJ~sQTqCx& z!SSF#ZfMhRhf~-xdA0bG?~<28^s@laOWg+vK1zpl5iRdTMU*2>Mknel@CJ!`t5FlL zTt`0q0b(zDe;|DFEf{2q{>d)AQ(M(@Dhw1x3q9e5Yb}14ioKuT8uV4IdKx~aym0x- z>$~bFvE51+`CgtBN_c3jFmEQd-N<0_A@JvQ@4Gi{W^Bk{Bi#1+y&eRsSC?m5#Ie7B z?oh(j#3u0p{;-(?`5-a%@ca54o!xzO94(=kE&_IHme+l5X6v+L5W`D8x*hzL!~zaD z)`2v-?Wdy@<~Z8^W%!;mR*f{V?7Ju+=kqp0t#;;K)r6&Cot3Mn z{yAsLH4Br;v1OXMUN@9gjd!Bjg{riRQX6V#+UAau$Nbvw#+I{QbUKwD?3>V-B5jn* z)A=%fY}v3AoWZA8_lCfDZBz@2R-tNmQrsPJV?p|&v97}V6y8^6D|u$WrRQ_0Z{>f8 zcN}@eIYY=REv{#ev&pD=>cb%UXya)eeKQAF0jbzDbL<1%z0W?>B9{Ix!Bn630uX7{ z7)?uIuslb2!gX~X#J7E;xd*-99zNRgMAjhs+Do%oD%C)KG=y-0_9ps4XX9#|@or+@ z^I61P(Q|Qr)6`+N*okm|K!ybgLFN(bmZ??7sfhvH#5A6SolC}-d;R11UCZWknntf|(Dm}*$KjF3qaz2eM@1NlL4Pa_XANlp36tLp zY~QBo(5){*ZkL1#KPr2tF#DXf##DTVPQuGp9Q~m*#hb&8EB4Wa`#-O?YBM)>`RW!N zj%(8}f>|5#5BUlhlKGSu$|JLaR$B?F46|Qe*`HJG_PqQ7UUO<)L~rh4!;?FAkDS7#KocDbWy(E0S; zh03+^h&`LGecleie9UYz;%i(ZoOWx%lQ%C5<;Q1IqmSyjAjOdKfGypqCM&xcNCm)H z{_>j@pPKpAH_>U|ZDVP+={mE0iCYKx!Cgc<9oDjaH9X~#Sb%R_MWj3V-q)Yr6WWrk zA$PsEN?v_B8|5Guv;DZHI)?U%$9o~)WlhHPcXvmG!g#ALu3YN6dL#b@kJ5?;BhQqc zo#PkQF4<#+RJ2R_2e+_u-@MhQB)EXaC=@lIUEmfIeHbwvQd3N^Td-7r^d<`587yp* zr(qu?RL$PnLs*2kLwv~O`{nB2Z{>Gq0x&;oZttoyl7kw+4O?4|cF z$%BBtfQk)UE0Hj7%r^$dcz#E`!s&E5=a%m~N80n>yG8HOiFBHl*FE6q3j0caCQ-g{ zpEBC2eM0%9B)_NI$OAwnmxmYJcuuP@^s*qewKMg{(_)^C3%S8@uokM_ac=(+2A~K} z_=w{^}WO3p5`^TtXEu!^Ko>8G&d`e_}DYW_Neq!`wW2kg2S@wgjE>JEyt{WyqsQF%6$ z3Qao5572rx>{q*RP!+EC?1izR_RXn~u9?skJA;Gj2z@76s~wxV-6K(+u?v4x7m-|} zR@<*lh}KQI&yzbJ9e5c@Jsap}^FFXVjkJy82<22THG8AmZ@~JpQAL7F4kC=5n`B|2 z$+~s^#@p|gpA>_LfDhB65GP|~gNTr>D;v^$eie9#y;CZN5Ao*7nZ|B&Kj^3RgN0tr3 z!^rv<5G!Q6@ILCiVMcD8mZJBKaAJ8(AEdEgB};C{9h?jf2nx}t`D23tzs&;Gm$hY?BYKCArQd7dr47leX-6 zR!CpZ@%)twC4IKyhLPTyb4ebz{=<%Iiz}piy7|}j7oRYRexQ=iY6*XeNrfP*#!ik6 zC{uu~E^HL;`H zB1LaH18{G`KE$MYp>DZ3-mh=YO+<}rX(uOC$6h_>iH;Y;&&@U~-OkvioPZlf#p<&g zlZK2r8V)c>!Z>Q$yx91dpYU$uNTZFu-mz^Sv5#@N!O3^H$5i61io(L(C$nlLROY=IfBiRwckKQ{udeXhE zW%Lbp*`{PV454WSje$c5Kh{L-@P9N|=K(J({CwlinU({6J zbiMEIL$I?ZCyJt0V*zI+Vgw=T2I;ZV`Oy! z*k_V3qy~p)y=FT$rQFBFd>-_P{_RhW_>Nfg=v(jyAHBe&=!JWE?;*U-sOR{AL6L&j zaCd*lA2z)_L@Yf6-a#Wsx1R%wn7a>!Z`DG~YM0~c=@zRLt$~K^r(l$v)6;1s8uTQ8 zQf>@fkEBQI$swAAqynVgc$x|AE>L79M+Wwf!JVJ+WeWpu4ga|pB{(xQ2Q)W@Y3x8h zEq8KDNSO38A$KGN=rRUx9Y6?Jb~*wJ(9M3DPGs`@_2gk!thG$ICGUXRtQG?}ccO_? zC5T-~%J0mq4gr8iLnKR2_}uV z^4ghR3}ljibUL}Scs!qjBfu4t@wz{ix^c+>LW&YjDAZ&j5cq5F#bB2$UwExCg9u1! zNWBL0V8RsD>?|_pXUG`COqN^ly<=9dZXZu3M;JA+EtQfefej9Pb0(MuC>pw`<#7Cv z@jG@HG@L#<&Pu_zZULRt1xyK~7S1LtCzR!gMo&OGhZN7UaL+*MC6iY|t_gjL%k+7a zEGz+8+=|`3Taz0L1}V}+_&61uzaIN_9AtN*4#ik=FDh@mS@A?|(-~?sNesRf!VVcu zRe~Of(V#bPzFf5cQ~ipfzqyrOc3sdwO1C|8eCRM(>^Y#D+<_<2pt_C z6HBo^YCE<0&~bmA*KhH2S=YmGT2FPGW|R{=@eI)F%(1+7@cjgO>jaG+g-PGZ3Gpo@ zV$elK(>|7w`d(}a6}p@wG4}@ox_<2$ZcF!0?vX&uBqsAwxbDE6M~L~DFJiO%ONkqO zGH|i0*l{5$2(Kcj!xajs)Tx}wYL9t48IiN?8)Hn$ew1{`Sri^eP5_Bf^+vvtGm(LU z(E05806hr&Rfna1@@e*DsK?cgnB@B3Uf`{c)DX~OuV+OGK9y`_!}o^eVvSiw;!Y*H!#rABM0KB~TJf1xkvk*?C26Dli)(Z;nSiVHqg@Ch0v zXx}^p%*;Dj`U~N`BNb}#I3hbJtgSWi>Ab7!xR2X5G!-WGk5mt(lGw6sn ztqOvB%`CiC{>(|SpFf-D>nKOM9fNQ+CfT}QpsDy`sqbt@HRHM?R4o=U$Ec9H(`aAp zGHUC|A*B;tpffKj@5cr?nOa7p2juLA`0R^7nr9fd$22EqVs5kNoplKMES;A7{oL6N zj$3OMC)~WW;`v$B?lk(sL0FSNi8|1@IJMWHjs1x8&HD9c()Bu{&b>G7zR@0A4t0cV zCD*>(#?JV`0-BiG?lDS)j6Ror-ZD^`Wz!>1tEYlV%#C6dUT#Y5-@@BR7;)ZwenV7m zRX>f$qbu}e@2coG41AkNh#VT=sXcHAkD!Rh+6KaTx1_?!t4s-mg$x1*Ljg#F8r8$i zZ#Bwxp4xuwZ@0j8qpF3FlWM5`MYbxA5`-|>GU+VjO*`o9VEpwg<*9E za0YW)vbwv`^SrVIgSArr2B?mhdNhHD@$swM(eWK`ue>{-)c>#5)gB*JL3o-Wde#~x zW(lK)(x7Ln(a(>?hKY*P3A9`+bmx@Q?K&N$OJ4ec0OI2tWZoZPW3N*>yaYmoj5t@8 zah+|T-9um18&-{WLG~K;4jEujLZV(ZnPjFS^whA=^EYMC_wKVn-;)dnH!m9Kjs#4J z9_+UG0&GjizC-I-%(J)I=Jb276MQtbWF1A{ud_4IKsiI|RNEm`!(vmvnHscx?gpIv znZ;FN+A#iA<;o4e)(IpxQ-x;&ON|)|L+a=(fC3^xE#S__I+EO3gNu=uU7z|WQb8e9 z-Tc)D(9!<=jwq{fg*4_$ya8JUK7aE~xrun(}B z+hMBm0x4n7VdOks{8Cg1CNE-`qBw{nVG#H^YgeAqO*MBu7?}9>a@ERXN6G%@na74^ zO%(mJ47tyh@N-*OBpwwYL`xe%HBt+zmSTjm);&4KK`s;#0_*Z4#Ms9*QriY-&Mx9dagrrL!EB##JkjkUa z1A~c=mVDwqiGJ_qnO8bPP0i*?3n7fZze;<5ntpg84+K~vqVnp(1pEay8u|z0>o64> zO%%^y7}@>~elg}TCQFm?5wMja%`MgDx5iI14R-9t;~yqLxvFqv+#~$r<}N0uV*Qd( zDsd?05_T5F!n)cj%yZUaC4D^(uUR67!2^=Xffw1=Ddrb(Wa?M=1zjVzwBA!Zow%B< zI1IICte4NtY7?9Oe@G^O`gP;`wJ#(gc*->&BGOMtD4Zum;<_>EkHav~NA_)k%vWhn z7kjZ?LX!hiN<*HF1sAXYy*j1LG@rr5r6<4YL{%-S{J$g`{e(%~l-tGNzaJdUQh`P2 ziOw9fi~|G{Cct3!2Kx}R)${|D_edgGx<5PL_-wY&n1x1msa93NyqIB=-8uMPtMDMn zC&f%mB-!)80yQ0`HZNv&YkOa}dUhQLh@bXNfvS@p>mlYe0Pzkq6I0%a&TIPdcz<>VwFRh&l?MFbd4sBJcxdbvcn? zmZtBuC6}mbV&)Y8%OV;1Y3=Z5zUQEWB6X3@!1aHd{!ub;P_w6@2TL)#AM;G}W_$%Qg(@vnvQqE|oS{z0S zzip8f4MCcSGrI&@cuwljfy(}8}t4}!J>e1ZuYE|qq-u1h(8dQA~i03CJBb*vcb9ngTL1({a_PNYo6Dy3ez ziV)qgyXo1ZJ{Z1fFvlpCJYIg2*8I%FMWpWG&MrfaP>4&(wnxD~wB974 znty7L13~bkie0p!sCJ@`c*TN<=PHOVQy@9x2$uAwB_<*EA$FWuZ=XD%+Ces6GqUjO7JV`Or~dfsCE zp<)iN@fI%>8>=G_p24o4Yb#_rtYM_r@L(rYW5(-5&~wF9){2B5d;FMOxIZ`&i=RXtjRiFi(y zAm&dFAcA!Sk4uEjr$LfD4fcy#k)o$HaWL}gfi%aiCq+fePzyJ@YMHY?f@GU;rH!|2 z72`-%`l?3Vr1g93@)zxuLs-p^E&(XG)9vMI3L9NQyKXw%=-VN#^Z&9z<4Ax@38=` z2IAf!s2Kg;0&Du!5&O#b-TS|^eJvUg#PIQOe*rkHp_l5*tckUe^$QoC)E*9YWA1ia z?S0;(RL|;;KR!*yXC8^|cq|ZC$@>EEG#iem4UTu-t;bw-d-|9BMVz~?WXb5t?v-oq z&-}YTeJ91md+0X2>xg+A^33X2!ye@V3PvsgsOvy`}4M71Rce*A4j%eZ*S3LlfloS(Y(Cr!U3LTsXjVS__l{BE`xb0)^eFirUBXX z^Q0HbRsMa!{Ld_|dJ2@UkTKHuCD#^Ae*Q2;>m`naS0IjKz4%g>4-}zEZTF^5jTVG_ zIz7goxuiZ;(6XWVihX2H`&GgEq3$>b;}?cL3Erw;z6o!|%QiT2w=sU%NDNc7+tMM& zbZ?{=fNV%>PEOMyAt1Yv*BWtZ*M>4$IY^Fn#4m36a^#vDaQv~1&Sw&BCz+_?KG|U^ z?n_f1D~R1F#AHL;cdjUdco;KT7vG<;X;$U?8G9Z_esJOTH@eUW{NmE6i(0E%S@eUj z;HuS!QJhPcKbPFuxcY_rFZ^_fndM=oPM9r~$)!uI?vW1_$m6_sTac7a3H8GLmVNnR zz?ov~jU!Fv;OEih68Jv}i}ayCDUKJHo=w_2VM@xHC?+c~(z_dPqBe9K#i^AX91)i* zywT6L7-@W4&I#_CBTx;P$)xb8?)?{A>b`9OD^9hg%YkFDLJh4w%{MBW08zhX_$iqeTc%u?%ujR_ z5!#zd`*ewfp596v__&L0rDOM+y)kzPrbK&~VsQya+W3N>hb3c@g{3U5#X;ZfPUKYu zQqWgm2bCDSPSepDA>#v0xL^GORj-jCRHZ8zYt0NnIWYm^^>oJq7pQ4L=roTJU5$yfSYh$~a)Xn6ilOBvy=kP4 zNvX+}39q4B$t;6CfM~pm0DEp7HB0o}rIigRFTet3u6^b&$^eS;5@?3ApeSkobq z!(}MTbYt3iX&ZNJuJA+NAx`KcqKa-`zcWTSPKjwpk+Y8y>H7225i&a zEYP=Fcq;4mGkKQ$pi*+Mdt54WLi>+Se}M^1`jD;Fe(a&6%ZA&xfy-_7n@=6z0A1xu zK9Rl_Ll30Gb)Va(-xvwat|knkK`xKM&xtO~`$t?8m}`$-*v{0Xhi6J)R_` z+8`9xpzYn?mJ78F*RIe!=a`^c9T*uh{%228ZUUZ?Dh-(2_lQ*Npx| z+|B06fV)xiuV7d800HOH&AMF0=B*+?gxX!&>!Qr`=)V1RdOv9WNb|GDl5L0E0Vg9(=H0b% z7$XfQL#k{9VLkSz5Zw6HYhZWW;bu(D@|3D`=xCoNxG4Iu|J^g~*X`Ce9TIb1`_{YA z?vG)Y&OcfHb?w<~c&zK6sJ;@CfF^h=wST!Vv+vN2arhG9731-BY~fJwOUv7#{=~Dp zA{_KZ%M7Xv;stNIK6reJnR>AnW8tpg`0^)|Y7xc4NDU_B$}&NTEasfl#M}@;ST9Q^ z&@-Id0`yF?ybuE7=UlPiN@LRrl3|9d5o`IjDaF$WM|R}KFWUKFGPj#3!fCzgyGsc* zy=ZjV^Nu@gO|ZpGOa+@M#ntqB^XB91Z!`PP+GPb!op{MM(k1sYfBlKV2s`6|(nx{q z=*dxb^Qlv{1cEAaQUl%F*eYd_x7S|5$fMf$<-!9@$vryCIcpr5$pF7_iUWh|rA@v9 zIu26nu~PI<(AdQqO{q7;pO}hMbQIS~9QpJ){K9~}v~Fk1d&jq&S-#G1i|&M;f5$l* z?e?x{=UP0^8YRMqKC#YmG5_L@?h*iti|}*U0Dk@uMF>C8h zBRu|B&Cyl%2GZ|Z{QPu}JYs|PQ`%R)?E0p!<*j#af8!hLy7R4k;|ekz5>S2xp{%2N z^L@h;d_Y-6AjKt&`3I3NbA^O?gkLv7dr7cI%|_h7R&b5@1?04r(s#f_GA7;DLTkqwYFP{^ur&I-PAJHaaWH%j zA-c2--+oCwNZ!<*f6ENt7KIIxqLU2{I3NUfafFX_ighcO{PsZ2IxZj4tH;+1^^Hh|`nU$qMeXtVWQiXNIoTNTCy^L5;l}C7n z>Gs!oA~x$3dr>Y716rrDY+6;-cm8h{4wK#x^~x_fD~Erj1DW@|54)@|9WqvXzV?)? z7TwWP-DI9z(|9U~o_-<0PLVhBQ=8+<<)RBc>aA8kqo*kMAL~y1>Lw>19C2sSd|TV( zX2SJ*ML0e7J1v+qQNNWQzdFT|U7+H?x=!kBw`! zhe_R-=1W$)mU|TcS=}K++mo|gj5OI25KpHbx8VEV_N{&wl&{6O{Pb9>TA(Ce#N?YU zsorY%cR0K8>mVNE@oeSS!BNeE^;aEuR`9JgK}AzaAQ4Bt48t$U0uEd4O%&xm7%3K! zCYgI|PRC!ooHFRS9EV`hbiFu`{h$)_NW6(+aRvZ6{P_8RI+@B@TA!n}hx3pvttcCY)8d*dPE8v%X`Y|Q!(iH1a7#VsBzaaJzlUg$rbrFk3 z($f9)%Vbrtk-xKIPlYL0ksUsHCV4VcfL_17{fZ?)cKgIc;T^fN|CSDvaZt;t6Q+|J zr`J1l#P5)YFlC$o`QRP%hlje3I8uWLelFaHkB`8Vg{=QENs1OSe(>F)Niwt!Q(oLe zasL1#>xSaDkYo>=!N)pO{r0CuFMi^-n2P>X68h=VXYQ@8uJSQyX|Ratv0n4=|6GWv)Ci>b2EoYQP58yu z7ECtZ7%z@WPtn@u7B;e8ff-=61Vs?T1FwI=FP)CVcWkcztr4H0v?{+ zWjXcpKA-_lz?2@*Q5+6%WW*2rg5%^?y1x6~QzlblesIO|k^hX<;S)LoZp_BLZs!=&6&XGkTGirR12=%59}}JaSfkQ2ta06f(RIpZv8PxY<)OfaQR*n@pQ==4xUBnpin!-sPdt zkbD92VAJYn{S@W#W8F#aZt~8-kxcRR)>#P-UakMta`1=}r(93(OJ*LO1ftssFx@qVWeZjPAS?wW;D2cne zFKbETx{l==7->@r4kPKXQT0_0{A+c_%qB zPBYwGcb(1=9oc0u2Q>px`tj;8JbM$^KIw5D()1$N(LySDPcajzaVr{csJ`w$OQ|Uh zGIQwu=W_6m=r%o^7J{u-x^6hs7{;Iyx@nMi$ad%C_`BWEv;r>TVhDgu73#GZwC1x{??Y3hF(D*mYsT!PoRdgsipvD4^awc(ays z`ymh)2BKb5dI!>u&WKoJaI~@?=|M+Oc$8)Vfz6442J`}ZF6o>eN;PH#2&Q$I>jAF1 zADqfV?*NQa#bzB8iVlpr3GSP|2A>Bbk;wmp$=|~Y%D4Q_lV4uL`!L!HQy*mYBif!~ zE>VCdqI%FTwIEk9|B98NqXqQ}F> zF8}Ya05JJ`hN)7GuJFfL?cSQAw0_i`zS{lUBkm|V++&kj{OxAaqVDhjjh>^! zT(uyyJ9ynTw9OsCS@8vP=dt7UsjaOe88iYrn`VM*`8&1sKTLizA)16)Y^o5fW}AfQ z#T`f?@bl{`m_n9s55v`%S#wzNi+WsV00Tn_dfbQ&+QTq=#AgG)d=P>uix{Rj1Cw6? zfnT_njLEp!(;h#7YOJ6(&HtY!Kb;zaldc^b7vH;ePX=WHq?1nLw`;o8@e5dz9ygJ)HgFnFcxyTAK*=r z8$Os+z45qT4ZaB&o>$*o1N9Kg_Q{xHE@_JCdl>19Z}WV3)rtmlkyYSK@tr%tAGk)l zLO&F5Jh||Zo2mb0QVs1H6AKaFNz9nv#M^c(K{?!+N5Ztg{SoZOE~et$8pQ_p9H zyTw=*tRFZmv0(J&8oa_1>KX&&i& z2kj6~BSAf!>0d_nnv4m-k(=(~mzF0ng&#u93|Rs1)(7}`#cVM=$nqX{5dY@kzhD6t z6Ao%4>#o7>JNuKsD^)NSm7LML8L)oV^z|$JCb=9_{6v~!6%8XDP2m@~fg*?J7WS`* zZCm?Q^gm03bENdf00CS|gM%)9#iOz-tG0)vBTl_tcJE@d>F5UjSJ$RP9DT;EABg#! zQ5PB_@i`caMT*Y@#LFderwQ%<#hlEm{CF{}an{_g#TxFh3mkL4=S zgKMEIbX3D5gQsu2T8+Bmrt{yXo39D8r4OaFby41uLcWR3*SNNE@MYurR?d%ZUVUoz zeh!RZ4q?O;ZJAQc^>Ab`48Oo3hDq~6W?&$MA=T4bTkG2JepW^!*8V)%KjnIR&VjrT zH}2=G*F{jQVu3H*jbY?Rf&>}UTcP~R`$*k9!vy3tM8o!>&}~VdN=zABI^~=hj?8}o zzYui~lhL_G5x^y^Z5^)wI9`k6!2aLT%`aPy^PbiYMS#4rKM>gW84PC(JypuAm7x_& zpU5{MZ6 z%3CaxKXy2_v@cpJ3v(-3LIIN`sgB8{qiB%aa09=QJwS$D=cgB9gkraPG&k5Po7;Jf_a8>!_gPn}Pgos*Z0Xm9AczNux<9PKSM)bhojzEt1@J?l$+{+&VuT&ly$WK!rTVx;nGFAxagahBip%P~H`P5^4z zpg+3if5{H~{}y)sTj<-P=&B;1p0jH8;}j<)uTFQ;u6w_;^2mPD<7;{Cp@k!+A=vJU z8QbF{?P-r?P0@oaf6O@UXE_hx6&v~o4DbB!X4-Ki+%qk}Ld%-d7}G#jFh7$2>aoJ) zeX!Ox_08hvix(TOmRMW&_BcXh8_2Kt0+odAcaoV%5Pm-zoU(Z9UMI{|qf#i5HXHK7JC^^VY8+2FDvA(Bth%9*QOD8$zlHDyK|3)u^Qt z@~Qq6`u)k2L*P*eJb?EGz5}8^z=A-MEdO!*{{Rlf?4kew diff --git a/art/SQLite_big.gif b/art/SQLite_big.gif deleted file mode 100644 index dc9e6a0e6cf97d4a4e601dac533c8166b72c4165..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7428 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 CE;7mzbECnVFfInwp!No1LAV zo}QkcpP!(hprN6mqN1Xsqobsxq@|^$rlzK+r>Cf>sHv%`s;a81tE;T6tgWrBuCA`H zudlGMu(7eRva+(Xv$M3cw6(Rhwzjsnx3{>sxVgExy1Kf%ySu!+yuH1>zP`S{zrVr3 z!NS7A!^6YG#KgtL#m2_Q$H&LW$jHgb$;->j%*@Qq&CSlv&d<-!(9qD)(b3b>)6~?| z)z#J3*4EhA*xA|H+S=ON+uPjS+}+*X-rnBd-{0Wi;Njun;^N}tgww2>+9_7?CtIC?(XjI@9*&N@bU5S^78WY^Yird^!4@i_V)Jo_xJet z`1$$y`uh6){r&#_{{R2~%*@OH0000000000000000000000000A^8LW004LZEC2ui z0IvYA000O6fOvv~goTEOh>41ejE#;KRI{ zpmv1Fxw9xq0U=TX-L#{GI-^iY5-6c`X(c2tszu#OQo##xRwe1Mz_n~i3pB$z3XWAASc86&n-E zBA^lW1yQIQiliY(} zcC0Wq8Uo6|9v>Jr0vGocXdf3N81+F9^z^{NP6C_|hJh5?7sd(Cy~F{7%|H>LP8WDl z;fVHmaluX>_@~Pq@xhdU5%rNMqjh!|k$_GixOYnmIwF-|JX&}d$aY*q43mJ&HP68O5&_fl#75M5_ zMyjGiX9`7dX_Izbfdd9rE;PXnTEtl0v0D+)sVPX1g^>ejG%1D+4M4Sk3=>kvEmszR zWeSoQAuvXeb~tgOSsE}=rk$FaC8a4lK)KMIGuE+$1cO1a#J__EY?cCj{)qw}MmYd^ z1;d0{BS94rcWjLbrRXq#l@M3R2CX7nlf)hG<~6{#ptQJ<0$7sBgheg8470=;G22fF zqwr8IKTD2C2faN9@N&!gJn zVQ|Y&1C5c`tF>|CLIYI12?-b(G2#?*=M{I@t{H(537-hTvqBeWd!G|&H$8Y!bhl>5 zz6u>6gePP#BtRDxN^vw{lkZfyYh8@a&I+B}v0g$aROm(EaFwpp>A{_F(F2EGVgp8C zP*}#>BHIoV?!ke9kqw-HaM1`9($S^lU{hXRf(wDLNe_!BM4*BGO!sX3OUMt$#YG2j zh)E0=8ERk?UVjbs-1haEPz;*b-w((IveA9<)id3Fs?fen41spnc!1-~!!o!9@OA~V z!|V8A06kfv1{d*xfv(`S@s*@}I92m`0hjhV&0Gf0qC-)IcY%IWs)`5fSw2=c! zBr1@`+Q}A$Nw_HPV+#eEsfOjIw(;1_;CVC=x-lGC=elE zVgNe2YnbgQ<~k}+pdl>81C;1mLauP1I4rXtJt(ID>!1cSIP{?qg=jPtQUOX3uN~yE zj}%~XfL-2`aCKV4%_h-Sm!=?a33?kgi*p_YA4gm8XhcUV35#j zJAiN><-NqCtPw0R3CkKF999x4SO{b7vjv#6$~BVBCuJ+U5EbNAvyFubWJAji5Ms)* z-#o2C_-Y@&z67u#tLtd*VA$A3BCHB|>v`h(lDS3}pRL_(YwpU{--^{fWPOQQb1OjQ zvSzJ!l*CjOQdRq06(d>IA^EJ^ny&WatC1jTLX3JIq?ROytX+p|Df`ZLL=_S?ZB|Z8 z;z5$km$E=jh)@?%QiYuKJ}S*ff1^g;{@2Kq9W;H!McI+j^K29&3#MO#TO(41C?KE< zA*g)}dXWr2u{=CTfQnbl;ugC&0SbWZwiZ&+Nz|7e@x0GG6JlaTmgfu)R)_`q`AZAexUL^s$@r&n_3<%{Es9Zxlb(>GJsn~LYwWVb`1)B(-%c}96cf%vEpKT?9Z z37MvS?9jzli}uYo2y#Xs;O6T7q|vRHAYwa=SRf?&EWX_YvVj zNO*|@E<}M8f_66anHO^2M}iBfU?y(N4uEg6n#zVt0xE1D0v0(Fr{)KHA&v2#HGx7D zUx%$P!M%%okL2deI9yObq4O;yeVc%_LL9EunD?v#w=xj+6r#ONs8=Du>$w2^-LV9m zfkKXjDkofbk?x{t+zY=0(;E{^109(kyz4~g6!JN`E?wqt8Gsbpwq|Uwt`my8NaKd1 zaBMIVA#8!(|1ZrO?zaQngXo%)@G6y)|5K76dFo zMrxRFJBT(4lVOAck#GIvTXq6A$fyq4CiEIVaj~9>Z4H#)iUg7-qa`ndWThyW^;e^? zF23af{sPjVFG8_XC>Acb%NORjqJbvJyFg>8c0UkXig0zzwddkXMX>-e&@MrO2JeOu z@sbM5G8q4L2hlPuZMP1+ku6#B1_5SL(?<#oWEKzT8o9D7z0wZAf&#-52WKJ&?u8M_ zq6(h^e=<@kr~Z;EWsnB3M<;X80VEMCtuQGbxM3CY1{n|&8+Z!Ov=tu+gu;;q<_Bhb zl5&rxgq9?L7-1-}@Fq}^gi_cVRB$&LkteedCc3qS)=>xES1(or3seF@WcWkTM>St! z3-4!O+}DQG@gy+8f3?toSj9GW7#u@VBr9@zB=I6BC51KOg(Z-Jm!g=HLa^!^|3KC%*LWnRiABPwy`2mF&(H|f29pNz^X_X$? zcMm&u;g1m+lTjH#a2c7g8NwD7pOF}X02s*^KP6!pz2g^m!HzA%7wC8hY*CK#SV(hG zkBKlA`S=!S!H bmSkC$W_gxqnU-p~mTcLUZuyqv5C{M}^9D)q diff --git a/art/powered_by_sqlite.gif b/art/powered_by_sqlite.gif deleted file mode 100644 index 5bfed023ee754825e304cbccadaae6c0f874e555..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3391 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 diff --git a/art/src_logo.gif b/art/src_logo.gif deleted file mode 100644 index c63ff6dcd121d839fd6698942115a058dbd043e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3348 zcmV+v4eRnpNk%w1VMhUB0OJq<`~3Xk>gd_z;l$O@&)wPR@9lo1n3A%nwadh%z_;`E z_3rcW`1<+w`1k++|NZ^_EC2ui07n5~000F3(8)=wy*TU5yZ>M)j$~<`XsWJk>%MR- zn@>R?Nv}Ja7Zi~k4Q%VaWFWa(C7gnSR}95tajUa5E9X__<2YW7~Hga%}y4Y z zd6}rGswfK!rz#Aj6a)qZtGBqhTmVhBy1&4D4+;SU12|KaM1Zxy&d*skOk)VjLVyQB z(A(TF4-3L(2YVB%5aB>)W`U<2#<`Wy_Bay&i)IYCE4lo@Ln9w2a{ zZJ)!3{+{q4P(ay&cM=hD64H>1?|Cr$+`6A}a%TXLSvUp(a0!Tz4VQAd8ifk^ zUd1d*^K=BdKS7ZEJQ)ES1pbgx2z&hpTMHc(a)S;%sP=+1vrRD{2j3Jhp%LbU0U$S9 zjiFu#$JK^Hfde@>g8-h5alnQvpa{kU66aPRD-sb=cxCiJfFZ3| zXabpY+U2MPMTPNW2suLW;RfBE3QT7uN)T$D8|4S4q8xxlotP>F5FP?QxZ(nWOI1bY(nfmI0zBpj|2G!QBRJ9crW0kFF8#+-KO^uf2%mM|_E zeOizqn1QbH27eSN0A{xoum@eT8^{XRs51N+#{k%hQ0lG)05Hr#Q%Pj8C^7*6zGVh*DT98TL5JWLyu!OG3Se>v7RxcfX1XqguLR3-#e#eu9BTlfshAZh zjy6}EVss-!o97Hss)$#v;@s8lyFVkPU${kZ3a-4kb;%368a&XW6VHb56d9^wk<_=S z4QIk81Gg&y$_A8u0o+f>T?DZP@GFefY*s+#$5us1uWoKrFkMKWUeQ{$;SDge1zU>| z*9HnjVYlJ_W9Ti!m1WelfWmy(8V1i2M80!E{!-_g4JKl69MQr=f{Yjm)C28n- z>Bzb@hR8B7pq~_#_Ar3$`NmfW5Ho-`M#KW!HDBuO<<;6TFH;Uw)RzqNHF7M|8Ce)L z>TFlUCjgN65{w7yQnt9G^a22rmI?L+^_A^)gpP+c>E#q)z&qT73ekxnY!?uo7^v2- z#2iL)@gjjFk^wo~xi2IVP{8mqvVy>Y2`?v^kV(Qsfv-(LDrb`j0q~{4a~usY)N7KL z7DxiT*)4u6(*T)B=Ku>f4Ir07gfh?uro?$5DY(fVMi@vlv>0$d+R##a(5EaEaqkx~ zlt})U6lk9kaM4ttq8$rnQzxszBLP&DK+Bjj58i+&dk!eo0gU)IywS@|r~%&YE|tSe zjE#0Hv0A!JBL+p?iH9cWjxSo+sVfS~eQCr%1FqwerIjua0L+#k$w9x9^bZ3C5Ktis zfCxnt<^g@Q#P?3Ou?R)71Kg2=Mh>}xFYX6gow`=7F33a*Owt{K`;i=V$C3yEsFO&# zk@?_K2Oj7#6^DyLQ*;#t&CR6(xZ~NKdKm(H$pI8*l)^J55KcB`Kug_ON&wu35zR$2 zJq~z4M0B};Qj<~ zG;ewb1I{x_CHw`a-_YcEu4!L2w{azHcxIdw_)?t+IsyHlbeA-=Wpi*tM+vZPq;Zto zIrmjlmW;!7v*A`8Pg2mBh-OWad*v!{x1rg*)B(I}3f)-g0R23!15;(?x@r+iGCYo& zMVtWMB8p49Jk>FC^Gu|oM8H2ZW_XpN2sg}!kFGwUs1%6aKpGkbY3YZdAIK`9Zu2wG z;4`Nls<-0^0I=iX)LH|PfCyq>IdVu1cHQup7TD6co*}CSW+SbHo|d&M&<`TjCc zQyF$8!>7Kuls;}XcK`?#Z!6G`?!3kiv5d+JNG2?wf@!?2;uAT;a4G}0;7;mg2h!_L7rjBrjTZooadZZa@yQG(IiA~suoAW;S6%3A4m_BNs*zD?b0U{H>jd$f zykf^sD5C*c49|7#oX!KW*nt;lwG@JzT}Tb3M_7txmNh`0rMQh_93kZbQY)zoTH6T` z^Pyd+FdqiU*wqo11F8cZEQ<9IwHh#AmW8cF6WrJUgg2 zxyz}F6O#waZfjh+6I4Yk+x|MK`P$%JG}VG*iDXaa1_5J=zHPMuA^y|1i;!m4iFmH68IyfY6sHe>A>Dl&CKKi%#}P(fRbdO0@B9>ccrZ?X)4zn5l>E- z30%F)Sk<~>a-GY-3IqXY_%Fx($KEr1r+ybaR47KHa?F>a?MO(@2Xuxg$I0v8uIHf1eH*A4~-c-nyl zUH}Jr)Cl*d4qHVr|Ahd=fHiI00}YHw>^@b~Y2chKETI2B;7PDDVU@fGCaiHoHfN zmM{jF5CA~k1QTG1iU^Fs_=>(*0mm4NvIvUGNQ{ee64?ia{n)Mvb9pjoX-w@hFeoD2l>J zjQ7Zm$moo{h>!f3kNTL88*vi-aWK~Bj+4lXuIP^e$&lm7kMsD87l4lS_>kPVkQe!n z`nUl%rEp46EC`7S_Nb8=*^nh^krPRdD5(J$NsshMi5$?8pz&=&7m|fYk}g@1I;oQ_ zd5tQ$jT_06IJuKT362~YLKQ&OXf5Kvykt@jo&6tx>`H~PBlW_17i}8p| z*@*x-kDeHoL|K$r8I(XNl~-AmCYh6Kx0NtaGrsqgt!R|zIF{cCk$Gv3DQTDW2#s_DxtOwbQG{7HiP@QKKzM`HBTMO- zq$vaFkuG32nx(m#EJ{(S5raoI(&#swtet eNh*D%hR3;_G Date: Fri, 20 Apr 2012 15:24:53 +0000 Subject: [PATCH 02/13] Fix for 2a5629202f. When considering whether or not a UNIQUE index may be used to optimize an ORDER BY clause, do not assume that all index entries are distinct unless there is some reason to believe that the index contains no NULL values. FossilOrigin-Name: 9870e4c4fef10112c987c40cb1b95255a7214202 --- manifest | 17 +++++----- manifest.uuid | 2 +- src/where.c | 28 +++++++++++----- test/tkt-2a5629202f.test | 71 ++++++++++++++++++++++++++++++++++++++++ test/where.test | 6 ++-- 5 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 test/tkt-2a5629202f.test diff --git a/manifest b/manifest index f029544c0d..700e725777 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sobsolete\sart. -D 2012-04-20T12:02:32.039 +C Fix\sfor\s2a5629202f.\sWhen\sconsidering\swhether\sor\snot\sa\sUNIQUE\sindex\smay\sbe\sused\sto\soptimize\san\sORDER\sBY\sclause,\sdo\snot\sassume\sthat\sall\sindex\sentries\sare\sdistinct\sunless\sthere\sis\ssome\sreason\sto\sbelieve\sthat\sthe\sindex\scontains\sno\sNULL\svalues. +D 2012-04-20T15:24:53.110 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -246,7 +246,7 @@ F src/vtab.c ab90fb600a3f5e4b7c48d22a4cdb2d6b23239847 F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f -F src/where.c 2112422a404dcca5d47f6630bdf180bccd36c62b +F src/where.c e25ae482e94226df7f95fa4e0545cc7064e86574 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 @@ -733,6 +733,7 @@ F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c 0ed13e09690f6204d7455fac3b0e8ece490f6eef F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 +F test/tkt-2a5629202f.test 1ab32e084e9fc3d36be6dee2617530846a0eb0b6 F test/tkt-2d1a5c67d.test b028a811049eb472cb2d3a43fc8ce4f6894eebda F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 F test/tkt-31338dca7e.test 1f714c14b6682c5db715e0bda347926a3456f7a9 @@ -931,7 +932,7 @@ F test/walro.test e6bb27762c9f22601cbb8bff6e0acfd124e74b63 F test/walshared.test 6dda2293880c300baf5d791c307f653094585761 F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test a2ed5270eb695284d4ad27d252517bdc3317ee2a -F test/where.test de337a3fe0a459ec7c93db16a519657a90552330 +F test/where.test 4c9f69987ed2aa0173fa930f2b41ab9879478cd8 F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554 F test/where3.test 667e75642102c97a00bf9b23d3cb267db321d006 F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 @@ -992,7 +993,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 3281972eaa46cb57fd9f0387063f47430dc0a3b4 -R 996fa506825219f1b7ce0687d37d97d8 -U drh -Z 27a58991babc71a559ca9c653e33aa72 +P 372a90e2264a29ce543c093766cdec764d18b5a5 +R c55b0e9d6060c081eba144f695f549a1 +U dan +Z 3f4edf7c59f1f66ed37303deb846aef3 diff --git a/manifest.uuid b/manifest.uuid index 19174a46d2..c191b9349f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -372a90e2264a29ce543c093766cdec764d18b5a5 \ No newline at end of file +9870e4c4fef10112c987c40cb1b95255a7214202 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 5471f71dcf..f2c180959b 100644 --- a/src/where.c +++ b/src/where.c @@ -1718,14 +1718,26 @@ static int isSortingIndex( } if( pIdx->onError!=OE_None && i==pIdx->nColumn && (wsFlags & WHERE_COLUMN_NULL)==0 - && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){ - /* All terms of this index match some prefix of the ORDER BY clause - ** and the index is UNIQUE and no terms on the tail of the ORDER BY - ** clause reference other tables in a join. If this is all true then - ** the order by clause is superfluous. Not that if the matching - ** condition is IS NULL then the result is not necessarily unique - ** even on a UNIQUE index, so disallow those cases. */ - return 1; + && !referencesOtherTables(pOrderBy, pMaskSet, j, base) + ){ + Column *aCol = pIdx->pTable->aCol; + int i; + + /* All terms of this index match some prefix of the ORDER BY clause, + ** the index is UNIQUE, and no terms on the tail of the ORDER BY + ** refer to other tables in a join. So, assuming that the index entries + ** visited contain no NULL values, then this index delivers rows in + ** the required order. + ** + ** It is not possible for any of the first nEqCol index fields to be + ** NULL (since the corresponding "=" operator in the WHERE clause would + ** not be true). So if all remaining index columns have NOT NULL + ** constaints attached to them, we can be confident that the visited + ** index entries are free of NULLs. */ + for(i=nEqCol; inColumn; i++){ + if( aCol[pIdx->aiColumn[i]].notNull==0 ) break; + } + return (i>=pIdx->nColumn); } return 0; } diff --git a/test/tkt-2a5629202f.test b/test/tkt-2a5629202f.test new file mode 100644 index 0000000000..037f100f65 --- /dev/null +++ b/test/tkt-2a5629202f.test @@ -0,0 +1,71 @@ +# 2012 April 19 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# The tests in this file were used while developing the SQLite 4 code. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix tkt-2a5629202f + +# This procedure executes the SQL. Then it checks to see if the OP_Sort +# opcode was executed. If an OP_Sort did occur, then "sort" is appended +# to the result. If no OP_Sort happened, then "nosort" is appended. +# +# This procedure is used to check to make sure sorting is or is not +# occurring as expected. +# +proc cksort {sql} { + set data [execsql $sql] + if {[db status sort]} {set x sort} {set x nosort} + lappend data $x + return $data +} + +do_execsql_test 1.1 { + CREATE TABLE t8(b TEXT, c TEXT); + INSERT INTO t8 VALUES('a', 'one'); + INSERT INTO t8 VALUES('b', 'two'); + INSERT INTO t8 VALUES(NULL, 'three'); + INSERT INTO t8 VALUES(NULL, 'four'); +} + +do_execsql_test 1.2 { + SELECT coalesce(b, 'null') || '/' || c FROM t8 x ORDER BY x.b, x.c +} {null/four null/three a/one b/two} + +do_execsql_test 1.3 { + CREATE UNIQUE INDEX i1 ON t8(b); + SELECT coalesce(b, 'null') || '/' || c FROM t8 x ORDER BY x.b, x.c +} {null/four null/three a/one b/two} + +#------------------------------------------------------------------------- +# + +do_execsql_test 2.1 { + CREATE TABLE t2(a, b NOT NULL, c); + CREATE UNIQUE INDEX t2ab ON t2(a, b); + CREATE UNIQUE INDEX t2ba ON t2(b, a); +} + +do_test 2.2 { + cksort { SELECT * FROM t2 WHERE a = 10 ORDER BY a, b, c } +} {nosort} + +do_test 2.3 { + cksort { SELECT * FROM t2 WHERE b = 10 ORDER BY a, b, c } +} {sort} + +do_test 2.4 { + cksort { SELECT * FROM t2 WHERE a IS NULL ORDER BY a, b, c } +} {sort} + +finish_test + diff --git a/test/where.test b/test/where.test index 9145bcc753..3826a5f64a 100644 --- a/test/where.test +++ b/test/where.test @@ -1105,15 +1105,17 @@ do_test where-14.4 { } } {1/1 1/4 4/1 4/4 nosort} do_test where-14.5 { + # This test case changed from "nosort" to "sort". See ticket 2a5629202f. cksort { SELECT x.a || '/' || y.a FROM t8 x, t8 y ORDER BY x.b, x.a||x.b } -} {4/1 4/4 1/1 1/4 nosort} +} {4/1 4/4 1/1 1/4 sort} do_test where-14.6 { + # This test case changed from "nosort" to "sort". See ticket 2a5629202f. cksort { SELECT x.a || '/' || y.a FROM t8 x, t8 y ORDER BY x.b, x.a||x.b DESC } -} {4/1 4/4 1/1 1/4 nosort} +} {4/1 4/4 1/1 1/4 sort} do_test where-14.7 { cksort { SELECT x.a || '/' || y.a FROM t8 x, t8 y ORDER BY x.b, y.a||y.b From 6a36f43586c0ad583e9c31e1cb559852a7504142 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 20 Apr 2012 16:59:24 +0000 Subject: [PATCH 03/13] Do not consider a DISTINCT clause redundant unless a subset of the result-set is collectively subject to a UNIQUE constraint and it can be guaranteed that all columns of the subset are NOT NULL (either due to NOT NULL constraints WHERE clause terms). Fix for [385a5b56b9]. FossilOrigin-Name: 7b8548b1872cc1225355ba8311e93dd08d6526e2 --- manifest | 15 +++++------ manifest.uuid | 2 +- src/where.c | 14 +++++++---- test/distinct.test | 33 ++++++++++++++++-------- test/tkt-385a5b56b9.test | 54 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 23 deletions(-) create mode 100644 test/tkt-385a5b56b9.test diff --git a/manifest b/manifest index 700e725777..164cba9eef 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sfor\s2a5629202f.\sWhen\sconsidering\swhether\sor\snot\sa\sUNIQUE\sindex\smay\sbe\sused\sto\soptimize\san\sORDER\sBY\sclause,\sdo\snot\sassume\sthat\sall\sindex\sentries\sare\sdistinct\sunless\sthere\sis\ssome\sreason\sto\sbelieve\sthat\sthe\sindex\scontains\sno\sNULL\svalues. -D 2012-04-20T15:24:53.110 +C Do\snot\sconsider\sa\sDISTINCT\sclause\sredundant\sunless\sa\ssubset\sof\sthe\sresult-set\sis\scollectively\ssubject\sto\sa\sUNIQUE\sconstraint\sand\sit\scan\sbe\sguaranteed\sthat\sall\scolumns\sof\sthe\ssubset\sare\sNOT\sNULL\s(either\sdue\sto\sNOT\sNULL\sconstraints\sWHERE\sclause\sterms).\sFix\sfor\s[385a5b56b9]. +D 2012-04-20T16:59:24.885 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -246,7 +246,7 @@ F src/vtab.c ab90fb600a3f5e4b7c48d22a4cdb2d6b23239847 F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f -F src/where.c e25ae482e94226df7f95fa4e0545cc7064e86574 +F src/where.c 8e9f01cd1604aa21cfa8e0258b7101e05082fa98 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 @@ -368,7 +368,7 @@ F test/descidx1.test 533dcbda614b0463b0ea029527fd27e5a9ab2d66 F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e -F test/distinct.test 8c6d12ba53ee8351a5b2d47628acdfad1fc97743 +F test/distinct.test da36612d05b9ed17e0425d4bfd7ab978d28a7e46 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 F test/e_createtable.test 48598b15e8fe6554d301e7b65a10c9851f177e84 F test/e_delete.test 89aa84d3d1bd284a0689ede04bce10226a5aeaa5 @@ -738,6 +738,7 @@ F test/tkt-2d1a5c67d.test b028a811049eb472cb2d3a43fc8ce4f6894eebda F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 F test/tkt-31338dca7e.test 1f714c14b6682c5db715e0bda347926a3456f7a9 F test/tkt-313723c356.test c47f8a9330523e6f35698bf4489bcb29609b53ac +F test/tkt-385a5b56b9.test 8eb87c4bbcc3fd4f33d73719de7e9d64973fa196 F test/tkt-38cb5df375.test f3cc8671f1eb604d4ae9cf886ed4366bec656678 F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7 F test/tkt-3a77c9714e.test 32bb28afa8c63fc76e972e996193139b63551ed9 @@ -993,7 +994,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 372a90e2264a29ce543c093766cdec764d18b5a5 -R c55b0e9d6060c081eba144f695f549a1 +P 9870e4c4fef10112c987c40cb1b95255a7214202 +R 7b0d4f32973f40703f4feb63496b017b U dan -Z 3f4edf7c59f1f66ed37303deb846aef3 +Z 293167d92a8f749c1bd20f8cdd573739 diff --git a/manifest.uuid b/manifest.uuid index c191b9349f..566056cbe1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9870e4c4fef10112c987c40cb1b95255a7214202 \ No newline at end of file +7b8548b1872cc1225355ba8311e93dd08d6526e2 \ No newline at end of file diff --git a/src/where.c b/src/where.c index f2c180959b..1729d912d6 100644 --- a/src/where.c +++ b/src/where.c @@ -1562,15 +1562,19 @@ static int isDistinctRedundant( ** list, or else the WHERE clause contains a term of the form "col=X", ** where X is a constant value. The collation sequences of the ** comparison and select-list expressions must match those of the index. + ** + ** 3. All of those index columns for which the WHERE clause does not + ** contain a "col=X" term are subject to a NOT NULL constraint. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->onError==OE_None ) continue; for(i=0; inColumn; i++){ int iCol = pIdx->aiColumn[i]; - if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) - && 0>findIndexCol(pParse, pDistinct, iBase, pIdx, i) - ){ - break; + if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){ + int iIdxCol = findIndexCol(pParse, pDistinct, iBase, pIdx, i); + if( iIdxCol<0 || pTab->aCol[pIdx->aiColumn[i]].notNull==0 ){ + break; + } } } if( i==pIdx->nColumn ){ @@ -1737,7 +1741,7 @@ static int isSortingIndex( for(i=nEqCol; inColumn; i++){ if( aCol[pIdx->aiColumn[i]].notNull==0 ) break; } - return (i>=pIdx->nColumn); + return (i==pIdx->nColumn); } return 0; } diff --git a/test/distinct.test b/test/distinct.test index 3bc8337942..3a33544561 100644 --- a/test/distinct.test +++ b/test/distinct.test @@ -77,20 +77,27 @@ do_execsql_test 1.0 { CREATE TABLE t2(x INTEGER PRIMARY KEY, y); - CREATE TABLE t3(c1 PRIMARY KEY, c2); + CREATE TABLE t3(c1 PRIMARY KEY NOT NULL, c2 NOT NULL); CREATE INDEX i3 ON t3(c2); + + CREATE TABLE t4(a, b NOT NULL, c NOT NULL, d NOT NULL); + CREATE UNIQUE INDEX t4i1 ON t4(b, c); + CREATE UNIQUE INDEX t4i2 ON t4(d COLLATE nocase); } foreach {tn noop sql} { - 1 1 "SELECT DISTINCT b, c FROM t1" - 2 1 "SELECT DISTINCT c FROM t1 WHERE b = ?" + 1.1 0 "SELECT DISTINCT b, c FROM t1" + 1.2 1 "SELECT DISTINCT b, c FROM t4" + 2.1 0 "SELECT DISTINCT c FROM t1 WHERE b = ?" + 2.2 1 "SELECT DISTINCT c FROM t4 WHERE b = ?" 3 1 "SELECT DISTINCT rowid FROM t1" 4 1 "SELECT DISTINCT rowid, a FROM t1" 5 1 "SELECT DISTINCT x FROM t2" 6 1 "SELECT DISTINCT * FROM t2" 7 1 "SELECT DISTINCT * FROM (SELECT * FROM t2)" - 8 1 "SELECT DISTINCT * FROM t1" + 8.1 0 "SELECT DISTINCT * FROM t1" + 8.2 1 "SELECT DISTINCT * FROM t4" 8 0 "SELECT DISTINCT a, b FROM t1" @@ -98,11 +105,16 @@ foreach {tn noop sql} { 10 0 "SELECT DISTINCT c FROM t1" 11 0 "SELECT DISTINCT b FROM t1" - 12 0 "SELECT DISTINCT a, d FROM t1" - 13 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t1" - 14 1 "SELECT DISTINCT a, d COLLATE nocase FROM t1" - 15 0 "SELECT DISTINCT a, d COLLATE binary FROM t1" - 16 1 "SELECT DISTINCT a, b, c COLLATE binary FROM t1" + 12.1 0 "SELECT DISTINCT a, d FROM t1" + 12.2 0 "SELECT DISTINCT a, d FROM t4" + 13.1 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t1" + 13.2 0 "SELECT DISTINCT a, b, c COLLATE nocase FROM t4" + 14.1 0 "SELECT DISTINCT a, d COLLATE nocase FROM t1" + 14.2 1 "SELECT DISTINCT a, d COLLATE nocase FROM t4" + + 15 0 "SELECT DISTINCT a, d COLLATE binary FROM t1" + 16.1 0 "SELECT DISTINCT a, b, c COLLATE binary FROM t1" + 16.2 1 "SELECT DISTINCT a, b, c COLLATE binary FROM t4" 16 0 "SELECT DISTINCT t1.rowid FROM t1, t2" 17 0 { /* Technically, it would be possible to detect that DISTINCT @@ -120,7 +132,8 @@ foreach {tn noop sql} { 24 0 "SELECT DISTINCT rowid/2 FROM t1" 25 1 "SELECT DISTINCT rowid/2, rowid FROM t1" - 26 1 "SELECT DISTINCT rowid/2, b FROM t1 WHERE c = ?" + 26.1 0 "SELECT DISTINCT rowid/2, b FROM t1 WHERE c = ?" + 26.2 1 "SELECT DISTINCT rowid/2, b FROM t4 WHERE c = ?" } { if {$noop} { do_distinct_noop_test 1.$tn $sql diff --git a/test/tkt-385a5b56b9.test b/test/tkt-385a5b56b9.test new file mode 100644 index 0000000000..614e82d0d5 --- /dev/null +++ b/test/tkt-385a5b56b9.test @@ -0,0 +1,54 @@ +# 2012 April 02 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# The tests in this file were used while developing the SQLite 4 code. +# +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix tkt-385a5b56b9 + +do_execsql_test 1.0 { + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(1, NULL); + INSERT INTO t1 VALUES(2, NULL); + INSERT INTO t1 VALUES(1, NULL); +} + +do_execsql_test 1.1 { SELECT DISTINCT x, y FROM t1 } {1 {} 2 {}} +do_execsql_test 1.2 { CREATE UNIQUE INDEX i1 ON t1(x, y) } +do_execsql_test 1.3 { SELECT DISTINCT x, y FROM t1 } {1 {} 2 {}} + + +#------------------------------------------------------------------------- + +do_execsql_test 2.0 { + CREATE TABLE t2(x, y NOT NULL); + CREATE UNIQUE INDEX t2x ON t2(x); + CREATE UNIQUE INDEX t2y ON t2(y); +} + +do_eqp_test 2.1 { SELECT DISTINCT x FROM t2 } { + 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2x (~1000000 rows)} +} + +do_eqp_test 2.2 { SELECT DISTINCT y FROM t2 } { + 0 0 0 {SCAN TABLE t2 (~1000000 rows)} +} + +do_eqp_test 2.3 { SELECT DISTINCT x, y FROM t2 WHERE y=10 } { + 0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?) (~1 rows)} +} + +do_eqp_test 2.4 { SELECT DISTINCT x, y FROM t2 WHERE x=10 } { + 0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x=?) (~1 rows)} +} + +finish_test + From 9b8d3572a94969ca6e6aebc8dbe81c6213e4671a Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 21 Apr 2012 11:33:39 +0000 Subject: [PATCH 04/13] If terminating interactive input to the command-line shell with ^D, issue an extra \n to move the cursor to the next line before exiting. FossilOrigin-Name: feff1ef0b8f7b51ae80a9d34380b46a5103bf6cd --- manifest | 15 +- manifest.uuid | 2 +- src/shell.c | 4 +- src/test_spellfix.c | 1951 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1963 insertions(+), 9 deletions(-) create mode 100644 src/test_spellfix.c diff --git a/manifest b/manifest index 164cba9eef..fd521769a8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sconsider\sa\sDISTINCT\sclause\sredundant\sunless\sa\ssubset\sof\sthe\sresult-set\sis\scollectively\ssubject\sto\sa\sUNIQUE\sconstraint\sand\sit\scan\sbe\sguaranteed\sthat\sall\scolumns\sof\sthe\ssubset\sare\sNOT\sNULL\s(either\sdue\sto\sNOT\sNULL\sconstraints\sWHERE\sclause\sterms).\sFix\sfor\s[385a5b56b9]. -D 2012-04-20T16:59:24.885 +C If\sterminating\sinteractive\sinput\sto\sthe\scommand-line\sshell\swith\s^D,\sissue\nan\sextra\s\\n\sto\smove\sthe\scursor\sto\sthe\snext\sline\sbefore\sexiting. +D 2012-04-21T11:33:39.769 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -174,7 +174,7 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 969ec2bc52db1b068054ecf5ddc74f244102a71d F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1 F src/select.c d7b9018b7dd2e821183d69477ab55c39b8272335 -F src/shell.c 11185a9a4574f363bd4268a2780d37480ae00040 +F src/shell.c dec1a1896ffa9eaedd6d9907cd43aca4b9d3295d F src/sqlite.h.in 4338f299fc83dada8407358d585c0e240ecb76a3 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqliteInt.h c5e917c4f1453f3972b1fd0c81105dfe4f09cc32 @@ -218,6 +218,7 @@ F src/test_quota.h ee5da2ae7f84d1c8e0e0e2ab33f01d69f10259b5 F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f +F src/test_spellfix.c 495535f3eb57acdc384572da570e869bb1834bf4 F src/test_stat.c d7035cfcc0ff1f93c000b621f36524318e004e11 F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd F src/test_syscall.c a992d8c80ea91fbf21fb2dd570db40e77dd7e6ae @@ -994,7 +995,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 9870e4c4fef10112c987c40cb1b95255a7214202 -R 7b0d4f32973f40703f4feb63496b017b -U dan -Z 293167d92a8f749c1bd20f8cdd573739 +P 7b8548b1872cc1225355ba8311e93dd08d6526e2 +R 6a28d821935f4caf8f00acbe95308ad8 +U drh +Z a4a6f8d23b8334a25a8498dbc291bb1a diff --git a/manifest.uuid b/manifest.uuid index 566056cbe1..7bec9efcd2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7b8548b1872cc1225355ba8311e93dd08d6526e2 \ No newline at end of file +feff1ef0b8f7b51ae80a9d34380b46a5103bf6cd \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 2607e680de..7fc16ffe12 100644 --- a/src/shell.c +++ b/src/shell.c @@ -2572,7 +2572,9 @@ static int process_input(struct callback_data *p, FILE *in){ free(zLine); zLine = one_input_line(zSql, in); if( zLine==0 ){ - break; /* We have reached EOF */ + /* End of input */ + if( stdin_is_interactive ) printf("\n"); + break; } if( seenInterrupt ){ if( in!=0 ) break; diff --git a/src/test_spellfix.c b/src/test_spellfix.c new file mode 100644 index 0000000000..5a221e0b1b --- /dev/null +++ b/src/test_spellfix.c @@ -0,0 +1,1951 @@ +/* +** 2012 April 10 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This module implements a VIRTUAL TABLE that can be used to search +** a large vocabulary for close matches. For example, this virtual +** table can be used to suggest corrections to misspelled words. Or, +** it could be used with FTS4 to do full-text search using potentially +** misspelled words. +** +** Create an instance of the virtual table this way: +** +** CREATE VIRTUAL TABLE demo USING spellfix1; +** +** The "spellfix1" term is the name of this module. The "demo" is the +** name of the virtual table you will be creating. The table is initially +** empty. You have to populate it with your vocabulary. Suppose you +** have a list of words in a table named "big_vocabulary". Then do this: +** +** INSERT INTO demo(word) SELECT word FROM big_vocabulary; +** +** If you intend to use this virtual table in cooperation with an FTS4 +** table (for spelling correctly of search terms) then you can extract +** the vocabulary using an fts3aux table: +** +** INSERT INTO demo(word) SELECT term FROM search_aux WHERE col='*'; +** +** You can also provide the virtual table with a "rank" for each word. +** The "rank" is an estimate of how common the word is. Larger numbers +** mean the word is more common. If you omit the rank when populating +** the table, then a rank of 1 is assumed. But if you have rank +** information, you can supply it and the virtual table will show a +** slight preference for selecting more commonly used terms. To +** populate the rank from an fts4aux table "search_aux" do something +** like this: +** +** INSERT INTO demo(word,rank) +** SELECT term, documents FROM search_aux WHERE col='*'; +** +** To query the virtual table, include a MATCH operator in the WHERE +** clause. For example: +** +** SELECT word FROM demo WHERE word MATCH 'kennasaw'; +** +** Using a dataset of American place names (derived from +** http://geonames.usgs.gov/domestic/download_data.htm) the query above +** returns 20 results beginning with: +** +** kennesaw +** kenosha +** kenesaw +** kenaga +** keanak +** +** If you append the character '*' to the end of the pattern, then +** a prefix search is performed. For example: +** +** SELECT word FROM demo WHERE word MATCH 'kennes*'; +** +** Yields 20 results beginning with: +** +** kennesaw +** kennestone +** kenneson +** kenneys +** keanes +** keenes +** +** The virtual table actually has a unique rowid with five columns plus three +** extra hidden columns. The columns are as follows: +** +** rowid A unique integer number associated with each +** vocabulary item in the table. This can be used +** as a foreign key on other tables in the database. +** +** word The text of the word that matches the pattern. +** Both word and pattern can contains unicode characters +** and can be mixed case. +** +** rank This is the rank of the word, as specified in the +** original INSERT statement. +** +** distance This is an edit distance or Levensthein distance going +** from the pattern to the word. +** +** langid This is the language-id of the word. All queries are +** against a single language-id, which defaults to 0. +** For any given query this value is the same on all rows. +** +** score The score is a combination of rank and distance. The +** idea is that a lower score is better. The virtual table +** attempts to find words with the lowest score and +** by default (unless overridden by ORDER BY) returns +** results in order of increasing score. +** +** top (HIDDEN) For any query, this value is the same on all +** rows. It is an integer which is the maximum number of +** rows that will be output. The actually number of rows +** output might be less than this number, but it will never +** be greater. The default value for top is 20, but that +** can be changed for each query by including a term of +** the form "top=N" in the WHERE clause of the query. +** +** scope (HIDDEN) For any query, this value is the same on all +** rows. The scope is a measure of how widely the virtual +** table looks for matching words. Smaller values of +** scope cause a broader search. The scope is normally +** choosen automatically and is capped at 4. Applications +** can change the scope by including a term of the form +** "scope=N" in the WHERE clause of the query. Increasing +** the scope will make the query run faster, but will reduce +** the possible corrections. +** +** srchcnt (HIDDEN) For any query, this value is the same on all +** rows. This value is an integer which is the number of +** of words examined using the edit-distance algorithm to +** find the top matches that are ultimately displayed. This +** value is for diagnostic use only. +** +** soundslike (HIDDEN) When inserting vocabulary entries, this field +** can be set to an spelling that matches what the word +** sounds like. See the DEALING WITH UNUSUAL AND DIFFICULT +** SPELLINGS section below for details. +** +** When inserting into or updating the virtual table, only the rowid, word, +** rank, and langid may be changes. Any attempt to set or modify the values +** of distance, score, top, scope, or srchcnt is silently ignored. +** +** ALGORITHM +** +** A shadow table named "%_vocab" (where the % is replaced by the name of +** the virtual table; Ex: "demo_vocab" for the "demo" virtual table) is +** constructed with these columns: +** +** id The unique id (INTEGER PRIMARY KEY) +** +** rank The rank of word. +** +** langid The language id for this entry. +** +** word The original UTF8 text of the vocabulary word +** +** k1 The word transliterated into lower-case ASCII. +** There is a standard table of mappings from non-ASCII +** characters into ASCII. Examples: "æ" -> "ae", +** "þ" -> "th", "ß" -> "ss", "á" -> "a", ... The +** accessory function spellfix1_translit(X) will do +** the non-ASCII to ASCII mapping. The built-in lower(X) +** function will convert to lower-case. Thus: +** k1 = lower(spellfix1_translit(word)). +** +** k2 This field holds a phonetic code derived from k1. Letters +** that have similar sounds are mapped into the same symbol. +** For example, all vowels and vowel clusters become the +** single symbol "A". And the letters "p", "b", "f", and +** "v" all become "B". All nasal sounds are represented +** as "N". And so forth. The mapping is base on +** ideas found in Soundex, Metaphone, and other +** long-standing phonetic matching systems. This key can +** be generated by the function spellfix1_charclass(X). +** Hence: k2 = spellfix1_charclass(k1) +** +** There is also a function for computing the Wagner edit distance or the +** Levenshtein distance between a pattern and a word. This function +** is exposed as spellfix1_editdist(X,Y). The edit distance function +** returns the "cost" of converting X into Y. Some transformations +** cost more than others. Changing one vowel into a different vowel, +** for example is relatively cheap, as is doubling a constant, or +** omitting the second character of a double-constant. Other transformations +** or more expensive. The idea is that the edit distance function returns +** a low cost of words that are similar and a higher cost for words +** that are futher apart. In this implementation, the maximum cost +** of any single-character edit (delete, insert, or substitute) is 100, +** with lower costs for some edits (such as transforming vowels). +** +** The "score" for a comparison is the edit distance between the pattern +** and the word, adjusted down by the base-2 logorithm of the word rank. +** For example, a match with distance 100 but rank 1000 would have a +** score of 122 (= 100 - log2(1000) + 32) where as a match with distance +** 100 with a rank of 1 would have a score of 131 (100 - log2(1) + 32). +** (NB: The constant 32 is added to each score to keep it from going +** negative in case the edit distance is zero.) In this way, frequently +** used words get a slightly lower cost which tends to move them toward +** the top of the list of alternative spellings. +** +** A straightforward implementation of a spelling corrector would be +** to compare the search term against every word in the vocabulary +** and select the 20 with the lowest scores. However, there will +** typically be hundreds of thousands or millions of words in the +** vocabulary, and so this approach is not fast enough. +** +** Suppose the term that is being spell-corrected is X. To limit +** the search space, X is converted to a k2-like key using the +** equivalent of: +** +** key = spellfix1_charclass(lower(spellfix1_translit(X))) +** +** This key is then limited to "scope" characters. The default scope +** value is 4, but an alternative scope can be specified using the +** "scope=N" term in the WHERE clause. After the key has been truncated, +** the edit distance is run against every term in the vocabulary that +** has a k2 value that begins with the abbreviated key. +** +** For example, suppose the input word is "Paskagula". The phonetic +** key is "BACACALA" which is then truncated to 4 characters "BACA". +** The edit distance is then run on the 4980 entries (out of +** 272,597 entries total) of the vocabulary whose k2 values begin with +** BACA, yielding "Pascagoula" as the best match. +** +** Only terms of the vocabulary with a matching langid are searched. +** Hence, the same table can contain entries from multiple languages +** and only the requested language will be used. The default langid +** is 0. +** +** DEALING WITH UNUSUAL AND DIFFICULT SPELLINGS +** +** The algorithm above works quite well for most cases, but there are +** exceptions. These exceptions can be dealt with by making additional +** entries in the virtual table using the "soundslike" column. +** +** For example, many words of Greek origin begin with letters "ps" where +** the "p" is silent. Ex: psalm, pseudonym, psoriasis, psyche. In +** another example, many Scottish surnames can be spelled with an +** initial "Mac" or "Mc". Thus, "MacKay" and "McKay" are both pronounced +** the same. +** +** Accommodation can be made for words that are not spelled as they +** sound by making additional entries into the virtual table for the +** same word, but adding an alternative spelling in the "soundslike" +** column. For example, the canonical entry for "psalm" would be this: +** +** INSERT INTO demo(word) VALUES('psalm'); +** +** To enhance the ability to correct the spelling of "salm" into +** "psalm", make an addition entry like this: +** +** INSERT INTO demo(word,soundslike) VALUES('psalm','salm'); +** +** It is ok to make multiple entries for the same word as long as +** each entry has a different soundslike value. Note that if no +** soundslike value is specified, the soundslike defaults to the word +** itself. +** +** Listed below are some cases where it might make sense to add additional +** soundslike entries. The specific entries will depend on the application +** and the target language. +** +** * Silent "p" in words beginning with "ps": psalm, psyche +** +** * Silent "p" in words beginning with "pn": pneumonia, pneumatic +** +** * Silent "p" in words beginning with "pt": pterodactyl, ptolemaic +** +** * Silent "d" in words beginning with "dj": djinn, Djikarta +** +** * Silent "k" in words beginning with "kn": knight, Knuthson +** +** * Silent "g" in words beginning with "gn": gnarly, gnome, gnat +** +** * "Mac" versus "Mc" beginning Scottish surnames +** +** * "Tch" sounds in Slavic words: Tchaikovsky vs. Chaykovsky +** +** * The letter "j" pronounced like "h" in Spanish: LaJolla +** +** * Words beginning with "wr" versus "r": write vs. rite +** +** * Miscellanous problem words such as "debt", "tsetse", +** "Nguyen", "Van Nuyes". +*/ +#if SQLITE_CORE +# include "sqliteInt.h" +#else +# include +# include +# include +# include "sqlite3ext.h" + SQLITE_EXTENSION_INIT1 +#endif /* !SQLITE_CORE */ + +/* +** Character classes for ASCII characters: +** +** 0 '' Silent letters: H W +** 1 'A' Any vowel: A E I O U (Y) +** 2 'B' A bilabeal stop or fricative: B F P V +** 3 'C' Other fricatives or back stops: C G J K Q S X Z +** 4 'D' Alveolar stops: D T +** 5 'H' Letter H at the beginning of a word +** 6 'L' Glides: L R +** 7 'M' Nasals: M N +** 8 'W' Letter W at the beginning of a word +** 9 'Y' Letter Y at the beginning of a word. +** 10 '9' A digit: 0 1 2 3 4 5 6 7 8 9 +** 11 ' ' White space +** 12 '?' Other. +*/ +#define CCLASS_SILENT 0 +#define CCLASS_VOWEL 1 +#define CCLASS_B 2 +#define CCLASS_C 3 +#define CCLASS_D 4 +#define CCLASS_H 5 +#define CCLASS_L 6 +#define CCLASS_M 7 +#define CCLASS_W 8 +#define CCLASS_Y 9 +#define CCLASS_DIGIT 10 +#define CCLASS_SPACE 11 +#define CCLASS_OTHER 12 + +/* +** The following table gives the character class for non-initial ASCII +** characters. +*/ +static const unsigned char midClass[] = { + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ + /* 0x */ 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 12, 11, 12, 12, 12, + /* 1x */ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + /* 2x */ 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + /* 3x */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, + /* 4x */ 12, 1, 2, 3, 4, 1, 2, 3, 0, 1, 3, 3, 6, 7, 7, 1, + /* 5x */ 2, 3, 6, 3, 4, 1, 2, 0, 3, 1, 3, 12, 12, 12, 12, 12, + /* 6x */ 12, 1, 2, 3, 4, 1, 2, 3, 0, 1, 3, 3, 6, 7, 7, 1, + /* 7x */ 2, 3, 6, 3, 4, 1, 2, 0, 3, 1, 3, 12, 12, 12, 12, 12, +}; + +/* +** This tables gives the character class for ASCII characters that form the +** initial character of a word. The only difference from midClass is with +** the letters H, W, and Y. +*/ +static const unsigned char initClass[] = { + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ + /* 0x */ 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 12, 11, 12, 12, 12, + /* 1x */ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + /* 2x */ 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + /* 3x */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, + /* 4x */ 12, 1, 2, 3, 4, 1, 2, 3, 5, 1, 3, 3, 6, 7, 7, 1, + /* 5x */ 2, 3, 6, 3, 4, 1, 2, 8, 3, 9, 3, 12, 12, 12, 12, 12, + /* 6x */ 12, 1, 2, 3, 4, 1, 2, 3, 5, 1, 3, 3, 6, 7, 7, 1, + /* 7x */ 2, 3, 6, 3, 4, 1, 2, 8, 3, 9, 3, 12, 12, 12, 12, 12, +}; + +/* +** Mapping from the character class number (0-12) to a symbol for each +** character class. Note that initClass[] can be used to map the class +** symbol back into the class number. +*/ +static const unsigned char className[] = ".ABCDHLMWY9 ?"; + +/* +** Generate a string of character classes corresponding to the +** ASCII characters in the input string zIn. If the input is not +** ASCII then the behavior is undefined. +** +** Space to hold the result is obtained from sqlite3_malloc() +** +** Return NULL if memory allocation fails. +*/ +static unsigned char *characterClassString(const unsigned char *zIn, int nIn){ + unsigned char *zOut = sqlite3_malloc( nIn + 1 ); + int i; + int nOut = 0; + char cPrev = 0x77; + const unsigned char *aClass = initClass; + + if( zOut==0 ) return 0; + for(i=0; i='A' && cTo<='Z') || (cTo>='a' && cTo<='z')) ){ + /* differ only in case */ + return 0; + } + classFrom = characterClass(cPrev, cFrom); + classTo = characterClass(cPrev, cTo); + if( classFrom==classTo ){ + /* Same character class */ + return classFrom=='A' ? 25 : 40; + } + if( classFrom>=CCLASS_B && classFrom<=CCLASS_Y + && classTo>=CCLASS_B && classTo<=CCLASS_Y ){ + /* Convert from one consonant to another, but in a different class */ + return 75; + } + /* Any other subsitution */ + return 100; +} + +/* +** Given two strings zA and zB which are pure ASCII, return the cost +** of transforming zA into zB. If zA ends with '*' assume that it is +** a prefix of zB and give only minimal penalty for extra characters +** on the end of zB. +** +** Smaller numbers mean a closer match. +** +** Negative values indicate an error: +** -1 One of the inputs is NULL +** -2 Non-ASCII characters on input +** -3 Unable to allocate memory +*/ +static int editdist(const char *zA, const char *zB){ + int nA, nB; /* Number of characters in zA[] and zB[] */ + int xA, xB; /* Loop counters for zA[] and zB[] */ + char cA, cB; /* Current character of zA and zB */ + char cAprev, cBprev; /* Previous character of zA and zB */ + int d; /* North-west cost value */ + int dc = 0; /* North-west character value */ + int res; /* Final result */ + int *m; /* The cost matrix */ + char *cx; /* Corresponding character values */ + int *toFree = 0; /* Malloced space */ + int mStack[60+15]; /* Stack space to use if not too much is needed */ + + /* Early out if either input is NULL */ + if( zA==0 || zB==0 ) return -1; + + /* Skip any common prefix */ + while( zA[0] && zA[0]==zB[0] ){ dc = zA[0]; zA++; zB++; } + if( zA[0]==0 && zB[0]==0 ) return 0; + +#if 0 + printf("A=\"%s\" B=\"%s\" dc=%c\n", zA, zB, dc?dc:' '); +#endif + + /* Verify input strings and measure their lengths */ + for(nA=0; zA[nA]; nA++){ + if( zA[nA]>127 ) return -2; + } + for(nB=0; zB[nB]; nB++){ + if( zB[nB]>127 ) return -2; + } + + /* Special processing if either string is empty */ + if( nA==0 ){ + cBprev = dc; + for(xB=res=0; (cB = zB[xB])!=0; xB++){ + res += insertOrDeleteCost(cBprev, cB)/FINAL_INS_COST_DIV; + cBprev = cB; + } + return res; + } + if( nB==0 ){ + cAprev = dc; + for(xA=res=0; (cA = zA[xA])!=0; xA++){ + res += insertOrDeleteCost(cAprev, cA); + cAprev = cA; + } + return res; + } + + /* A is a prefix of B */ + if( zA[0]=='*' && zA[1]==0 ) return 0; + + /* Allocate and initialize the Wagner matrix */ + if( nB<(sizeof(mStack)*4)/(sizeof(mStack[0])*5) ){ + m = mStack; + }else{ + m = toFree = sqlite3_malloc( (nB+1)*5*sizeof(m[0])/4 ); + if( m==0 ) return -3; + } + cx = (char*)&m[nB+1]; + + /* Compute the Wagner edit distance */ + m[0] = 0; + cx[0] = dc; + cBprev = dc; + for(xB=1; xB<=nB; xB++){ + cB = zB[xB-1]; + cx[xB] = cB; + m[xB] = m[xB-1] + insertOrDeleteCost(cBprev, cB); + cBprev = cB; + } + cAprev = dc; + for(xA=1; xA<=nA; xA++){ + int lastA = (xA==nA); + cA = zA[xA-1]; + if( cA=='*' && lastA ) break; + d = m[0]; + dc = cx[0]; + m[0] = d + insertOrDeleteCost(cAprev, cA); + cBprev = 0; + for(xB=1; xB<=nB; xB++){ + int totalCost, insCost, delCost, subCost, ncx; + cB = zB[xB-1]; + + /* Cost to insert cB */ + insCost = insertOrDeleteCost(cx[xB-1], cB); + if( lastA ) insCost /= FINAL_INS_COST_DIV; + + /* Cost to delete cA */ + delCost = insertOrDeleteCost(cx[xB], cA); + + /* Cost to substitute cA->cB */ + subCost = substituteCost(cx[xB-1], cA, cB); + + /* Best cost */ + totalCost = insCost + m[xB-1]; + ncx = cB; + if( (delCost + m[xB])nA ){ + res = m[nA]; + for(xB=nA+1; xB<=nB; xB++){ + if( m[xB]=0xc0 ){ + c = sqlite3Utf8Trans1[c-0xc0]; + while( i=xBtm ){ + x = (xTop + xBtm)/2; + if( translit[x].cFrom==c ){ + zOut[nOut++] = translit[x].cTo0; + if( translit[x].cTo1 ){ + zOut[nOut++] = translit[x].cTo1; + /* Add an extra "ch" after the "sh" for Щ and щ */ + if( c==0x0429 || c== 0x0449 ){ + zOut[nOut++] = 'c'; + zOut[nOut++] = 'h'; + } + } + c = 0; + break; + }else if( translit[x].cFrom>c ){ + xTop = x-1; + }else{ + xBtm = x+1; + } + } + if( c ) zOut[nOut++] = '?'; + } + } + zOut[nOut] = 0; + return zOut; +} + +/* +** spellfix1_translit(X) +** +** Convert a string that contains non-ASCII Roman characters into +** pure ASCII. +*/ +static void transliterateSqlFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zIn = sqlite3_value_text(argv[0]); + int nIn = sqlite3_value_bytes(argv[0]); + unsigned char *zOut = transliterate(zIn, nIn); + if( zOut==0 ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_text(context, (char*)zOut, -1, sqlite3_free); + } +} + +/* +** spellfix1_scriptcode(X) +** +** Try to determine the dominant script used by the word X and return +** its ISO 15924 numeric code. +** +** The current implementation only understands the following scripts: +** +** 215 (Latin) +** 220 (Cyrillic) +** 200 (Greek) +** +** This routine will return 998 if the input X contains characters from +** two or more of the above scripts or 999 if X contains no characters +** from any of the above scripts. +*/ +static void scriptCodeSqlFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const unsigned char *zIn = sqlite3_value_text(argv[0]); + int nIn = sqlite3_value_bytes(argv[0]); + int c, sz; + int scriptMask = 0; + int res; +# define SCRIPT_LATIN 0x0001 +# define SCRIPT_CYRILLIC 0x0002 +# define SCRIPT_GREEK 0x0004 + + while( nIn>0 ){ + c = utf8Read(zIn, nIn, &sz); + zIn += sz; + nIn -= sz; + if( c<0x02af ){ + scriptMask |= SCRIPT_LATIN; + }else if( c>=0x0400 && c<=0x04ff ){ + scriptMask |= SCRIPT_CYRILLIC; + }else if( c>=0x0386 && c<=0x03ce ){ + scriptMask |= SCRIPT_GREEK; + } + } + switch( scriptMask ){ + case 0: res = 999; break; + case SCRIPT_LATIN: res = 215; break; + case SCRIPT_CYRILLIC: res = 220; break; + case SCRIPT_GREEK: res = 200; break; + default: res = 998; break; + } + sqlite3_result_int(context, res); +} + +/***************************************************************************** +** Fuzzy-search virtual table +*****************************************************************************/ + +typedef struct spellfix1_vtab spellfix1_vtab; +typedef struct spellfix1_cursor spellfix1_cursor; + +/* Fuzzy-search virtual table object */ +struct spellfix1_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; /* Database connection */ + char *zDbName; /* Name of database holding this table */ + char *zTableName; /* Name of the virtual table */ +}; + +/* Fuzzy-search cursor object */ +struct spellfix1_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + spellfix1_vtab *pVTab; /* The table to which this cursor belongs */ + int nRow; /* Number of rows of content */ + int nAlloc; /* Number of allocated rows */ + int iRow; /* Current row of content */ + int iLang; /* Value of the lang= constraint */ + int iTop; /* Value of the top= constraint */ + int iScope; /* Value of the scope= constraint */ + int nSearch; /* Number of vocabulary items checked */ + struct spellfix1_row { /* For each row of content */ + sqlite3_int64 iRowid; /* Rowid for this row */ + char *zWord; /* Text for this row */ + int iRank; /* Rank for this row */ + int iDistance; /* Distance from pattern for this row */ + int iScore; /* Score for sorting */ + } *a; +}; + +/* +** Construct one or more SQL statements from the format string given +** and then evaluate those statements. The success code is written +** into *pRc. +** +** If *pRc is initially non-zero then this routine is a no-op. +*/ +static void spellfix1DbExec( + int *pRc, /* Success code */ + sqlite3 *db, /* Database in which to run SQL */ + const char *zFormat, /* Format string for SQL */ + ... /* Arguments to the format string */ +){ + va_list ap; + char *zSql; + if( *pRc ) return; + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( zSql==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + *pRc = sqlite3_exec(db, zSql, 0, 0, 0); + sqlite3_free(zSql); + } +} + +/* +** xDisconnect/xDestroy method for the fuzzy-search module. +*/ +static int spellfix1Uninit(int isDestroy, sqlite3_vtab *pVTab){ + spellfix1_vtab *p = (spellfix1_vtab*)pVTab; + int rc = SQLITE_OK; + if( isDestroy ){ + sqlite3 *db = p->db; + spellfix1DbExec(&rc, db, "DROP TABLE IF EXISTS \"%w\".\"%w_vocab\"", + p->zDbName, p->zTableName); + } + if( rc==SQLITE_OK ){ + sqlite3_free(p->zTableName); + sqlite3_free(p); + } + return rc; +} +static int spellfix1Disconnect(sqlite3_vtab *pVTab){ + return spellfix1Uninit(0, pVTab); +} +static int spellfix1Destroy(sqlite3_vtab *pVTab){ + return spellfix1Uninit(1, pVTab); +} + +/* +** xConnect/xCreate method for the spellfix1 module. Arguments are: +** +** argv[0] -> module name ("spellfix1") +** argv[1] -> database name +** argv[2] -> table name +** argv[3].. -> optional arguments (currently ignored) +*/ +static int spellfix1Init( + int isCreate, + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, + char **pzErr +){ + spellfix1_vtab *pNew = 0; + const char *zModule = argv[0]; + const char *zDbName = argv[1]; + const char *zTableName = argv[2]; + int nDbName; + int rc = SQLITE_OK; + + if( argc<3 ){ + *pzErr = sqlite3_mprintf( + "%s: wrong number of CREATE VIRTUAL TABLE arguments", argv[0] + ); + rc = SQLITE_ERROR; + }else{ + nDbName = strlen(zDbName); + pNew = sqlite3_malloc( sizeof(*pNew) + nDbName + 1); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pNew, 0, sizeof(*pNew)); + pNew->zDbName = (char*)&pNew[1]; + memcpy(pNew->zDbName, zDbName, nDbName+1); + pNew->zTableName = sqlite3_mprintf("%s", zTableName); + pNew->db = db; + if( pNew->zTableName==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(word,rank,distance,langid," + "score,top HIDDEN,scope HIDDEN,srchcnt HIDDEN," + "soundslike HIDDEN)" + ); + } + if( rc==SQLITE_OK && isCreate ){ + sqlite3_uint64 r; + spellfix1DbExec(&rc, db, + "CREATE TABLE IF NOT EXISTS \"%w\".\"%w_vocab\"(\n" + " id INTEGER PRIMARY KEY,\n" + " rank INT,\n" + " langid INT,\n" + " word TEXT,\n" + " k1 TEXT,\n" + " k2 TEXT\n" + ");\n", + zDbName, zTableName + ); + sqlite3_randomness(sizeof(r), &r); + spellfix1DbExec(&rc, db, + "CREATE INDEX IF NOT EXISTS \"%w\".\"%w_index_%llx\" " + "ON \"%w_vocab\"(langid,k2);", + zDbName, zModule, r, zTableName + ); + } + } + } + + *ppVTab = (sqlite3_vtab *)pNew; + return rc; +} + +/* +** The xConnect and xCreate methods +*/ +static int spellfix1Connect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, + char **pzErr +){ + return spellfix1Init(0, db, pAux, argc, argv, ppVTab, pzErr); +} +static int spellfix1Create( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, + char **pzErr +){ + return spellfix1Init(1, db, pAux, argc, argv, ppVTab, pzErr); +} + +/* +** Reset a cursor so that it contains zero rows of content but holds +** space for N rows. +*/ +static void spellfix1ResetCursor(spellfix1_cursor *pCur, int N){ + int i; + for(i=0; inRow; i++){ + sqlite3_free(pCur->a[i].zWord); + } + pCur->a = sqlite3_realloc(pCur->a, sizeof(pCur->a[0])*N); + pCur->nAlloc = N; + pCur->nRow = 0; + pCur->iRow = 0; + pCur->nSearch = 0; +} + +/* +** Close a fuzzy-search cursor. +*/ +static int spellfix1Close(sqlite3_vtab_cursor *cur){ + spellfix1_cursor *pCur = (spellfix1_cursor *)cur; + spellfix1ResetCursor(pCur, 0); + sqlite3_free(pCur); + return SQLITE_OK; +} + +/* +** Search for terms of these forms: +** +** (A) word MATCH $str +** (B) langid == $langid +** (C) top = $top +** (D) scope = $scope +** +** The plan number is a bit mask formed with these bits: +** +** 0x01 (A) is found +** 0x02 (B) is found +** 0x04 (C) is found +** 0x08 (D) is found +** +** filter.argv[*] values contains $str, $langid, $top, and $scope, +** if specified and in that order. +*/ +static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + int iPlan = 0; + int iLangTerm = -1; + int iTopTerm = -1; + int iScopeTerm = -1; + int i; + const struct sqlite3_index_constraint *pConstraint; + pConstraint = pIdxInfo->aConstraint; + for(i=0; inConstraint; i++, pConstraint++){ + if( pConstraint->usable==0 ) continue; + + /* Terms of the form: word MATCH $str */ + if( (iPlan & 1)==0 + && pConstraint->iColumn==0 + && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH + ){ + iPlan |= 1; + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + pIdxInfo->aConstraintUsage[i].omit = 1; + } + + /* Terms of the form: langid = $langid */ + if( (iPlan & 2)==0 + && pConstraint->iColumn==3 + && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ + ){ + iPlan |= 2; + iLangTerm = i; + } + + /* Terms of the form: top = $top */ + if( (iPlan & 4)==0 + && pConstraint->iColumn==5 + && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ + ){ + iPlan |= 4; + iTopTerm = i; + } + + /* Terms of the form: scope = $scope */ + if( (iPlan & 8)==0 + && pConstraint->iColumn==6 + && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ + ){ + iPlan |= 8; + iScopeTerm = i; + } + } + if( iPlan&1 ){ + int idx = 2; + pIdxInfo->idxNum = iPlan; + if( pIdxInfo->nOrderBy==1 + && pIdxInfo->aOrderBy[0].iColumn==4 + && pIdxInfo->aOrderBy[0].desc==0 + ){ + pIdxInfo->orderByConsumed = 1; /* Default order by iScore */ + } + if( iPlan&2 ){ + pIdxInfo->aConstraintUsage[iLangTerm].argvIndex = idx++; + pIdxInfo->aConstraintUsage[iLangTerm].omit = 1; + } + if( iPlan&4 ){ + pIdxInfo->aConstraintUsage[iTopTerm].argvIndex = idx++; + pIdxInfo->aConstraintUsage[iTopTerm].omit = 1; + } + if( iPlan&8 ){ + pIdxInfo->aConstraintUsage[iScopeTerm].argvIndex = idx++; + pIdxInfo->aConstraintUsage[iScopeTerm].omit = 1; + } + pIdxInfo->estimatedCost = (double)10000; + }else{ + pIdxInfo->idxNum = 0; + pIdxInfo->estimatedCost = (double)10000000; + } + return SQLITE_OK; +} + +/* +** Open a new fuzzy-search cursor. +*/ +static int spellfix1Open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ + spellfix1_vtab *p = (spellfix1_vtab*)pVTab; + spellfix1_cursor *pCur; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + pCur->pVTab = p; + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Adjust a distance measurement by the words rank in order to show +** preference to common words. +*/ +static int spellfix1Score(int iDistance, int iRank){ + int iLog2; + for(iLog2=0; iRank>0; iLog2++, iRank>>=1){} + return iDistance + 32 - iLog2; +} + +/* +** Compare two spellfix1_row objects for sorting purposes in qsort() such +** that they sort in order of increasing distance. +*/ +static int spellfix1RowCompare(const void *A, const void *B){ + const struct spellfix1_row *a = (const struct spellfix1_row*)A; + const struct spellfix1_row *b = (const struct spellfix1_row*)B; + return a->iScore - b->iScore; +} + +/* +** This version of the xFilter method work if the MATCH term is present +** and we are doing a scan. +*/ +static int spellfix1FilterForMatch( + spellfix1_cursor *pCur, + int idxNum, + int argc, + sqlite3_value **argv +){ + const unsigned char *zPatternIn; + char *zPattern; + int nPattern; + char *zClass; + int nClass; + int iLimit = 20; + int iScope = 4; + int iLang = 0; + char *zSql; + int rc; + sqlite3_stmt *pStmt; + int idx = 1; + spellfix1_vtab *p = pCur->pVTab; + + if( idxNum&2 ){ + iLang = sqlite3_value_int(argv[idx++]); + } + if( idxNum&4 ){ + iLimit = sqlite3_value_int(argv[idx++]); + if( iLimit<1 ) iLimit = 1; + } + if( idxNum&8 ){ + iScope = sqlite3_value_int(argv[idx++]); + if( iScope<1 ) iScope = 1; + } + spellfix1ResetCursor(pCur, iLimit); + zPatternIn = sqlite3_value_text(argv[0]); + if( zPatternIn==0 ) return SQLITE_OK; + zPattern = (char*)transliterate(zPatternIn, sqlite3_value_bytes(argv[0])); + if( zPattern==0 ) return SQLITE_NOMEM; + nPattern = strlen(zPattern); + if( zPattern[nPattern-1]=='*' ) nPattern--; + if( nPatterniScope ){ + zClass[iScope] = 0; + nClass = iScope; + } + zSql = sqlite3_mprintf( + "SELECT id, word, rank, k1" + " FROM \"%w\".\"%w_vocab\"" + " WHERE langid=%d AND k2 GLOB '%q*'", + p->zDbName, p->zTableName, iLang, zClass + ); + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + if( rc==SQLITE_OK ){ + const char *zK1; + int iDist; + int iRank; + int iScore; + int iWorst = 999999999; + int idx; + int idxWorst; + int i; + + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + zK1 = (const char*)sqlite3_column_text(pStmt, 3); + if( zK1==0 ) continue; + pCur->nSearch++; + iRank = sqlite3_column_int(pStmt, 2); + iDist = editdist(zPattern, zK1); + iScore = spellfix1Score(iDist,iRank); + if( pCur->nRownAlloc ){ + idx = pCur->nRow; + }else if( iScorea[idx].zWord); + }else{ + continue; + } + pCur->a[idx].zWord = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); + pCur->a[idx].iRowid = sqlite3_column_int64(pStmt, 0); + pCur->a[idx].iRank = iRank; + pCur->a[idx].iDistance = iDist; + pCur->a[idx].iScore = iScore; + if( pCur->nRownAlloc ) pCur->nRow++; + if( pCur->nRow==pCur->nAlloc ){ + iWorst = pCur->a[0].iScore; + idxWorst = 0; + for(i=1; inRow; i++){ + iScore = pCur->a[i].iScore; + if( iWorsta, pCur->nRow, sizeof(pCur->a[0]), spellfix1RowCompare); + pCur->iTop = iLimit; + pCur->iScope = iScope; + sqlite3_finalize(pStmt); + sqlite3_free(zPattern); + sqlite3_free(zClass); + return SQLITE_OK; +} + +/* +** This version of xFilter handles a full-table scan case +*/ +static int spellfix1FilterForFullScan( + spellfix1_cursor *pCur, + int idxNum, + int argc, + sqlite3_value **argv +){ + spellfix1ResetCursor(pCur, 0); + return SQLITE_OK; +} + + +/* +** Called to "rewind" a cursor back to the beginning so that +** it starts its output over again. Always called at least once +** prior to any spellfix1Column, spellfix1Rowid, or spellfix1Eof call. +*/ +static int spellfix1Filter( + sqlite3_vtab_cursor *cur, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + spellfix1_cursor *pCur = (spellfix1_cursor *)cur; + int rc; + if( idxNum & 1 ){ + rc = spellfix1FilterForMatch(pCur, idxNum, argc, argv); + }else{ + rc = spellfix1FilterForFullScan(pCur, idxNum, argc, argv); + } + return rc; +} + + +/* +** Advance a cursor to its next row of output +*/ +static int spellfix1Next(sqlite3_vtab_cursor *cur){ + spellfix1_cursor *pCur = (spellfix1_cursor *)cur; + if( pCur->iRow < pCur->nRow ) pCur->iRow++; + return SQLITE_OK; +} + +/* +** Return TRUE if we are at the end-of-file +*/ +static int spellfix1Eof(sqlite3_vtab_cursor *cur){ + spellfix1_cursor *pCur = (spellfix1_cursor *)cur; + return pCur->iRow>=pCur->nRow; +} + +/* +** Return columns from the current row. +*/ +static int spellfix1Column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ + spellfix1_cursor *pCur = (spellfix1_cursor*)cur; + switch( i ){ + case 0: { + sqlite3_result_text(ctx, pCur->a[pCur->iRow].zWord, -1, SQLITE_STATIC); + break; + } + case 1: { + sqlite3_result_int(ctx, pCur->a[pCur->iRow].iRank); + break; + } + case 2: { + sqlite3_result_int(ctx, pCur->a[pCur->iRow].iDistance); + break; + } + case 3: { + sqlite3_result_int(ctx, pCur->iLang); + break; + } + case 4: { + sqlite3_result_int(ctx, pCur->a[pCur->iRow].iScore); + break; + } + case 5: { + sqlite3_result_int(ctx, pCur->iTop); + break; + } + case 6: { + sqlite3_result_int(ctx, pCur->iScope); + break; + } + case 7: { + sqlite3_result_int(ctx, pCur->nSearch); + break; + } + default: { + sqlite3_result_null(ctx); + break; + } + } + return SQLITE_OK; +} + +/* +** The rowid. +*/ +static int spellfix1Rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + spellfix1_cursor *pCur = (spellfix1_cursor*)cur; + *pRowid = pCur->a[pCur->iRow].iRowid; + return SQLITE_OK; +} + +/* +** The xUpdate() method. +*/ +static int spellfix1Update( + sqlite3_vtab *pVTab, + int argc, + sqlite3_value **argv, + sqlite_int64 *pRowid +){ + int rc = SQLITE_OK; + sqlite3_int64 rowid, newRowid; + spellfix1_vtab *p = (spellfix1_vtab*)pVTab; + sqlite3 *db = p->db; + + if( argc==1 ){ + /* A delete operation on the rowid given by argv[0] */ + rowid = *pRowid = sqlite3_value_int64(argv[0]); + spellfix1DbExec(&rc, db, "DELETE FROM \"%w\".\"%w_vocab\" " + " WHERE id=%lld", + p->zDbName, p->zTableName, rowid); + }else{ + const unsigned char *zWord = sqlite3_value_text(argv[2]); + int nWord = sqlite3_value_bytes(argv[2]); + int iLang = sqlite3_value_int(argv[5]); + int iRank = sqlite3_value_int(argv[3]); + const unsigned char *zSoundslike = sqlite3_value_text(argv[10]); + int nSoundslike = sqlite3_value_bytes(argv[10]); + char *zK1, *zK2; + int i; + char c; + + if( zWord==0 ){ + pVTab->zErrMsg = sqlite3_mprintf("%w.word may not be NULL", + p->zTableName); + return SQLITE_CONSTRAINT; + } + if( iRank<1 ) iRank = 1; + if( zSoundslike ){ + zK1 = (char*)transliterate(zSoundslike, nSoundslike); + }else{ + zK1 = (char*)transliterate(zWord, nWord); + } + if( zK1==0 ) return SQLITE_NOMEM; + for(i=0; (c = zK1[i])!=0; i++){ + if( c>='A' && c<='Z' ) zK1[i] += 'a' - 'A'; + } + zK2 = (char*)characterClassString((const unsigned char*)zK1, i); + if( zK2==0 ){ + sqlite3_free(zK1); + return SQLITE_NOMEM; + } + if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ + spellfix1DbExec(&rc, db, + "INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) " + "VALUES(%d,%d,%Q,%Q,%Q)", + p->zDbName, p->zTableName, + iRank, iLang, zWord, zK1, zK2 + ); + *pRowid = sqlite3_last_insert_rowid(db); + }else{ + rowid = sqlite3_value_int64(argv[0]); + newRowid = *pRowid = sqlite3_value_int64(argv[1]); + spellfix1DbExec(&rc, db, + "UPDATE \"%w\".\"%w_vocab\" SET id=%lld, rank=%d, lang=%d," + " word=%Q, rank=%d, k1=%Q, k2=%Q WHERE id=%lld", + p->zDbName, p->zTableName, newRowid, iRank, iLang, + zWord, zK1, zK2, rowid + ); + } + sqlite3_free(zK1); + sqlite3_free(zK2); + } + return rc; +} + +/* +** Rename the spellfix1 table. +*/ +static int spellfix1Rename(sqlite3_vtab *pVTab, const char *zNew){ + spellfix1_vtab *p = (spellfix1_vtab*)pVTab; + sqlite3 *db = p->db; + int rc = SQLITE_OK; + char *zNewName = sqlite3_mprintf("%s", zNew); + if( zNewName==0 ){ + return SQLITE_NOMEM; + } + spellfix1DbExec(&rc, db, + "ALTER TABLE \"%w\".\"%w_vocab\" RENAME TO \"%w_vocab\"", + p->zDbName, p->zTableName, zNewName + ); + if( rc==SQLITE_OK ){ + sqlite3_free(p->zTableName); + p->zTableName = zNewName; + } + return rc; +} + + +/* +** A virtual table module that provides fuzzy search. +*/ +static sqlite3_module spellfix1Module = { + 0, /* iVersion */ + spellfix1Create, /* xCreate - handle CREATE VIRTUAL TABLE */ + spellfix1Connect, /* xConnect - reconnected to an existing table */ + spellfix1BestIndex, /* xBestIndex - figure out how to do a query */ + spellfix1Disconnect, /* xDisconnect - close a connection */ + spellfix1Destroy, /* xDestroy - handle DROP TABLE */ + spellfix1Open, /* xOpen - open a cursor */ + spellfix1Close, /* xClose - close a cursor */ + spellfix1Filter, /* xFilter - configure scan constraints */ + spellfix1Next, /* xNext - advance a cursor */ + spellfix1Eof, /* xEof - check for end of scan */ + spellfix1Column, /* xColumn - read data */ + spellfix1Rowid, /* xRowid - read data */ + spellfix1Update, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + spellfix1Rename, /* xRename */ +}; + +/* +** Register the various functions and the virtual table. +*/ +static int spellfix1Register(sqlite3 *db){ + int nErr = 0; + int i; + nErr += sqlite3_create_function(db, "spellfix1_translit", 1, SQLITE_UTF8, 0, + transliterateSqlFunc, 0, 0); + nErr += sqlite3_create_function(db, "spellfix1_editdist", 2, SQLITE_UTF8, 0, + editdistSqlFunc, 0, 0); + nErr += sqlite3_create_function(db, "spellfix1_charclass", 1, SQLITE_UTF8, 0, + characterClassSqlFunc, 0, 0); + nErr += sqlite3_create_function(db, "spellfix1_scriptcode", 1, SQLITE_UTF8, 0, + scriptCodeSqlFunc, 0, 0); + nErr += sqlite3_create_module(db, "spellfix1", &spellfix1Module, 0); + + /* Verify sanity of the translit[] table */ + for(i=0; i Date: Mon, 23 Apr 2012 12:38:05 +0000 Subject: [PATCH 05/13] Update the ".table" command in the shell to show all tables in all attached databases, and to avoid using the deprecated sqlite3_get_table() function. FossilOrigin-Name: ce2d06e2533763a8008e7a405630293d8f9a3108 --- manifest | 12 +++---- manifest.uuid | 2 +- src/shell.c | 99 ++++++++++++++++++++++++++++++++------------------- 3 files changed, 70 insertions(+), 43 deletions(-) diff --git a/manifest b/manifest index fd521769a8..9c161337e4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C If\sterminating\sinteractive\sinput\sto\sthe\scommand-line\sshell\swith\s^D,\sissue\nan\sextra\s\\n\sto\smove\sthe\scursor\sto\sthe\snext\sline\sbefore\sexiting. -D 2012-04-21T11:33:39.769 +C Update\sthe\s".table"\scommand\sin\sthe\sshell\sto\sshow\sall\stables\sin\sall\nattached\sdatabases,\sand\sto\savoid\susing\sthe\sdeprecated\ssqlite3_get_table()\nfunction. +D 2012-04-23T12:38:05.598 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -174,7 +174,7 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 969ec2bc52db1b068054ecf5ddc74f244102a71d F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1 F src/select.c d7b9018b7dd2e821183d69477ab55c39b8272335 -F src/shell.c dec1a1896ffa9eaedd6d9907cd43aca4b9d3295d +F src/shell.c 151a17fe8464e40097c13672b6f756a38988147a F src/sqlite.h.in 4338f299fc83dada8407358d585c0e240ecb76a3 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqliteInt.h c5e917c4f1453f3972b1fd0c81105dfe4f09cc32 @@ -995,7 +995,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 7b8548b1872cc1225355ba8311e93dd08d6526e2 -R 6a28d821935f4caf8f00acbe95308ad8 +P feff1ef0b8f7b51ae80a9d34380b46a5103bf6cd +R 684c337b6696cf99874c83d471c520fc U drh -Z a4a6f8d23b8334a25a8498dbc291bb1a +Z 459397b23e497549b544849ef1acdc2b diff --git a/manifest.uuid b/manifest.uuid index 7bec9efcd2..27adcb8c75 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -feff1ef0b8f7b51ae80a9d34380b46a5103bf6cd \ No newline at end of file +ce2d06e2533763a8008e7a405630293d8f9a3108 \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 7fc16ffe12..34b72c4d62 100644 --- a/src/shell.c +++ b/src/shell.c @@ -2248,46 +2248,71 @@ static int do_meta_command(char *zLine, struct callback_data *p){ }else if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){ + sqlite3_stmt *pStmt; char **azResult; - int nRow; - char *zErrMsg; + int nRow, nAlloc; + char *zSql = 0; + int ii; open_db(p); - if( nArg==1 ){ - rc = sqlite3_get_table(p->db, - "SELECT name FROM sqlite_master " - "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' " - "UNION ALL " - "SELECT name FROM sqlite_temp_master " - "WHERE type IN ('table','view') " - "ORDER BY 1", - &azResult, &nRow, 0, &zErrMsg - ); - }else{ - zShellStatic = azArg[1]; - rc = sqlite3_get_table(p->db, - "SELECT name FROM sqlite_master " - "WHERE type IN ('table','view') AND name LIKE shellstatic() " - "UNION ALL " - "SELECT name FROM sqlite_temp_master " - "WHERE type IN ('table','view') AND name LIKE shellstatic() " - "ORDER BY 1", - &azResult, &nRow, 0, &zErrMsg - ); - zShellStatic = 0; + rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); + if( rc ) return rc; + zSql = sqlite3_mprintf( + "SELECT name FROM sqlite_master" + " WHERE type IN ('table','view')" + " AND name NOT LIKE 'sqlite_%%'" + " AND name LIKE ?1"); + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); + if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue; + if( strcmp(zDbName,"temp")==0 ){ + zSql = sqlite3_mprintf( + "%z UNION ALL " + "SELECT 'temp.' || name FROM sqlite_temp_master" + " WHERE type IN ('table','view')" + " AND name NOT LIKE 'sqlite_%%'" + " AND name LIKE ?1", zSql); + }else{ + zSql = sqlite3_mprintf( + "%z UNION ALL " + "SELECT '%q.' || name FROM \"%w\".sqlite_master" + " WHERE type IN ('table','view')" + " AND name NOT LIKE 'sqlite_%%'" + " AND name LIKE ?1", zSql, zDbName, zDbName); + } } - if( zErrMsg ){ - fprintf(stderr,"Error: %s\n", zErrMsg); - sqlite3_free(zErrMsg); - rc = 1; - }else if( rc != SQLITE_OK ){ - fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n"); - rc = 1; + sqlite3_finalize(pStmt); + zSql = sqlite3_mprintf("%z ORDER BY 1", zSql); + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + if( rc ) return rc; + nRow = nAlloc = 0; + azResult = 0; + if( nArg>1 ){ + sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT); }else{ + sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC); + } + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + if( nRow>=nAlloc ){ + char **azNew; + int n = nAlloc*2 + 10; + azNew = sqlite3_realloc(azResult, sizeof(azResult[0])*n); + if( azNew==0 ){ + fprintf(stderr, "Error: out of memory\n"); + break; + } + nAlloc = n; + azResult = azNew; + } + azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0)); + if( azResult[nRow] ) nRow++; + } + sqlite3_finalize(pStmt); + if( nRow>0 ){ int len, maxlen = 0; int i, j; int nPrintCol, nPrintRow; - for(i=1; i<=nRow; i++){ - if( azResult[i]==0 ) continue; + for(i=0; imaxlen ) maxlen = len; } @@ -2295,14 +2320,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( nPrintCol<1 ) nPrintCol = 1; nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; for(i=0; i=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){ @@ -2437,6 +2463,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ }else if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){ + open_db(p); output_file_close(p->traceOut); p->traceOut = output_file_open(azArg[1]); #ifndef SQLITE_OMIT_TRACE From b202d70a8780f09d1e72474c693133fd0c75dbab Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 24 Apr 2012 12:12:57 +0000 Subject: [PATCH 06/13] Fix a sign-extension problem for BLOB output in ".insert" mode of the command-line shell. FossilOrigin-Name: 282f2a74c23aa3fca6087bdeaf5d961b4f5bbe47 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 9c161337e4..fa3712737a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sthe\s".table"\scommand\sin\sthe\sshell\sto\sshow\sall\stables\sin\sall\nattached\sdatabases,\sand\sto\savoid\susing\sthe\sdeprecated\ssqlite3_get_table()\nfunction. -D 2012-04-23T12:38:05.598 +C Fix\sa\ssign-extension\sproblem\sfor\sBLOB\soutput\sin\s".insert"\smode\sof\sthe\ncommand-line\sshell. +D 2012-04-24T12:12:57.348 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -174,7 +174,7 @@ F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 969ec2bc52db1b068054ecf5ddc74f244102a71d F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1 F src/select.c d7b9018b7dd2e821183d69477ab55c39b8272335 -F src/shell.c 151a17fe8464e40097c13672b6f756a38988147a +F src/shell.c 04399b2f9942bd02ed5ffee3b84bcdb39c52a1e6 F src/sqlite.h.in 4338f299fc83dada8407358d585c0e240ecb76a3 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqliteInt.h c5e917c4f1453f3972b1fd0c81105dfe4f09cc32 @@ -995,7 +995,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P feff1ef0b8f7b51ae80a9d34380b46a5103bf6cd -R 684c337b6696cf99874c83d471c520fc +P ce2d06e2533763a8008e7a405630293d8f9a3108 +R 3cb8ce97e629e462f046b05d1b3f651d U drh -Z 459397b23e497549b544849ef1acdc2b +Z 1d5f5dcc20d86aab9e41b01973a0dba1 diff --git a/manifest.uuid b/manifest.uuid index 27adcb8c75..3baf8a3fc6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ce2d06e2533763a8008e7a405630293d8f9a3108 \ No newline at end of file +282f2a74c23aa3fca6087bdeaf5d961b4f5bbe47 \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 34b72c4d62..73341fc3cc 100644 --- a/src/shell.c +++ b/src/shell.c @@ -499,7 +499,7 @@ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ int i; char *zBlob = (char *)pBlob; fprintf(out,"X'"); - for(i=0; i Date: Tue, 24 Apr 2012 12:46:05 +0000 Subject: [PATCH 07/13] Move the shell test scripts into the test/ subfolder so that they are run automatically by "make test". FossilOrigin-Name: 9fb7da6904e479f4671eeebf1a4b7e4e4e4f2b7b --- manifest | 22 ++++++++-------- manifest.uuid | 2 +- {tool => test}/shell1.test | 50 +++++++++---------------------------- {tool => test}/shell2.test | 49 +++++++++--------------------------- {tool => test}/shell3.test | 51 +++++++++----------------------------- {tool => test}/shell4.test | 39 ++++++++++------------------- {tool => test}/shell5.test | 40 ++++++++++-------------------- test/tester.tcl | 10 ++++++++ 8 files changed, 84 insertions(+), 179 deletions(-) rename {tool => test}/shell1.test (96%) rename {tool => test}/shell2.test (86%) rename {tool => test}/shell3.test (76%) rename {tool => test}/shell4.test (83%) rename {tool => test}/shell5.test (92%) diff --git a/manifest b/manifest index fa3712737a..1e7684a508 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\ssign-extension\sproblem\sfor\sBLOB\soutput\sin\s".insert"\smode\sof\sthe\ncommand-line\sshell. -D 2012-04-24T12:12:57.348 +C Move\sthe\sshell\stest\sscripts\sinto\sthe\stest/\ssubfolder\sso\sthat\sthey\sare\nrun\sautomatically\sby\s"make\stest". +D 2012-04-24T12:46:05.097 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -689,6 +689,11 @@ F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9 F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf +F test/shell1.test 6d5a331713a7eadde26802b6be7f6330a1064319 w tool/shell1.test +F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a w tool/shell2.test +F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59 w tool/shell3.test +F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9 w tool/shell4.test +F test/shell5.test fa2188bbb13fe2d183fd04a5f7b512650c35ef5d w tool/shell5.test F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 @@ -720,7 +725,7 @@ F test/tclsqlite.test 1597d353308531527583481d14d9da52ea8ed0af F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test 51edd31c65ed1560dd600b1796e8325df96318e2 F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d -F test/tester.tcl 7db9e90e4a9cc57ea92118ee011634f86dc8e847 +F test/tester.tcl dc0f9daa0a7c257df86a1a7603d5df2236e49145 F test/thread001.test 7cc2ce08f9cde95964736d11e91f9ab610f82f91 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -972,11 +977,6 @@ F tool/omittest.tcl 72a49b8a9a8b0bf213a438180307a0df836d4380 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/shell1.test 20dfe7099cf2afe37aecd69afb7678d14f7a0abf -F tool/shell2.test 5dc76b8005b465f420fed8241621da7513060ff3 -F tool/shell3.test 4fad469e8003938426355afdf34155f08c587836 -F tool/shell4.test 35f9c3d452b4e76d5013c63e1fd07478a62f14ce -F tool/shell5.test 0e987fb8d40638bb5c90163cb58cbe3e07dbed56 F tool/showdb.c 2e28d8e499b016485672e9a7ac65dacc0d28ff69 F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02 F tool/showwal.c f09e5a80a293919290ec85a6a37c85a5ddcf37d9 @@ -995,7 +995,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P ce2d06e2533763a8008e7a405630293d8f9a3108 -R 3cb8ce97e629e462f046b05d1b3f651d +P 282f2a74c23aa3fca6087bdeaf5d961b4f5bbe47 +R fb1a373c8aab089fc987aaa3b3a46480 U drh -Z 1d5f5dcc20d86aab9e41b01973a0dba1 +Z d17213a51e75d7b6538576f270927349 diff --git a/manifest.uuid b/manifest.uuid index 3baf8a3fc6..4c160508c7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -282f2a74c23aa3fca6087bdeaf5d961b4f5bbe47 \ No newline at end of file +9fb7da6904e479f4671eeebf1a4b7e4e4e4f2b7b \ No newline at end of file diff --git a/tool/shell1.test b/test/shell1.test similarity index 96% rename from tool/shell1.test rename to test/shell1.test index 9dd9df5555..473d5a3845 100644 --- a/tool/shell1.test +++ b/test/shell1.test @@ -11,7 +11,6 @@ # # The focus of this file is testing the CLI shell tool. # -# $Id: shell1.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $ # # Test plan: @@ -20,44 +19,19 @@ # shell1-2.*: Basic "dot" command token parsing. # shell1-3.*: Basic test that "dot" command can be called. # - -package require sqlite3 - -set CLI "./sqlite3" - -proc do_test {name cmd expected} { - puts -nonewline "$name ..." - set res [uplevel $cmd] - if {$res eq $expected} { - puts Ok - } else { - puts Error - puts " Got: $res" - puts " Expected: $expected" - exit - } +set testdir [file dirname $argv0] +source $testdir/tester.tcl +if {$tcl_platform(platform)=="windows"} { + set CLI "sqlite3.exe" +} else { + set CLI "./sqlite3" } - -proc execsql {sql} { - uplevel [list db eval $sql] +if {![file executable $CLI]} { + finish_test + return } - -proc catchsql {sql} { - set rc [catch {uplevel [list db eval $sql]} msg] - list $rc $msg -} - -proc catchcmd {db {cmd ""}} { - global CLI - set out [open cmds.txt w] - puts $out $cmd - close $out - set line "exec $CLI $db < cmds.txt" - set rc [catch { eval $line } msg] - list $rc $msg -} - -file delete -force test.db test.db.journal +db close +forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db #---------------------------------------------------------------------------- @@ -717,4 +691,4 @@ do_test shell1-3-28.1 { ".log stdout\nSELECT coalesce(sqlite_log(123,'hello'),'456');" } "0 {(123) hello\n456}" -puts "CLI tests completed successfully" +finish_test diff --git a/tool/shell2.test b/test/shell2.test similarity index 86% rename from tool/shell2.test rename to test/shell2.test index b63fafc365..826093262e 100644 --- a/tool/shell2.test +++ b/test/shell2.test @@ -18,44 +18,19 @@ # # shell2-1.*: Misc. test of various tickets and reported errors. # - -package require sqlite3 - -set CLI "./sqlite3" - -proc do_test {name cmd expected} { - puts -nonewline "$name ..." - set res [uplevel $cmd] - if {$res eq $expected} { - puts Ok - } else { - puts Error - puts " Got: $res" - puts " Expected: $expected" - exit - } +set testdir [file dirname $argv0] +source $testdir/tester.tcl +if {$tcl_platform(platform)=="windows"} { + set CLI "sqlite3.exe" +} else { + set CLI "./sqlite3" } - -proc execsql {sql} { - uplevel [list db eval $sql] +if {![file executable $CLI]} { + finish_test + return } - -proc catchsql {sql} { - set rc [catch {uplevel [list db eval $sql]} msg] - list $rc $msg -} - -proc catchcmd {db {cmd ""}} { - global CLI - set out [open cmds.txt w] - puts $out $cmd - close $out - set line "exec $CLI $db < cmds.txt" - set rc [catch { eval $line } msg] - list $rc $msg -} - -file delete -force test.db test.db.journal +db close +forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db @@ -219,4 +194,4 @@ b 1 2}} -puts "CLI tests completed successfully" +finish_test diff --git a/tool/shell3.test b/test/shell3.test similarity index 76% rename from tool/shell3.test rename to test/shell3.test index d37adff2d3..d02177b7f6 100644 --- a/tool/shell3.test +++ b/test/shell3.test @@ -19,47 +19,21 @@ # shell3-1.*: Basic tests for running SQL statments from command line. # shell3-2.*: Basic tests for running SQL file from command line. # - -package require sqlite3 - -set CLI "./sqlite3" - -proc do_test {name cmd expected} { - puts -nonewline "$name ..." - set res [uplevel $cmd] - if {$res eq $expected} { - puts Ok - } else { - puts Error - puts " Got: $res" - puts " Expected: $expected" - exit - } +set testdir [file dirname $argv0] +source $testdir/tester.tcl +if {$tcl_platform(platform)=="windows"} { + set CLI "sqlite3.exe" +} else { + set CLI "./sqlite3" } - -proc execsql {sql} { - uplevel [list db eval $sql] +if {![file executable $CLI]} { + finish_test + return } - -proc catchsql {sql} { - set rc [catch {uplevel [list db eval $sql]} msg] - list $rc $msg -} - -proc catchcmd {db {cmd ""}} { - global CLI - set out [open cmds.txt w] - puts $out $cmd - close $out - set line "exec $CLI $db < cmds.txt" - set rc [catch { eval $line } msg] - list $rc $msg -} - -file delete -force test.db test.db.journal +db close +forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db - #---------------------------------------------------------------------------- # shell3-1.*: Basic tests for running SQL statments from command line. # @@ -120,5 +94,4 @@ do_test shell3-2.7 { catchcmd "foo.db" "CREATE TABLE" } {1 {Error: incomplete SQL: CREATE TABLE}} - -puts "CLI tests completed successfully" +finish_test diff --git a/tool/shell4.test b/test/shell4.test similarity index 83% rename from tool/shell4.test rename to test/shell4.test index 085c279bb3..5af44c8fd7 100644 --- a/tool/shell4.test +++ b/test/shell4.test @@ -19,33 +19,20 @@ # # shell4-1.*: Basic tests specific to the "stats" command. # - -set CLI "./sqlite3" - -proc do_test {name cmd expected} { - puts -nonewline "$name ..." - set res [uplevel $cmd] - if {$res eq $expected} { - puts Ok - } else { - puts Error - puts " Got: $res" - puts " Expected: $expected" - exit - } +set testdir [file dirname $argv0] +source $testdir/tester.tcl +if {$tcl_platform(platform)=="windows"} { + set CLI "sqlite3.exe" +} else { + set CLI "./sqlite3" } - -proc catchcmd {db {cmd ""}} { - global CLI - set out [open cmds.txt w] - puts $out $cmd - close $out - set line "exec $CLI $db < cmds.txt" - set rc [catch { eval $line } msg] - list $rc $msg +if {![file executable $CLI]} { + finish_test + return } - -file delete -force test.db test.db.journal +db close +forcedelete test.db test.db-journal test.db-wal +sqlite3 db test.db #---------------------------------------------------------------------------- # Test cases shell4-1.*: Tests specific to the "stats" command. @@ -126,4 +113,4 @@ SELECT 1; [regexp {Autoindex Inserts} $res] } {1 1 1} -puts "CLI tests completed successfully" +finish_test diff --git a/tool/shell5.test b/test/shell5.test similarity index 92% rename from tool/shell5.test rename to test/shell5.test index 828d71c97a..d90cedf949 100644 --- a/tool/shell5.test +++ b/test/shell5.test @@ -19,33 +19,20 @@ # # shell5-1.*: Basic tests specific to the ".import" command. # - -set CLI "./sqlite3" - -proc do_test {name cmd expected} { - puts -nonewline "$name ..." - set res [uplevel $cmd] - if {$res eq $expected} { - puts Ok - } else { - puts Error - puts " Got: $res" - puts " Expected: $expected" - exit - } +set testdir [file dirname $argv0] +source $testdir/tester.tcl +if {$tcl_platform(platform)=="windows"} { + set CLI "sqlite3.exe" +} else { + set CLI "./sqlite3" } - -proc catchcmd {db {cmd ""}} { - global CLI - set out [open cmds.txt w] - puts $out $cmd - close $out - set line "exec $CLI $db < cmds.txt" - set rc [catch { eval $line } msg] - list $rc $msg +if {![file executable $CLI]} { + finish_test + return } - -file delete -force test.db test.db.journal +db close +forcedelete test.db test.db-journal test.db-wal +sqlite3 db test.db #---------------------------------------------------------------------------- # Test cases shell5-1.*: Basic handling of the .import and .separator commands. @@ -239,5 +226,4 @@ do_test shell5-1.7.1 { SELECT COUNT(*) FROM t3;}] } [list 0 $rows] - -puts "CLI tests completed successfully" +finish_test diff --git a/test/tester.tcl b/test/tester.tcl index 5bc7eb704d..d1c4f0bd6c 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -518,6 +518,16 @@ proc do_test {name cmd expected} { flush stdout } +proc catchcmd {db {cmd ""}} { + global CLI + set out [open cmds.txt w] + puts $out $cmd + close $out + set line "exec $CLI $db < cmds.txt" + set rc [catch { eval $line } msg] + list $rc $msg +} + proc filepath_normalize {p} { # test cases should be written to assume "unix"-like file paths if {$::tcl_platform(platform)!="unix"} { From 5128e85cde8d9a347ed53b53b290c9b7a7fd7629 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 24 Apr 2012 13:14:49 +0000 Subject: [PATCH 08/13] New test cases for the ".dump" and ".mode insert" commands of the shell. FossilOrigin-Name: dfce8569765614462a3952d1761c10d579984665 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- test/shell1.test | 29 +++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 1e7684a508..89e022de88 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Move\sthe\sshell\stest\sscripts\sinto\sthe\stest/\ssubfolder\sso\sthat\sthey\sare\nrun\sautomatically\sby\s"make\stest". -D 2012-04-24T12:46:05.097 +C New\stest\scases\sfor\sthe\s".dump"\sand\s".mode\sinsert"\scommands\sof\sthe\sshell. +D 2012-04-24T13:14:49.245 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -689,11 +689,11 @@ F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9 F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf -F test/shell1.test 6d5a331713a7eadde26802b6be7f6330a1064319 w tool/shell1.test -F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a w tool/shell2.test -F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59 w tool/shell3.test -F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9 w tool/shell4.test -F test/shell5.test fa2188bbb13fe2d183fd04a5f7b512650c35ef5d w tool/shell5.test +F test/shell1.test 7dcd612b0018ddad783647d984fffa76791ffd3d +F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a +F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59 +F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9 +F test/shell5.test fa2188bbb13fe2d183fd04a5f7b512650c35ef5d F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 @@ -995,7 +995,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 282f2a74c23aa3fca6087bdeaf5d961b4f5bbe47 -R fb1a373c8aab089fc987aaa3b3a46480 +P 9fb7da6904e479f4671eeebf1a4b7e4e4e4f2b7b +R 6b8677ba1888a50ec99e6b37809051dc U drh -Z d17213a51e75d7b6538576f270927349 +Z 48923fe0d240285d5799cf9cb9177252 diff --git a/manifest.uuid b/manifest.uuid index 4c160508c7..83609d3c1d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9fb7da6904e479f4671eeebf1a4b7e4e4e4f2b7b \ No newline at end of file +dfce8569765614462a3952d1761c10d579984665 \ No newline at end of file diff --git a/test/shell1.test b/test/shell1.test index 473d5a3845..a05b3dcab2 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -691,4 +691,33 @@ do_test shell1-3-28.1 { ".log stdout\nSELECT coalesce(sqlite_log(123,'hello'),'456');" } "0 {(123) hello\n456}" +# Test the output of the ".dump" command +# +do_test shell1-4.1 { + db eval { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(null), (1), (2.25), ('hello'), (x'807f'); + } + catchcmd test.db {.dump} +} {0 {PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE t1(x); +INSERT INTO "t1" VALUES(NULL); +INSERT INTO "t1" VALUES(1); +INSERT INTO "t1" VALUES(2.25); +INSERT INTO "t1" VALUES('hello'); +INSERT INTO "t1" VALUES(X'807F'); +COMMIT;}} + +# Test the output of ".mode insert" +# +do_test shell1-4.2 { + catchcmd test.db ".mode insert t1\nselect * from t1;" +} {0 {INSERT INTO t1 VALUES(NULL); +INSERT INTO t1 VALUES(1); +INSERT INTO t1 VALUES(2.25); +INSERT INTO t1 VALUES('hello'); +INSERT INTO t1 VALUES(X'807f');}} + + finish_test From 9250581af4c512da09bfe05dd127c444f9e33b97 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 26 Apr 2012 22:47:20 +0000 Subject: [PATCH 09/13] All virtual table constructors to be invoked recursively. A test case for this has been added to TH3. FossilOrigin-Name: 696a5a40bb28c4a54c9951f877b67015dc00bf55 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vtab.c | 5 +++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 89e022de88..e43f7adf6d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\stest\scases\sfor\sthe\s".dump"\sand\s".mode\sinsert"\scommands\sof\sthe\sshell. -D 2012-04-24T13:14:49.245 +C All\svirtual\stable\sconstructors\sto\sbe\sinvoked\srecursively.\s\sA\stest\scase\sfor\nthis\shas\sbeen\sadded\sto\sTH3. +D 2012-04-26T22:47:20.079 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -243,7 +243,7 @@ F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb F src/vdbemem.c cb55e84b8e2c15704968ee05f0fae25883299b74 F src/vdbesort.c b25814d385895544ebc8118245c8311ded7f81c9 F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843 -F src/vtab.c ab90fb600a3f5e4b7c48d22a4cdb2d6b23239847 +F src/vtab.c ae657b1c22cff43863458e768a44f915c07bc0e4 F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f @@ -995,7 +995,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 9fb7da6904e479f4671eeebf1a4b7e4e4e4f2b7b -R 6b8677ba1888a50ec99e6b37809051dc +P dfce8569765614462a3952d1761c10d579984665 +R bec439cef707f78d31474bb08e34e278 U drh -Z 48923fe0d240285d5799cf9cb9177252 +Z 9d4076ab5b78bad3c903da31eaeee8ce diff --git a/manifest.uuid b/manifest.uuid index 83609d3c1d..f648b7b37a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dfce8569765614462a3952d1761c10d579984665 \ No newline at end of file +696a5a40bb28c4a54c9951f877b67015dc00bf55 \ No newline at end of file diff --git a/src/vtab.c b/src/vtab.c index c7221cd3b7..c561f7198f 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -447,7 +447,7 @@ static int vtabCallConstructor( int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), char **pzErr ){ - VtabCtx sCtx; + VtabCtx sCtx, *pPriorCtx; VTable *pVTable; int rc; const char *const*azArg = (const char *const*)pTab->azModuleArg; @@ -472,9 +472,10 @@ static int vtabCallConstructor( assert( xConstruct ); sCtx.pTab = pTab; sCtx.pVTable = pVTable; + pPriorCtx = db->pVtabCtx; db->pVtabCtx = &sCtx; rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); - db->pVtabCtx = 0; + db->pVtabCtx = pPriorCtx; if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; if( SQLITE_OK!=rc ){ From 3f17aefb353999cea242d938862fe35394268e3c Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 27 Apr 2012 01:08:02 +0000 Subject: [PATCH 10/13] Enhance the do_test proc in the test suite so that if the expected result is of the form "/.../" or "~/.../" then regular expression matching is done between result and the "..." part of the expectation. In the ~/.../ case, we expect there to be no match. FossilOrigin-Name: c9a734406c016329e80d887f7438206e41c52ce7 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/tester.tcl | 22 +++++++++++++++++----- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index e43f7adf6d..8bf337192d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C All\svirtual\stable\sconstructors\sto\sbe\sinvoked\srecursively.\s\sA\stest\scase\sfor\nthis\shas\sbeen\sadded\sto\sTH3. -D 2012-04-26T22:47:20.079 +C Enhance\sthe\sdo_test\sproc\sin\sthe\stest\ssuite\sso\sthat\sif\sthe\sexpected\sresult\nis\sof\sthe\sform\s"/.../"\sor\s"~/.../"\sthen\sregular\sexpression\smatching\sis\sdone\nbetween\sresult\sand\sthe\s"..."\spart\sof\sthe\sexpectation.\s\sIn\sthe\s~/.../\scase,\nwe\sexpect\sthere\sto\sbe\sno\smatch. +D 2012-04-27T01:08:02.413 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -725,7 +725,7 @@ F test/tclsqlite.test 1597d353308531527583481d14d9da52ea8ed0af F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test 51edd31c65ed1560dd600b1796e8325df96318e2 F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d -F test/tester.tcl dc0f9daa0a7c257df86a1a7603d5df2236e49145 +F test/tester.tcl 17b5f402d0e60e8c8ce751288b228fe9337f40c2 F test/thread001.test 7cc2ce08f9cde95964736d11e91f9ab610f82f91 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -995,7 +995,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P dfce8569765614462a3952d1761c10d579984665 -R bec439cef707f78d31474bb08e34e278 +P 696a5a40bb28c4a54c9951f877b67015dc00bf55 +R cec8a879e3e3cce3faf837e46a46ad14 U drh -Z 9d4076ab5b78bad3c903da31eaeee8ce +Z 3ce2501ea7e4d58e039b2073955afa3e diff --git a/manifest.uuid b/manifest.uuid index f648b7b37a..8010df66ac 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -696a5a40bb28c4a54c9951f877b67015dc00bf55 \ No newline at end of file +c9a734406c016329e80d887f7438206e41c52ce7 \ No newline at end of file diff --git a/test/tester.tcl b/test/tester.tcl index d1c4f0bd6c..71100a2e6e 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -474,7 +474,6 @@ proc incr_ntest {} { # Invoke the do_test procedure to run a single test # proc do_test {name cmd expected} { - global argv cmdlinearg fix_testname name @@ -505,11 +504,24 @@ proc do_test {name cmd expected} { if {[catch {uplevel #0 "$cmd;\n"} result]} { puts "\nError: $result" fail_test $name - } elseif {[string compare $result $expected]} { - puts "\nExpected: \[$expected\]\n Got: \[$result\]" - fail_test $name } else { - puts " Ok" + if {[regexp {^~?/.*/$} $expected]} { + if {[string index $expected 0]=="~"} { + set re [string range $expected 2 end-1] + set ok [expr {![regexp $re $result]}] + } else { + set re [string range $expected 1 end-1] + set ok [regexp $re $result] + } + } else { + set ok [expr {[string compare $result $expected]==0}] + } + if {!$ok} { + puts "\nExpected: \[$expected\]\n Got: \[$result\]" + fail_test $name + } else { + puts " Ok" + } } } else { puts " Omitted" From 70331cd725e1accad75eac281689d3a8b6a9b700 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 27 Apr 2012 01:09:06 +0000 Subject: [PATCH 11/13] Enhance the processing of ORDER BY clauses on compound queries to better match terms of the order by against expressions in the result set, in order to enable better query optimization. FossilOrigin-Name: a49e909c8738317c8383ce93771c0a9c4cf270bc --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/resolve.c | 7 ++++++- test/select9.test | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 8bf337192d..21aacd2021 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\sdo_test\sproc\sin\sthe\stest\ssuite\sso\sthat\sif\sthe\sexpected\sresult\nis\sof\sthe\sform\s"/.../"\sor\s"~/.../"\sthen\sregular\sexpression\smatching\sis\sdone\nbetween\sresult\sand\sthe\s"..."\spart\sof\sthe\sexpectation.\s\sIn\sthe\s~/.../\scase,\nwe\sexpect\sthere\sto\sbe\sno\smatch. -D 2012-04-27T01:08:02.413 +C Enhance\sthe\sprocessing\sof\sORDER\sBY\sclauses\son\scompound\squeries\sto\sbetter\nmatch\sterms\sof\sthe\sorder\sby\sagainst\sexpressions\sin\sthe\sresult\sset,\sin\sorder\nto\senable\sbetter\squery\soptimization. +D 2012-04-27T01:09:06.388 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -171,7 +171,7 @@ F src/pragma.c e708b3bb5704605816f617e0b1d63a5488060715 F src/prepare.c ec4989f7f480544bdc4192fe663470d2a2d7d61e F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 -F src/resolve.c 969ec2bc52db1b068054ecf5ddc74f244102a71d +F src/resolve.c 748e75299faff345f34f0e5bd02a2bac8aa69fcd F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1 F src/select.c d7b9018b7dd2e821183d69477ab55c39b8272335 F src/shell.c 04399b2f9942bd02ed5ffee3b84bcdb39c52a1e6 @@ -676,7 +676,7 @@ F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535 F test/select6.test cc25a8650cf9a4d4f74e586c45a75f9836516b18 F test/select7.test dad6f00f0d49728a879d6eb6451d4752db0b0abe F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d -F test/select9.test 74c0fb2c6eecb0219cbed0cbe3df136f8fbf9343 +F test/select9.test c0ca3cd87a8ebb04de2cb1402c77df55d911a0ea F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532 F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25 F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977 @@ -995,7 +995,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 696a5a40bb28c4a54c9951f877b67015dc00bf55 -R cec8a879e3e3cce3faf837e46a46ad14 +P c9a734406c016329e80d887f7438206e41c52ce7 +R 726c49ce225b59d324679d0a91302d23 U drh -Z 3ce2501ea7e4d58e039b2073955afa3e +Z fb90c7a1a92b2c585d3a7791f60ba9a6 diff --git a/manifest.uuid b/manifest.uuid index 8010df66ac..3897809680 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c9a734406c016329e80d887f7438206e41c52ce7 \ No newline at end of file +a49e909c8738317c8383ce93771c0a9c4cf270bc \ No newline at end of file diff --git a/src/resolve.c b/src/resolve.c index 6590cd8ac4..090fa79842 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -883,7 +883,7 @@ static int resolveOrderGroupBy( ExprList *pOrderBy, /* An ORDER BY or GROUP BY clause to resolve */ const char *zType /* Either "ORDER" or "GROUP", as appropriate */ ){ - int i; /* Loop counter */ + int i, j; /* Loop counters */ int iCol; /* Column number */ struct ExprList_item *pItem; /* A term of the ORDER BY clause */ Parse *pParse; /* Parsing context */ @@ -920,6 +920,11 @@ static int resolveOrderGroupBy( if( sqlite3ResolveExprNames(pNC, pE) ){ return 1; } + for(j=0; jpEList->nExpr; j++){ + if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr)==0 ){ + pItem->iOrderByCol = j+1; + } + } } return sqlite3ResolveOrderGroupBy(pParse, pSelect, pOrderBy, zType); } diff --git a/test/select9.test b/test/select9.test index 085dee0bd1..9f54014cf9 100644 --- a/test/select9.test +++ b/test/select9.test @@ -415,5 +415,40 @@ do_test select9-4.X { } } {} +# Testing to make sure that queries involving a view of a compound select +# are planned efficiently. This detects a problem reported on the mailing +# list on 2012-04-26. See +# +# http://www.mail-archive.com/sqlite-users%40sqlite.org/msg69746.html +# +# For additional information. +# +do_test select9-5.1 { + db eval { + CREATE TABLE t51(x, y); + CREATE TABLE t52(x, y); + CREATE VIEW v5 as + SELECT x, y FROM t51 + UNION ALL + SELECT x, y FROM t52; + CREATE INDEX t51x ON t51(x); + CREATE INDEX t52x ON t52(x); + EXPLAIN QUERY PLAN + SELECT * FROM v5 WHERE x='12345' ORDER BY y; + } +} {~/SCAN TABLE/} ;# Uses indices with "*" +do_test select9-5.2 { + db eval { + EXPLAIN QUERY PLAN + SELECT x, y FROM v5 WHERE x='12345' ORDER BY y; + } +} {~/SCAN TABLE/} ;# Uses indices with "x, y" +do_test select9-5.3 { + db eval { + EXPLAIN QUERY PLAN + SELECT x, y FROM v5 WHERE +x='12345' ORDER BY y; + } +} {/SCAN TABLE/} ;# Full table scan if the "+x" prevents index usage. + finish_test From a4c5860e6fe8aede90f3b693d2955989fc6a97d1 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 27 Apr 2012 16:38:11 +0000 Subject: [PATCH 12/13] Fix a minor deviation from the coding style guidelines. FossilOrigin-Name: 1e51bffe777587cd05bd7db5e02d6291c3eb8c1a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/pager.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 21aacd2021..0d9e6e5a6e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\sprocessing\sof\sORDER\sBY\sclauses\son\scompound\squeries\sto\sbetter\nmatch\sterms\sof\sthe\sorder\sby\sagainst\sexpressions\sin\sthe\sresult\sset,\sin\sorder\nto\senable\sbetter\squery\soptimization. -D 2012-04-27T01:09:06.388 +C Fix\sa\sminor\sdeviation\sfrom\sthe\scoding\sstyle\sguidelines. +D 2012-04-27T16:38:11.705 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -161,7 +161,7 @@ F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 F src/os_unix.c 424d46e0edab969293c2223f09923b2178171f47 F src/os_win.c 5e9e933a412ab35de2a6506b3c6a8295b31b309e -F src/pager.c 85988507fa20acc60defb834722eddf4633e4aeb +F src/pager.c bb5635dde0b152797836d1c72275284724bb563c F src/pager.h ef1eaf8593e78f73885c1dfac27ad83bee23bdc5 F src/parse.y eb054bb40a5bf90d3422a01ed0e5df229461727a F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 @@ -995,7 +995,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P c9a734406c016329e80d887f7438206e41c52ce7 -R 726c49ce225b59d324679d0a91302d23 +P a49e909c8738317c8383ce93771c0a9c4cf270bc +R b188dfa7c7a5aca6dba55435d29b09a3 U drh -Z fb90c7a1a92b2c585d3a7791f60ba9a6 +Z afa94c75b9ca22f35aabedc6458ef96f diff --git a/manifest.uuid b/manifest.uuid index 3897809680..e3f6e297e3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a49e909c8738317c8383ce93771c0a9c4cf270bc \ No newline at end of file +1e51bffe777587cd05bd7db5e02d6291c3eb8c1a \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 2d603122d5..b93e0aa866 100644 --- a/src/pager.c +++ b/src/pager.c @@ -3003,7 +3003,7 @@ static int pagerWalFrames( PgHdr *p; PgHdr **ppNext = &pList; nList = 0; - for(p=pList; (*ppNext = p); p=p->pDirty){ + for(p=pList; (*ppNext = p)!=0; p=p->pDirty){ if( p->pgno<=nTruncate ){ ppNext = &p->pDirty; nList++; From 7a9fc59efad39cc1780aa0ba6fb77414190c2ec3 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 1 May 2012 14:21:57 +0000 Subject: [PATCH 13/13] Update a test in io.test to account for [05f98d4eec]. FossilOrigin-Name: bfa61e781cb442be641486e7e55a1518e888d830 --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/io.test | 6 +++++- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 0d9e6e5a6e..4f0a71baca 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sminor\sdeviation\sfrom\sthe\scoding\sstyle\sguidelines. -D 2012-04-27T16:38:11.705 +C Update\sa\stest\sin\sio.test\sto\saccount\sfor\s[05f98d4eec]. +D 2012-05-01T14:21:57.706 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -536,7 +536,7 @@ F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4 F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1 F test/intpkey.test 537669fd535f62632ca64828e435b9e54e8d677f -F test/io.test b278aa8fa609ed0dcc825df31b2d9f526c5a52bd +F test/io.test 36d251507d72e92b965fb2f0801c2f0b56335bcf F test/ioerr.test 40bb2cfcab63fb6aa7424cd97812a84bc16b5fb8 F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd @@ -995,7 +995,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P a49e909c8738317c8383ce93771c0a9c4cf270bc -R b188dfa7c7a5aca6dba55435d29b09a3 -U drh -Z afa94c75b9ca22f35aabedc6458ef96f +P 1e51bffe777587cd05bd7db5e02d6291c3eb8c1a +R 2c954175673c357079573f576ee6e960 +U dan +Z 199b9a45180c95acb6ae422881191984 diff --git a/manifest.uuid b/manifest.uuid index e3f6e297e3..8d74f647e3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1e51bffe777587cd05bd7db5e02d6291c3eb8c1a \ No newline at end of file +bfa61e781cb442be641486e7e55a1518e888d830 \ No newline at end of file diff --git a/test/io.test b/test/io.test index 58caeeebbc..9363b0c292 100644 --- a/test/io.test +++ b/test/io.test @@ -146,11 +146,15 @@ do_test io-2.2 { # written because page 1 - the change-counter page - is written using # an out-of-band method that bypasses the write counter. # +# UPDATE: As of [05f98d4eec] (adding SQLITE_DBSTATUS_CACHE_WRITE), the +# second write is also counted. So this now reports two writes and a +# single fsync. +# sqlite3_simulate_device -char atomic do_test io-2.3 { execsql { INSERT INTO abc VALUES(3, 4) } list [nWrite db] [nSync] -} {1 1} +} {2 1} # Test that the journal file is not created and the change-counter is # updated when the atomic-write optimization is used.