You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafodion.apache.org by hz...@apache.org on 2016/05/10 21:58:00 UTC

[2/4] incubator-trafodion git commit: TRAFODION-1710 setString() method and numerics with scale

TRAFODION-1710 setString() method and numerics with scale

The setString() method did not accept strings with digits after
the decimal point, like setString(1, "123.45").


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafodion/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafodion/commit/a4caa9ac
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafodion/tree/a4caa9ac
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafodion/diff/a4caa9ac

Branch: refs/heads/master
Commit: a4caa9ac4afe331358a74b211784a08779ca298e
Parents: a2786b5
Author: Hans Zeller <hz...@apache.org>
Authored: Tue May 10 01:49:18 2016 +0000
Committer: Hans Zeller <hz...@apache.org>
Committed: Tue May 10 01:49:18 2016 +0000

----------------------------------------------------------------------
 core/sql/sqludr/sqludr.cpp                      | 107 +++++++++++++++++--
 .../java/org/trafodion/sql/udr/TupleInfo.java   |  86 +++++++++++++--
 .../java/org/trafodion/sql/udr/TypeInfo.java    |   6 ++
 3 files changed, 181 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/a4caa9ac/core/sql/sqludr/sqludr.cpp
----------------------------------------------------------------------
diff --git a/core/sql/sqludr/sqludr.cpp b/core/sql/sqludr/sqludr.cpp
index f1741b9..3ea6ad6 100644
--- a/core/sql/sqludr/sqludr.cpp
+++ b/core/sql/sqludr/sqludr.cpp
@@ -696,6 +696,10 @@ TypeInfo::TypeInfo(SQLTypeCode sqlType,
       // length is the length in characters, but d_.length_ is
       // the byte length, multiply by min bytes per char
       d_.length_ = length * minBytesPerChar();
+      if (d_.length_ < 0)
+        throw UDRException(38900,
+                           "Length of a character type must not be negative, got %d",
+                           d_.length_);
       if (d_.collation_ == UNDEFINED_COLLATION)
         throw UDRException(38900,"Collation must be specified for CHAR type in TypeInfo::TypeInfo");
       break;
@@ -711,6 +715,10 @@ TypeInfo::TypeInfo(SQLTypeCode sqlType,
       if (d_.length_ > 32767)
         // see also CharType::CharType in ../common/CharType.cpp
         d_.flags_ |= TYPE_FLAG_4_BYTE_VC_LEN;
+      if (d_.length_ < 0)
+        throw UDRException(38900,
+                           "Length of a varchar type must not be negative, got %d",
+                           d_.length_);
       break;
 
     case CLOB:
@@ -2012,13 +2020,16 @@ void TypeInfo::setString(const char *val, int stringLen, char *row) const
     case DECIMAL_UNSIGNED:
       {
         char buf[200];
-        long lval;
-        double dval;
+        long lval = 0;
+        double dval = 0.0;
         int numCharsConsumed = 0;
         int rc = 0;
+        int vScale = 0;
+        bool sawMinusDot = false;
 
         // ignore trailing blanks
-        while (val[stringLen-1] == ' ')
+        while (val[stringLen-1] == ' ' ||
+               val[stringLen-1] == '\t')
           stringLen--;
 
         if (stringLen+1 > sizeof(buf))
@@ -2032,15 +2043,89 @@ void TypeInfo::setString(const char *val, int stringLen, char *row) const
         buf[stringLen] = 0;
 
         if (isApproxNumeric)
-          rc = sscanf(buf,"%lf%n", &dval, &numCharsConsumed) < 0;
+          rc = sscanf(buf,"%lf%n", &dval, &numCharsConsumed);
         else
-          rc = sscanf(buf,"%ld%n", &lval, &numCharsConsumed) < 0;
+          rc = sscanf(buf,"%ld%n", &lval, &numCharsConsumed);
 
-        if (rc < 0)
-          throw UDRException(
-               38900,
-               "Error in setString(), \"%s\" is not a numeric value",
-               buf);
+        if (rc <= 0)
+          {
+            bool isOK = false;
+
+            // could not read a long or float value, this could be an error
+            // or a number that starts with '.' or '-.' with optional
+            // leading white space. Check for this special case before
+            // raising an exception.
+            if (!isApproxNumeric && d_.scale_ > 0 && numCharsConsumed == 0)
+              {
+                while (buf[numCharsConsumed] == ' ' ||
+                       buf[numCharsConsumed] == '\t')
+                  numCharsConsumed++;
+                if (buf[numCharsConsumed] == '-' &&
+                    buf[numCharsConsumed+1] == '.')
+                  {
+                    // the number starts with "-.", remember
+                    // to negate it at the end and go on
+                    sawMinusDot = true;
+                    numCharsConsumed++; // skip over the '-'
+                    isOK = true;
+                  }
+                else if (buf[numCharsConsumed] == '.')
+                  {
+                    // the number starts with '.', that's
+                    // ok, continue on
+                    isOK = true;
+                  }
+              }
+
+            if (!isOK)
+              throw UDRException(
+                   38900,
+                   "Error in setString(), \"%s\" is not a numeric value",
+                   buf);
+          }
+
+        if (d_.scale_ > 0 && !isApproxNumeric)
+          {
+            if (buf[numCharsConsumed] == '.')
+              {
+                int sign = (lval < 0 ? -1 : 1);
+
+                // skip over the decimal dot
+                numCharsConsumed++;
+
+                // process digits following the dot
+                while (numCharsConsumed < stringLen &&
+                       buf[numCharsConsumed] >= '0' &&
+                       buf[numCharsConsumed] <= '9' &&
+                       lval <= LONG_MAX/10)
+                  {
+                    lval = 10*lval +
+                      ((int)(buf[numCharsConsumed++] - '0')) * sign;
+                    vScale++;
+                  }
+              }
+
+            if (sawMinusDot)
+              lval = -lval;
+
+            while (vScale < d_.scale_)
+              if (lval <= LONG_MAX/10)
+                {
+                  lval *= 10;
+                  vScale++;
+                }
+              else
+                throw UDRException(
+                     38900,
+                     "Error in setString(): Value %s exceeds range for a long",
+                     buf);
+
+            if (vScale > d_.scale_)
+              throw UDRException(
+                     38900,
+                     "Error in setString(): Value %s exceeds scale %d",
+                     buf, d_.scale_);
+          }
 
         // check for any non-white space left after conversion
         while (numCharsConsumed < stringLen)
@@ -2048,7 +2133,7 @@ void TypeInfo::setString(const char *val, int stringLen, char *row) const
               buf[numCharsConsumed] != '\t')
             throw UDRException(
                  38900,
-                 "Found non-numeric character in setString for a numeric column: %s",
+                 "Error in setString(): \"%s\" is not a valid, in-range numeric value",
                  buf);
           else
             numCharsConsumed++;

http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/a4caa9ac/core/sql/src/main/java/org/trafodion/sql/udr/TupleInfo.java
----------------------------------------------------------------------
diff --git a/core/sql/src/main/java/org/trafodion/sql/udr/TupleInfo.java b/core/sql/src/main/java/org/trafodion/sql/udr/TupleInfo.java
index e118f44..65dac20 100644
--- a/core/sql/src/main/java/org/trafodion/sql/udr/TupleInfo.java
+++ b/core/sql/src/main/java/org/trafodion/sql/udr/TupleInfo.java
@@ -1326,13 +1326,85 @@ public class TupleInfo extends TMUDRSerializableObject {
         case NUMERIC_UNSIGNED:
         case DECIMAL_UNSIGNED:
             long lval;
-            try {lval = Long.parseLong(val);}
-            catch (Exception e1) {
-                throw new UDRException(
-                                       38900,
-                                       "Error in setString() \"%s\" is not a long value",
-                                       val);
-            }
+            int scale = t.getScale();
+
+            if (scale == 0)
+                {
+                    try {lval = Long.parseLong(val);}
+                    catch (Exception e1) {
+                        throw new UDRException(
+                          38900,
+                          "Error in setString() \"%s\" is not a long value",
+                          val);
+                    }
+                }
+            else
+                {
+                    // setLong wants a long value that is scaled up by "scale"
+                    // e.g. 12.34 with a column of scale 3 would become 12340.
+                    boolean negate = false;
+                    String tval = val.trim();
+                    // scale of value read
+                    int vScale = 0;
+
+                    if (tval.charAt(0) == '-')
+                        {
+                            negate = true;
+                            tval = tval.substring(1,tval.length()).trim();
+                        }
+
+                    try {
+                        // position of decimal dot or decimal digit after the dot
+                        int ddPos = tval.indexOf('.');
+                        int len = tval.length();
+
+                        if (ddPos < 0)
+                            // no dot is the same as a trailing dot
+                            ddPos = len;
+
+                        if (ddPos > 0)
+                            // read the number before the (optional) decimal point
+                            lval = Long.parseLong(tval.substring(0, ddPos));
+                        else
+                            // the number starts with a dot
+                            lval = 0;
+
+                        // read any digits after the decimal point
+                        if (++ddPos < len)
+                            {
+                                long fraction = Long.parseLong(tval.substring(ddPos, len));
+                                vScale = (len - ddPos);
+
+                                for (int s=0; s<vScale; s++)
+                                    lval *= 10;
+
+                                lval += fraction;
+                            }
+
+                        if (negate)
+                            lval = -lval;
+
+                        // Now we got the value in lval with a scale of vScale.
+                        // Scale it up to "scale"
+                        while (vScale < scale)
+                            {
+                                lval *= 10;
+                                vScale++;
+                            }
+
+                    } catch (Exception e2) {
+                        throw new UDRException(
+                          38900,
+                          "Error in setString(): \"%s\" is not an in-range numeric value",
+                          val);
+                    }
+
+                    if (vScale > scale)
+                        throw new UDRException(
+                          38900,
+                          "Error in setString(): Scale of value %s exceeds that of the column, %d",
+                          val, scale);
+                }
             setLong(colNum, lval);
             break;
         

http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/a4caa9ac/core/sql/src/main/java/org/trafodion/sql/udr/TypeInfo.java
----------------------------------------------------------------------
diff --git a/core/sql/src/main/java/org/trafodion/sql/udr/TypeInfo.java b/core/sql/src/main/java/org/trafodion/sql/udr/TypeInfo.java
index e42d0b2..de7fdc6 100644
--- a/core/sql/src/main/java/org/trafodion/sql/udr/TypeInfo.java
+++ b/core/sql/src/main/java/org/trafodion/sql/udr/TypeInfo.java
@@ -334,6 +334,9 @@ public class TypeInfo extends TMUDRSerializableObject {
             // length is the length in characters, but length_ is
             // the byte length, multiply by min bytes per char
             length_ = length * minBytesPerChar();
+            if (length_ < 0)
+                throw new UDRException(38900,"Length of a character type must not be negative, got %d",
+                                       length_);
             if (collation_ == SQLCollationCode.UNDEFINED_COLLATION.ordinal())
                 throw new UDRException(38900,"Collation must be specified for CHAR type in TypeInfo::TypeInfo");
             break;
@@ -349,6 +352,9 @@ public class TypeInfo extends TMUDRSerializableObject {
             if (length_ > 32767)
                 // see also CharType::CharType in ../common/CharType.cpp
                 flags_ |= TYPE_FLAG_4_BYTE_VC_LEN;
+            if (length_ < 0)
+                throw new UDRException(38900,"Length of a varchar type must not be negative, got %d",
+                                       length_);
             break;
 
         case CLOB: