Github user divyabhargov commented on a diff in the pull request:
https://github.com/apache/hawq/pull/1353#discussion_r215082304
--- Diff:
pxf/pxf-jdbc/src/main/java/org/apache/hawq/pxf/plugins/jdbc/JdbcResolver.java
---
@@ -0,0 +1,364 @@
+package org.apache.hawq.pxf.plugins.jdbc;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import org.apache.hawq.pxf.api.io.DataType;
+import org.apache.hawq.pxf.api.utilities.ColumnDescriptor;
+import org.apache.hawq.pxf.api.utilities.InputData;
+import org.apache.hawq.pxf.api.OneField;
+import org.apache.hawq.pxf.api.OneRow;
+import org.apache.hawq.pxf.api.ReadResolver;
+import org.apache.hawq.pxf.api.UserDataException;
+import org.apache.hawq.pxf.api.WriteResolver;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * JDBC tables resolver
+ */
+public class JdbcResolver extends JdbcPlugin implements ReadResolver,
WriteResolver {
+ /**
+ * Class constructor
+ */
+ public JdbcResolver(InputData input) throws UserDataException {
+ super(input);
+ }
+
+ /**
+ * getFields() implementation
+ *
+ * @throws SQLException if the provided {@link OneRow} object is
invalid
+ */
+ @Override
+ public List<OneField> getFields(OneRow row) throws SQLException {
+ ResultSet result = (ResultSet) row.getData();
+ LinkedList<OneField> fields = new LinkedList<>();
+
+ for (ColumnDescriptor column : columns) {
+ String colName = column.columnName();
+ Object value = null;
+
+ OneField oneField = new OneField();
+ oneField.type = column.columnTypeCode();
+
+ switch (DataType.get(oneField.type)) {
+ case INTEGER:
+ value = result.getInt(colName);
+ break;
+ case FLOAT8:
+ value = result.getDouble(colName);
+ break;
+ case REAL:
+ value = result.getFloat(colName);
+ break;
+ case BIGINT:
+ value = result.getLong(colName);
+ break;
+ case SMALLINT:
+ value = result.getShort(colName);
+ break;
+ case BOOLEAN:
+ value = result.getBoolean(colName);
+ break;
+ case BYTEA:
+ value = result.getBytes(colName);
+ break;
+ case VARCHAR:
+ case BPCHAR:
+ case TEXT:
+ case NUMERIC:
+ value = result.getString(colName);
+ break;
+ case DATE:
+ value = result.getDate(colName);
+ break;
+ case TIMESTAMP:
+ value = result.getTimestamp(colName);
+ break;
+ default:
+ throw new UnsupportedOperationException("Field type '"
+ DataType.get(oneField.type).toString() + "' (column '" + column.toString() +
"') is not supported");
+ }
+
+ oneField.val = value;
+ fields.add(oneField);
+ }
+ return fields;
+ }
+
+ /**
+ * setFields() implementation
+ *
+ * @return OneRow with the data field containing a List<OneField>
+ * OneFields are not reordered before being passed to Accessor; at the
+ * moment, there is no way to correct the order of the fields if it is
not.
+ * In practice, the 'record' provided is always ordered the right way.
+ *
+ * @throws UnsupportedOperationException if field of some type is not
supported
+ */
+ @Override
+ public OneRow setFields(List<OneField> record) throws
UnsupportedOperationException, ParseException {
+ int column_index = 0;
+ for (OneField oneField : record) {
+ ColumnDescriptor column = columns.get(column_index);
+ if (
+ LOG.isDebugEnabled() &&
+ DataType.get(column.columnTypeCode()) !=
DataType.get(oneField.type)
+ ) {
+ LOG.warn("The provided tuple of data may be disordered.
Datatype of column with descriptor '" + column.toString() + "' must be '" +
DataType.get(column.columnTypeCode()).toString() + "', but actual is '" +
DataType.get(oneField.type).toString() + "'");
+ }
+
+ // Check that data type is supported
+ switch (DataType.get(oneField.type)) {
+ case BOOLEAN:
+ case INTEGER:
+ case FLOAT8:
+ case REAL:
+ case BIGINT:
+ case SMALLINT:
+ case NUMERIC:
+ case VARCHAR:
+ case BPCHAR:
+ case TEXT:
+ case BYTEA:
+ case TIMESTAMP:
+ case DATE:
+ break;
+ default:
+ throw new UnsupportedOperationException("Field type '"
+ DataType.get(oneField.type).toString() + "' (column '" + column.toString() +
"') is not supported");
+ }
+
+ if (LOG.isDebugEnabled()) {
+ if (DataType.get(oneField.type) == DataType.BYTEA) {
+ LOG.debug("OneField content (conversion from BYTEA):
'" + new String((byte[])oneField.val) + "'");
+ }
+ }
+
+ // Convert TEXT columns into native data types
+ if ((oneField.val != null) && (DataType.get(oneField.type) ==
DataType.TEXT) && (DataType.get(column.columnTypeCode()) != DataType.TEXT)) {
--- End diff --
This bit failed for us when we had a timestamp or date field that had a
NULL value. The type reported by GPDBWritable was not being converted from TEXT
to timestamp, because conversion of types would only apply if the value were
not NULL. Even if the value is null, we want oneField's type to be the column
type code and not string.
Here's the snippet that worked for us:
```
if (LOG.isDebugEnabled()) {
if (DataType.get(oneField.type) == DataType.BYTEA) {
LOG.debug("OneField content (conversion from BYTEA): '"
+ new String((byte[])oneField.val) + "'");
}
}
// convert values of non TEXT types represented as text by the
GPDBWritable serializer into native types
if ((DataType.get(oneField.type) == DataType.TEXT) &&
(DataType.get(column.columnTypeCode()) != DataType.TEXT)) {
// convert type information
oneField.type = column.columnTypeCode();
// Convert values if they are present (not null)
if ((oneField.val != null)) {
String rawVal = (String)oneField.val;
if (LOG.isDebugEnabled()) {
LOG.debug("OneField content (conversion from TEXT):
'" + rawVal + "'");
}
...
```
and remove
```
oneField.type = column.columnTypeCode();
```
from the bottom of the `if` statement.
---