소스 검색

Merge pull request #12526 from ghalliday/issue22044

HPCC-22044 Fix problems with KEYED() DATA substrings

Reviewed-By: Shamser Ahmed <shamser.ahmed@lexisnexis.co.uk>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 6 년 전
부모
커밋
dc739e2915

+ 8 - 0
ecl/hql/hqlfilter.cpp

@@ -437,6 +437,14 @@ IHqlExpression * castToFieldAndBack(IHqlExpression * left, IHqlExpression * righ
             return ensureExprType(castToField, rightType);
         }
     case no_substring:
+    {
+        OwnedHqlExpr cast = castToFieldAndBack(left->queryChild(0), right);
+        //Theoretically needed for all types.  In practice this only makes a difference for data since strings
+        //ignore trailing spaces
+        if (left->queryType()->getTypeCode() == type_data)
+            return replaceChild(left, 0, cast.getClear());
+        return cast.getClear();
+    }
     case no_add:
     case no_sub:
         return castToFieldAndBack(left->queryChild(0), right);

+ 15 - 9
rtl/eclrtl/rtlnewkey.cpp

@@ -231,15 +231,21 @@ void applySubString(TransitionMask & mask, const RtlTypeInfo & type, MemoryBuffe
     MemoryBuffer resized;
     getStretchedValue(resized, truncType, type, value);
 
-    buff.clear();
-    getStretchedValue(buff, type, truncType, resized.bytes());
-
-    // x >= 'ab' becomes x > 'a' => clear the equal item
-    // x < 'ab' becomes x <= 'a' => set the equal item
-    if (mask & CMPlt)
-        mask |= CMPeq;
-    else if (mask & CMPgt)
-        mask &= ~CMPeq;
+    MemoryBuffer stretched;
+    getStretchedValue(stretched, type, truncType, resized.bytes());
+
+    //Work around for a problem comparing data values
+    if (type.compare((const byte *)stretched.toByteArray(), value) != 0)
+    {
+        // x >= 'ab' becomes x > 'a' => clear the equal item
+        // x < 'ab' becomes x <= 'a' => set the equal item
+        if (mask & CMPlt)
+            mask |= CMPeq;
+        else if (mask & CMPgt)
+            mask &= ~CMPeq;
+    }
+    //value may have come from buff, so only modify the output when the function is finished.
+    stretched.swapWith(buff);
 }
 
 void checkSubString(TransitionMask & mask, const RtlTypeInfo & type, MemoryBuffer & buff, size32_t subLength)

+ 14 - 0
rtl/eclrtl/rtlnktest.cpp

@@ -925,6 +925,7 @@ protected:
     const RtlStringTypeInfo str2 = RtlStringTypeInfo(type_string, 2);
     const RtlStringTypeInfo str4 = RtlStringTypeInfo(type_string, 4);
     const RtlStringTypeInfo strx = RtlStringTypeInfo(type_string|RFTMunknownsize, 0);
+    const RtlDataTypeInfo data4 = RtlDataTypeInfo(type_data, 4);
     const RtlFieldInfo id = RtlFieldInfo("id", nullptr, &int2);
     const RtlFieldInfo extra = RtlFieldInfo("extra", nullptr, &strx);
     const RtlFieldInfo padding = RtlFieldInfo("padding", nullptr, &str1);
@@ -1421,6 +1422,19 @@ protected:
         testBound(str4, "A", 4, false, false, 4, "A  \x1F");
         testBound(str4, "X", 3, false, false, 4, "X \x1F\xFF");
 
+        //Lower bounds
+        testBound(data4, "X", MatchFullString, true, true, 4, "X\x00\x00\x00");
+        testBound(data4, "X", 4, true, true, 4, "X\x00\x00\x00");
+        testBound(data4, "X", 3, true, true, 4, "X\x00\x00\x00");
+        testBound(data4, "A", MatchFullString, true, false, 4, "A\x00\x00\x01");
+        testBound(data4, "A", 4, true, false, 4, "A\x00\x00\x01");
+        testBound(data4, "X", 3, true, false, 4, "X\x00\x01\x00");
+        //Upper bounds
+        testBound(data4, "X", 4, false, true, 4, "X\x00\x00\x00");
+        testBound(data4, "X", 3, false, true, 4, "X\x00\x00\xFF");
+        testBound(data4, "A", 4, false, false, 4, "@\xFF\xFF\xFF");
+        testBound(data4, "X", 3, false, false, 4, "W\xFF\xFF\xFF");
+
         //Horrible cases
         const RtlQStringTypeInfo qstr4(type_qstring, 4);
         testBoundQstr(qstr4, "AAAA", MatchFullString, true, true, 4, "AAAA");

+ 15 - 11
testing/regress/ecl/indexsubstring.ecl

@@ -21,13 +21,17 @@ prefix := setup.Files(false, false).QueryFilePrefix;
 #onwarning (4522, ignore);
 #onwarning (4523, ignore);
 
-//version multiPart=false
+//version multiPart=false,isKeyed=true
+//version multiPart=false,isKeyed=false
 
 import ^ as root;
 multiPart := #IFDEFINED(root.multiPart, false);
+isKeyed := #IFDEFINED(root.isKeyed, true);
 
 //--- end of version configuration ---
 
+mkKeyed(boolean value) := IF(isKeyed, KEYED(value), value);
+
 postcodes := DATASET([{'KT19 1AA'}, {'KT19 1AB'}, {'KT19 1AC'}, {'KT19 1AD'},
                       {'KT20 1AE'}, {'KT20 1AF'}, {'KT20 1AG'}, {'KT20 1AH'},
                       {'KT21 1AI'}, {'KT21 1AJ'}, {'KT21 1AK'}, {'KT21 1AL'},
@@ -58,12 +62,12 @@ SET OF STRING PartialPostcodeStored2:= ['KT19','KT40','KT3 ','KT20 1AEEE', 'KT50
 SET OF STRING8 PartialPostcodeStored8:= ['KT19','KT40','KT3 ','KT50']:stored('PartialPostcode8');
 SET OF STRING3 PartialPostcodeStoredX:= ['KT2']:stored('PartialPostcodeX');
 
-partialmatch1 := INDX_Postcode( KEYED(postcode[1..4] IN PartialPostcode) );
-partialmatch2 := INDX_Postcode( KEYED(postcode[1..4] IN PartialPostcodeStored) );
-partialmatch3 := INDX_Postcode( KEYED(postcode[..4] IN PartialPostcodeStored) );
-partialmatch4 := INDX_Postcode( KEYED(postcode[..4] IN PartialPostcodestored2) );
-fullmatch1 := INDX_Postcode( KEYED(postcode IN PartialPostcodeStored) );
-fullmatch2 := INDX_Postcode( KEYED(postcode IN PartialPostcodeStored2) );
+partialmatch1 := INDX_Postcode( mkKeyed(postcode[1..4] IN PartialPostcode) );
+partialmatch2 := INDX_Postcode( mkKeyed(postcode[1..4] IN PartialPostcodeStored) );
+partialmatch3 := INDX_Postcode( mkKeyed(postcode[..4] IN PartialPostcodeStored) );
+partialmatch4 := INDX_Postcode( mkKeyed(postcode[..4] IN PartialPostcodestored2) );
+fullmatch1 := INDX_Postcode( mkKeyed(postcode IN PartialPostcodeStored) );
+fullmatch2 := INDX_Postcode( mkKeyed(postcode IN PartialPostcodeStored2) );
 
 four := 4 : stored('four');
 
@@ -71,10 +75,10 @@ partialmatch5 := INDX_Postcode( postcode[1..four] IN PartialPostcode );
 partialmatch6 := INDX_Postcode( postcode[1..four] IN PartialPostcodeStored );
 partialmatch7 := INDX_Postcode( postcode[..four] IN PartialPostcodeStored );
 partialmatch8 := INDX_Postcode( postcode[..four] IN PartialPostcodestored2 );
-partialmatch9 := INDX_Postcode( KEYED(postcode[..4] IN PartialPostcodestored8) );
-partialmatch10 := INDX_Postcode( KEYED(IF(four=4, postcode[..four] IN PartialPostcodestored8,true)) );
-partialmatch11 := INDX_Postcode( KEYED(postcode[..four] IN IF(four=4, PartialPostcodestored8, all)) );
-partialmatch12 := INDX_Postcode( KEYED(postcode[..four] IN PartialPostcodestored8) OR (KEYED(postcode[..3] IN PartialPostcodestoredX)) );
+partialmatch9 := INDX_Postcode( mkKeyed(postcode[..4] IN PartialPostcodestored8) );
+partialmatch10 := INDX_Postcode( mkKeyed(IF(four=4, postcode[..four] IN PartialPostcodestored8,true)) );
+partialmatch11 := INDX_Postcode( mkKeyed(postcode[..four] IN IF(four=4, PartialPostcodestored8, all)) );
+partialmatch12 := INDX_Postcode( mkKeyed(postcode[..four] IN PartialPostcodestored8) OR (mkKeyed(postcode[..3] IN PartialPostcodestoredX)) );
 
 SEQUENTIAL(
   outputraw,

+ 112 - 0
testing/regress/ecl/indexsubstring2.ecl

@@ -0,0 +1,112 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2016 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+import $.setup;
+prefix := setup.Files(false, false).QueryFilePrefix;
+
+#onwarning (4522, ignore);
+#onwarning (4523, ignore);
+
+//version multiPart=false,isKeyed=true
+//version multiPart=false,isKeyed=false
+
+import ^ as root;
+multiPart := #IFDEFINED(root.multiPart, false);
+isKeyed := #IFDEFINED(root.isKeyed, true);
+
+//--- end of version configuration ---
+
+mkKeyed(boolean value) := IF(isKeyed, KEYED(value), value);
+
+postcodes := DATASET([{D'KT19 1AA'}, {D'KT19 1AB'}, {D'KT19 1AC'}, {D'KT19 1AD'},
+                      {D'KT20 1AE'}, {D'KT20 1AF'}, {D'KT20 1AG'}, {D'KT20 1AH'},
+                      {D'KT21 1AI'}, {D'KT21 1AJ'}, {D'KT21 1AK'}, {D'KT21 1AL'},
+                      {D'KT22 1AM'}, {D'KT22 1AN'}, {D'KT22 1AO'}, {D'KT22 1AA'},
+                      {D'KT23 1AB'}, {D'KT23 1AC'}, {D'KT23 1AD'}, {D'KT23 1AE'},
+                      {D'KT30 1AF'}, {D'KT30 1AG'}, {D'KT30 1AH'}, {D'KT30 1AI'},
+                      {D'KT31 1AJ'}, {D'KT31 1AK'}, {D'KT31 1AL'}, {D'KT31 1AM'},
+                      {D'KT32 1AN'}, {D'KT32 1AO'}, {D'KT32 1AA'}, {D'KT32 1AB'},
+                      {D'KT40 1AC'}, {D'KT40 1AD'}, {D'KT40 1AE'}, {D'KT40 1AF'},
+                      {D'KT41 1AG'}, {D'KT41 1AH'}, {D'KT41 1AI'}, {D'KT41 1AJ'},
+                      {D'KT41 1AK'}, {D'KT41 1AL'}, {D'KT41 1AM'}, {D'KT41 1AN'},
+                      {D'KT50 2AB'}, {D'KT50 3DE'}, {D'KT50 4FG'}, {D'KT50 5HI'},
+                      {D'KT60 2AB'}, {D'KT60 3DE'}, {D'KT60 4FG'}, {D'KT60 5HI'},
+                      {D'KT3'}, {D'KT4'},{D'KT50'}], {data8 postcode});
+
+outputraw := OUTPUT(postcodes,,prefix + 'postcodes', OVERWRITE);
+
+
+Rawfile := DATASET(prefix + 'postcodes', { DATA8 postcode, UNSIGNED8
+                                      __filepos {virtual(fileposition)}}, FLAT);
+
+INDX_Postcode := INDEX(Rawfile, {postcode, __filepos}, prefix + 'postcode.key');
+BuildIndexOp := BUILDINDEX(INDX_Postcode, OVERWRITE);
+
+SET OF DATA4 PartialPostcode:= [D'KT19',D'KT40',D'KT3\000',D'KT20 1AEEE',D'KT50',D'KT60 3DE'];
+SET OF DATA4 PartialPostcodeStored:= [D'KT19',D'KT40',D'KT3\000',D'KT20 1AEEE', D'KT50',D'KT60 3DE']:stored('PartialPostcode');
+SET OF DATA PartialPostcodeStored2:= [D'KT19',D'KT40',D'KT3\000',D'KT20 1AEEE', D'KT50',D'KT60 3DE']:stored('PartialPostcode2');
+SET OF DATA8 PartialPostcodeStored8:= [D'KT19',D'KT40',D'KT3\000',D'KT50']:stored('PartialPostcode8');
+SET OF DATA PartialPostcodeStoredX:= [D'KT19',D'KT40',D'KT3\000',D'KT50']:stored('PartialPostcodeX');
+SET OF DATA3 PartialPostcodeStored2S:= [D'KT2']:stored('PartialPostcode2S');
+
+partialmatch1 := INDX_Postcode( mkKeyed(postcode[1..4] IN PartialPostcode) );
+partialmatch2 := INDX_Postcode( mkKeyed(postcode[1..4] IN PartialPostcodeStored) );
+partialmatch3 := INDX_Postcode( mkKeyed(postcode[..4] IN PartialPostcodeStored) );
+partialmatch4 := INDX_Postcode( mkKeyed(postcode[..4] IN PartialPostcodestored2) );
+fullmatch1 := INDX_Postcode( mkKeyed(postcode IN PartialPostcodeStored) );
+fullmatch2 := INDX_Postcode( mkKeyed(postcode IN PartialPostcodeStored2) );
+
+four := 4 : stored('four');
+
+partialmatch5 := INDX_Postcode( postcode[1..four] IN PartialPostcode );
+partialmatch6 := INDX_Postcode( postcode[1..four] IN PartialPostcodeStored );
+partialmatch7 := INDX_Postcode( postcode[..four] IN PartialPostcodeStored );
+partialmatch8 := INDX_Postcode( postcode[..four] IN PartialPostcodestored2 );
+partialmatch9 := INDX_Postcode( mkKeyed(postcode[..4] IN PartialPostcodestoredX) );
+partialmatch10 := INDX_Postcode( mkKeyed(IF(four=4, postcode[..four] IN PartialPostcodestoredX,true)) );
+partialmatch11 := INDX_Postcode( mkKeyed(postcode[..four] IN IF(four=4, PartialPostcodestoredX, all)) );
+partialmatch12 := INDX_Postcode( mkKeyed(postcode[..four] IN PartialPostcodestoredX) OR mkKeyed(postcode[..3] IN PartialPostcodestored2S)   );
+//None of these match because trailing \0 characters are not ignored.
+partialmatch13 := INDX_Postcode( mkKeyed(postcode[..4] IN PartialPostcodestored8) );
+partialmatch14 := INDX_Postcode( mkKeyed(IF(four=4, postcode[..four] IN PartialPostcodestored8,true)) );
+partialmatch15 := INDX_Postcode( mkKeyed(postcode[..four] IN IF(four=4, PartialPostcodestored8, all)) );
+
+
+z(dataset(recordof(INDX_Postcode)) ds) := TABLE(ds, { string8 postcode := (>string8<)ds.postcode, __filepos });
+
+SEQUENTIAL(
+  outputraw,
+  BuildIndexOp,
+  OUTPUT(z(partialmatch1)),  // match KT19*, KT40*, KT3, KT20*, KT50* and KT60*
+  OUTPUT(z(partialmatch2)),  // match KT19*, KT40*, KT3, KT20*, KT50* and KT60*
+  OUTPUT(z(partialmatch3)),  // match KT19*, KT40*, KT3, KT20*, KT50* and KT60*
+  OUTPUT(z(partialmatch4)),  // match KT19*, KT40*, KT3 and KT50*
+  OUTPUT(z(fullmatch1)),     // match KT3 and KT50
+  OUTPUT(z(fullmatch2)),     // match KT3, KT50 and KT60 3DE
+  OUTPUT(z(partialmatch5)),  // match KT19*, KT40*, KT3, KT20*, KT50* and KT60*
+  OUTPUT(z(partialmatch6)),  // match KT19*, KT40*, KT3, KT20*, KT50* and KT60*
+  OUTPUT(z(partialmatch7)),  // match KT19*, KT40*, KT3, KT20*, KT50* and KT60*
+  OUTPUT(z(partialmatch8)),  // match KT19*, KT40*, KT3 and KT50*
+  OUTPUT(z(partialmatch9)),  // match KT19*, KT40*, KT3 and KT50*
+  OUTPUT(z(partialmatch10)),  // match KT19*, KT40*, KT3 and KT50*
+  OUTPUT(z(partialmatch11)),  // match KT19*, KT40*, KT3 and KT50*
+  OUTPUT(z(partialmatch12)),  // match KT19*, KT40*, KT3 and KT50*, and KT2*
+  //OUTPUT(z(partialmatch13)),  // blank
+  OUTPUT(z(partialmatch13)),  // blank
+  OUTPUT(z(partialmatch14)),  // blank
+  OUTPUT(z(partialmatch15)),  // blank
+);

+ 273 - 0
testing/regress/ecl/key/indexsubstring2.xml

@@ -0,0 +1,273 @@
+<Dataset name='Result 1'>
+</Dataset>
+<Dataset name='Result 2'>
+</Dataset>
+<Dataset name='Result 3'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT20 1AE</postcode><__filepos>32</__filepos></Row>
+ <Row><postcode>KT20 1AF</postcode><__filepos>40</__filepos></Row>
+ <Row><postcode>KT20 1AG</postcode><__filepos>48</__filepos></Row>
+ <Row><postcode>KT20 1AH</postcode><__filepos>56</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+ <Row><postcode>KT60 2AB</postcode><__filepos>384</__filepos></Row>
+ <Row><postcode>KT60 3DE</postcode><__filepos>392</__filepos></Row>
+ <Row><postcode>KT60 4FG</postcode><__filepos>400</__filepos></Row>
+ <Row><postcode>KT60 5HI</postcode><__filepos>408</__filepos></Row>
+</Dataset>
+<Dataset name='Result 4'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT20 1AE</postcode><__filepos>32</__filepos></Row>
+ <Row><postcode>KT20 1AF</postcode><__filepos>40</__filepos></Row>
+ <Row><postcode>KT20 1AG</postcode><__filepos>48</__filepos></Row>
+ <Row><postcode>KT20 1AH</postcode><__filepos>56</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+ <Row><postcode>KT60 2AB</postcode><__filepos>384</__filepos></Row>
+ <Row><postcode>KT60 3DE</postcode><__filepos>392</__filepos></Row>
+ <Row><postcode>KT60 4FG</postcode><__filepos>400</__filepos></Row>
+ <Row><postcode>KT60 5HI</postcode><__filepos>408</__filepos></Row>
+</Dataset>
+<Dataset name='Result 5'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT20 1AE</postcode><__filepos>32</__filepos></Row>
+ <Row><postcode>KT20 1AF</postcode><__filepos>40</__filepos></Row>
+ <Row><postcode>KT20 1AG</postcode><__filepos>48</__filepos></Row>
+ <Row><postcode>KT20 1AH</postcode><__filepos>56</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+ <Row><postcode>KT60 2AB</postcode><__filepos>384</__filepos></Row>
+ <Row><postcode>KT60 3DE</postcode><__filepos>392</__filepos></Row>
+ <Row><postcode>KT60 4FG</postcode><__filepos>400</__filepos></Row>
+ <Row><postcode>KT60 5HI</postcode><__filepos>408</__filepos></Row>
+</Dataset>
+<Dataset name='Result 6'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+</Dataset>
+<Dataset name='Result 7'>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+</Dataset>
+<Dataset name='Result 8'>
+ <Row><postcode>KT60 3DE</postcode><__filepos>392</__filepos></Row>
+</Dataset>
+<Dataset name='Result 9'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT20 1AE</postcode><__filepos>32</__filepos></Row>
+ <Row><postcode>KT20 1AF</postcode><__filepos>40</__filepos></Row>
+ <Row><postcode>KT20 1AG</postcode><__filepos>48</__filepos></Row>
+ <Row><postcode>KT20 1AH</postcode><__filepos>56</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+ <Row><postcode>KT60 2AB</postcode><__filepos>384</__filepos></Row>
+ <Row><postcode>KT60 3DE</postcode><__filepos>392</__filepos></Row>
+ <Row><postcode>KT60 4FG</postcode><__filepos>400</__filepos></Row>
+ <Row><postcode>KT60 5HI</postcode><__filepos>408</__filepos></Row>
+</Dataset>
+<Dataset name='Result 10'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT20 1AE</postcode><__filepos>32</__filepos></Row>
+ <Row><postcode>KT20 1AF</postcode><__filepos>40</__filepos></Row>
+ <Row><postcode>KT20 1AG</postcode><__filepos>48</__filepos></Row>
+ <Row><postcode>KT20 1AH</postcode><__filepos>56</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+ <Row><postcode>KT60 2AB</postcode><__filepos>384</__filepos></Row>
+ <Row><postcode>KT60 3DE</postcode><__filepos>392</__filepos></Row>
+ <Row><postcode>KT60 4FG</postcode><__filepos>400</__filepos></Row>
+ <Row><postcode>KT60 5HI</postcode><__filepos>408</__filepos></Row>
+</Dataset>
+<Dataset name='Result 11'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT20 1AE</postcode><__filepos>32</__filepos></Row>
+ <Row><postcode>KT20 1AF</postcode><__filepos>40</__filepos></Row>
+ <Row><postcode>KT20 1AG</postcode><__filepos>48</__filepos></Row>
+ <Row><postcode>KT20 1AH</postcode><__filepos>56</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+ <Row><postcode>KT60 2AB</postcode><__filepos>384</__filepos></Row>
+ <Row><postcode>KT60 3DE</postcode><__filepos>392</__filepos></Row>
+ <Row><postcode>KT60 4FG</postcode><__filepos>400</__filepos></Row>
+ <Row><postcode>KT60 5HI</postcode><__filepos>408</__filepos></Row>
+</Dataset>
+<Dataset name='Result 12'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+</Dataset>
+<Dataset name='Result 13'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+</Dataset>
+<Dataset name='Result 14'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+</Dataset>
+<Dataset name='Result 15'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+</Dataset>
+<Dataset name='Result 16'>
+ <Row><postcode>KT19 1AA</postcode><__filepos>0</__filepos></Row>
+ <Row><postcode>KT19 1AB</postcode><__filepos>8</__filepos></Row>
+ <Row><postcode>KT19 1AC</postcode><__filepos>16</__filepos></Row>
+ <Row><postcode>KT19 1AD</postcode><__filepos>24</__filepos></Row>
+ <Row><postcode>KT20 1AE</postcode><__filepos>32</__filepos></Row>
+ <Row><postcode>KT20 1AF</postcode><__filepos>40</__filepos></Row>
+ <Row><postcode>KT20 1AG</postcode><__filepos>48</__filepos></Row>
+ <Row><postcode>KT20 1AH</postcode><__filepos>56</__filepos></Row>
+ <Row><postcode>KT21 1AI</postcode><__filepos>64</__filepos></Row>
+ <Row><postcode>KT21 1AJ</postcode><__filepos>72</__filepos></Row>
+ <Row><postcode>KT21 1AK</postcode><__filepos>80</__filepos></Row>
+ <Row><postcode>KT21 1AL</postcode><__filepos>88</__filepos></Row>
+ <Row><postcode>KT22 1AA</postcode><__filepos>120</__filepos></Row>
+ <Row><postcode>KT22 1AM</postcode><__filepos>96</__filepos></Row>
+ <Row><postcode>KT22 1AN</postcode><__filepos>104</__filepos></Row>
+ <Row><postcode>KT22 1AO</postcode><__filepos>112</__filepos></Row>
+ <Row><postcode>KT23 1AB</postcode><__filepos>128</__filepos></Row>
+ <Row><postcode>KT23 1AC</postcode><__filepos>136</__filepos></Row>
+ <Row><postcode>KT23 1AD</postcode><__filepos>144</__filepos></Row>
+ <Row><postcode>KT23 1AE</postcode><__filepos>152</__filepos></Row>
+ <Row><postcode>KT3&#xe000;&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>416</__filepos></Row>
+ <Row><postcode>KT40 1AC</postcode><__filepos>256</__filepos></Row>
+ <Row><postcode>KT40 1AD</postcode><__filepos>264</__filepos></Row>
+ <Row><postcode>KT40 1AE</postcode><__filepos>272</__filepos></Row>
+ <Row><postcode>KT40 1AF</postcode><__filepos>280</__filepos></Row>
+ <Row><postcode>KT50&#xe000;&#xe000;&#xe000;&#xe000;</postcode><__filepos>432</__filepos></Row>
+ <Row><postcode>KT50 2AB</postcode><__filepos>352</__filepos></Row>
+ <Row><postcode>KT50 3DE</postcode><__filepos>360</__filepos></Row>
+ <Row><postcode>KT50 4FG</postcode><__filepos>368</__filepos></Row>
+ <Row><postcode>KT50 5HI</postcode><__filepos>376</__filepos></Row>
+</Dataset>
+<Dataset name='Result 17'>
+</Dataset>
+<Dataset name='Result 18'>
+</Dataset>
+<Dataset name='Result 19'>
+</Dataset>