/* * 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. */ package com.aliyun.odps.data; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import com.aliyun.odps.Column; import com.aliyun.odps.TableSchema; /** * 基于数组的{@link Record}实现 * * @see Record */ public class ArrayRecord implements Record { private static final String DEFAULT_CHARSET = "utf-8"; private Column[] columns; private final Object[] values; private HashMap<String, Integer> nameMap = new HashMap<String, Integer>(); public ArrayRecord(Column[] columns) { if (columns == null) { throw new IllegalArgumentException(); } this.columns = columns; values = new Object[columns.length]; for (int i = 0; i < columns.length; i++) { nameMap.put(columns[i].getName(), i); } } public ArrayRecord(TableSchema schema) { this(schema.getColumns().toArray(new Column[0])); } @Override public int getColumnCount() { return values.length; } @Override public Column[] getColumns() { return columns; } @Override public void set(int idx, Object value) { values[idx] = OdpsTypeTransformer.transform(value, columns[idx].getTypeInfo()); } @Override public Object get(int idx) { return values[idx]; } @Override public void set(String columnName, Object value) { set(getColumnIndex(columnName), value); } @Override public Object get(String columnName) { return values[getColumnIndex(columnName)]; } @Override public void setBigint(int idx, Long value) { set(idx, value); } @Override public Long getBigint(int idx) { return getInternal(idx); } @Override public void setBigint(String columnName, Long value) { setBigint(getColumnIndex(columnName), value); } @Override public Long getBigint(String columnName) { return getBigint(getColumnIndex(columnName)); } @Override public void setDouble(int idx, Double value) { set(idx, value); } @Override public Double getDouble(int idx) { return getInternal(idx); } @Override public void setDouble(String columnName, Double value) { setDouble(getColumnIndex(columnName), value); } @Override public Double getDouble(String columnName) { return getDouble(getColumnIndex(columnName)); } @Override public void setBoolean(int idx, Boolean value) { set(idx, value); } @Override public Boolean getBoolean(int idx) { return getInternal(idx); } @Override public void setBoolean(String columnName, Boolean value) { setBoolean(getColumnIndex(columnName), value); } @Override public Boolean getBoolean(String columnName) { return getBoolean(getColumnIndex(columnName)); } @Override public void setDatetime(int idx, Date value) { set(idx, value); } @Override public Date getDatetime(int idx) { return getInternal(idx); } @Override public void setDatetime(String columnName, Date value) { setDatetime(getColumnIndex(columnName), value); } @Override public Date getDatetime(String columnName) { return getDatetime(getColumnIndex(columnName)); } @Override public void setDecimal(int idx, BigDecimal value) { set(idx, value); } @Override public BigDecimal getDecimal(int idx) { return getInternal(idx); } @Override public void setDecimal(String columnName, BigDecimal value) { setDecimal(getColumnIndex(columnName), value); } @Override public BigDecimal getDecimal(String columnName) { return getDecimal(getColumnIndex(columnName)); } @Override public void setString(int idx, String value) { set(idx, value); } @Override public String getString(int idx) { Object obj = values[idx]; if (obj == null) { return null; } if (obj instanceof byte []) { return bytesToString((byte []) obj); } return getInternal(idx); } @Override public void setString(String columnName, String value) { setString(getColumnIndex(columnName), value); } @Override public String getString(String columnName) { return getString(getColumnIndex(columnName)); } @Override public void setString(int idx, byte[] value) { set(idx, value); } @Override public void setString(String columnName, byte[] value) { setString(getColumnIndex(columnName), value); } @Override public byte[] getBytes(int idx) { Object obj = values[idx]; if (obj == null) { return null; } if (obj instanceof byte[]) { return (byte[]) obj; } else if (obj instanceof String) { return stringToBytes((String) obj); } else if (obj instanceof Binary) { return ((Binary) obj).data(); } else if (obj instanceof AbstractChar) { return stringToBytes(((AbstractChar)obj).getValue()); } else { throw new RuntimeException("Does not support getBytes for type other than String/Binary/Char/VarChar, sees " + obj.getClass()); } } @Override public byte[] getBytes(String columnName) { return getBytes(getColumnIndex(columnName)); } public void setBinary(int idx, Binary value) { set(idx, value); } public void setBinary(String columnName, Binary value) { setBinary(getColumnIndex(columnName), value); } public Binary getBinary(int idx) { return getInternal(idx); } public Binary getBinary(String columnName) { return getBinary(getColumnIndex(columnName)); } @Override public void set(Object[] values) { if (values == null || columns.length != values.length) { throw new IllegalArgumentException(); } for (int i = 0; i < values.length; ++i) { set(i, values[i]); } } @Override public Object[] toArray() { return values; } private int getColumnIndex(String name) { Integer idx = nameMap.get(name); if (idx == null) { throw new IllegalArgumentException("No such column:" + name); } return idx; } public void clear() { for (int i = 0; i < values.length; i++) { values[i] = null; } } public void setArray(String columnName, List list) { setArray(getColumnIndex(columnName), list); } /** * 设置对应索引列的值,该列是 Array 类型 * * @param idx * 列索引 * @param list 注意,String 将被转换为 byte[] 进行存储,转换过程使用 UTF-8 编码 * 列值 */ public void setArray(int idx, List list) { set(idx, list); } /** * 设置对应索引列的值,该列是 Map 类型 * * @param idx * 列索引 * @param map Map 中 String 类型的 key/value 将被转换为 byte[] 存储,转换过程使用 UTF-8 编码 * 列值 */ public void setMap(int idx, Map map) { set(idx, map); } public void setMap(String columnName, Map map) { setMap(getColumnIndex(columnName), map); } public <T> List<T> getArray(Class<T> className, String columnName) { return getArray(className, getColumnIndex(columnName)); } /** * 获取对应索引列的值,该列是 Array 类型 * * @param <T> * 返回 List 的元素类型,当类型为 String 时,内部存储的 byte[] 将使用 UTF-8 编码为 String 并返回 * @param className * 返回 List 的元素类型名称 * @param idx * 列索引值 * @return Array 类型的列值 */ public <T> List<T> getArray(Class<T> className, int idx) { List list = getArray(idx); if (list == null || list.isEmpty()) { return list; } List<T> newList = new ArrayList<T>(list.size()); for (Object obj : list) { if ((obj instanceof String) && (className == byte[].class)) { newList.add((T) stringToBytes((String) obj)); } else { newList.add(className.cast(obj)); } } return newList; } public List getArray(String columnName) { return getArray(getColumnIndex(columnName)); } public List getArray(int idx) { return getInternal(idx); } public <k, v> Map<k, v> getMap(Class<k> keyClass, Class<v> valueClass, String columnName) { return getMap(keyClass, valueClass, getColumnIndex(columnName)); } /** * 获取对应索引列的值,该列是 Map 类型 * * @param <k> * 待获取的 map 中 key 的类型,当类型为 String 时,内部存储的 byte[] 将使用 UTF-8 编码为 String 并返回 * @param <v> * 待获取的 map 中 value 的类型,当类型为 String 时,内部存储的 byte[] 将使用 UTF-8 编码为 String 并返回 * @param keyClass * 待获取的 map 中 key 的类型名称 * @param valueClass * 待获取的 map 中 value 的类型名称 * @param idx * 列索引值 * @return Map 类型的列值 */ public <k, v> Map<k, v> getMap(Class<k> keyClass, Class<v> valueClass, int idx) { Map map = getMap(idx); if (map == null || map.isEmpty()) { return map; } Map<k, v> newMap = new HashMap<k, v>(map.size(), 1.0f); Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); Object key = entry.getKey(); Object value = entry.getValue(); if (keyClass == byte [].class && key != null && key instanceof String) { key = stringToBytes((String) key); } if (valueClass == byte [].class && value != null && value instanceof String) { value = stringToBytes((String) value); } newMap.put(keyClass.cast(key), valueClass.cast(value)); } return newMap; } public Map getMap(String columnName) { return getMap(getColumnIndex(columnName)); } public Map getMap(int idx) { return getInternal(idx); } public void setChar(int idx, Char value) { set(idx, value); } public void setChar(String columnName, Char value) { setChar(getColumnIndex(columnName), value); } public Char getChar(int idx) { return getInternal(idx); } public Char getChar(String columnName) { return getChar(getColumnIndex(columnName)); } public void setVarchar(int idx, Varchar value) { set(idx, value); } public void setVarchar(String columnName, Varchar value) { setVarchar(getColumnIndex(columnName), value); } public Varchar getVarchar(int idx) { return getInternal(idx); } public Varchar getVarchar(String columnName) { return getVarchar(getColumnIndex(columnName)); } public void setDate(int idx, java.sql.Date value) { set(idx, value); } public java.sql.Date getDate(int idx) { return getInternal(idx); } public void setDate(String columnName, java.sql.Date value) { setDate(getColumnIndex(columnName), value); } public java.sql.Date getDate(String columnName) { return getDate(getColumnIndex(columnName)); } public void setTimestamp(int idx, Timestamp value) { set(idx, value); } public Timestamp getTimestamp(int idx) { return getInternal(idx); } public void setTimestamp(String columnName, Timestamp value) { setTimestamp(getColumnIndex(columnName), value); } public Timestamp getTimestamp(String columnName) { return getTimestamp(getColumnIndex(columnName)); } public void setFloat(int idx, Float value) { set(idx, value); } public void setFloat(String columnName, Float value) { setFloat(getColumnIndex(columnName), value); } public Float getFloat(int idx) { return getInternal(idx); } public Float getFloat(String columnName) { return getFloat(getColumnIndex(columnName)); } public void setInt(int idx, Integer value) { set(idx, value); } public void setInt(String columnName, Integer value) { setInt(getColumnIndex(columnName), value); } public Integer getInt(int idx) { return getInternal(idx); } public Integer getInt(String columnName) { return getInt(getColumnIndex(columnName)); } public void setTinyint(int idx, Byte value) { set(idx, value); } public void setTinyint(String columnName, Byte value) { setTinyint(getColumnIndex(columnName), value); } public Byte getTinyint(int idx) { return getInternal(idx); } public Byte getTinyint(String columnName) { return getTinyint(getColumnIndex(columnName)); } public void setSmallint(int idx, Short value) { set(idx, value); } public void setSmallint(String columnName, Short value) { setSmallint(getColumnIndex(columnName), value); } public Short getSmallint(int idx) { return getInternal(idx); } public Short getSmallint(String columnName) { return getSmallint(getColumnIndex(columnName)); } public void setStruct(int idx, Struct value) { set(idx, value); } public void setStruct(String columnName, Struct value) { setStruct(getColumnIndex(columnName), value); } public Struct getStruct(int idx) { return getInternal(idx); } public Struct getStruct(String columnName) { return getStruct(getColumnIndex(columnName)); } @Override public boolean isNull(int idx) { return values[idx] == null; } @Override public boolean isNull(String columnName) { return isNull(getColumnIndex(columnName)); } @Override public Record clone() { ArrayRecord record = new ArrayRecord(getColumns()); record.set(values); return record; } @SuppressWarnings({"unchecked"}) private <T> T getInternal(int idx) { if (values[idx] == null) { return null; } return (T) values[idx]; } /** * 使用默认 charset,将 byte array 转成 string * @param bytes * byte array * @return 字符串 */ static String bytesToString(byte[] bytes) { try { return new String(bytes, DEFAULT_CHARSET); } catch (UnsupportedEncodingException e) { throw new IllegalArgumentException(e.getMessage(), e); } } /** * 将 string 转成 byte array,使用默认 charset * @param string * 字符串 * @return byte array */ static byte[] stringToBytes(String string) { try { return string.getBytes(DEFAULT_CHARSET); } catch (UnsupportedEncodingException e) { throw new IllegalArgumentException(e.getMessage(), e); } } }