Repository: trafodion Updated Branches: refs/heads/master 44db81913 -> e6e3e3c1d
[TRAFODION-3158] Make EncodedValue error handling more robust Project: http://git-wip-us.apache.org/repos/asf/trafodion/repo Commit: http://git-wip-us.apache.org/repos/asf/trafodion/commit/64e5ed11 Tree: http://git-wip-us.apache.org/repos/asf/trafodion/tree/64e5ed11 Diff: http://git-wip-us.apache.org/repos/asf/trafodion/diff/64e5ed11 Branch: refs/heads/master Commit: 64e5ed11a2d1deae8d748d7d749abb5007ae0c41 Parents: b09048a Author: Dave Birdsall <dbirds...@apache.org> Authored: Mon Jul 23 17:24:57 2018 +0000 Committer: Dave Birdsall <dbirds...@apache.org> Committed: Mon Jul 23 17:24:57 2018 +0000 ---------------------------------------------------------------------- core/sql/optimizer/EncodedValue.cpp | 85 +++++++++++++++++++++++++++++--- core/sql/optimizer/EncodedValue.h | 11 +++-- 2 files changed, 85 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafodion/blob/64e5ed11/core/sql/optimizer/EncodedValue.cpp ---------------------------------------------------------------------- diff --git a/core/sql/optimizer/EncodedValue.cpp b/core/sql/optimizer/EncodedValue.cpp index f05297a..f8c6b7b 100644 --- a/core/sql/optimizer/EncodedValue.cpp +++ b/core/sql/optimizer/EncodedValue.cpp @@ -648,8 +648,62 @@ EncodedValue::EncodedValue (ItemExpr *expr, void EncodedValue::constructorFunction (const NAWchar * theValue, const NAColumnArray &columns, + NABoolean okToReportErrors, ConstValue* cvPtrs[]) { + // Some notes about error reporting for this function: + // + // The error reporting for this function is a little strange + // and should be re-engineered when we can imagine a better + // design for it. + // + // This function is called from two very different contexts. + // + // One is from the constructors of global objects, to provide + // convenient encoded constants. Being global objects, this + // call is made as a result of global constructor calls before + // the C++ main for the process is invoked. As such, we cannot + // depend on other global objects being constructed. So, for + // example, we cannot depend on CmpCommon::diags() being + // initialized, as C++ makes no guarantees about the order in + // which global objects are created. Too, it does no good to + // throw a C++ exception as there would be nothing to catch it + // and process it. So, if an error happens in this code path, + // we'll simply assert. + // + // The other is in the course of histogram processing. Histograms + // have been read in, and now we want to encode the boundary + // values in the histogram. These might be stale or corrupted + // so that condition has to be detected. When detected, this + // routine raises a warning in CmpCommon::diags(), and then + // throws a C++ exception. + // + // This warning processing has to be done carefully. The way + // it works is that lower level routines report errors into + // CmpCommon::diags(). This routine checks for such errors and + // if it sees any, it throws them away, replacing them with + // a warning in CmpCommon::diags(). It then throws a C++ + // exception which is typically caught by HSHistogrmCursor::fetch + // (ustat/hs_read.cpp). We use default histograms in that case. + // + // Why do we throw away the errors? We do this because of the + // way the Normalizer handles CmpCommon::diags(). During + // synthesise logical properties processing, histograms may + // be read and processed. (Note: They can be read and processed + // from other phases as well, such as table analysis.) The + // Normalizer checks for errors in CmpCommon::diags(), and if + // found, retries compilation. On the retry, CmpCommon::diags() + // will be cleared, and the histograms code will simply use + // a default histogram. So, if there is any error in + // CmpCommon::diags(), we will lose the histogram warnings + // generated in this method. + // + // Note that if there is already an error in CmpCommon::diags() + // when this method is called, we'll lose the histogram warnings + // anyway. Sigh. + + Lng32 mark = okToReportErrors ? CmpCommon::diags()->mark() : -1; + // Find the first non-blank char. const NAWchar *item = theValue; while (*item == L' ') @@ -657,10 +711,17 @@ EncodedValue::constructorFunction (const NAWchar * theValue, if ( *item != L'(' ) // must be '(' { - *CmpCommon::diags() << DgSqlCode(CATALOG_HISTOGRM_HISTINTS_TABLES_CONTAIN_BAD_VALUE) + if (okToReportErrors) + { + *CmpCommon::diags() << DgSqlCode(CATALOG_HISTOGRM_HISTINTS_TABLES_CONTAIN_BAD_VALUE) << DgWString0(theValue) << DgString1(columns[0]->getFullColRefNameAsAnsiString()); - CmpInternalException("Bad Interval Boundary", __FILE__ , __LINE__).throwException(); + CmpInternalException("Bad Interval Boundary", __FILE__ , __LINE__).throwException(); + } + else + { + CMPASSERT(FALSE); // developer needs to fix the bug + } } item++; @@ -766,11 +827,19 @@ EncodedValue::constructorFunction (const NAWchar * theValue, if ( next == NULL ) // should never happen! { - *CmpCommon::diags() + if (okToReportErrors) + { + CmpCommon::diags()->rewind(mark,TRUE); // get rid of any diags we may have added + *CmpCommon::diags() << DgSqlCode(CATALOG_HISTOGRM_HISTINTS_TABLES_CONTAIN_BAD_VALUE) << DgWString0(theValue) << DgString1(columns[i]->getFullColRefNameAsAnsiString()); - CmpInternalException("Bad Interval Boundary", __FILE__ , __LINE__).throwException(); + CmpInternalException("Bad Interval Boundary", __FILE__ , __LINE__).throwException(); + } + else + { + CMPASSERT(FALSE); // developer needs to fix the bug + } } Lng32 len = BOUNDARY_LEN; @@ -803,6 +872,10 @@ EncodedValue::constructorFunction (const NAWchar * theValue, break; } + // Parser assumes CmpCommon::diags() is initialized and available + // so okToReportErrors better be true in this code path. + CMPASSERT(okToReportErrors); + // invoke parser to parse the char string and generate a ConstValue Parser parser(CmpCommon::context()); @@ -863,9 +936,7 @@ EncodedValue::constructorFunction (const NAWchar * theValue, (entries == 1 && constVal->getType()->getTypeQualifier() != colType->getTypeQualifier())) { - if (CmpCommon::diags()->getNumber(DgSqlCode::ERROR_)) - CmpCommon::diags()->deleteError(0); - + CmpCommon::diags()->rewind(mark,TRUE); // get rid of any diags parser may have added *CmpCommon::diags() << DgSqlCode(CATALOG_HISTOGRM_HISTINTS_TABLES_CONTAIN_BAD_VALUE) << DgWString0(theValue) http://git-wip-us.apache.org/repos/asf/trafodion/blob/64e5ed11/core/sql/optimizer/EncodedValue.h ---------------------------------------------------------------------- diff --git a/core/sql/optimizer/EncodedValue.h b/core/sql/optimizer/EncodedValue.h index 961adeb..4bc5e84 100644 --- a/core/sql/optimizer/EncodedValue.h +++ b/core/sql/optimizer/EncodedValue.h @@ -165,24 +165,27 @@ public: // construct a multi-attribute value given a string representation // of the multi-attribute value, and a description of the columns + + // Note: This constructor is used to construct global objects, so + // it cannot report errors. EncodedValue (const NAWchar *theValue) : valueList_(NULL), heap_(HISTHEAP) { const NAColumnArray empty ((CollHeap*) 0 /* NULL CollHeap* */) ; - constructorFunction (theValue, empty) ; + constructorFunction (theValue, empty, FALSE) ; } EncodedValue (const wchar_t *theValue, const NAColumnArray &columns, ConstValue* cvPtrs[] = NULL) : valueList_(NULL), heap_(HISTHEAP) - { constructorFunction (theValue, columns, cvPtrs) ; } + { constructorFunction (theValue, columns, TRUE, cvPtrs) ; } EncodedValue (const NAWchar *theValue, const NAColumn * column) : valueList_(NULL), heap_(HISTHEAP) { NAColumnArray columns ; columns.insertAt (0,(NAColumn*)(column)) ; - constructorFunction (theValue, columns) ; + constructorFunction (theValue, columns, TRUE) ; } EncodedValue (const EncodedValue & other, NAMemory * h = 0); @@ -192,7 +195,7 @@ private: // thing, I've created a non-ctor function that both of them // call. Sooner or later we can stop using the ctor that takes // a NAColumnArray as its parameter ... - void constructorFunction (const wchar_t * theValue, const NAColumnArray & columns, ConstValue** cvPtr = NULL) ; + void constructorFunction (const wchar_t * theValue, const NAColumnArray & columns, NABoolean okToReportErrors, ConstValue** cvPtr = NULL) ; public: // construct a single-attribute value from a constant or list of constants