浏览代码

Merge pull request #5827 from ghalliday/issue10977

HPCC-10977 Categorise the code generator warnings

Reviewed-By: Jamie Noss <james.noss@lexisnexis.com>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 11 年之前
父节点
当前提交
a687aefdf0

+ 88 - 12
ecl/hql/hqlerror.cpp

@@ -19,16 +19,89 @@
 #include "hqlerror.hpp"
 #include "hqlerrors.hpp"
 
+//---------------------------------------------------------------------------------------------------------------------
+
+ErrorSeverity getSeverity(IAtom * name)
+{
+    if (name == failAtom)
+        return SeverityFatal;
+    if (name == errorAtom)
+        return SeverityError;
+    if (name == warningAtom)
+        return SeverityWarning;
+    if (name == ignoreAtom)
+        return SeverityIgnore;
+    if (name == logAtom)
+        return SeverityInfo;
+    return SeverityUnknown;
+}
+
+ErrorSeverity queryDefaultSeverity(WarnErrorCategory category)
+{
+    if (category == CategoryError)
+        return SeverityFatal;
+    if (category == CategoryInformation)
+        return SeverityInfo;
+    if (category == CategoryMistake)
+        return SeverityError;
+    return SeverityWarning;
+}
+
+WarnErrorCategory getCategory(const char * category)
+{
+    if (strieq(category, "all"))
+        return CategoryAll;
+    if (strieq(category, "cast"))
+        return CategoryCast;
+    if (strieq(category, "confuse"))
+        return CategoryConfuse;
+    if (strieq(category, "deprecated"))
+        return CategoryDeprecated;
+    if (strieq(category, "efficiency"))
+        return CategoryEfficiency;
+    if (strieq(category, "fold"))
+        return CategoryFolding;
+    if (strieq(category, "future"))
+        return CategoryFuture;
+    if (strieq(category, "ignored"))
+        return CategoryIgnored;
+    if (strieq(category, "index"))
+        return CategoryIndex;
+    if (strieq(category, "info"))
+        return CategoryInformation;
+    if (strieq(category, "mistake"))
+        return CategoryMistake;
+    if (strieq(category, "limit"))
+        return CategoryLimit;
+    if (strieq(category, "syntax"))
+        return CategorySyntax;
+    if (strieq(category, "unusual"))
+        return CategoryUnusual;
+    if (strieq(category, "unexpected"))
+        return CategoryUnexpected;
+    return CategoryUnknown;
+}
+
+ErrorSeverity getCheckSeverity(IAtom * name)
+{
+    ErrorSeverity severity = getSeverity(name);
+    assertex(severity != SeverityUnknown);
+    return severity;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------
+
 class HQL_API CECLError : public CInterfaceOf<IECLError>
 {
 public:
-    CECLError(ErrorSeverity _severity, int _no, const char* _msg, const char* _filename, int _lineno, int _column, int _position);
+    CECLError(WarnErrorCategory _category,ErrorSeverity _severity, int _no, const char* _msg, const char* _filename, int _lineno, int _column, int _position);
 
     virtual int             errorCode() const { return no; }
     virtual StringBuffer &  errorMessage(StringBuffer & ret) const { return ret.append(msg); }
     virtual MessageAudience errorAudience() const { return MSGAUD_user; }
     virtual const char* getFilename() const { return filename; }
-    virtual WarnErrorCategory getCategory() const { return CategoryUnknown; }
+    virtual WarnErrorCategory getCategory() const { return category; }
     virtual int getLine() const { return lineno; }
     virtual int getColumn() const { return column; }
     virtual int getPosition() const { return position; }
@@ -38,6 +111,7 @@ public:
 
 protected:
     ErrorSeverity severity;
+    WarnErrorCategory category;
     int no;
     StringAttr msg;
     StringAttr filename;
@@ -46,8 +120,8 @@ protected:
     int position;
 };
 
-CECLError::CECLError(ErrorSeverity _severity, int _no, const char* _msg, const char* _filename, int _lineno, int _column, int _position):
-  severity(_severity), msg(_msg), filename(_filename)
+CECLError::CECLError(WarnErrorCategory _category, ErrorSeverity _severity, int _no, const char* _msg, const char* _filename, int _lineno, int _column, int _position):
+  category(_category),severity(_severity), msg(_msg), filename(_filename)
 {
     no = _no;
     lineno = _lineno;
@@ -70,14 +144,14 @@ StringBuffer& CECLError::toString(StringBuffer& buf) const
 
 IECLError * CECLError::cloneSetSeverity(ErrorSeverity newSeverity) const
 {
-    return new CECLError(newSeverity,
+    return new CECLError(category, newSeverity,
                          errorCode(), msg, filename,
                          getLine(), getColumn(), getPosition());
 }
 
-extern HQL_API IECLError *createECLError(ErrorSeverity severity, int errNo, const char *msg, const char * filename, int lineno, int column, int pos)
+extern HQL_API IECLError *createECLError(WarnErrorCategory category, ErrorSeverity severity, int errNo, const char *msg, const char * filename, int lineno, int column, int pos)
 {
-    return new CECLError(severity,errNo,msg,filename,lineno,column,pos);
+    return new CECLError(category,severity,errNo,msg,filename,lineno,column,pos);
 }
 
 //---------------------------------------------------------------------------------------------------------------------
@@ -88,9 +162,10 @@ void IErrorReceiver::reportError(int errNo, const char *msg, const char *filenam
     report(err);
 }
 
-void IErrorReceiver::reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int position)
+void IErrorReceiver::reportWarning(WarnErrorCategory category, int warnNo, const char *msg, const char *filename, int lineno, int column, int position)
 {
-    Owned<IECLError> warn = createECLError(SeverityWarning,warnNo,msg,filename,lineno,column,position);
+    ErrorSeverity severity = queryDefaultSeverity(category);
+    Owned<IECLError> warn = createECLError(category, severity,warnNo,msg,filename,lineno,column,position);
     report(warn);
 }
 
@@ -332,18 +407,19 @@ void checkEclVersionCompatible(Shared<IErrorReceiver> & errors, const char * ecl
             if (major != LANGUAGE_VERSION_MAJOR)
             {
                 VStringBuffer msg("Mismatch in major version number (%s v %s)", eclVersion, LANGUAGE_VERSION);
-                errors->reportWarning(HQLERR_VersionMismatch, msg.str(), NULL, 0, 0, 0);
+                errors->reportWarning(CategoryUnexpected, HQLERR_VersionMismatch, msg.str(), NULL, 0, 0, 0);
             }
             else if (minor != LANGUAGE_VERSION_MINOR)
             {
                 VStringBuffer msg("Mismatch in minor version number (%s v %s)", eclVersion, LANGUAGE_VERSION);
-                errors->reportWarning(HQLERR_VersionMismatch, msg.str(), NULL, 0, 0, 0);
+                Owned<IECLError> warning = createECLError(CategoryUnexpected, SeverityInfo, HQLERR_VersionMismatch, msg.str(), NULL, 0, 0);
+                errors.setown(new ErrorInserter(*errors, warning));
             }
             else if (subminor != LANGUAGE_VERSION_SUB)
             {
                 //This adds the warning if any other warnings occur.
                 VStringBuffer msg("Mismatch in subminor version number (%s v %s)", eclVersion, LANGUAGE_VERSION);
-                Owned<IECLError> warning = createECLError(SeverityWarning, HQLERR_VersionMismatch, msg.str(), NULL, 0, 0);
+                Owned<IECLError> warning = createECLError(CategoryUnexpected, SeverityInfo, HQLERR_VersionMismatch, msg.str(), NULL, 0, 0);
                 errors.setown(new ErrorInserter(*errors, warning));
             }
         }

+ 16 - 5
ecl/hql/hqlerror.hpp

@@ -39,19 +39,23 @@ inline bool isFatal(ErrorSeverity severity) { return severity == SeverityFatal;
 //TBD in a separate commit - add support for warnings to be associated with different categories
 enum WarnErrorCategory
 {
+    CategoryInformation,// Some kind of information [default severity information]
+
     CategoryCast,       // Suspicious casts between types or out of range values
     CategoryConfuse,    // Likely to cause confusion
     CategoryDeprecated, // deprecated features or syntax
     CategoryEfficiency, // Something that is likely to be inefficient
+    CategoryFolding,    // Unusual results from constant folding
     CategoryFuture,     // Likely to cause problems in future versions
     CategoryIgnored,    // Something that has no effect, or is ignored
     CategoryIndex,      // Unusual indexing of datasets or strings
-    CategoryMistyped,   // Almost certainly mistyped
+    CategoryMistake,    // Almost certainly a mistake
+    CategoryLimit,      // An operation that should really have some limits to protect data runaway
     CategorySyntax,     // Invalid syntax which is painless to recover from
     CategoryUnusual,    // Not strictly speaking an error, but highly unusual and likely to be a mistake
     CategoryUnexpected, // Code that could be correct, but has the potential for unexpected behaviour
 
-    CategoryError,
+    CategoryError,      // Typically severity fatal
     CategoryAll,
     CategoryUnknown,
     CategoryMax,
@@ -81,7 +85,7 @@ interface HQL_API IErrorReceiver : public IInterface
 
     //global helper functions
     void reportError(int errNo, const char *msg, const char *filename, int lineno, int column, int pos);
-    void reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos);
+    void reportWarning(WarnErrorCategory category, int warnNo, const char *msg, const char *filename, int lineno, int column, int pos);
 };
 
 typedef IArrayOf<IECLError> IECLErrorArray;
@@ -153,10 +157,17 @@ private:
 
 //---------------------------------------------------------------------------------------------------------------------
 
-extern HQL_API IECLError *createECLError(ErrorSeverity severity, int errNo, const char *msg, const char *filename, int lineno=0, int column=0, int pos=0);
+ErrorSeverity queryDefaultSeverity(WarnErrorCategory category);
+WarnErrorCategory getCategory(const char * category);
+ErrorSeverity getSeverity(IAtom * name);
+ErrorSeverity getCheckSeverity(IAtom * name);
+
+//---------------------------------------------------------------------------------------------------------------------
+
+extern HQL_API IECLError *createECLError(WarnErrorCategory category, ErrorSeverity severity, int errNo, const char *msg, const char *filename, int lineno=0, int column=0, int pos=0);
 inline IECLError * createECLError(int errNo, const char *msg, const char *filename, int lineno=0, int column=0, int pos=0)
 {
-    return createECLError(SeverityFatal, errNo, msg, filename, lineno, column, pos);
+    return createECLError(CategoryError, SeverityFatal, errNo, msg, filename, lineno, column, pos);
 }
 extern HQL_API void reportErrors(IErrorReceiver & receiver, IECLErrorArray & errors);
 void HQL_API reportErrorVa(IErrorReceiver * errors, int errNo, const ECLlocation & loc, const char* format, va_list args);

+ 4 - 4
ecl/hql/hqlerrors.hpp

@@ -525,10 +525,10 @@
 
 #define ECODETEXT(x)                (x), (x##_Text)
 
-#define WARNING(x)                  reportWarning(x, x##_Text)
-#define WARNING1(x, a)              reportWarning(x, x##_Text, a)
-#define WARNING2(x, a, b)           reportWarning(x, x##_Text, a, b)
-#define WARNING3(x, a, b, c)        reportWarning(x, x##_Text, a, b, c)
+#define WARNING(cat, x)                  reportWarning(cat, x, x##_Text)
+#define WARNING1(cat, x, a)              reportWarning(cat, x, x##_Text, a)
+#define WARNING2(cat, x, a, b)           reportWarning(cat, x, x##_Text, a, b)
+#define WARNING3(cat, x, a, b, c)        reportWarning(cat, x, x##_Text, a, b, c)
 
 #define ERRORAT(e, x)               reportError(e, x, x##_Text)
 #define ERRORAT1(e, x, a)           reportError(e, x, x##_Text, a)

+ 1 - 1
ecl/hql/hqlexpr.cpp

@@ -8064,7 +8064,7 @@ IHqlExpression *CHqlRemoteScope::lookupSymbol(IIdAtom * searchName, unsigned loo
     if (repositoryFlags&ob_sandbox)
     {
         if (ctx.errs)
-            ctx.errs->reportWarning(WRN_DEFINITION_SANDBOXED,"Definition is sandboxed",filename,0,0,0);
+            ctx.errs->reportWarning(CategoryInformation,WRN_DEFINITION_SANDBOXED,"Definition is sandboxed",filename,0,0,0);
     }
 
     if (!(newSymbol->isExported() || (lookupFlags & LSFsharedOK)))

+ 8 - 8
ecl/hql/hqlgram.hpp

@@ -564,26 +564,26 @@ public:
     IHqlExpression * nextEnumValue();
 
 // Error handling
-    void doReportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos);
+    void doReportWarning(WarnErrorCategory category, int warnNo, const char *msg, const char *filename, int lineno, int column, int pos);
     void reportError(int errNo, const attribute& a, const char* format, ...) __attribute__((format(printf, 4, 5)));
     void reportError(int errNo, const ECLlocation & pos, const char* format, ...) __attribute__((format(printf, 4, 5)));
-    void reportMacroExpansionPosition(int errNo, HqlLex * lexer, bool isError);
+    void reportMacroExpansionPosition(IECLError * warning, HqlLex * lexer);
     void reportErrorUnexpectedX(const attribute & errpos, IAtom * unexpected);
 
     // Don't use overloading: va_list is the same as char*!!
     void reportErrorVa(int errNo, const ECLlocation & a, const char* format, va_list args);
     void reportError(int errNo, const char *msg, int lineno, int column, int position=0);
-    void reportWarning(int warnNo, const ECLlocation & pos, const char* format, ...) __attribute__((format(printf, 4, 5)));
-    void reportWarning(ErrorSeverity severity, int warnNo, const ECLlocation & pos, const char* format, ...) __attribute__((format(printf, 5, 6)));
-    void reportWarningVa(int errNo, const attribute& a, const char* format, va_list args);
-    void reportWarning(int warnNo, const char *msg, int lineno, int column);
+    void reportWarning(WarnErrorCategory category, int warnNo, const ECLlocation & pos, const char* format, ...) __attribute__((format(printf, 5,6)));
+    void reportWarning(WarnErrorCategory category, ErrorSeverity severity, int warnNo, const ECLlocation & pos, const char* format, ...) __attribute__((format(printf, 6, 7)));
+    void reportWarningVa(WarnErrorCategory category, int errNo, const attribute& a, const char* format, va_list args);
+    void reportWarning(WarnErrorCategory category, int warnNo, const char *msg, int lineno, int column);
     void addResult(IHqlExpression *query, const attribute& errpos);
 
     // interface IErrorReceiver
     virtual void reportError(int errNo, const char *msg, const char *filename=NULL, int lineno=0, int column=0, int pos=0);
     virtual void report(IECLError * error);
     virtual IECLError * mapError(IECLError * error);
-    virtual void reportWarning(int warnNo, const char *msg, const char *filename=NULL, int lineno=0, int column=0, int pos=0);
+    void reportWarning(WarnErrorCategory category, int warnNo, const char *msg, const char *filename=NULL, int lineno=0, int column=0, int pos=0);
     virtual size32_t errCount();
     virtual size32_t warnCount();
     
@@ -1100,7 +1100,7 @@ class HqlLex
 
         IHqlExpression *lookupSymbol(IIdAtom * name, const attribute& errpos);
         void reportError(const YYSTYPE & returnToken, int errNo, const char *format, ...) __attribute__((format(printf, 4, 5)));
-        void reportWarning(const YYSTYPE & returnToken, int warnNo, const char *format, ...) __attribute__((format(printf, 4, 5)));
+        void reportWarning(WarnErrorCategory category, const YYSTYPE & returnToken, int warnNo, const char *format, ...) __attribute__((format(printf, 5, 6)));
 
         void beginNestedHash(unsigned kind) { hashendKinds.append(kind); hashendFlags.append(0); }
         void endNestedHash() { hashendKinds.pop(); hashendFlags.pop(); }

+ 14 - 14
ecl/hql/hqlgram.y

@@ -669,7 +669,7 @@ importItem
     | importSelectorList AS '*'
                         {
                             if (queryLegacyImportSemantics())
-                                parser->reportWarning(ERR_DEPRECATED, $1.pos, "IMPORT <module> AS * is deprecated, use IMPORT * FROM <module>");
+                                parser->reportWarning(CategoryDeprecated, ERR_DEPRECATED, $1.pos, "IMPORT <module> AS * is deprecated, use IMPORT * FROM <module>");
                             else
                                 parser->reportError(ERR_DEPRECATED, $1.pos, "IMPORT <module> AS * is deprecated, use IMPORT * FROM <module>");
                             parser->processImportAll($1);
@@ -1460,7 +1460,7 @@ metaCommandWithNoSemicolon
     : setMetaCommand
                         {
                             //These are really treated like actions now, this is here for backward compatibility
-                            parser->reportWarning(ERR_DEPRECATED, $1.pos, "#command with no trailing semicolon is deprecated");
+                            parser->reportWarning(CategoryDeprecated, ERR_DEPRECATED, $1.pos, "#command with no trailing semicolon is deprecated");
                             parser->addResult($1.getExpr(), $1);
                             $$.clear();
                         }
@@ -2481,7 +2481,7 @@ actionStmt
                         {
                             parser->normalizeExpression($3);
                             // change error to warning.
-                            parser->reportWarning(WRN_CASENOCONDITION, $1.pos, "CASE does not have any conditions");
+                            parser->reportWarning(CategoryUnusual, WRN_CASENOCONDITION, $1.pos, "CASE does not have any conditions");
                             HqlExprArray list;
                             parser->endList(list);
                             ::Release($3.getExpr());
@@ -3875,7 +3875,7 @@ attriblist
 attrib
     : knownOrUnknownId EQ UNKNOWN_ID        
                         {
-                            parser->reportWarning(WRN_OBSOLETED_SYNTAX,$1.pos,"Syntax obsoleted; use alternative: id = '<string constant>'");
+                            parser->reportWarning(CategoryDeprecated, SeverityError, WRN_OBSOLETED_SYNTAX,$1.pos,"Syntax obsoleted; use alternative: id = '<string constant>'");
                             $$.setExpr(createAttribute($1.getId()->lower(), createConstant(*$3.getId())));
                         }
     | knownOrUnknownId EQ expr %prec reduceAttrib
@@ -5634,7 +5634,7 @@ primexpr1
                             parser->normalizeExpression($3);
                             parser->normalizeExpression($6);
                             // change error to warning.
-                            parser->reportWarning(WRN_CASENOCONDITION, $1.pos, "CASE does not have any conditions");
+                            parser->reportWarning(CategoryUnusual, WRN_CASENOCONDITION, $1.pos, "CASE does not have any conditions");
                             HqlExprArray args;
                             parser->endList(args);
                             ::Release($3.getExpr());
@@ -6089,7 +6089,7 @@ primexpr1
                         }
     | COUNT             {
                             $$.setExpr(parser->getActiveCounter($1));
-                            parser->reportWarning(SeverityError, ERR_COUNTER_NOT_COUNT, $1.pos, "Use of COUNT instead of COUNTER is deprecated");
+                            parser->reportWarning(CategoryDeprecated, SeverityError, ERR_COUNTER_NOT_COUNT, $1.pos, "Use of COUNT instead of COUNTER is deprecated");
                         }
     | COUNTER               {
                             $$.setExpr(parser->getActiveCounter($1));
@@ -6427,7 +6427,7 @@ primexpr1
     | EXISTS '(' expressionList ')'
                         {
                             if (parser->isSingleValuedExpressionList($3))
-                                parser->reportWarning(WRN_SILLY_EXISTS,$1.pos,"EXISTS() on a scalar expression is always true, was this intended?");
+                                parser->reportWarning(CategoryMistake, WRN_SILLY_EXISTS,$1.pos,"EXISTS() on a scalar expression is always true, was this intended?");
 
                             OwnedHqlExpr list = parser->createListFromExpressionList($3);
                             $$.setExpr(createValue(no_existslist, makeBoolType(), LINK(list)));
@@ -7405,7 +7405,7 @@ simpleDictionary
                         {
                             parser->normalizeExpression($3, type_scalar, false);
                             // change error to warning.
-                            parser->reportWarning(WRN_CASENOCONDITION, $1.pos, "CASE does not have any conditions");
+                            parser->reportWarning(CategoryUnusual, WRN_CASENOCONDITION, $1.pos, "CASE does not have any conditions");
                             HqlExprArray list;
                             parser->endList(list);
                             $3.release();
@@ -7655,7 +7655,7 @@ simpleDataSet
                             
                             IHqlExpression * limit = $5.getExpr();
                             if (limit->queryValue() && limit->queryValue()->getIntValue() == 0)
-                                parser->reportWarning(WRN_CHOOSEN_ALL,$1.pos,"Use CHOOSEN(dataset, ALL) to remove implicit choosen.  CHOOSEN(dataset, 0) now returns no records.");
+                                parser->reportWarning(CategoryUnusual, WRN_CHOOSEN_ALL,$1.pos,"Use CHOOSEN(dataset, ALL) to remove implicit choosen.  CHOOSEN(dataset, 0) now returns no records.");
                             $$.setExpr(createDataset(no_choosen, $3.getExpr(), createComma(limit, $6.getExpr())), $1);
                             parser->attachPendingWarnings($$);
                         }
@@ -7867,7 +7867,7 @@ simpleDataSet
                             HqlExprArray sortItems;
                             parser->endList(sortItems);
                             if (!queryAttribute(sortedAtom, sortItems))
-                                parser->reportWarning(WRN_MERGE_RECOMMEND_SORTED, $1.pos, "MERGE without an explicit SORTED() attribute is deprecated");
+                                parser->reportWarning(CategoryDeprecated, WRN_MERGE_RECOMMEND_SORTED, $1.pos, "MERGE without an explicit SORTED() attribute is deprecated");
 
                             IHqlExpression * ds = $3.getExpr();
                             parser->expandSortedAsList(sortItems);
@@ -8116,7 +8116,7 @@ simpleDataSet
                             OwnedHqlExpr newSorted;
                             if (!sorted)
                             {
-                                parser->reportWarning(WRN_MERGE_RECOMMEND_SORTED, $1.pos, "MERGE without an explicit SORTED() attribute is deprecated");
+                                parser->reportWarning(CategoryDeprecated, WRN_MERGE_RECOMMEND_SORTED, $1.pos, "MERGE without an explicit SORTED() attribute is deprecated");
                                 OwnedHqlExpr order = getExistingSortOrder(ds, isLocal, true);
                                 HqlExprArray sorts;
                                 if (order)
@@ -8360,7 +8360,7 @@ simpleDataSet
                             {
                                 parser->checkGrouping($7, dataset,record,grouping);
                                 if (dataset->getOperator() == no_group && isGrouped(dataset))
-                                    parser->reportWarning(WRN_GROUPINGIGNORED, $3.pos, "Grouping of table input will have no effect, was this intended?");
+                                    parser->reportWarning(CategoryIgnored, WRN_GROUPINGIGNORED, $3.pos, "Grouping of table input will have no effect, was this intended?");
                             }
 
                             HqlExprArray args;
@@ -8866,7 +8866,7 @@ simpleDataSet
                         {
                             parser->normalizeExpression($3, type_scalar, false);
                             // change error to warning.
-                            parser->reportWarning(WRN_CASENOCONDITION, $1.pos, "CASE does not have any conditions");
+                            parser->reportWarning(CategoryUnusual, WRN_CASENOCONDITION, $1.pos, "CASE does not have any conditions");
                             HqlExprArray list;
                             parser->endList(list);
                             $3.release();
@@ -12280,7 +12280,7 @@ featureValueList
 featureModifiers
     : '{' featureValueList '}'
                         {
-                            parser->reportWarning(WRN_FEATURE_NOT_REPEAT, $1.pos, "Curly brackets are not used for repeats - they are reserved for future functionality");
+                            parser->reportWarning(CategorySyntax, SeverityError, WRN_FEATURE_NOT_REPEAT, $1.pos, "Curly brackets are not used for repeats - they are reserved for future functionality");
                             $$.setExpr($2.getExpr());
                         }
     ;

+ 82 - 97
ecl/hql/hqlgram2.cpp

@@ -54,6 +54,7 @@
 //#define USE_WHEN_FOR_SIDEEFFECTS
 #define MANYFIELDS_THRESHOLD                        2000
 #define MAX_SENSIBLE_FIELD_LENGTH                   1000000000
+#define MAX_POSSIBLE_FIELD_LENGTH                   (INFINITE_LENGTH-1)
 
 struct TokenMap
 {
@@ -176,9 +177,6 @@ protected:
 };
 
 
-/* This enables warning on a assignall which tries to reassign a field. */
-//#define _WARN_ON_ASSIGNALL
-
 void attribute::annotateExprWithLocation()
 {
     if ((atr_type==t_expr) && expr && !queryLocation(expr))
@@ -264,23 +262,13 @@ bool HqlGramCtx::hasAnyActiveParameters()
 }
 
 
-static IECLError * createErrorVA(ErrorSeverity severity, int errNo, const ECLlocation & pos, const char* format, va_list args)
+static IECLError * createErrorVA(WarnErrorCategory category, ErrorSeverity severity, int errNo, const ECLlocation & pos, const char* format, va_list args)
 {
     StringBuffer msg;
     msg.valist_appendf(format, args);
-    return createECLError(severity, errNo, msg.str(), pos.sourcePath->str(), pos.lineno, pos.column, pos.position);
-}
-
-static IECLError * createError(ErrorSeverity severity, int errNo, const ECLlocation & pos, const char* format, ...)
-{
-    va_list args;
-    va_start(args, format);
-    IECLError * error = createErrorVA(severity, errNo, pos, format, args);
-    va_end(args);
-    return error;
+    return createECLError(category, severity, errNo, msg.str(), pos.sourcePath->str(), pos.lineno, pos.column, pos.position);
 }
 
-
 void HqlGram::gatherActiveParameters(HqlExprCopyArray & target)
 {
     ForEachItemIn(i2, defineScopes)
@@ -974,7 +962,7 @@ IHqlExpression * HqlGram::processUserAggregate(const attribute & mainPos, attrib
     OwnedHqlExpr grouping = itemsAttr ? processSortList(*itemsAttr, no_aggregate, dataset, sortItems, NULL, &attrs) : NULL;
 
     if (grouping && (dataset->getOperator() == no_group) && isGrouped(dataset))
-        reportWarning(WRN_GROUPINGIGNORED, dsAttr.pos, "Grouping of aggregate input will have no effect, was this intended?");
+        reportWarning(CategoryIgnored, WRN_GROUPINGIGNORED, dsAttr.pos, "Grouping of aggregate input will have no effect, was this intended?");
 
     HqlExprArray args;
     args.append(*LINK(dataset));
@@ -1754,11 +1742,8 @@ void HqlGram::addAssignall(IHqlExpression *tgt, IHqlExpression *src, const attri
     assignall = assignall->closeExpr();
     if (assignall->numChildren() > firstAssign) 
         curTransform->addOperand(assignall);
-    else // empty assignall.
-    {
-        //reportWarning(WRN_TRANX_EMPTYASSIGNALL, errpos.pos, "Assignment has no effect; ignored");
+    else
         assignall->Release();
-    }
 }
 
 
@@ -1875,13 +1860,6 @@ void HqlGram::doAddAssignCompound(IHqlExpression * assignall, IHqlExpression * t
                     else
                         doAddAssignment(assignall,LINK(lhs),LINK(rhs),errpos);
                 }
-                else
-                {
-    #ifdef _WARN_ON_ASSIGNALL
-                    StringBuffer fldName;
-                    reportWarning(WRN_TRANX_HASASSIGNEDVALUE, errpos.pos, "A value for \"%s\" has already been specified", getFldName(lhs,fldName).str());
-    #endif
-                }   
             }
         }
     }
@@ -2066,7 +2044,7 @@ void HqlGram::doCheckAssignedNormalizeTransform(HqlExprArray * assigns, IHqlExpr
                         //Not very nice - only ok in some situations....
                         if (cur->hasAttribute(virtualAtom))
                         {
-                            reportWarning(ERR_TRANS_NOVALUE4FIELD, errpos.pos, "Transform does not supply a value for field \"%s\"", fldName.str());
+                            reportWarning(CategorySyntax, ERR_TRANS_NOVALUE4FIELD, errpos.pos, "Transform does not supply a value for field \"%s\"", fldName.str());
                             OwnedHqlExpr null = createNullExpr(cur);
                             if (assigns)
                                 assigns->append(*createAssign(LINK(targetSelected), LINK(null)));
@@ -2264,7 +2242,7 @@ void HqlGram::addFields(const attribute &errpos, IHqlExpression *e, IHqlExpressi
         if (match)
         {
             if (!clone)
-                reportWarning(ERR_REC_DUPFIELD, errpos.pos, "A field called %s is already defined in this record",id->str());
+                reportWarning(CategorySyntax, ERR_REC_DUPFIELD, errpos.pos, "A field called %s is already defined in this record",id->str());
             continue;
         }
 
@@ -2396,7 +2374,7 @@ void HqlGram::addField(const attribute &errpos, IIdAtom * name, ITypeInfo *_type
                     canNotAssignTypeError(fieldType,defvalueType,errpos);
                 IValue * constValue = defaultValue->queryValue();
                 if (constValue && (constValue->rangeCompare(expectedType) > 0))
-                    reportWarning(ERR_TYPE_INCOMPATIBLE, errpos.pos, "%s", "Default value too large");
+                    reportWarning(CategorySyntax, ERR_TYPE_INCOMPATIBLE, errpos.pos, "%s", "Default value too large");
                 if (expectedType->getTypeCode() != type_row)
                 {
                     HqlExprArray allAttrs;
@@ -2424,7 +2402,7 @@ void HqlGram::addField(const attribute &errpos, IIdAtom * name, ITypeInfo *_type
     case type_decimal:
         if (fieldType->getSize() == UNKNOWN_LENGTH)
         {
-            reportWarning(ERR_BAD_FIELD_TYPE, errpos.pos, "Fields of unknown length decimal not currently supported");
+            reportWarning(CategorySyntax, ERR_BAD_FIELD_TYPE, errpos.pos, "Fields of unknown length decimal not currently supported");
             fieldType.setown(makeDecimalType(MAX_DECIMAL_DIGITS, MAX_DECIMAL_PRECISION, fieldType->isSigned()));
         }
         break;
@@ -2457,8 +2435,14 @@ void HqlGram::addField(const attribute &errpos, IIdAtom * name, ITypeInfo *_type
         }
     }
 
-    if ((fieldType->getSize() != UNKNOWN_LENGTH) && (fieldType->getSize() > MAX_SENSIBLE_FIELD_LENGTH))
-        reportError(ERR_BAD_FIELD_SIZE, errpos, "Field %s is too large", name->str());
+    size32_t fieldSize = fieldType->getSize();
+    if (fieldSize != UNKNOWN_LENGTH)
+    {
+        if (fieldSize > MAX_SENSIBLE_FIELD_LENGTH)
+            reportWarning(CategoryEfficiency, SeverityError, ERR_BAD_FIELD_SIZE, errpos.pos, "Field %s is larger than max sensible size", name->str());
+        else if (fieldSize > MAX_POSSIBLE_FIELD_LENGTH)
+            reportError(ERR_BAD_FIELD_SIZE, errpos.pos, "Field %s is too large", name->str());
+    }
 
     OwnedHqlExpr newField = createField(name, fieldType.getClear(), value.getClear(), attrs);
     OwnedHqlExpr annotated = createLocationAnnotation(LINK(newField), errpos.pos);
@@ -3527,7 +3511,7 @@ void HqlGram::checkMaxCompatible(IHqlExpression * sortOrder, IHqlExpression * va
 void HqlGram::checkSvcAttrNoValue(IHqlExpression* attr, const attribute& errpos)
 {
     if (attr->numChildren()>0)
-        reportWarning(WRN_SVC_ATTRNEEDNOVALUE, errpos.pos,"Service attribute '%s' requires no value; ignored",attr->queryName()->str());
+        reportWarning(CategorySyntax, WRN_SVC_ATTRNEEDNOVALUE, errpos.pos,"Service attribute '%s' requires no value; ignored",attr->queryName()->str());
 }
 
 void cleanupService(IHqlScope*& serviceScope)
@@ -3644,7 +3628,7 @@ IHqlExpression* HqlGram::checkServiceDef(IHqlScope* serviceScope,IIdAtom * name,
 
                 /* should be really an error */
                 if (invalid)
-                    reportWarning(ERR_SVC_INVALIDINCLUDE,errpos.pos,"Invalid include: can not be empty");
+                    reportWarning(CategorySyntax, ERR_SVC_INVALIDINCLUDE,errpos.pos, "Invalid include: can not be empty");
             }
             else if (name == eclrtlAtom)
             {
@@ -3678,7 +3662,7 @@ IHqlExpression* HqlGram::checkServiceDef(IHqlScope* serviceScope,IIdAtom * name,
                 //backward compatibility
             }
             else // unsupported
-                reportWarning(WRN_SVC_UNSUPPORTED_ATTR, errpos.pos, "Unsupported service attribute: '%s'; ignored", name->str());
+                reportWarning(CategorySyntax,WRN_SVC_UNSUPPORTED_ATTR, errpos.pos, "Unsupported service attribute: '%s'; ignored", name->str());
         }
 
         // check attribute conflicts
@@ -3687,7 +3671,7 @@ IHqlExpression* HqlGram::checkServiceDef(IHqlScope* serviceScope,IIdAtom * name,
         if (cApi)   apiAttrs++;
         if (bcdApi) apiAttrs++;
         if (apiAttrs>1)
-            reportWarning(ERR_SVC_ATTRCONFLICTS, errpos.pos, "Attributes eclrtl, bcd, c are conflict: only 1 can be used at a time");
+            reportWarning(CategorySyntax, ERR_SVC_ATTRCONFLICTS, errpos.pos, "Attributes eclrtl, bcd, c are conflict: only 1 can be used at a time");
     }
 
     if (!hasEntrypoint)
@@ -3809,7 +3793,7 @@ bool HqlGram::checkAlienTypeDef(IHqlScope* scope, const attribute& errpos)
             else
             {
                 if (phyLen)
-                    reportWarning(WRN_USRTYPE_EXTRAPHYLEN,errpos.pos,"physicalLength not needed since the type size is known");
+                    reportWarning(CategoryIgnored, WRN_USRTYPE_EXTRAPHYLEN,errpos.pos,"physicalLength not needed since the type size is known");
             }
         }
 
@@ -3875,19 +3859,19 @@ ITypeInfo * HqlGram::checkStringIndex(attribute & strAttr, attribute & idxAttr)
     if (info.knownStart() && (startIndex < 1 || ((strSize != UNKNOWN_LENGTH) && startIndex > strSize)))
     {
         if (startIndex<1)
-            reportWarning(ERR_SUBSTR_INVALIDRANGE, idxAttr.pos,"Invalid substring range: start index %d must >= 1", startIndex);
+            reportWarning(CategoryIndex, ERR_SUBSTR_INVALIDRANGE, idxAttr.pos,"Invalid substring range: start index %d must >= 1", startIndex);
         else  /* assert: strSize != UNKNOWN_LENGTH */
-            reportWarning(ERR_SUBSTR_INVALIDRANGE, idxAttr.pos,"Invalid substring range: index %d out of bound: 1..%d", startIndex, strSize);
+            reportWarning(CategoryIndex, ERR_SUBSTR_INVALIDRANGE, idxAttr.pos,"Invalid substring range: index %d out of bound: 1..%d", startIndex, strSize);
     }
     else if (info.knownEnd() && (endIndex < 1 || ((strSize != UNKNOWN_LENGTH) && endIndex > strSize)))
     {
         if (endIndex < 1)
-            reportWarning(ERR_SUBSTR_INVALIDRANGE, idxAttr.pos, "Invalid substring range: end index %d must >= 1", endIndex);
+            reportWarning(CategoryIndex, ERR_SUBSTR_INVALIDRANGE, idxAttr.pos, "Invalid substring range: end index %d must >= 1", endIndex);
         else
-            reportWarning(ERR_SUBSTR_INVALIDRANGE, idxAttr.pos, "Invalid substring range: index %d out of bound: 1..%d", endIndex, strSize);
+            reportWarning(CategoryIndex, ERR_SUBSTR_INVALIDRANGE, idxAttr.pos, "Invalid substring range: index %d out of bound: 1..%d", endIndex, strSize);
     }
     else if (info.knownStart() && info.knownEnd() && startIndex > endIndex)
-        reportWarning(ERR_SUBSTR_INVALIDRANGE, idxAttr.pos, "Invalid substring range: start index %d > end index %d", startIndex, endIndex);
+        reportWarning(CategoryIndex, ERR_SUBSTR_INVALIDRANGE, idxAttr.pos, "Invalid substring range: start index %d > end index %d", startIndex, endIndex);
 
     unsigned resultSize = UNKNOWN_LENGTH;
 //  if (strSize != UNKNOWN_LENGTH)
@@ -4215,7 +4199,7 @@ IHqlExpression * HqlGram::createSortExpr(node_operator op, attribute & dsAttr, c
     IHqlExpression *sortOrder = processSortList(orderAttr, no_sort, input, args, &joinedClause, &attrs);
     if (!sortOrder)
     {
-        reportError(ERR_SORT_EMPTYLIST, orderAttr, "The list to be sorted on is empty");
+        reportWarning(CategoryMistake, SeverityError, ERR_SORT_EMPTYLIST, orderAttr.pos, "The list to be sorted on is empty");
         return input;
     }
 
@@ -4308,7 +4292,7 @@ void HqlGram::ensureTypeCanBeIndexed(attribute &a)
         default:
             {
                 StringBuffer typeName;
-                reportWarning(ERR_TYPEMISMATCH_STRING, a.pos, "substring applied to value of type %s", getFriendlyTypeStr(t1, typeName).str());
+                reportWarning(CategorySyntax, ERR_TYPEMISMATCH_STRING, a.pos, "substring applied to value of type %s", getFriendlyTypeStr(t1, typeName).str());
                 ensureString(a);
                 break;
             }
@@ -4916,9 +4900,9 @@ void HqlGram::promoteToSameCompareType(attribute &a1, attribute &a2, node_operat
         }
 
         if (alwaysTrue)
-            reportWarning(WRN_COND_ALWAYS_TRUE, a2.pos, "Condition is always true");
+            reportWarning(CategoryFolding, WRN_COND_ALWAYS_TRUE, a2.pos, "Condition is always true");
         if (alwaysFalse)
-            reportWarning(WRN_COND_ALWAYS_FALSE, a2.pos, "Condition is always false");
+            reportWarning(CategoryFolding, WRN_COND_ALWAYS_FALSE, a2.pos, "Condition is always false");
     }
 
 #if 0
@@ -4952,9 +4936,9 @@ void HqlGram::warnIfFoldsToConstant(IHqlExpression * expr, const attribute & err
         if (folded->queryValue())
         {
             if (folded->queryValue()->getBoolValue())
-                reportWarning(WRN_COND_ALWAYS_TRUE, errpos.pos, "Condition is always true");
+                reportWarning(CategoryFolding, WRN_COND_ALWAYS_TRUE, errpos.pos, "Condition is always true");
             else
-                reportWarning(WRN_COND_ALWAYS_FALSE, errpos.pos, "Condition is always false");
+                reportWarning(CategoryFolding, WRN_COND_ALWAYS_FALSE, errpos.pos, "Condition is always false");
         }
     }
 }
@@ -4964,7 +4948,7 @@ void HqlGram::warnIfRecordPacked(IHqlExpression * expr, const attribute & errpos
 {
     IHqlExpression * record = expr->queryRecord();
     if (record && record->hasAttribute(packedAtom))
-        reportWarning(WRN_PACKED_MAY_CHANGE, errpos.pos, "Packed record used for external input or output, packed formats may change");
+        reportWarning(CategoryFuture, WRN_PACKED_MAY_CHANGE, errpos.pos, "Packed record used for external input or output, packed formats may change");
 }
 
 
@@ -5169,7 +5153,7 @@ void HqlGram::checkCaseForDuplicates(HqlExprArray & exprs, attribute &err)
             StringBuffer s;
             s.append("Duplicate case entry: ");
             toECL(e1, s, false);
-            reportWarning(WRN_DUPLICATECASE, err.pos, "%s", s.str());
+            reportWarning(CategoryIgnored, WRN_DUPLICATECASE, err.pos, "%s", s.str());
         }
         else
             e1->setTransformExtraUnlinked(e1);
@@ -5221,7 +5205,7 @@ void HqlGram::checkReal(attribute &a1)
         Owned<ITypeInfo> realType = makeRealType(DEFAULT_REAL_SIZE);
         if (t1->getTypeCode() == type_decimal)
         {
-            reportWarning(ERR_TYPEMISMATCH_REAL, a1.pos, "Decimal implicitly converted to a real");
+            reportWarning(CategoryCast, ERR_TYPEMISMATCH_REAL, a1.pos, "Decimal implicitly converted to a real");
         }
         else
         {
@@ -5262,7 +5246,7 @@ void HqlGram::checkPositive(attribute &a1)
         //MORE: Recode to allow decimal and other types
         Owned<IValue> zero = value->queryType()->castFrom(0, (const char *)NULL);
         if (value->compare(zero) < 0)
-            reportError(ERR_TYPEMISMATCH_INT, a1, "Type mismatch - the value must be positive");
+            reportWarning(CategoryIndex, SeverityError, ERR_TYPEMISMATCH_INT, a1.pos, "Type mismatch - the value must be positive");
     }   
 }
 
@@ -5687,12 +5671,12 @@ IHqlExpression * HqlGram::processSortList(const attribute & errpos, node_operato
         else if (eop == no_constant)
         {
             if ((op != no_hash) && (op != no_hash32) && (op != no_hash64) && (op != no_crc) && (op != no_hashmd5) && (op != no_list))
-                reportWarning(ERR_CONSTANT_DAFT, errpos.pos, "Constant group/sort clauses make no sense");
+                reportWarning(CategoryUnusual, ERR_CONSTANT_DAFT, errpos.pos, "Constant group/sort clauses make no sense");
         }
         else if (!containsAnyDataset(&e))
         {
             if ((op != no_hash) && (op != no_hash32) && (op != no_hash64) && (op != no_crc) && (op != no_hashmd5) && (op != no_list))
-                reportWarning(WRN_SORT_INVARIANT, errpos.pos, "Sort/Group element is not related to the dataset");
+                reportWarning(CategoryUnusual, WRN_SORT_INVARIANT, errpos.pos, "Sort/Group element is not related to the dataset");
         }
         else if (e.isDatarow() && expandRows)
         {
@@ -5801,13 +5785,13 @@ void HqlGram::reportErrorUnexpectedX(const attribute& errpos, IAtom * unexpected
     reportError(ERR_UNEXPECTED_ATTRX, errpos, "Unexpected attribute %s", unexpected->str());
 }
 
-void HqlGram::doReportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
+void HqlGram::doReportWarning(WarnErrorCategory category, int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
 {
-    Owned<IECLError> error = createECLError(SeverityWarning, warnNo, msg, filename, lineno, column, pos);
+    Owned<IECLError> error = createECLError(category, queryDefaultSeverity(category), warnNo, msg, filename, lineno, column, pos);
     report(error);
 }
 
-void HqlGram::reportMacroExpansionPosition(int errNo, HqlLex * lexer, bool isError)
+void HqlGram::reportMacroExpansionPosition(IECLError * warning, HqlLex * lexer)
 {
     if (expandingMacroPosition)
         return;
@@ -5815,21 +5799,22 @@ void HqlGram::reportMacroExpansionPosition(int errNo, HqlLex * lexer, bool isErr
     if (!macro)
         return;
 
-    reportMacroExpansionPosition(errNo, macro, isError);
+    reportMacroExpansionPosition(warning, macro);
     StringBuffer s;
     s.appendf("While expanding macro %s", macro->getMacroName());
 
     expandingMacroPosition = true;
-    if (isError)
-        errorHandler->reportError(errNo, s.str(), lexer->querySourcePath()->str(), lexer->get_yyLineNo(), lexer->get_yyColumn(), 0);
+    unsigned code = warning->errorCode();
+    if (warning->getSeverity() == SeverityFatal)
+        errorHandler->reportError(code, s.str(), lexer->querySourcePath()->str(), lexer->get_yyLineNo(), lexer->get_yyColumn(), 0);
     else
-        doReportWarning(errNo, s.str(), lexer->querySourcePath()->str(), lexer->get_yyLineNo(), lexer->get_yyColumn(), 0);
+        doReportWarning(warning->getCategory(), code, s.str(), lexer->querySourcePath()->str(), lexer->get_yyLineNo(), lexer->get_yyColumn(), 0);
     expandingMacroPosition = false;
 }
 
 void HqlGram::reportErrorVa(int errNo, const ECLlocation & pos, const char* format, va_list args)
 {
-    Owned<IECLError> error = createErrorVA(SeverityFatal, errNo, pos, format, args);
+    Owned<IECLError> error = createErrorVA(CategoryError, SeverityFatal, errNo, pos, format, args);
     report(error);
 }
 
@@ -5842,47 +5827,47 @@ void HqlGram::reportError(int errNo, const char *msg, int lineno, int column, in
     }
 }
 
-void HqlGram::reportWarning(int warnNo, const ECLlocation & pos, const char* format, ...)
+void HqlGram::reportWarning(WarnErrorCategory category, int warnNo, const ECLlocation & pos, const char* format, ...)
 {
     if (errorHandler && !errorDisabled)
     {
         va_list args;
         va_start(args, format);
-        Owned<IECLError> error = createErrorVA(SeverityWarning, warnNo, pos, format, args);
+        Owned<IECLError> error = createErrorVA(category, queryDefaultSeverity(category), warnNo, pos, format, args);
         va_end(args);
 
         report(error);
     }
 }
 
-void HqlGram::reportWarning(ErrorSeverity severity, int warnNo, const ECLlocation & pos, const char* format, ...)
+void HqlGram::reportWarning(WarnErrorCategory category, ErrorSeverity severity, int warnNo, const ECLlocation & pos, const char* format, ...)
 {
     if (errorHandler && !errorDisabled)
     {
         StringBuffer msg;
         va_list args;
         va_start(args, format);
-        Owned<IECLError> error = createErrorVA(severity, warnNo, pos, format, args);
+        Owned<IECLError> error = createErrorVA(category, severity, warnNo, pos, format, args);
         va_end(args);
 
         report(error);
     }
 }
 
-void HqlGram::reportWarningVa(int warnNo, const attribute& a, const char* format, va_list args)
+void HqlGram::reportWarningVa(WarnErrorCategory category, int warnNo, const attribute& a, const char* format, va_list args)
 {
     const ECLlocation & pos = a.pos;
     if (errorHandler && !errorDisabled)
     {
-        Owned<IECLError> error = createErrorVA(SeverityWarning, warnNo, pos, format, args);
+        Owned<IECLError> error = createErrorVA(category, queryDefaultSeverity(category), warnNo, pos, format, args);
         report(error);
     }
 }
 
-void HqlGram::reportWarning(int warnNo, const char *msg, int lineno, int column)
+void HqlGram::reportWarning(WarnErrorCategory category, int warnNo, const char *msg, int lineno, int column)
 {
     if (errorHandler && !errorDisabled)
-        doReportWarning(warnNo, msg, querySourcePathText(), lineno, column, 0);
+        doReportWarning(category, warnNo, msg, querySourcePathText(), lineno, column, 0);
 }
 
 
@@ -5923,14 +5908,14 @@ void HqlGram::report(IECLError* error)
             }
         }
 
-        reportMacroExpansionPosition(error->errorCode(), lexObject, isFatalError);
+        reportMacroExpansionPosition(error, lexObject);
     }
 }
 
-void HqlGram::reportWarning(int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
+void HqlGram::reportWarning(WarnErrorCategory category, int warnNo, const char *msg, const char *filename, int lineno, int column, int pos)
 {
     if (errorHandler && !errorDisabled)
-        doReportWarning(warnNo, msg, filename, lineno, column, pos);
+        doReportWarning(category, warnNo, msg, filename, lineno, column, pos);
 }
 
 size32_t HqlGram::errCount()
@@ -6878,7 +6863,7 @@ void HqlGram::checkOutputRecord(attribute & errpos, bool outerLevel)
     bool allConstant = true;
     errpos.setExpr(checkOutputRecord(record, errpos, allConstant, outerLevel));
     if (allConstant && (record->getOperator() != no_null) && (record->numChildren() != 0))
-        reportWarning(WRN_OUTPUT_ALL_CONSTANT,errpos.pos,"All values for OUTPUT are constant - is this the intention?");
+        reportWarning(CategoryUnusual, WRN_OUTPUT_ALL_CONSTANT,errpos.pos,"All values for OUTPUT are constant - is this the intention?");
 }
 
 void HqlGram::checkSoapRecord(attribute & errpos)
@@ -7455,7 +7440,7 @@ void HqlGram::checkGrouping(const attribute& errpos, HqlExprArray & parms, IHqlE
                         if (id)
                             msg.append("'").append(id->str()).append("' ");
                         msg.append("in TABLE does not appear to be properly defined by grouping conditions");
-                        reportWarning(ERR_GROUP_BADSELECT,errpos.pos, "%s", msg.str());
+                        reportWarning(CategoryUnexpected, ERR_GROUP_BADSELECT,errpos.pos, "%s", msg.str());
                     }
                 }
                 else if (field->isDatarow())
@@ -7675,7 +7660,7 @@ void HqlGram::checkDistribution(attribute &errpos, IHqlExpression *input, bool l
             if (!inputIsGrouped || ignoreGrouping)
             {
                 const char * name = getName(input);
-                reportWarning(WRN_LOCALONEXPLICITDIST,errpos.pos,"Input %s is explicitly DISTRIBUTEd but LOCAL not specified", name);
+                reportWarning(CategoryEfficiency, WRN_LOCALONEXPLICITDIST,errpos.pos,"Input %s is explicitly DISTRIBUTEd but LOCAL not specified", name);
             }
         }
     }
@@ -7748,7 +7733,7 @@ void HqlGram::checkJoinFlags(const attribute &err, IHqlExpression * join)
     {
         //The following should be, and will become, an error.  However too many legacy queries have it, so make a warning for now.
         if (isAll)
-            reportWarning(ERR_KEYEDINDEXINVALID, err.pos, "ALL is not compatible with LOOKUP");
+            reportWarning(CategorySyntax, ERR_KEYEDINDEXINVALID, err.pos, "ALL is not compatible with LOOKUP");
         if (isSmart)
             reportError(ERR_KEYEDINDEXINVALID, err.pos, "SMART is not compatible with LOOKUP");
     }
@@ -7769,7 +7754,7 @@ void HqlGram::checkJoinFlags(const attribute &err, IHqlExpression * join)
                 IHqlExpression * indexDataset = index->queryChild(0)->queryNormalizedSelector();
 
                 if (indexDataset != rhs->queryNormalizedSelector())
-                    reportWarning(ERR_KEYEDNOTMATCHDATASET,err.pos,"Parameter to KEYED is not an index on the RIGHT dataset");
+                    reportWarning(CategoryUnusual, ERR_KEYEDNOTMATCHDATASET,err.pos,"Parameter to KEYED is not an index on the RIGHT dataset");
                 else if (!isFilteredDiskFile(rhs))
                     reportError(ERR_KEYEDNOTMATCHDATASET,err,"RIGHT side of a full keyed join must be a disk file");
                 else
@@ -7818,7 +7803,7 @@ void HqlGram::checkJoinFlags(const attribute &err, IHqlExpression * join)
         if (rowLimit && !isMany)
             reportError(ERR_BADKIND_LOOKUPJOIN, err, "%s joins do not support LIMIT (they can only match 1 entry)", joinText);
         if (isKey(join->queryChild(1)))
-            reportWarning(ERR_BADKIND_LOOKUPJOIN, err.pos, "%s specified on an unfiltered keyed join - was this intended?", joinText);
+            reportWarning(CategoryEfficiency, ERR_BADKIND_LOOKUPJOIN, err.pos, "%s specified on an unfiltered keyed join - was this intended?", joinText);
     }
     else if (isKeyedJoin(join))
     {
@@ -7866,7 +7851,7 @@ void HqlGram::checkJoinFlags(const attribute &err, IHqlExpression * join)
         while (cur->getOperator() == no_filter)
             cur = cur->queryChild(0);
         if (isKey(cur))
-            reportWarning(ERR_BAD_JOINFLAG, err.pos, "Filtered RIGHT prevents a keyed join being used.  Consider including the filter in the join condition.");
+            reportWarning(CategoryEfficiency, ERR_BAD_JOINFLAG, err.pos, "Filtered RIGHT prevents a keyed join being used.  Consider including the filter in the join condition.");
     }
 
     IHqlExpression * group = join->queryAttribute(groupAtom);
@@ -7909,9 +7894,9 @@ void HqlGram::checkLoopFlags(const attribute &err, IHqlExpression * loopExpr)
     {
         unsigned base = (loopExpr->getOperator() == no_loop ? 1 : 2);
         if (!queryRealChild(loopExpr, base))
-            reportWarning(WRN_BAD_LOOPFLAG, err.pos, "PARALLEL is currently only supported with a defined number of iterations");
+            reportWarning(CategorySyntax, WRN_BAD_LOOPFLAG, err.pos, "PARALLEL is currently only supported with a defined number of iterations");
         if (queryRealChild(loopExpr, base+2))
-            reportWarning(WRN_BAD_LOOPFLAG, err.pos, "PARALLEL is not supported with dataset loop termination condition");
+            reportWarning(CategorySyntax, WRN_BAD_LOOPFLAG, err.pos, "PARALLEL is not supported with dataset loop termination condition");
     }
 }
 
@@ -8478,7 +8463,7 @@ void HqlGram::ensureMapToRecordsMatch(OwnedHqlExpr & defaultExpr, HqlExprArray &
         if (value != checked)
         {
             args.replace(*replaceChild(&mapTo, 1, checked), i);
-            reportWarning(ERR_TYPE_INCOMPATIBLE, errpos.pos, "Datasets in list have slightly different records");
+            reportWarning(CategoryCast, ERR_TYPE_INCOMPATIBLE, errpos.pos, "Datasets in list have slightly different records");
         }
     }
 
@@ -8490,7 +8475,7 @@ void HqlGram::ensureMapToRecordsMatch(OwnedHqlExpr & defaultExpr, HqlExprArray &
         if (defaultExpr != checked)
         {
             defaultExpr.set(checked);
-            reportWarning(ERR_TYPE_INCOMPATIBLE, errpos.pos, "Default value has a slightly different record");
+            reportWarning(CategoryCast, ERR_TYPE_INCOMPATIBLE, errpos.pos, "Default value has a slightly different record");
         }
     }
 
@@ -8592,7 +8577,7 @@ void HqlGram::checkMergeInputSorted(attribute &atr, bool isLocal)
         return;
     if (!isLocal && appearsToBeSorted(expr, true, true))
     {
-        reportWarning(WRN_MERGE_NOT_SORTED, atr.pos, "INPUT to MERGE appears to be sorted locally but not globally");
+        reportWarning(CategoryUnexpected, WRN_MERGE_NOT_SORTED, atr.pos, "INPUT to MERGE appears to be sorted locally but not globally");
         return;
     }
         
@@ -8610,9 +8595,9 @@ void HqlGram::checkMergeInputSorted(attribute &atr, bool isLocal)
     }
     
     if (isGrouped(expr) && appearsToBeSorted(expr, false, false))
-        reportWarning(WRN_MERGE_NOT_SORTED, atr.pos, "Input to MERGE is only sorted with the group");
+        reportWarning(CategoryUnexpected, WRN_MERGE_NOT_SORTED, atr.pos, "Input to MERGE is only sorted with the group");
     else
-        reportWarning(WRN_MERGE_NOT_SORTED, atr.pos, "Input to MERGE doesn't appear to be sorted");
+        reportWarning(CategoryUnexpected, WRN_MERGE_NOT_SORTED, atr.pos, "Input to MERGE doesn't appear to be sorted");
 }
 
 
@@ -8651,7 +8636,7 @@ void HqlGram::checkNotAlreadyDefined(IIdAtom * name, IHqlScope * scope, const at
     if (expr)
     {
         if (legacyImportSemantics && isImport(expr))
-            reportWarning(ERR_ID_REDEFINE, idattr.pos, "Identifier '%s' hides previous import", name->str());
+            reportWarning(CategoryConfuse, ERR_ID_REDEFINE, idattr.pos, "Identifier '%s' hides previous import", name->str());
         else
             reportError(ERR_ID_REDEFINE, idattr, "Identifier '%s' is already defined", name->str());
     }
@@ -8716,7 +8701,7 @@ IHqlExpression * HqlGram::addSideEffects(IHqlExpression * expr)
             }
 
             ECLlocation location(next);
-            reportWarning(ERR_RESULT_IGNORED, location, "Expression ignored");
+            reportWarning(CategoryIgnored, ERR_RESULT_IGNORED, location, "Expression ignored");
         }
         else
             compound = createCompound(next.getClear(), compound);
@@ -8954,7 +8939,7 @@ IHqlExpression * HqlGram::associateSideEffects(IHqlExpression * expr, const ECLl
             {
                 if (expr->isScope())
                 {
-                    Owned<IECLError> error = createError(SeverityError, ERR_RESULT_IGNORED_SCOPE, errpos, "Cannot associate a side effect with a module - action will be lost");
+                    Owned<IECLError> error = createECLError(CategorySyntax, SeverityError, ERR_RESULT_IGNORED_SCOPE, "Cannot associate a side effect with a module - action will be lost", errpos.sourcePath->str(), errpos.lineno, errpos.column, errpos.position);
                     //Unusual processing.  Create a warning and save it in the parse context
                     //The reason is that this error is reporting "the associated side-effects will be lost" - but
                     //the same will apply to the warning, and if it's lost there will be no way to report it later...
@@ -8991,7 +8976,7 @@ void HqlGram::doDefineSymbol(DefineIdSt * defineid, IHqlExpression * _expr, IHql
 
         //Ignore SHARED and EXPORT flags 
         if (defineid->scope & (EXPORT_FLAG | SHARED_FLAG))
-            reportWarning(WRN_EXPORT_IGNORED, idattr.pos, "EXPORT/SHARED qualifiers are ignored in this context");
+            reportWarning(CategorySyntax, WRN_EXPORT_IGNORED, idattr.pos, "EXPORT/SHARED qualifiers are ignored in this context");
 
         defineid->scope = 0;
         defineSymbolInScope(activeScope.privateScope, defineid, expr.getClear(), failure, idattr, assignPos, semiColonPos, isParametered, activeScope.activeParameters, activeScope.createDefaults());
@@ -9012,7 +8997,7 @@ void HqlGram::doDefineSymbol(DefineIdSt * defineid, IHqlExpression * _expr, IHql
                 {
                     //Make this warning come out now - otherwise a subsequent error about an undefined symbol makes less sense.
                     RestoreValueBlock<bool> block(associateWarnings, false);
-                    reportWarning(ERR_UNEXPECTED_PUBLIC_ID, idattr.pos, "Name of exported symbol '%s' does not match the expected name '%s'", name->str(), expectedAttribute->str());
+                    reportWarning(CategorySyntax, ERR_UNEXPECTED_PUBLIC_ID, idattr.pos, "Name of exported symbol '%s' does not match the expected name '%s'", name->str(), expectedAttribute->str());
                 }
                 defineid->scope = 0;
             }
@@ -9448,7 +9433,7 @@ IHqlExpression * HqlGram::extractBranchMatch(const attribute & errpos, IHqlExpre
         // The following test is no good though, we need to check if reused only in this branch.
 //      if (curSym.isShared())
 //          return NULL;
-        reportWarning(WRN_COND_ASSIGN_NO_PREV, errpos.pos, "Conditional assignment to %s isn't defined in all branches, and has no previous definition", id->str());
+        reportWarning(CategoryMistake, WRN_COND_ASSIGN_NO_PREV, errpos.pos, "Conditional assignment to %s isn't defined in all branches, and has no previous definition", id->str());
         return NULL;
     }
 
@@ -9713,7 +9698,7 @@ IHqlExpression * HqlGram::createLibraryInstance(const attribute & errpos, IHqlEx
     }
 
     if (body->hasAttribute(libraryAtom))
-        reportWarning(WRN_NOT_INTERFACE, errpos.pos, "LIBRARY() seems to reference an implementation rather than the interface definition");
+        reportWarning(CategorySyntax, WRN_NOT_INTERFACE, errpos.pos, "LIBRARY() seems to reference an implementation rather than the interface definition");
     IHqlExpression * internalAttr = queryAttributeInList(internalAtom,name);
     if (internalAttr)
     {
@@ -9923,7 +9908,7 @@ void HqlGram::canNotAssignTypeWarn(ITypeInfo* expected, ITypeInfo* given, const
     StringBuffer msg("Incompatible types: should cast ");
     getFriendlyTypeStr(given, msg).append(" to a ");
     getFriendlyTypeStr(expected, msg);
-    reportWarning(ERR_TYPE_INCOMPATIBLE, errpos.pos, "%s", msg.str());
+    reportWarning(CategoryCast, ERR_TYPE_INCOMPATIBLE, errpos.pos, "%s", msg.str());
 }
 
 IIdAtom * HqlGram::getNameFromExpr(attribute& attr)
@@ -10198,7 +10183,7 @@ void HqlGram::defineImport(const attribute & errpos, IHqlExpression * imported,
         if (previous->queryBody() == imported->queryBody())
             return;
 
-        reportWarning(ERR_ID_REDEFINE, errpos.pos, "import hides previously defined identifier");
+        reportWarning(CategoryConfuse, ERR_ID_REDEFINE, errpos.pos, "import hides previously defined identifier");
     }
 
     parseScope->defineSymbol(newName, NULL, LINK(imported), false, false, ob_import, NULL, errpos.pos.lineno, errpos.pos.column, errpos.pos.position, 0, errpos.pos.position);

+ 6 - 6
ecl/hql/hqllex.l

@@ -99,7 +99,7 @@ int HqlLex::lookupIdentifierToken(YYSTYPE & returnToken, HqlLex * lexer, bool lo
         StringBuffer alternativeText;
         if (alternative && alternative->queryValue())
             alternative->queryValue()->getStringValue(alternativeText);
-        lexer->reportWarning(returnToken, ERR_DEPRECATED_ATTR, "Definition %s is marked as deprecated.  %s", name->str(), alternativeText.str());
+        lexer->reportWarning(CategoryDeprecated, returnToken, ERR_DEPRECATED_ATTR, "Definition %s is marked as deprecated.  %s", name->str(), alternativeText.str());
     }                   
     
 #if defined(TRACE_MACRO)
@@ -1592,7 +1592,7 @@ FUNCTIONMACRO|MACRO {
                         }
                         if (after > MAX_DECIMAL_PRECISION)
                         {
-                            lexer->reportWarning(returnToken, ERR_ILLSIZE_DECIMAL, "Decimal constant may lose significant digits (>%d)", MAX_DECIMAL_PRECISION);
+                            lexer->reportWarning(CategoryCast, returnToken, ERR_ILLSIZE_DECIMAL, "Decimal constant may lose significant digits (>%d)", MAX_DECIMAL_PRECISION);
                             after = MAX_DECIMAL_PRECISION;
                         }
                         Owned<ITypeInfo> type = makeDecimalType(before+after, after, true);
@@ -1750,7 +1750,7 @@ FUNCTIONMACRO|MACRO {
                                     *bf++ = value;
                                     if(!(isValidAsciiLikeCharacter(value) || (tc == type_data)))
                                     {
-                                        lexer->reportWarning(returnToken, ERR_STRING_NON_ASCII, "Character in string literal is not defined in encoding " ASCII_LIKE_CODEPAGE);
+                                        lexer->reportWarning(CategoryCast, returnToken, ERR_STRING_NON_ASCII, "Character in string literal is not defined in encoding " ASCII_LIKE_CODEPAGE);
                                         if (lexer->isAborting())
                                             return EOF;
                                     }
@@ -1800,7 +1800,7 @@ FUNCTIONMACRO|MACRO {
                                 {
                                     finger += extraCharsRead;
                                     if (*bf == ASCII_LIKE_SUBS_CHAR)
-                                        lexer->reportWarning(returnToken, ERR_STRING_NON_ASCII, "Character in string literal is not defined in encoding " ASCII_LIKE_CODEPAGE ", try using a unicode constant");
+                                        lexer->reportWarning(CategoryCast, returnToken, ERR_STRING_NON_ASCII, "Character in string literal is not defined in encoding " ASCII_LIKE_CODEPAGE ", try using a unicode constant");
                                 }
                                 bf++;
                             }
@@ -1875,7 +1875,7 @@ FUNCTIONMACRO|MACRO {
 [xX]\'{err_hexpairs}\'  { 
                         /* error pattern: odd hex data */
                         setupdatepos;
-                        lexer->reportWarning(returnToken, ERR_HEXDATA_ODDDIGITS,"hex data must have even number of hex digits");
+                        lexer->reportWarning(CategorySyntax, returnToken, ERR_HEXDATA_ODDDIGITS,"hex data must have even number of hex digits");
                         char* str = (char*)malloc(CUR_TOKEN_LENGTH-1);
                         str[0] = '0'; // add a leading zero
                         strncpy(str+1,(char*)CUR_TOKEN_TEXT+2,CUR_TOKEN_LENGTH-3);
@@ -1920,7 +1920,7 @@ FUNCTIONMACRO|MACRO {
 \357\273\277        {
                         setupdatepos;
                         if (lexer->yyPosition != 3)
-                            lexer->reportWarning(returnToken, ERR_STRING_ILLDELIMITER, "Misplaced BOM - should be at the start of the file");
+                            lexer->reportWarning(CategorySyntax, returnToken, ERR_STRING_ILLDELIMITER, "Misplaced BOM - should be at the start of the file");
                     }
 
 "("                 {

+ 5 - 4
ecl/hql/hqlparse.cpp

@@ -125,7 +125,8 @@ void CTemplateContext::reportWarning(int warnNo,const char* format,...)
         va_start(args, format);
         StringBuffer msg;
         msg.valist_appendf(format,args);
-        m_lookupContext.errs->reportWarning(warnNo,msg.str(),NULL,m_startLine,m_startCol,0);
+        WarnErrorCategory category = CategoryUnusual; // a reasonable default
+        m_lookupContext.errs->reportWarning(category, warnNo,msg.str(),NULL,m_startLine,m_startCol,0);
         va_end(args);
     }
 }
@@ -989,7 +990,7 @@ void HqlLex::doError(YYSTYPE & returnToken, bool isError)
     if (isError)
         reportError(returnToken, ERR_HASHERROR, "#ERROR: %s", buf.str());
     else
-        reportWarning(returnToken, WRN_HASHWARNING, "#WARNING: %s", buf.str());
+        reportWarning(CategoryUnusual, returnToken, WRN_HASHWARNING, "#WARNING: %s", buf.str());
 }
 
 void HqlLex::doExport(YYSTYPE & returnToken, bool toXml)
@@ -1967,13 +1968,13 @@ void HqlLex::reportError(const YYSTYPE & returnToken, int errNo, const char *for
     }
 }
 
-void HqlLex::reportWarning(const YYSTYPE & returnToken, int warnNo, const char *format, ...)
+void HqlLex::reportWarning(WarnErrorCategory category, const YYSTYPE & returnToken, int warnNo, const char *format, ...)
 {
     if (yyParser)
     {
         va_list args;
         va_start(args, format);
-        yyParser->reportWarningVa(warnNo, returnToken, format, args);
+        yyParser->reportWarningVa(category, warnNo, returnToken, format, args);
         va_end(args);
     }
 }

+ 4 - 55
ecl/hql/hqlutil.cpp

@@ -5503,7 +5503,7 @@ protected:
     void createTempTableAssign(HqlExprArray & assigns, IHqlExpression * self, IHqlExpression * curRow, IHqlExpression * expr, unsigned & col, IHqlExpression * selector, HqlMapTransformer & mapper, bool included);
     IHqlExpression * createTempTableTransform(IHqlExpression * self, IHqlExpression * curRow, IHqlExpression * expr, unsigned & col, IHqlExpression * selector, HqlMapTransformer & mapper, bool included);
 
-    void reportWarning(IHqlExpression * location, int code,const char *format, ...) __attribute__((format(printf, 4, 5)));
+    void reportWarning(WarnErrorCategory category, IHqlExpression * location, int code,const char *format, ...) __attribute__((format(printf, 5, 6)));
     void reportError(IHqlExpression * location, int code,const char *format, ...) __attribute__((format(printf, 4, 5)));
 
 protected:
@@ -5728,7 +5728,7 @@ void TempTableTransformer::createTempTableAssign(HqlExprArray & assigns, IHqlExp
             if (included)
             {
                 if (!mappedValue)
-                    reportWarning(NULL, HQLWRN_CouldNotConstantFoldIf, HQLWRN_CouldNotConstantFoldIf_Text);
+                    reportWarning(CategoryUnexpected, NULL, HQLWRN_CouldNotConstantFoldIf, HQLWRN_CouldNotConstantFoldIf_Text);
                 else if (!mappedValue->getBoolValue())
                     included = false;
             }
@@ -5768,7 +5768,7 @@ void TempTableTransformer::reportError(IHqlExpression * location, int code,const
     errorProcessor.report(err);
 }
 
-void TempTableTransformer::reportWarning(IHqlExpression * location, int code,const char *format, ...)
+void TempTableTransformer::reportWarning(WarnErrorCategory category, IHqlExpression * location, int code,const char *format, ...)
 {
     ECLlocation * where = &defaultLocation;
     ECLlocation thisLocation;
@@ -5783,7 +5783,7 @@ void TempTableTransformer::reportWarning(IHqlExpression * location, int code,con
     va_start(args, format);
     errorMsg.valist_appendf(format, args);
     va_end(args);
-    errorProcessor.reportWarning(code, errorMsg.str(), where->sourcePath->str(), where->lineno, where->column, where->position);
+    errorProcessor.reportWarning(category, code, errorMsg.str(), where->sourcePath->str(), where->lineno, where->column, where->position);
 }
 
 IHqlExpression *getDictionaryKeyRecord(IHqlExpression *record)
@@ -6463,57 +6463,6 @@ void gatherGraphReferences(HqlExprCopyArray & graphs, IHqlExpression * value, bo
 
 //---------------------------------------------------------------------------
 
-ErrorSeverity getSeverity(IAtom * name)
-{
-    if (name == failAtom)
-        return SeverityFatal;
-    if (name == errorAtom)
-        return SeverityError;
-    if (name == warningAtom)
-        return SeverityWarning;
-    if (name == ignoreAtom)
-        return SeverityIgnore;
-    if (name == logAtom)
-        return SeverityInfo;
-    return SeverityUnknown;
-}
-
-WarnErrorCategory getCategory(const char * category)
-{
-    if (strieq(category, "all"))
-        return CategoryAll;
-    if (strieq(category, "cast"))
-        return CategoryCast;
-    if (strieq(category, "confuse"))
-        return CategoryConfuse;
-    if (strieq(category, "deprecated"))
-        return CategoryDeprecated;
-    if (strieq(category, "efficiency"))
-        return CategoryEfficiency;
-    if (strieq(category, "future"))
-        return CategoryFuture;
-    if (strieq(category, "ignored"))
-        return CategoryIgnored;
-    if (strieq(category, "index"))
-        return CategoryIndex;
-    if (strieq(category, "mistype"))
-        return CategoryMistyped;
-    if (strieq(category, "syntax"))
-        return CategorySyntax;
-    if (strieq(category, "unusual"))
-        return CategoryUnusual;
-    if (strieq(category, "unexpected"))
-        return CategoryUnexpected;
-    return CategoryUnknown;
-}
-
-static ErrorSeverity getCheckSeverity(IAtom * name)
-{
-    ErrorSeverity severity = getSeverity(name);
-    assertex(severity != SeverityUnknown);
-    return severity;
-}
-
 static ErrorSeverity getWarningAction(unsigned errorCode, const HqlExprArray & overrides, unsigned first, ErrorSeverity defaultSeverity)
 {
     //warnings are assumed to be infrequent, so don't worry about efficiency here.

+ 2 - 1
ecl/hql/hqlxmldb.hpp

@@ -20,6 +20,7 @@
 #include "jiface.hpp"
 #include "jiter.hpp"
 #include "hql.hpp"
+#include "hqlerror.hpp"
 
 //-----------------------------------------------------------------------------
 // Class Definitions
@@ -58,7 +59,7 @@ interface ITemplateContext : public IInterface
     virtual StringBuffer& demangle(const char* mangled, StringBuffer& demangled) = 0;
 
     virtual void reportError(int errNo,const char* format,...) __attribute__((format(printf, 3, 4))) = 0;
-    virtual void reportWarning(int warnNo,const char* format,...) __attribute__((format(printf, 3, 4))) = 0;      
+    virtual void reportWarning(int warnNo,const char* format,...) __attribute__((format(printf, 3, 4))) = 0;
 
     // Ideally, the user has no need to use this.
     virtual IEclRepository* queryDataServer() = 0;

+ 4 - 4
ecl/hqlcpp/hqlcerrors.hpp

@@ -581,9 +581,9 @@
 #define HQLERR_UnknownCompoundAssign_Text       "INTERNAL: Unrecognised compound assign %s"
 #define HQLERR_ReadSpillBeforeWriteFix_Text     "INTERNAL: Attempt to read spill file %s before it is written.  Try adding #option ('allowThroughSpill', false); to the query."
 
-#define WARNINGAT(e, x)                 reportWarning(e, x, x##_Text)
-#define WARNINGAT1(e, x, a)             reportWarning(e, x, x##_Text, a)
-#define WARNINGAT2(e, x, a, b)          reportWarning(e, x, x##_Text, a, b)
-#define WARNINGAT3(e, x, a, b, c)       reportWarning(e, x, x##_Text, a, b, c)
+#define WARNINGAT(cat, e, x)                 reportWarning(cat, e, x, x##_Text)
+#define WARNINGAT1(cat, e, x, a)             reportWarning(cat, e, x, x##_Text, a)
+#define WARNINGAT2(cat, e, x, a, b)          reportWarning(cat, e, x, x##_Text, a, b)
+#define WARNINGAT3(cat, e, x, a, b, c)       reportWarning(cat, e, x, x##_Text, a, b, c)
 
 #endif

+ 8 - 7
ecl/hqlcpp/hqlcpp.cpp

@@ -2035,37 +2035,38 @@ bool HqlCppTranslator::getDebugFlag(const char * name, bool defValue)
     return wu()->getDebugValueBool(name, defValue);
 }
 
-void HqlCppTranslator::doReportWarning(IHqlExpression * location, unsigned id, const char * msg)
+void HqlCppTranslator::doReportWarning(WarnErrorCategory category, IHqlExpression * location, unsigned id, const char * msg)
 {
     Owned<IECLError> warnError;
     if (!location)
         location = queryActiveActivityLocation();
+    ErrorSeverity severity = queryDefaultSeverity(category);
     if (location)
-        warnError.setown(createECLError(SeverityWarning, id, msg, location->querySourcePath()->str(), location->getStartLine(), location->getStartColumn(), 0));
+        warnError.setown(createECLError(category, severity, id, msg, location->querySourcePath()->str(), location->getStartLine(), location->getStartColumn(), 0));
     else
-        warnError.setown(createECLError(SeverityWarning, id, msg, NULL, 0, 0, 0));
+        warnError.setown(createECLError(category, severity, id, msg, NULL, 0, 0, 0));
 
     errorProcessor->report(warnError);
 }
 
-void HqlCppTranslator::reportWarning(IHqlExpression * location, unsigned id, const char * msg, ...)
+void HqlCppTranslator::reportWarning(WarnErrorCategory category, IHqlExpression * location, unsigned id, const char * msg, ...)
 {
     StringBuffer s;
     va_list args;
     va_start(args, msg);
     s.valist_appendf(msg, args);
     va_end(args);
-    doReportWarning(location, id, s.str());
+    doReportWarning(category, location, id, s.str());
 }
 
-void HqlCppTranslator::reportWarning(unsigned id, const char * msg, ...)
+void HqlCppTranslator::reportWarning(WarnErrorCategory category, unsigned id, const char * msg, ...)
 {
     StringBuffer s;
     va_list args;
     va_start(args, msg);
     s.valist_appendf(msg, args);
     va_end(args);
-    doReportWarning(NULL, id, s.str());
+    doReportWarning(category, NULL, id, s.str());
 }
 
 void HqlCppTranslator::addWorkunitException(WUExceptionSeverity severity, unsigned code, const char * text, IHqlExpression * location)

+ 4 - 4
ecl/hqlcpp/hqlcpp.ipp

@@ -915,9 +915,9 @@ public:
     bool registerGlobalUsage(IHqlExpression * filename);
     IHqlExpression * queryActiveNamedActivity();
     IHqlExpression * queryActiveActivityLocation() const;
-    void reportWarning(unsigned id, const char * msg, ...) __attribute__((format(printf, 3, 4)));
-    void reportWarning(IHqlExpression * location, unsigned id, const char * msg, ...) __attribute__((format(printf, 4, 5)));
-    void reportError(IHqlExpression * location, int code,const char *format, ...) __attribute__((format(printf, 4, 5)));
+    void reportWarning(WarnErrorCategory category, unsigned id, const char * msg, ...) __attribute__((format(printf, 4, 5)));
+    void reportWarning(WarnErrorCategory category, IHqlExpression * location, unsigned id, const char * msg, ...) __attribute__((format(printf, 5, 6)));
+    void reportError(IHqlExpression * location, int code, const char *format, ...) __attribute__((format(printf, 4, 5)));
     void reportErrorDirect(IHqlExpression * location, int code,const char *msg, bool alwaysAbort);
     void addWorkunitException(WUExceptionSeverity severity, unsigned code, const char * msg, IHqlExpression * location);
     void useFunction(IHqlExpression * funcdef);
@@ -1821,7 +1821,7 @@ protected:
 
 //ThorHole helper functions...
     IHqlExpression * doBuildDatabaseLoader(BuildCtx & ctx, IHqlExpression * expr);
-    void doReportWarning(IHqlExpression * location, unsigned id, const char * msg);
+    void doReportWarning(WarnErrorCategory category, IHqlExpression * location, unsigned id, const char * msg);
 
     void optimizePersists(HqlExprArray & exprs);
     void allocateSequenceNumbers(HqlExprArray & exprs);

+ 1 - 1
ecl/hqlcpp/hqlcppcase.cpp

@@ -397,7 +397,7 @@ IHqlExpression * HqlCppCaseInfo::buildIndexedMap(BuildCtx & ctx, IHqlExpression
         if (mapTo->getOperator() != no_constant)
             throwUnexpected();
         if (replaceIndex >= num)
-            translator.reportWarning(HQLWRN_CaseCanNeverMatch, "CASE entry %d can never match the test condition", replaceIndex);
+            translator.reportWarning(CategoryIgnored, HQLWRN_CaseCanNeverMatch, "CASE entry %d can never match the test condition", replaceIndex);
         else
             values.replace(*LINK(mapTo),replaceIndex);
     }

+ 3 - 3
ecl/hqlcpp/hqlcppds.cpp

@@ -2734,9 +2734,9 @@ void HqlCppTranslator::doBuildCheckDatasetLimit(BuildCtx & ctx, IHqlExpression *
                 failMessage->queryValue()->getStringValue(failMessageText);
         }
         if (failMessageText.length())
-            WARNING1(HQLWRN_LimitAlwaysExceededX, failMessageText.str());
+            WARNING1(CategoryUnexpected, HQLWRN_LimitAlwaysExceededX, failMessageText.str());
         else
-            WARNING(HQLWRN_LimitAlwaysExceeded);
+            WARNING(CategoryUnexpected, HQLWRN_LimitAlwaysExceeded);
     }
 
     if (!fail)
@@ -5325,7 +5325,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityForceLocal(BuildCtx & ctx, IHq
     IHqlExpression * child = expr->queryChild(0);
     if (targetHThor() || (targetThor() && !insideChildQuery(ctx)))
     {
-        WARNING(HQLWRN_LocalHasNoEffect);
+        WARNING(CategoryIgnored, HQLWRN_LocalHasNoEffect);
         return buildCachedActivity(ctx, child);
     }
 

+ 6 - 6
ecl/hqlcpp/hqlhtcpp.cpp

@@ -2286,7 +2286,7 @@ void ActivityInstance::buildSuffix()
         if (options.spotComplexClasses && (approxSize >= options.complexClassesThreshold))
         {
             if ((options.complexClassesActivityFilter == 0) || (kind == options.complexClassesActivityFilter))
-                translator.WARNING2(HQLWRN_ComplexHelperClass, activityId, approxSize);
+                translator.WARNING2(CategoryEfficiency, HQLWRN_ComplexHelperClass, activityId, approxSize);
         }
         if (options.showActivitySizeInGraph)
             addAttributeInt("approxClassSize", approxSize);
@@ -11686,7 +11686,7 @@ void HqlCppTranslator::doBuildJoinRowLimitHelper(ActivityInstance & instance, IH
             StringBuffer fname;
             if (filename)
                 getExprECL(filename, fname.append(" "));
-            WARNING2(HQLWRN_ImplicitJoinLimit, options.defaultImplicitKeyedJoinLimit, fname.str());
+            WARNING2(CategoryLimit, HQLWRN_ImplicitJoinLimit, options.defaultImplicitKeyedJoinLimit, fname.str());
         }
     }
 }
@@ -11784,7 +11784,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityJoinOrDenormalize(BuildCtx & c
         dataset2.set(dataset2->queryChild(0));
 
     if (expr->hasAttribute(groupedAtom) && targetThor())
-        WARNING(HQLWRN_GroupedJoinIsLookupJoin);
+        WARNING(CategoryEfficiency, HQLWRN_GroupedJoinIsLookupJoin);
 
     //Hash and smart joins are not valid inside child queries - convert to a normal join.
     //The flags should already have been stripped if targetting hthor/roxie
@@ -11874,7 +11874,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityJoinOrDenormalize(BuildCtx & c
             //Possibly if KEEP(1) was added, no limits, no skipping in transform etc.
             if (isLookupJoin && !isManyLookup)
                 isAllJoin = false;
-            WARNING(HQLWRN_JoinConditionFoldedNowAll);
+            WARNING(CategoryUnusual, HQLWRN_JoinConditionFoldedNowAll);
         }
         else
         {
@@ -14078,7 +14078,7 @@ void HqlCppTranslator::checkAmbiguousRollupCondition(IHqlExpression * expr)
         OwnedHqlExpr newSelect = replaceSelector(select, dataset->queryNormalizedSelector(), queryActiveTableSelector());
         StringBuffer selectText;
         getExprECL(newSelect, selectText);
-        reportWarning(queryLocation(expr), ECODETEXT(HQLWRN_AmbiguousRollupCondition), selectText.str());
+        reportWarning(CategoryUnexpected, queryLocation(expr), ECODETEXT(HQLWRN_AmbiguousRollupCondition), selectText.str());
     }
 }
 
@@ -15389,7 +15389,7 @@ void HqlCppTranslator::buildLimitHelpers(BuildCtx & ctx, IHqlExpression * rowLim
     doBuildUnsigned64Function(ctx, "getRowLimit", rowLimit);
 
     if (isZero(rowLimit))
-        WARNING(HQLWRN_LimitIsZero);
+        WARNING(CategoryUnusual, HQLWRN_LimitIsZero);
 
     if (!isSkip)
     {

+ 2 - 2
ecl/hqlcpp/hqlnlp.cpp

@@ -634,7 +634,7 @@ void HqlCppTranslator::doBuildParseValidators(BuildCtx & classctx, IHqlExpressio
 void HqlCppTranslator::doBuildParseCompiled(BuildCtx & classctx, MemoryBuffer & buffer)
 {
     if (buffer.length() > 1000000)
-        WARNING1(HQLWRN_ParseVeryLargeDefinition, buffer.length());
+        WARNING1(CategoryEfficiency, HQLWRN_ParseVeryLargeDefinition, buffer.length());
 
     BuildCtx funcctx(classctx);
 
@@ -723,7 +723,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivityParse(BuildCtx & ctx, IHqlExpr
     nlpParse->compileSearchPattern();
     nlpParse->queryParser()->serialize(buffer);
     if (nlpParse->isGrammarAmbiguous())
-        WARNING1(HQLWRN_GrammarIsAmbiguous, instance->activityId);
+        WARNING1(CategoryEfficiency, HQLWRN_GrammarIsAmbiguous, instance->activityId);
 
     doBuildParseCompiled(instance->classctx, buffer);
     updateTimer("workunit;Generate PARSE: Compile", msTick()-startCompileTime);

+ 6 - 6
ecl/hqlcpp/hqlsource.cpp

@@ -2016,7 +2016,7 @@ void SourceBuilder::buildKeyedLimitHelper(IHqlExpression * self)
         func1ctx.addQuotedCompound("virtual unsigned __int64 getKeyedLimit()");
         translator.buildReturn(func1ctx, limitValue);
         if (isZero(limitValue))
-            translator.WARNING(HQLWRN_KeyedLimitIsZero);
+            translator.WARNING(CategoryUnusual, HQLWRN_KeyedLimitIsZero);
 
         LinkedHqlExpr fail = keyedLimitExpr->queryChild(2);
         if (!fail || fail->isAttribute())
@@ -4637,7 +4637,7 @@ void MonitorExtractor::buildKeySegment(BuildMonitorState & buildState, BuildCtx
                         translator.throwError3(HQLERR_KeyedFollowsGap, getExprECL(field, s).str(), buildState.implicitWildField->queryChild(1)->queryName()->str(), queryKeyName(keyname));
                     else if (!buildState.doneImplicitWarning)
                     {
-                        translator.WARNING3(HQLWRN_KeyedFollowsGap, getExprECL(field, s).str(), buildState.implicitWildField->queryChild(1)->queryName()->str(), queryKeyName(keyname));
+                        translator.WARNING3(CategoryEfficiency, HQLWRN_KeyedFollowsGap, getExprECL(field, s).str(), buildState.implicitWildField->queryChild(1)->queryName()->str(), queryKeyName(keyname));
                         buildState.doneImplicitWarning = true;
                     }
                 }
@@ -4647,7 +4647,7 @@ void MonitorExtractor::buildKeySegment(BuildMonitorState & buildState, BuildCtx
     if (buildState.wildWasKeyed && (matches.ordinality() == 0))
     {
         StringBuffer keyname;
-        translator.WARNING2(HQLWRN_FoldRemoveKeyed, field->queryName()->str(), queryKeyName(keyname));
+        translator.WARNING2(CategoryFolding, HQLWRN_FoldRemoveKeyed, field->queryName()->str(), queryKeyName(keyname));
     }
 
     StringBuffer s;
@@ -4664,7 +4664,7 @@ void MonitorExtractor::buildKeySegment(BuildMonitorState & buildState, BuildCtx
             else
             {
                 StringBuffer keyname;
-                translator.WARNING2(HQLERR_OptKeyedFollowsWild, getExprECL(field, s).str(), queryKeyName(keyname));
+                translator.WARNING2(CategoryEfficiency, HQLERR_OptKeyedFollowsWild, getExprECL(field, s).str(), queryKeyName(keyname));
             }
         }
         //previous condition folded so always true, so keyed,opt will always be a wildcard.
@@ -6201,9 +6201,9 @@ void IndexReadBuilderBase::buildMembers(IHqlExpression * expr)
         {
             StringBuffer keyname;
             if (implicitLimit)
-                translator.WARNINGAT2(queryLocation(expr), HQLWRN_ImplicitReadAddLimit, implicitLimit, monitors.queryKeyName(keyname));
+                translator.WARNINGAT2(CategoryLimit, queryLocation(expr), HQLWRN_ImplicitReadAddLimit, implicitLimit, monitors.queryKeyName(keyname));
             else
-                translator.WARNINGAT1(queryLocation(expr), HQLWRN_ImplicitReadLimit, monitors.queryKeyName(keyname));
+                translator.WARNINGAT1(CategoryLimit, queryLocation(expr), HQLWRN_ImplicitReadLimit, monitors.queryKeyName(keyname));
         }
 
         if (implicitLimit)

+ 31 - 27
ecl/hqlcpp/hqlttcpp.cpp

@@ -296,7 +296,7 @@ void NewThorStoredReplacer::doAnalyseBody(IHqlExpression * expr)
             StringBuffer nameText,valueText;
             name->getStringValue(nameText);
             if (isOptionTooLate(nameText.str()))
-                translator.reportWarning(HQLWRN_OptionSetToLate, HQLWRN_OptionSetToLate_Text, nameText.str());
+                translator.reportWarning(CategoryIgnored, HQLWRN_OptionSetToLate, HQLWRN_OptionSetToLate_Text, nameText.str());
 
             if (value->queryType()->getTypeCode() == type_boolean)
                 valueText.append(value->getBoolValue() ? 1 : 0);
@@ -1371,7 +1371,7 @@ IHqlExpression * SequenceNumberAllocator::createTransformed(IHqlExpression * exp
     case no_outputscalar:
         if (applyDepth)
         {
-            translator.WARNINGAT(expr, HQLERR_ScalarOutputWithinApply);
+            translator.WARNINGAT(CategoryUnexpected, expr, HQLERR_ScalarOutputWithinApply);
         }
         break;
     }
@@ -2226,7 +2226,7 @@ IHqlExpression * ThorHqlTransformer::normalizeRollup(IHqlExpression * expr)
 
             if (equalities.ordinality() == 0)
             {
-                translator.reportWarning(queryLocation(expr), ECODETEXT(HQLWRN_AmbiguousRollupNoGroup));
+                translator.reportWarning(CategoryEfficiency, queryLocation(expr), ECODETEXT(HQLWRN_AmbiguousRollupNoGroup));
             }
             else
             {
@@ -5653,7 +5653,7 @@ IHqlExpression * WorkflowTransformer::extractWorkflow(IHqlExpression * untransfo
                         throwError1(HQLERR_DuplicateDefinitionDiffType, s.str());
                 }
                 else if (translator.queryOptions().allowStoredDuplicate)            // only here as a temporary workaround
-                    translator.reportWarning(queryActiveLocation(expr), HQLERR_DuplicateDefinition, HQLERR_DuplicateDefinition_Text, s.str());
+                    translator.reportWarning(CategoryMistake, queryActiveLocation(expr), HQLERR_DuplicateDefinition, HQLERR_DuplicateDefinition_Text, s.str());
                 else
                 {
                     if (queryLocationIndependent(prevValue) != queryLocationIndependent(value))
@@ -6590,7 +6590,7 @@ void WorkflowTransformer::analyseExpr(IHqlExpression * expr)
                 if (expr->queryName())
                     s.appendf(" '%s'", expr->queryName()->str());
                 //MORE: Better if we also kept nested track of locations
-                translator.WARNINGAT1(queryActiveLocation(expr), HQLWRN_WorkflowSeemsToBeDependent, s.str());
+                translator.WARNINGAT1(CategoryMistake, queryActiveLocation(expr), HQLWRN_WorkflowSeemsToBeDependent, s.str());
             }
 
             unsigned prevWfid = activeWfid;
@@ -7384,9 +7384,9 @@ IHqlExpression * ExplicitGlobalTransformer::createTransformed(IHqlExpression * e
                             s.append(" in ").append(symbol->queryName());
                     }
                     if (op == no_nothor)
-                        translator.reportWarning(queryActiveLocation(expr), ECODETEXT(HQLWRN_NoThorContextDependent), s.str());
+                        translator.reportWarning(CategoryMistake, queryActiveLocation(expr), ECODETEXT(HQLWRN_NoThorContextDependent), s.str());
                     else
-                        translator.reportWarning(queryActiveLocation(expr), ECODETEXT(HQLWRN_GlobalDoesntSeemToBe), s.str());
+                        translator.reportWarning(CategoryMistake, queryActiveLocation(expr), ECODETEXT(HQLWRN_GlobalDoesntSeemToBe), s.str());
                 }
                 if (value->getOperator() == no_createset)
                 {
@@ -7503,7 +7503,7 @@ protected:
                 StringBuffer s;
                 if (filename)
                     getExprECL(filename, s);
-                translator.WARNINGAT1(queryActiveLocation(expr), HQLWRN_OutputDependendOnScope, s.str());
+                translator.WARNINGAT1(CategoryMistake, queryActiveLocation(expr), HQLWRN_OutputDependendOnScope, s.str());
 
     #if 0
                 checkIndependentOfScope(expr);
@@ -7513,7 +7513,10 @@ protected:
         default:
             if (!isIndependentOfScope(expr))
             {
-                translator.WARNINGAT(queryActiveLocation(expr), HQLWRN_GlobalActionDependendOnScope);
+                //There appears to be partial support for functions generated as workflow items - which are not
+                //scope independent since they depend on their paramaters => don't complain about them
+                if (expr->getOperator() != no_return_stmt)
+                    translator.WARNINGAT(CategoryMistake, queryActiveLocation(expr), HQLWRN_GlobalActionDependendOnScope);
 
     #if 0
                 checkIndependentOfScope(expr);
@@ -9060,7 +9063,7 @@ void HqlScopeTagger::checkActiveRow(IHqlExpression * expr)
         getECL(expr, exprText);
         elideString(exprText, 20);
         VStringBuffer msg("ROW(%s) - dataset argument is not in scope.  Did you mean dataset[1]?", exprText.str());
-        reportError(msg, SeverityFatal);
+        reportError(CategoryError, msg);
     }
 }
 
@@ -9091,7 +9094,7 @@ void HqlScopeTagger::reportSelectorError(IHqlExpression * selector, IHqlExpressi
             getExprIdentifier(datasetName, selector).str());
     }
 
-    reportError(msg, SeverityFatal);
+    reportError(CategoryError, msg);
 }
 
 
@@ -9109,7 +9112,7 @@ IHqlExpression * HqlScopeTagger::transformSelect(IHqlExpression * expr)
             case no_right:
                 StringBuffer exprText, datasetName;
                 VStringBuffer msg("%s - %s not in scope, possibly passed into a global/workflow definition", getECL(expr, exprText), getExprIdentifier(datasetName, ds).str());
-                reportError(msg, SeverityFatal);
+                reportError(CategoryError, msg);
                 break;
             }
         }
@@ -9123,7 +9126,7 @@ IHqlExpression * HqlScopeTagger::transformSelect(IHqlExpression * expr)
         {
             StringBuffer exprText;
             VStringBuffer msg("dictionary %s must be explicitly NORMALIZED", getECL(expr, exprText));
-            reportError(msg, SeverityFatal);
+            reportError(CategoryError, msg);
         }
         else if (expr->isDataset())
         {
@@ -9131,7 +9134,7 @@ IHqlExpression * HqlScopeTagger::transformSelect(IHqlExpression * expr)
             {
                 StringBuffer exprText;
                 VStringBuffer msg("dataset %s may not be supported without using NORMALIZE", getECL(expr, exprText));
-                reportError(msg, SeverityWarning);
+                reportError(CategoryUnexpected, msg);
             }
         }
         else
@@ -9208,7 +9211,7 @@ IHqlExpression * HqlScopeTagger::transformNewDataset(IHqlExpression * expr, bool
             {
                 StringBuffer exprText;
                 VStringBuffer msg("%s - Need to use active(dataset) to refer to the current row of an active dataset", getECL(expr, exprText));
-                reportError(msg, SeverityFatal);
+                reportError(CategoryError, msg);
             }
         }
         return transformed.getClear();
@@ -9220,7 +9223,7 @@ IHqlExpression * HqlScopeTagger::transformNewDataset(IHqlExpression * expr, bool
         {
             StringBuffer exprText;
             VStringBuffer msg("%s - Need to use active(dataset) to refer to the current row of an active dataset", getECL(expr, exprText));
-            reportError(msg, SeverityFatal);
+            reportError(CategoryError, msg);
         }
 
         return ensureActiveRow(transformed->queryNormalizedSelector());
@@ -9328,7 +9331,7 @@ IHqlExpression * HqlScopeTagger::transformWithin(IHqlExpression * dataset, IHqlE
     {
         StringBuffer exprText;
         VStringBuffer msg("%s - dataset filtered by WITHIN is too complex", getECL(dataset, exprText));
-        reportError(msg, SeverityFatal);
+        reportError(CategoryError, msg);
         return transform(dataset);
     }
 
@@ -9352,7 +9355,7 @@ IHqlExpression * HqlScopeTagger::transformRelated(IHqlExpression * expr)
     {
         StringBuffer exprText;
         VStringBuffer msg("dataset \"%s\" used in WITHIN is not in scope", getECL(scope, exprText));
-        reportError(msg, SeverityFatal);
+        reportError(CategoryError, msg);
     }
 
     //Check the ds is a table
@@ -9361,7 +9364,7 @@ IHqlExpression * HqlScopeTagger::transformRelated(IHqlExpression * expr)
     {
         StringBuffer exprText;
         VStringBuffer msg("dataset \"%s\" used as parameter to WITHIN is too complex", getECL(expr, exprText));
-        reportError(msg, SeverityFatal);
+        reportError(CategoryError, msg);
     }
 
     return transformWithin(ds, scope->queryNormalizedSelector());
@@ -9437,7 +9440,7 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
             {
                 StringBuffer exprText;
                 VStringBuffer msg("dataset %s mistakenly interpreted as a datarow, possibly due to missing dataset() in parameter type", getECL(ds, exprText));
-                reportError(msg, SeverityFatal);
+                reportError(CategoryError, msg);
             }
             return transformAmbiguousChildren(expr);
         }
@@ -9465,7 +9468,7 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
             {
                 StringBuffer exprText;
                 VStringBuffer msg("dataset expression (%s) assigned to field '%s' with type row", getECL(rhs, exprText), lhs->queryChild(1)->queryName()->str());
-                reportError(msg.str(), SeverityFatal);
+                reportError(CategoryError, msg.str());
             }
             if (rhs == newRhs)
                 return LINK(expr);
@@ -9481,7 +9484,7 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
         {
             OwnedHqlExpr transformed = Parent::createTransformed(expr);
             if (transformed->queryChild(0)->isDataset())
-                reportError("PROJECT() row argument resolved to a dataset.  Missing DATASET() from parameter type?", SeverityFatal);
+                reportError(CategoryError, "PROJECT() row argument resolved to a dataset.  Missing DATASET() from parameter type?");
             return transformed.getClear();
         }
     case no_merge:
@@ -9505,7 +9508,7 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
                 {
                     if (sorts.item(i).isAttribute())
                     {
-                        reportError(HQLWRN_MergeBadSortOrder_Text, SeverityWarning);
+                        reportError(CategorySyntax, HQLWRN_MergeBadSortOrder_Text);
                         sorts.remove(i);
                     }
                 }
@@ -9519,14 +9522,15 @@ IHqlExpression * HqlScopeTagger::createTransformed(IHqlExpression * expr)
 }
 
 
-void HqlScopeTagger::reportError(const char * msg, ErrorSeverity severity)
+void HqlScopeTagger::reportError(WarnErrorCategory category, const char * msg)
 {
     IHqlExpression * location = errorMapper.queryActiveSymbol();
     //Make this an error when we are confident...
     int startLine= location ? location->getStartLine() : 0;
     int startColumn = location ? location->getStartColumn() : 0;
     ISourcePath * sourcePath = location ? location->querySourcePath() : NULL;
-    Owned<IECLError> err = createECLError(severity, ERR_ASSERT_WRONGSCOPING, msg, sourcePath->str(), startLine, startColumn, 0);
+    ErrorSeverity severity = queryDefaultSeverity(category);
+    Owned<IECLError> err = createECLError(category, severity, ERR_ASSERT_WRONGSCOPING, msg, sourcePath->str(), startLine, startColumn, 0);
     errors.report(err);        // will throw immediately if it is an error.
 }
 
@@ -10324,10 +10328,10 @@ IHqlExpression * NestedCompoundTransformer::createTransformed(IHqlExpression * e
                     location = queryActiveLocation();
                 if (!isSimpleSideeffect(sideEffect))
                 {
-                    //MORE: This should be an error, but there are still occasional false positives e.g., OUTPUT(ds1.childds)
+                    //MORE: This should possibly be an error, but there are still false positives e.g., OUTPUT(ds1.childds)
                     //so needs to stay a warning.
 //                  translator.ERRORAT1(location, HQLERR_GlobalSideEffectDependent, s.str());
-                    translator.WARNINGAT1(location, HQLWRN_GlobalSideEffectDependent, s.str());
+                    translator.WARNINGAT1(CategoryUnexpected, location, HQLWRN_GlobalSideEffectDependent, s.str());
                 }
                 break;
             }

+ 1 - 1
ecl/hqlcpp/hqlttcpp.ipp

@@ -1045,7 +1045,7 @@ protected:
     IHqlExpression * transformWithin(IHqlExpression * dataset, IHqlExpression * scope);
 
     bool isValidNormalizeSelector(IHqlExpression * expr);
-    void reportError(const char * msg, ErrorSeverity severity);
+    void reportError(WarnErrorCategory category, const char * msg);
     void reportSelectorError(IHqlExpression * selector, IHqlExpression * expr);
 
 protected:

+ 20 - 0
ecl/regress/existscheck.ecl

@@ -0,0 +1,20 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+#onwarning ('mistake', warning);
+
+output(exists(true));

+ 30 - 0
ecl/regress/largefield.ecl

@@ -0,0 +1,30 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+#onwarning ('efficiency', ignore);
+
+namesRecord :=
+            RECORD
+string2000000000  surname;
+string10        forename;
+integer2        age := 25;
+            END;
+
+namesTable := dataset('x',namesRecord,FLAT);
+
+
+output(nofold(namesTable)(surname[1] in ['0','1','3']),,'out.d00',overwrite);

+ 1 - 1
ecl/regress/library10.eclxml

@@ -14,7 +14,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<Archive useArchivePlugins="1">
+<Archive useArchivePlugins="1" legacyImport="1">
  <Module name="example">
   <Attribute name="namesRecord">
 

+ 1 - 0
ecl/regress/serial7a_error.ecl

@@ -19,6 +19,7 @@
 //Unfortunately it gets optimized away by EXISTS(x) always being true.  Check a warning is output.
 
 #option ('pickBestEngine', false);
+#onwarning (1051, warning);
 
 IMPORT SerialTest;