Commit 46b809ad authored by Mark Heppner's avatar Mark Heppner

Use Java classes as the lookup for column and parameter types

parent 501e2ff5
......@@ -129,15 +129,15 @@ class Cursor(object):
self._signature = signature
self._column_data_types = []
self._parameter_data_types = []
if signature is None:
if signature is None or signature.SerializeToString() == '':
return
for i, column in enumerate(signature.columns):
dtype = TypeHelper.from_rep(column.type.rep)
for column in signature.columns:
dtype = TypeHelper.from_class(column.column_class_name)
self._column_data_types.append(dtype)
for parameter in signature.parameters:
dtype = TypeHelper.from_phoenix(parameter.type_name)
dtype = TypeHelper.from_class(parameter.class_name)
self._parameter_data_types.append(dtype)
def _set_frame(self, frame):
......@@ -168,7 +168,7 @@ class Cursor(object):
def _transform_parameters(self, parameters):
typed_parameters = []
for value, data_type in zip(parameters, self._parameter_data_types):
field_name, rep, mutate = data_type
field_name, rep, mutate_to, cast_from = data_type
typed_value = common_pb2.TypedValue()
if value is None:
......@@ -178,8 +178,8 @@ class Cursor(object):
typed_value.null = False
# use the mutator function
if mutate is not None:
value = mutate(value)
if mutate_to is not None:
value = mutate_to(value)
typed_value.type = rep
setattr(typed_value, field_name, value)
......@@ -241,7 +241,7 @@ class Cursor(object):
elif column.scalar_value.null:
tmp_row.append(None)
else:
field_name, cast = self._column_data_types[i]
field_name, rep, mutate_to, cast_from = self._column_data_types[i]
# get the value from the field_name
# TODO handle None
......@@ -249,8 +249,8 @@ class Cursor(object):
# cast the value
# TODO try/catch the casting
if cast is not None:
value = cast(value)
if cast_from is not None:
value = cast_from(value)
tmp_row.append(value)
return tmp_row
......
......@@ -14,15 +14,13 @@
import time
import datetime
import base64
from decimal import Decimal
from phoenixdb.calcite import common_pb2
__all__ = [
'Date', 'Time', 'Timestamp', 'DateFromTicks', 'TimeFromTicks', 'TimestampFromTicks',
'Binary', 'STRING', 'BINARY', 'NUMBER', 'DATETIME', 'ROWID', 'BOOLEAN',
'REP_TYPES', 'REP_TYPES_MAP', 'PHOENIX_PARAMETERS', 'PHOENIX_PARAMETERS_MAP',
'TypeHelper',
'JAVA_CLASSES', 'JAVA_CLASSES_MAP', 'TypeHelper',
]
......@@ -60,7 +58,9 @@ def Binary(value):
"""Constructs an object capable of holding a binary (long) string value."""
if isinstance(value, _BinaryString):
return value
return _BinaryString(base64.b64encode(value))
# TODO base64 encoding doesn't seem necessary with protobufs
#return _BinaryString(base64.b64encode(value))
return _BinaryString(value)
class _BinaryString(str):
......@@ -132,156 +132,61 @@ BOOLEAN = ColumnType(['BOOLEAN'])
# XXX ARRAY
REP_TYPES = {
JAVA_CLASSES = {
'bool_value': [
common_pb2.PRIMITIVE_BOOLEAN,
common_pb2.BOOLEAN,
('java.lang.Boolean', common_pb2.BOOLEAN, None, None),
],
'string_value': [
common_pb2.PRIMITIVE_CHAR,
common_pb2.CHARACTER,
common_pb2.STRING,
common_pb2.BIG_DECIMAL,
# TODO DECIMAL type (java.math.BigDecimal) is set to a Rep.OBJECT...why?
common_pb2.OBJECT,
('java.lang.Character', common_pb2.CHARACTER, None, None),
('java.lang.String', common_pb2.STRING, None, None),
('java.math.BigDecimal', common_pb2.BIG_DECIMAL, str, Decimal),
],
'number_value': [
common_pb2.PRIMITIVE_BYTE,
common_pb2.PRIMITIVE_INT,
common_pb2.PRIMITIVE_SHORT,
common_pb2.PRIMITIVE_LONG,
common_pb2.BYTE,
common_pb2.INTEGER,
common_pb2.SHORT,
common_pb2.LONG,
common_pb2.BIG_INTEGER,
common_pb2.JAVA_SQL_TIME,
common_pb2.JAVA_SQL_TIMESTAMP,
common_pb2.JAVA_SQL_DATE,
common_pb2.JAVA_UTIL_DATE,
common_pb2.NUMBER,
('java.lang.Integer', common_pb2.INTEGER, None, int),
('java.lang.Short', common_pb2.SHORT, None, int),
('java.lang.Long', common_pb2.LONG, None, long),
('java.lang.Byte', common_pb2.BYTE, None, int),
('java.sql.Time', common_pb2.JAVA_SQL_TIME, time_to_java_sql_time, time_from_java_sql_time),
('java.sql.Date', common_pb2.JAVA_SQL_DATE, date_to_java_sql_date, date_from_java_sql_date),
('java.sql.Timestamp', common_pb2.JAVA_SQL_TIMESTAMP, datetime_to_java_sql_timestamp, datetime_from_java_sql_timestamp),
],
'bytes_value': [
common_pb2.BYTE_STRING,
# TODO base64 encoding doesn't seem necessary with protobufs
('[B', common_pb2.BYTE_STRING, Binary, None),
],
'double_value': [
common_pb2.PRIMITIVE_FLOAT,
common_pb2.PRIMITIVE_DOUBLE,
common_pb2.FLOAT,
common_pb2.DOUBLE,
# if common_pb2.FLOAT is used, incorrect values are sent
('java.lang.Float', common_pb2.DOUBLE, float, float),
('java.lang.Double', common_pb2.DOUBLE, float, float),
]
}
"""Groups of Rep types."""
REP_TYPES_MAP = dict( (v, k) for k in REP_TYPES for v in REP_TYPES[k] )
JAVA_CLASSES_MAP = dict( (v[0], (k, v[1], v[2], v[3])) for k in JAVA_CLASSES for v in JAVA_CLASSES[k] )
"""Flips the available types to allow for faster lookup by Rep."""
PHOENIX_PARAMETERS = {
'bool_value': [
('BOOLEAN', common_pb2.BOOLEAN),
],
'string_value': [
('CHAR', common_pb2.CHARACTER),
('VARCHAR', common_pb2.STRING),
('DECIMAL', common_pb2.BIG_DECIMAL),
],
'number_value': [
('INTEGER', common_pb2.INTEGER),
('UNSIGNED_INT', common_pb2.INTEGER),
('BIGINT', common_pb2.LONG),
('UNSIGNED_LONG', common_pb2.LONG),
('TINYINT', common_pb2.BYTE),
('UNSIGNED_TINYINT', common_pb2.BYTE),
('SMALLINT', common_pb2.SHORT),
('UNSIGNED_SMALLINT', common_pb2.SHORT),
('DATE', common_pb2.JAVA_SQL_DATE),
('UNSIGNED_DATE', common_pb2.JAVA_SQL_DATE),
('TIME', common_pb2.JAVA_SQL_TIME),
('UNSIGNED_TIME', common_pb2.JAVA_SQL_TIME),
('TIMESTAMP', common_pb2.JAVA_SQL_TIMESTAMP),
('UNSIGNED_TIMESTAMP', common_pb2.JAVA_SQL_TIMESTAMP),
],
'bytes_value': [
('BINARY', common_pb2.BYTE_STRING),
('VARBINARY', common_pb2.BYTE_STRING),
],
'double_value': [
('FLOAT', common_pb2.FLOAT),
('UNSIGNED_FLOAT', common_pb2.FLOAT),
('DOUBLE', common_pb2.DOUBLE),
('UNSIGNED_DOUBLE', common_pb2.DOUBLE),
]
}
"""Map Phoenix types to Reps."""
PHOENIX_PARAMETERS_MAP = dict( (v[0], (k, v[1])) for k in PHOENIX_PARAMETERS for v in PHOENIX_PARAMETERS[k] )
"""Flips the Phoenix types to allow for faster lookup by type."""
class TypeHelper(object):
@staticmethod
def from_rep(rep):
"""Finds a method to cast from a Python value into a Phoenix type.
def from_class(klass):
"""Retrieves a Rep and functions to cast to/from based on the Java class.
:param rep:
The Rep enum from ``common_pb2.Rep``.
:param klass:
The string of the Java class for the column or parameter.
=
:returns: tuple ``(field_name, cast_type)``
:returns: tuple ``(field_name, rep, mutate_to, cast_from)``
WHERE
``field_name`` is the attribute in ``common_pb2.TypedValue``
``cast_type`` is the method to cast from the Phoenix value to the Python value
``rep`` is the common_pb2.Rep enum
``mutate_to`` is the function to cast values into Phoenix values, if any
``cast_from`` is the function to cast from the Phoenix value to the Python value, if any
"""
field_name = None
cast_type = None
if rep in REP_TYPES_MAP:
field_name = REP_TYPES_MAP[rep]
if rep == common_pb2.BIG_DECIMAL:
cast_type = Decimal
elif rep == common_pb2.BYTE:
cast_type = bytes
elif rep == common_pb2.BYTE_STRING:
cast_type = base64.b64decode
elif rep == common_pb2.JAVA_SQL_DATE:
cast_type = date_from_java_sql_date
elif rep == common_pb2.JAVA_SQL_TIME:
cast_type = time_from_java_sql_time
elif rep == common_pb2.JAVA_SQL_TIMESTAMP:
cast_type = datetime_from_java_sql_timestamp
return field_name, cast_type
rep = None
mutate_to = None
cast_from = None
@staticmethod
def from_phoenix(type_name):
"""Converts a Phoenix parameter type into a Rep and a mutator method.
if klass in JAVA_CLASSES_MAP:
field_name, rep, mutate_to, cast_from = JAVA_CLASSES_MAP[klass]
:param type_name:
The JDBC type name from ``common_pb2.AvaticaParameter``.
=
:returns: tuple ``(field_name, rep, mutate_type)``
WHERE
``field_name`` is the attribute in ``common_pb2.TypedValue``
``rep`` is a ``common_pb2.Rep`` type
``mutate_type`` is the method to mutate the Python value to the JDBC value
"""
field_name = None
rep = None
mutate_type = None
if type_name in PHOENIX_PARAMETERS_MAP:
field_name, rep = PHOENIX_PARAMETERS_MAP[type_name]
if type_name == 'DECIMAL':
mutate_type = str
elif type_name == 'BINARY' or type_name == 'VARBINARY':
mutate_type = Binary
elif type_name == 'DATE':
mutate_type = date_to_java_sql_date
elif type_name == 'TIME':
mutate_type = time_to_java_sql_time
elif type_name == 'TIMESTAMP':
mutate_type = datetime_to_java_sql_timestamp
return field_name, rep, mutate_type
return field_name, rep, mutate_to, cast_from
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment