Переглянути джерело

HPCC-18209 Avoid losing casts which change signed-ness from sort orders

This might possibly have caused an incorrect sort order (e.g. a negative
value cast as unsigned).  It could also create an internal inconsistency
which caused a stack fault by repeatedly applying a transformation.

Signed-off-by: Gavin Halliday <gavin.halliday@lexisnexis.com>
Gavin Halliday 7 роки тому
батько
коміт
d9fad27f69

+ 13 - 0
ecl/hql/hqlutil.cpp

@@ -4265,6 +4265,19 @@ bool castPreservesValueAndOrder(IHqlExpression * expr)
     IHqlExpression * uncast = expr->queryChild(0);
     ITypeInfo * castType = expr->queryType();
     ITypeInfo * uncastType = uncast->queryType();
+    if (!preservesValue(castType, uncastType))
+        return false;
+    if (!preservesOrder(castType, uncastType))
+        return false;
+    return true;
+}
+
+bool castPreservesInformationAndOrder(IHqlExpression * expr)
+{
+    assertex(isCast(expr));
+    IHqlExpression * uncast = expr->queryChild(0);
+    ITypeInfo * castType = expr->queryType();
+    ITypeInfo * uncastType = uncast->queryType();
     if (castLosesInformation(castType, uncastType))
         return false;
     if (!preservesOrder(castType, uncastType))

+ 2 - 0
ecl/hql/hqlutil.hpp

@@ -513,6 +513,8 @@ interface IDefRecordElement;
 extern HQL_API IDefRecordElement * createMetaRecord(IHqlExpression * record, IMaxSizeCallback * callback);
 
 extern HQL_API bool castPreservesValueAndOrder(IHqlExpression * expr);
+extern HQL_API bool castPreservesInformationAndOrder(IHqlExpression * expr); // Similar to castPreservesValueAndOrder, but allows signed->unsigned differences
+
 extern HQL_API void expandRowSelectors(HqlExprArray & target, HqlExprArray const & source);
 extern HQL_API IHqlExpression * extractCppBodyAttrs(unsigned len, const char * value);
 extern HQL_API unsigned cleanupEmbeddedCpp(unsigned len, char * buffer);

+ 1 - 1
ecl/hqlcpp/hqlstep.cpp

@@ -212,7 +212,7 @@ IHqlExpression * SteppingCondition::simplifyArgument(IHqlExpression * expr, Shar
         {
         case no_cast:
         case no_implicitcast:
-            if (!castPreservesValueAndOrder(expr))
+            if (!castPreservesInformationAndOrder(expr))
                 return expr;
             expr = expr->queryChild(0);
             break;

+ 0 - 1
ecl/regress/localbug.ecl

@@ -474,7 +474,6 @@ END;
 
 DG_MemFile := DATASET(DG_MemFileName,DG_MemFileRec,FLAT);
 
-#line(0)
 //UseStandardFiles
 //tidyoutput
 //nothor

+ 12 - 1
testing/regress/ecl/key/sort3.xml

@@ -69,5 +69,16 @@
 <Dataset name='Result 8'>
 </Dataset>
 <Dataset name='Result 9'>
- <Row><Result_9>done</Result_9></Row>
+ <Row><uv>65025</uv><sv>GAVIN     </sv></Row>
+ <Row><uv>65025</uv><sv>CHARLIE   </sv></Row>
+ <Row><uv>1</uv><sv>Jim       </sv></Row>
+ <Row><uv>257</uv><sv>JAMES     </sv></Row>
+ <Row><uv>257</uv><sv>ABSALOM   </sv></Row>
+ <Row><uv>257</uv><sv>BARNEY    </sv></Row>
+ <Row><uv>257</uv><sv>CHARLIE   </sv></Row>
+ <Row><uv>257</uv><sv>JETHROW   </sv></Row>
+ <Row><uv>257</uv><sv>DANIEL    </sv></Row>
+</Dataset>
+<Dataset name='Result 10'>
+ <Row><Result_10>done</Result_10></Row>
 </Dataset>

+ 3 - 0
testing/regress/ecl/sort3.ecl

@@ -36,6 +36,8 @@ SomeFile := DATASET([{0x001,'GAVIN'},
                     ],MyRec);
 
 p := PROJECT(SomeFile, TRANSFORM(myRec2, SELF := LEFT; SELF := []));
+p2 := PROJECT(SomeFile, TRANSFORM(myRec, SELF.uv := LEFT.uv - 0x200; SELF := LEFT));
+s2 := SORT(p2, uv);
 
 sequential(
     output(SORT(SomeFile, uv)), // needs to be stable
@@ -46,5 +48,6 @@ sequential(
     output(SORT(SomeFile, (string20)sv,(unsigned4)uv)), // can be unstable
     buildindex(NOFOLD(SomeFile), { uv }, { SomeFile }, 'REGRESS:dummyIndex1',overwrite);
     buildindex(NOFOLD(p), { uv }, { p }, 'REGRESS:dummyIndex2',overwrite);
+    output(SORT(s2, (integer2)uv));
     output('done')
 );