http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/2faae457/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 65dac20..2b1ffad 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 @@ -209,9 +209,15 @@ public class TupleInfo extends TMUDRSerializableObject { // see also code in LmTypeIsString() in file ../generator/LmExpr.cpp if (origSQLType == TypeInfo.SQLTypeCode.NUMERIC || origSQLType == TypeInfo.SQLTypeCode.NUMERIC_UNSIGNED || - origSQLType == TypeInfo.SQLTypeCode.INTERVAL) + origSQLType == TypeInfo.SQLTypeCode.INTERVAL || + origSQLType == TypeInfo.SQLTypeCode.BOOLEAN) { - if (t.getByteLength() == 2) + if (t.getByteLength() == 1) + if (origSQLType == TypeInfo.SQLTypeCode.NUMERIC_UNSIGNED) + tempSQLType = TypeInfo.SQLTypeCode.TINYINT_UNSIGNED; + else + tempSQLType = TypeInfo.SQLTypeCode.TINYINT; + else if (t.getByteLength() == 2) if (origSQLType == TypeInfo.SQLTypeCode.NUMERIC_UNSIGNED) tempSQLType = TypeInfo.SQLTypeCode.SMALLINT_UNSIGNED; else @@ -228,6 +234,10 @@ public class TupleInfo extends TMUDRSerializableObject { switch (tempSQLType) { + case TINYINT: + result = row_.get(t.getDataOffset()) ; + break; + case SMALLINT: result = row_.getShort(t.getDataOffset()) ; break; @@ -240,12 +250,22 @@ public class TupleInfo extends TMUDRSerializableObject { result = row_.getLong(t.getDataOffset()) ; break; + case TINYINT_UNSIGNED: + result = row_.get(t.getDataOffset()) ; + if (result < 0) + result = result + 256; + break; + case SMALLINT_UNSIGNED: - result = row_.getShort(t.getDataOffset()) ; // need to fix + result = row_.getShort(t.getDataOffset()) ; + if (result < 0) + result = result + 65536; break; case INT_UNSIGNED: - result = row_.getInt(t.getDataOffset()) ; // need to fix + result = row_.getInt(t.getDataOffset()) ; + if (result < 0) + result = result + 4294967296L; break; case DECIMAL_LSE: @@ -484,6 +504,8 @@ public class TupleInfo extends TMUDRSerializableObject { case SMALLINT_UNSIGNED: case INT_UNSIGNED: case NUMERIC_UNSIGNED: + case TINYINT: + case TINYINT_UNSIGNED: { long num = getLong(colNum); if (wasNull_) @@ -609,6 +631,13 @@ public class TupleInfo extends TMUDRSerializableObject { "Invalid interval code in TupleInfo::getString()"); } } + case BOOLEAN: + { + if (getBoolean(colNum)) + return "1"; + else + return "0"; + } default: throw new UDRException( @@ -640,6 +669,106 @@ public class TupleInfo extends TMUDRSerializableObject { } /** + * Get a boolean value of a column or parameter + * + * <p> This method is modeled after the JDBC interface. + * It can be used on boolean, numeric and character columns. + * Numeric columns need to have a value of 0 (false) or 1 (true), + * character columns need to have a value of "0" (false) or "1" (true). + * + * <p> Use this method at runtime. It can also be used for + * actual parameters that are available at compile time. + * + * @param colNum Column number. + * @return Boolean value. + * If the value was a NULL value, an empty string + * is returned. The wasNull() method can be used to + * determine whether a NULL value was returned. + * @throws UDRException + */ + public boolean getBoolean(int colNum) throws UDRException { + if (!row_.hasArray()) + throw new UDRException( + 38900, + "Row not available for getBoolean() or related method"); + TypeInfo t = getType(colNum); + if (!t.isAvailable()) + throw new UDRException( + 38900, + "Offset for column not set, getBoolean() or related method not available"); + + if (t.getIsNullable() && + row_.getShort(t.getIndOffset()) != 0) + { + wasNull_ = true; + return false; + } + + wasNull_ = false; + switch (t.getSQLTypeClass()) + { + case CHARACTER_TYPE: + { + String sval = getString(colNum).trim(); + + if (sval.compareTo("0") == 0) + return false; + else if (sval.compareTo("1") == 0) + return true; + else + throw new UDRException( + 38900, + "getBoolean() encountered string value %s, booleans must be 0 or 1", + sval); + } + + case NUMERIC_TYPE: + case BOOLEAN_TYPE: + { + long lval = getLong(colNum); + + if (lval <0 || lval > 1) + throw new UDRException( + 38900, + "getBoolean() encountered value %ld, booleans must be 0 or 1", + lval); + return (lval != 0); + } + + default: + { + throw new UDRException( + 38900, + "getBoolean() not supported for type %s", + t.toString(false)); + } + } + } + + /** + * Get a boolean value of a column or parameter identified by name. + * + * <p> This method is modeled after the JDBC interface. + * It can be used on boolean, numeric and character columns. + * Numeric columns need to have a value of 0 (false) or 1 (true), + * character columns need to have a value of "0" (false) or "1" (true). + * + * <p> Use this method at runtime. It cannot be used for + * actual parameters that are available at compile time, use + * getString(int colNum) instead, since actual parameters are not named. + * + * @param colName Name of an existing column. + * @return Boolean value. + * If the value was a NULL value, false + * is returned. The wasNull() method can be used to + * determine whether a NULL value was returned. + * @throws UDRException + */ + public boolean getBoolean(String colName) throws UDRException { + return getBoolean(getColNum(colName)); + } + + /** * Get a pointer to the raw data value of a column. * * Using this method requires knowledge of the data layout @@ -1042,7 +1171,12 @@ public class TupleInfo extends TMUDRSerializableObject { tempSQLType == TypeInfo.SQLTypeCode.NUMERIC_UNSIGNED || tempSQLType == TypeInfo.SQLTypeCode.INTERVAL) { - if (t.getByteLength() == 2) + if (t.getByteLength() == 1) + if (tempSQLType == TypeInfo.SQLTypeCode.NUMERIC_UNSIGNED) + tempSQLType = TypeInfo.SQLTypeCode.TINYINT_UNSIGNED; + else + tempSQLType = TypeInfo.SQLTypeCode.TINYINT; + else if (t.getByteLength() == 2) if (tempSQLType == TypeInfo.SQLTypeCode.NUMERIC_UNSIGNED) tempSQLType = TypeInfo.SQLTypeCode.SMALLINT_UNSIGNED; else @@ -1059,11 +1193,28 @@ public class TupleInfo extends TMUDRSerializableObject { switch (tempSQLType) { + case BOOLEAN: + if (val != 0 && val != 1) + throw new UDRException( + 38900, + "Overflow/Underflow when assigning %d to BOOLEAN type", + (int) val); + // fall through to next case + case TINYINT: + if (val > Byte.MAX_VALUE || val < Byte.MIN_VALUE) + throw new UDRException( + 38900, + "Overflow/Underflow when assigning %d to TINYINT type", + (int) val); + row_.put(t.getDataOffset(), (byte) val); + break; + case SMALLINT: if (val > Short.MAX_VALUE || val < Short.MIN_VALUE) throw new UDRException( 38900, - "Overflow/Underflow when assigining to SMALLINT type"); + "Overflow/Underflow when assigning %d to SMALLINT type", + (int) val); row_.putShort(t.getDataOffset(), (short) val); break; @@ -1079,19 +1230,48 @@ public class TupleInfo extends TMUDRSerializableObject { row_.putLong(t.getDataOffset(), val); break; + case TINYINT_UNSIGNED: + if (val < 0 || val > Byte.MAX_VALUE) + if (val > (2 * Byte.MAX_VALUE + 1)) + throw new UDRException( + 38900, + "Overflow/underflow when assigning to TINYINT UNSIGNED type"); + else + // use the signed value that has the same bit + // pattern as the desired unsigned value, since + // Java doesn't support "unsigned" basic types + val = val + Byte.MIN_VALUE + Byte.MIN_VALUE; + + row_.put(t.getDataOffset(), (byte) val); + break; + case SMALLINT_UNSIGNED: if (val < 0 || val > Short.MAX_VALUE) - throw new UDRException( - 38900, - "Overflow/underflow when assigning to SMALLINT UNSIGNED type"); + if (val > (2 * Short.MAX_VALUE + 1)) + throw new UDRException( + 38900, + "Overflow/underflow when assigning to SMALLINT UNSIGNED type"); + else + // use the signed value that has the same bit + // pattern as the desired unsigned value, since + // Java doesn't support "unsigned" basic types + val = val + Short.MIN_VALUE + Short.MIN_VALUE; + row_.putShort(t.getDataOffset(), (short) val); break; case INT_UNSIGNED: if (val < 0 || val > Integer.MAX_VALUE) - throw new UDRException( - 38900, - "Overflow/underflow when assigning to an INT UNSIGNED type"); + if (val > (2 * Integer.MAX_VALUE + 1)) + throw new UDRException( + 38900, + "Overflow/underflow when assigning to an INT UNSIGNED type"); + else + // use the signed value that has the same bit + // pattern as the desired unsigned value, since + // Java doesn't support "unsigned" basic types + val = val + Integer.MIN_VALUE + Integer.MIN_VALUE; + row_.putInt(t.getDataOffset(), (int) val); break; @@ -1316,11 +1496,13 @@ public class TupleInfo extends TMUDRSerializableObject { setDouble(colNum, dval); break ; + case TINYINT: case SMALLINT: case INT: case LARGEINT: case NUMERIC: case DECIMAL_LSE: + case TINYINT_UNSIGNED: case SMALLINT_UNSIGNED: case INT_UNSIGNED: case NUMERIC_UNSIGNED: @@ -1558,6 +1740,24 @@ public class TupleInfo extends TMUDRSerializableObject { setLong(colNum, result); } break; + + case BOOLEAN: + { + String trimmedval = val.trim(); // remove leading and trailing blanks + + if (trimmedval.compareTo("0") == 0 || + trimmedval.compareTo("false") == 0 || + trimmedval.compareTo("FALSE") == 0) + setLong(colNum, 0); + else if (trimmedval.compareTo("1") == 0 || + trimmedval.compareTo("true") == 0 || + trimmedval.compareTo("TRUE") == 0) + setLong(colNum, 1); + else throw new UDRException( + 38900, + "Invalid value %s encountered in setString() for a boolean data type", + trimmedval); + } case UNDEFINED_SQL_TYPE: default:
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/2faae457/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 de7fdc6..1facfc7 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 @@ -36,7 +36,7 @@ public class TypeInfo extends TMUDRSerializableObject { public enum SQLTypeCode { UNDEFINED_SQL_TYPE, - /** 16 bit integer */ + /** 16 bit integer */ SMALLINT, /** 32 bit integer */ INT, @@ -73,49 +73,59 @@ public class TypeInfo extends TMUDRSerializableObject { /** Binary Large Object */ BLOB, /** Character Large Object */ - CLOB + CLOB, + /** 8 bit integer */ + TINYINT, + /** unsigned 8 bit integer */ + TINYINT_UNSIGNED, + /** boolean */ + BOOLEAN }; /** Classes of types defined in the SQL standard */ public enum SQLTypeClassCode { /** char and varchar types */ - CHARACTER_TYPE, + CHARACTER_TYPE, /** exact and approximate numerics */ - NUMERIC_TYPE, + NUMERIC_TYPE, /** date/time/timestamp */ - DATETIME_TYPE, + DATETIME_TYPE, /** day/month or hour/second intervals */ INTERVAL_TYPE, /** BLOBs and CLOBs */ - LOB_TYPE, + LOB_TYPE, + /** Boolean */ + BOOLEAN_TYPE, /** undefined value */ - UNDEFINED_TYPE_CLASS + UNDEFINED_TYPE_CLASS }; /** More detailed type information, but not as detailed as the actual type */ public enum SQLTypeSubClassCode { /** CHAR type */ - FIXED_CHAR_TYPE, + FIXED_CHAR_TYPE, /** VARCHAR type */ - VAR_CHAR_TYPE, + VAR_CHAR_TYPE, /** Exact numeric */ - EXACT_NUMERIC_TYPE, + EXACT_NUMERIC_TYPE, /** Approximate numeric (floating point) */ - APPROXIMATE_NUMERIC_TYPE, + APPROXIMATE_NUMERIC_TYPE, /** Date */ - DATE_TYPE, + DATE_TYPE, /** Time */ - TIME_TYPE, + TIME_TYPE, /** Timestamp (date + time + optional fractional seconds) */ - TIMESTAMP_TYPE, + TIMESTAMP_TYPE, /** Intervals involving year and month */ - YEAR_MONTH_INTERVAL_TYPE, + YEAR_MONTH_INTERVAL_TYPE, /** Intervals involving days/hours/minutes/seconds */ DAY_SECOND_INTERVAL_TYPE, /** LOBs */ - LOB_SUB_CLASS, + LOB_SUB_CLASS, + /** Boolean */ + BOOLEAN_SUB_CLASS, /** undefined value */ UNDEFINED_TYPE_SUB_CLASS }; @@ -248,6 +258,12 @@ public class TypeInfo extends TMUDRSerializableObject { switch (sqlType) { + case TINYINT: + length_ = 1; + precision_ = 0; + scale_ = 0; + break; + case SMALLINT: length_ = 2; precision_ = 0; @@ -287,6 +303,12 @@ public class TypeInfo extends TMUDRSerializableObject { length_ += 1; // for the decimal point break; + case TINYINT_UNSIGNED: + length_ = 1; + precision_ = 0; + scale_ = 0; + break; + case SMALLINT_UNSIGNED: length_ = 2; precision_ = 0; @@ -469,6 +491,12 @@ public class TypeInfo extends TMUDRSerializableObject { } break; + case BOOLEAN: + length_ = 1; + precision_ = 0; + scale_ = 0; + break; + case UNDEFINED_SQL_TYPE: // this case is reached when we call the default constructor, // type and other fields still need to be defined @@ -751,6 +779,12 @@ public class TypeInfo extends TMUDRSerializableObject { return SQLTypeCode.BLOB; case 19: return SQLTypeCode.CLOB; + case 20: + return SQLTypeCode.TINYINT; + case 21: + return SQLTypeCode.TINYINT_UNSIGNED; + case 22: + return SQLTypeCode.BOOLEAN; default: return SQLTypeCode.UNDEFINED_SQL_TYPE; } @@ -775,6 +809,8 @@ public class TypeInfo extends TMUDRSerializableObject { case 9: case 10: case 11: + case 20: + case 21: return SQLTypeClassCode.NUMERIC_TYPE; case 12: @@ -793,6 +829,9 @@ public class TypeInfo extends TMUDRSerializableObject { case 19: return SQLTypeClassCode.LOB_TYPE; + case 22: + return SQLTypeClassCode.BOOLEAN_TYPE; + case 0: default: break; @@ -819,6 +858,8 @@ public class TypeInfo extends TMUDRSerializableObject { case 7: case 8: case 9: + case 20: + case 21: return SQLTypeSubClassCode.EXACT_NUMERIC_TYPE; case 10: case 11: @@ -865,6 +906,9 @@ public class TypeInfo extends TMUDRSerializableObject { case 18: case 19: return SQLTypeSubClassCode.LOB_SUB_CLASS; + + case 22: + return SQLTypeSubClassCode.BOOLEAN_SUB_CLASS; case 0: default: @@ -1095,7 +1139,9 @@ public class TypeInfo extends TMUDRSerializableObject { "Decimal precision %d is out of the allowed range of 1-18", decimalPrecision); - if (decimalPrecision < 5) + if (decimalPrecision < 3) + return 1; + else if (decimalPrecision < 5) return 2; else if (decimalPrecision < 10) return 4; @@ -1110,6 +1156,9 @@ public class TypeInfo extends TMUDRSerializableObject { case UNDEFINED_SQL_TYPE: sb.append("undefined_sql_type"); break; + case TINYINT: + sb.append("TINYINT"); + break; case SMALLINT: sb.append("SMALLINT"); break; @@ -1125,6 +1174,9 @@ public class TypeInfo extends TMUDRSerializableObject { case DECIMAL_LSE: sb.append(String.format("DECIMAL(%d,%d)",getPrecision(), getScale())); break; + case TINYINT_UNSIGNED: + sb.append("TINYINT UNSIGNED"); + break; case SMALLINT_UNSIGNED: sb.append("SMALLINT UNSIGNED"); break; @@ -1255,6 +1307,9 @@ public class TypeInfo extends TMUDRSerializableObject { case CLOB: sb.append("CLOB"); break; + case BOOLEAN: + sb.append("BOOLEAN"); + break; default: sb.append("invalid SQL type!"); break; http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/2faae457/core/sql/src/main/java/org/trafodion/sql/udr/UDR.java ---------------------------------------------------------------------- diff --git a/core/sql/src/main/java/org/trafodion/sql/udr/UDR.java b/core/sql/src/main/java/org/trafodion/sql/udr/UDR.java index 2546089..b6d636a 100644 --- a/core/sql/src/main/java/org/trafodion/sql/udr/UDR.java +++ b/core/sql/src/main/java/org/trafodion/sql/udr/UDR.java @@ -261,13 +261,26 @@ public abstract class UDR * parallelism, either in absolute or relative terms. * <p> * The default behavior is to allow any degree of parallelism for - * TMUDFs with one table-valued input, and to force serial execution - * in all other cases. The reason is that for a single table-valued - * input, there is a natural way to parallelize the function by - * parallelizing its input a la MapReduce. In all other cases, - * parallel execution requires active participation by the UDF, - * which is why the UDF needs to signal explicitly that it can - * handle such flavors of parallelism. + * TMUDFs of function type UDRInvocationInfo.MAPPER or + * UDRInvocationInfo.REDUCER (or REDUCER_NC) that have exactly + * one table-valued input. The default behavior forces serial + * execution in all other cases. The reason is that for a single + * table-valued input, there is a natural way to parallelize the + * function by parallelizing its input a la MapReduce. In all + * other cases, parallel execution requires active participation + * by the UDF, which is why the UDF needs to signal explicitly + * that it can handle such flavors of parallelism. + * + * Default implementation: + * {@code + * if (info.getNumTableInputs() == 1 && + * (info.getFuncType() == UDRInvocationInfo.FuncType.MAPPER || + * info.getFuncType() == UDRInvocationInfo.FuncType.REDUCER || + * info.getFuncType() == UDRInvocationInfo.FuncType.REDUCER_NC)) + * plan.setDesiredDegreeOfParallelism(UDRPlanInfo.ANY_DEGREE_OF_PARALLELISM); + * else + * plan.setDesiredDegreeOfParallelism(1); // serial execution + * } * <p> * Note that this is NOT foolproof, and that the TMUDF might still * need to validate the PARTITION BY and ORDER BY syntax used in its @@ -276,6 +289,7 @@ public abstract class UDR * @see UDRPlanInfo#getDesiredDegreeOfParallelism * @see UDRPlanInfo#setDesiredDegreeOfParallelism * @see UDRInvocationInfo#getNumParallelInstances + * @see UDRInvocationInfo#setFuncType * * @param info A description of the UDR invocation. * @param plan Plan-related description of the UDR invocation. @@ -285,8 +299,12 @@ public abstract class UDR UDRPlanInfo plan) throws UDRException { - if (info.getNumTableInputs() == 1) - plan.setDesiredDegreeOfParallelism(UDRPlanInfo.SpecialDegreeOfParallelism.ANY_DEGREE_OF_PARALLELISM.getSpecialDegreeOfParallelism()); + if (info.getNumTableInputs() == 1 && + (info.getFuncType() == UDRInvocationInfo.FuncType.MAPPER || + info.getFuncType() == UDRInvocationInfo.FuncType.REDUCER || + info.getFuncType() == UDRInvocationInfo.FuncType.REDUCER_NC)) + plan.setDesiredDegreeOfParallelism(UDRPlanInfo.SpecialDegreeOfParallelism. + ANY_DEGREE_OF_PARALLELISM.getSpecialDegreeOfParallelism()); else plan.setDesiredDegreeOfParallelism(1); // serial execution }; http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/2faae457/core/sql/src/main/java/org/trafodion/sql/udr/UDRInvocationInfo.java ---------------------------------------------------------------------- diff --git a/core/sql/src/main/java/org/trafodion/sql/udr/UDRInvocationInfo.java b/core/sql/src/main/java/org/trafodion/sql/udr/UDRInvocationInfo.java index 478a993..58e99f2 100644 --- a/core/sql/src/main/java/org/trafodion/sql/udr/UDRInvocationInfo.java +++ b/core/sql/src/main/java/org/trafodion/sql/udr/UDRInvocationInfo.java @@ -62,7 +62,14 @@ public class UDRInvocationInfo extends TMUDRSerializableObject * This allows the compiler to parallelize execution and * to push predicates on the partitioning column(s) down * to table-valued inputs. */ - REDUCER; + REDUCER, + /** Same as REDUCER, except that in this case the + * UDF does not require the rows belonging to a key + * to be grouped together, they can be non-contiguous + * (NC). This can avoid a costly sort of the input + * table in cases where a highly reducing UDF can keep + * a table of all the keys in memory. */ + REDUCER_NC; private static FuncType[] allValues = values(); public static FuncType fromOrdinal(int n) {return allValues[n];} @@ -1036,6 +1043,7 @@ public class UDRInvocationInfo extends TMUDRSerializableObject case EXACT_NUMERIC_TYPE: case YEAR_MONTH_INTERVAL_TYPE: case DAY_SECOND_INTERVAL_TYPE: + case BOOLEAN_SUB_CLASS: { long l = in(it).getLong(ic); @@ -1151,7 +1159,8 @@ public class UDRInvocationInfo extends TMUDRSerializableObject System.out.print(String.format("Function type : %s\n", (funcType_ == FuncType.GENERIC ? "GENERIC" : (funcType_ == FuncType.MAPPER ? "MAPPER" : (funcType_ == FuncType.REDUCER ? "REDUCER" : - "Invalid function type"))))); + (funcType_ == FuncType.REDUCER_NC ? "REDUCER_NC" : + "Invalid function type")))))); System.out.print(String.format("User id : %s\n", getCurrentUser())); System.out.print(String.format("Session user id : %s\n", getSessionUser())); System.out.print(String.format("User role : %s\n", getCurrentRole()));
