1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.arrow.gandiva.expression; 19 20 import org.apache.arrow.flatbuf.DateUnit; 21 import org.apache.arrow.flatbuf.IntervalUnit; 22 import org.apache.arrow.flatbuf.TimeUnit; 23 import org.apache.arrow.flatbuf.Type; 24 import org.apache.arrow.gandiva.exceptions.GandivaException; 25 import org.apache.arrow.gandiva.exceptions.UnsupportedTypeException; 26 import org.apache.arrow.gandiva.ipc.GandivaTypes; 27 import org.apache.arrow.util.Preconditions; 28 import org.apache.arrow.vector.types.pojo.ArrowType; 29 import org.apache.arrow.vector.types.pojo.Field; 30 import org.apache.arrow.vector.types.pojo.Schema; 31 32 /** 33 * Utility methods to convert between Arrow and Gandiva types. 34 */ 35 public class ArrowTypeHelper { ArrowTypeHelper()36 private ArrowTypeHelper() {} 37 38 static final int WIDTH_8 = 8; 39 static final int WIDTH_16 = 16; 40 static final int WIDTH_32 = 32; 41 static final int WIDTH_64 = 64; 42 initArrowTypeInt( ArrowType.Int intType, GandivaTypes.ExtGandivaType.Builder builder)43 private static void initArrowTypeInt( 44 ArrowType.Int intType, GandivaTypes.ExtGandivaType.Builder builder) throws GandivaException { 45 int width = intType.getBitWidth(); 46 47 if (intType.getIsSigned()) { 48 switch (width) { 49 case WIDTH_8: { 50 builder.setType(GandivaTypes.GandivaType.INT8); 51 return; 52 } 53 case WIDTH_16: { 54 builder.setType(GandivaTypes.GandivaType.INT16); 55 return; 56 } 57 case WIDTH_32: { 58 builder.setType(GandivaTypes.GandivaType.INT32); 59 return; 60 } 61 case WIDTH_64: { 62 builder.setType(GandivaTypes.GandivaType.INT64); 63 return; 64 } 65 default: { 66 throw new UnsupportedTypeException("Unsupported width for integer type"); 67 } 68 } 69 } 70 71 // unsigned int 72 switch (width) { 73 case WIDTH_8: { 74 builder.setType(GandivaTypes.GandivaType.UINT8); 75 return; 76 } 77 case WIDTH_16: { 78 builder.setType(GandivaTypes.GandivaType.UINT16); 79 return; 80 } 81 case WIDTH_32: { 82 builder.setType(GandivaTypes.GandivaType.UINT32); 83 return; 84 } 85 case WIDTH_64: { 86 builder.setType(GandivaTypes.GandivaType.UINT64); 87 return; 88 } 89 default: { 90 throw new UnsupportedTypeException("Unsupported width for integer type"); 91 } 92 } 93 } 94 initArrowTypeFloat( ArrowType.FloatingPoint floatType, GandivaTypes.ExtGandivaType.Builder builder)95 private static void initArrowTypeFloat( 96 ArrowType.FloatingPoint floatType, GandivaTypes.ExtGandivaType.Builder builder) 97 throws GandivaException { 98 switch (floatType.getPrecision()) { 99 case HALF: { 100 builder.setType(GandivaTypes.GandivaType.HALF_FLOAT); 101 break; 102 } 103 case SINGLE: { 104 builder.setType(GandivaTypes.GandivaType.FLOAT); 105 break; 106 } 107 case DOUBLE: { 108 builder.setType(GandivaTypes.GandivaType.DOUBLE); 109 break; 110 } 111 default: { 112 throw new UnsupportedTypeException("Floating point type with unknown precision"); 113 } 114 } 115 } 116 initArrowTypeDecimal(ArrowType.Decimal decimalType, GandivaTypes.ExtGandivaType.Builder builder)117 private static void initArrowTypeDecimal(ArrowType.Decimal decimalType, 118 GandivaTypes.ExtGandivaType.Builder builder) { 119 Preconditions.checkArgument(decimalType.getPrecision() > 0 && 120 decimalType.getPrecision() <= 38, "Gandiva only supports decimals of upto 38 " + 121 "precision. Input precision : " + decimalType.getPrecision()); 122 builder.setPrecision(decimalType.getPrecision()); 123 builder.setScale(decimalType.getScale()); 124 builder.setType(GandivaTypes.GandivaType.DECIMAL); 125 } 126 initArrowTypeDate(ArrowType.Date dateType, GandivaTypes.ExtGandivaType.Builder builder)127 private static void initArrowTypeDate(ArrowType.Date dateType, 128 GandivaTypes.ExtGandivaType.Builder builder) { 129 short dateUnit = dateType.getUnit().getFlatbufID(); 130 switch (dateUnit) { 131 case DateUnit.DAY: { 132 builder.setType(GandivaTypes.GandivaType.DATE32); 133 break; 134 } 135 case DateUnit.MILLISECOND: { 136 builder.setType(GandivaTypes.GandivaType.DATE64); 137 break; 138 } 139 default: { 140 // not supported 141 break; 142 } 143 } 144 } 145 initArrowTypeTime(ArrowType.Time timeType, GandivaTypes.ExtGandivaType.Builder builder)146 private static void initArrowTypeTime(ArrowType.Time timeType, 147 GandivaTypes.ExtGandivaType.Builder builder) { 148 short timeUnit = timeType.getUnit().getFlatbufID(); 149 switch (timeUnit) { 150 case TimeUnit.SECOND: { 151 builder.setType(GandivaTypes.GandivaType.TIME32); 152 builder.setTimeUnit(GandivaTypes.TimeUnit.SEC); 153 break; 154 } 155 case TimeUnit.MILLISECOND: { 156 builder.setType(GandivaTypes.GandivaType.TIME32); 157 builder.setTimeUnit(GandivaTypes.TimeUnit.MILLISEC); 158 break; 159 } 160 case TimeUnit.MICROSECOND: { 161 builder.setType(GandivaTypes.GandivaType.TIME64); 162 builder.setTimeUnit(GandivaTypes.TimeUnit.MICROSEC); 163 break; 164 } 165 case TimeUnit.NANOSECOND: { 166 builder.setType(GandivaTypes.GandivaType.TIME64); 167 builder.setTimeUnit(GandivaTypes.TimeUnit.NANOSEC); 168 break; 169 } 170 default: { 171 // not supported 172 } 173 } 174 } 175 initArrowTypeTimestamp(ArrowType.Timestamp timestampType, GandivaTypes.ExtGandivaType.Builder builder)176 private static void initArrowTypeTimestamp(ArrowType.Timestamp timestampType, 177 GandivaTypes.ExtGandivaType.Builder builder) { 178 short timeUnit = timestampType.getUnit().getFlatbufID(); 179 switch (timeUnit) { 180 case TimeUnit.SECOND: { 181 builder.setType(GandivaTypes.GandivaType.TIMESTAMP); 182 builder.setTimeUnit(GandivaTypes.TimeUnit.SEC); 183 break; 184 } 185 case TimeUnit.MILLISECOND: { 186 builder.setType(GandivaTypes.GandivaType.TIMESTAMP); 187 builder.setTimeUnit(GandivaTypes.TimeUnit.MILLISEC); 188 break; 189 } 190 case TimeUnit.MICROSECOND: { 191 builder.setType(GandivaTypes.GandivaType.TIMESTAMP); 192 builder.setTimeUnit(GandivaTypes.TimeUnit.MICROSEC); 193 break; 194 } 195 case TimeUnit.NANOSECOND: { 196 builder.setType(GandivaTypes.GandivaType.TIMESTAMP); 197 builder.setTimeUnit(GandivaTypes.TimeUnit.NANOSEC); 198 break; 199 } 200 default: { 201 // not supported 202 } 203 } 204 } 205 initArrowTypeInterval(ArrowType.Interval interval, GandivaTypes.ExtGandivaType.Builder builder)206 private static void initArrowTypeInterval(ArrowType.Interval interval, 207 GandivaTypes.ExtGandivaType.Builder builder) { 208 short intervalUnit = interval.getUnit().getFlatbufID(); 209 switch (intervalUnit) { 210 case IntervalUnit.YEAR_MONTH: { 211 builder.setType(GandivaTypes.GandivaType.INTERVAL); 212 builder.setIntervalType(GandivaTypes.IntervalType.YEAR_MONTH); 213 break; 214 } 215 case IntervalUnit.DAY_TIME: { 216 builder.setType(GandivaTypes.GandivaType.INTERVAL); 217 builder.setIntervalType(GandivaTypes.IntervalType.DAY_TIME); 218 break; 219 } 220 default: { 221 // not supported 222 } 223 } 224 } 225 226 /** 227 * Converts an arrow type into a protobuf. 228 * 229 * @param arrowType Arrow type to be converted 230 * @return Protobuf representing the arrow type 231 */ arrowTypeToProtobuf(ArrowType arrowType)232 public static GandivaTypes.ExtGandivaType arrowTypeToProtobuf(ArrowType arrowType) 233 throws GandivaException { 234 GandivaTypes.ExtGandivaType.Builder builder = GandivaTypes.ExtGandivaType.newBuilder(); 235 236 byte typeId = arrowType.getTypeID().getFlatbufID(); 237 switch (typeId) { 238 case Type.NONE: { // 0 239 builder.setType(GandivaTypes.GandivaType.NONE); 240 break; 241 } 242 case Type.Null: { // 1 243 // TODO: Need to handle this later 244 break; 245 } 246 case Type.Int: { // 2 247 ArrowTypeHelper.initArrowTypeInt((ArrowType.Int) arrowType, builder); 248 break; 249 } 250 case Type.FloatingPoint: { // 3 251 ArrowTypeHelper.initArrowTypeFloat((ArrowType.FloatingPoint) arrowType, builder); 252 break; 253 } 254 case Type.Binary: { // 4 255 builder.setType(GandivaTypes.GandivaType.BINARY); 256 break; 257 } 258 case Type.Utf8: { // 5 259 builder.setType(GandivaTypes.GandivaType.UTF8); 260 break; 261 } 262 case Type.Bool: { // 6 263 builder.setType(GandivaTypes.GandivaType.BOOL); 264 break; 265 } 266 case Type.Decimal: { // 7 267 ArrowTypeHelper.initArrowTypeDecimal((ArrowType.Decimal) arrowType, builder); 268 break; 269 } 270 case Type.Date: { // 8 271 ArrowTypeHelper.initArrowTypeDate((ArrowType.Date) arrowType, builder); 272 break; 273 } 274 case Type.Time: { // 9 275 ArrowTypeHelper.initArrowTypeTime((ArrowType.Time) arrowType, builder); 276 break; 277 } 278 case Type.Timestamp: { // 10 279 ArrowTypeHelper.initArrowTypeTimestamp((ArrowType.Timestamp) arrowType, builder); 280 break; 281 } 282 case Type.Interval: { // 11 283 ArrowTypeHelper.initArrowTypeInterval((ArrowType.Interval) arrowType, builder); 284 break; 285 } 286 case Type.List: { // 12 287 break; 288 } 289 case Type.Struct_: { // 13 290 break; 291 } 292 case Type.Union: { // 14 293 break; 294 } 295 case Type.FixedSizeBinary: { // 15 296 break; 297 } 298 case Type.FixedSizeList: { // 16 299 break; 300 } 301 case Type.Map: { // 17 302 break; 303 } 304 default: { 305 break; 306 } 307 } 308 309 if (!builder.hasType()) { 310 // type has not been set 311 // throw an exception 312 throw new UnsupportedTypeException("Unsupported type " + arrowType.toString()); 313 } 314 315 return builder.build(); 316 } 317 318 /** 319 * Converts an arrow field object to a protobuf. 320 * @param field Arrow field to be converted 321 * @return Protobuf representing the arrow field 322 */ arrowFieldToProtobuf(Field field)323 public static GandivaTypes.Field arrowFieldToProtobuf(Field field) throws GandivaException { 324 GandivaTypes.Field.Builder builder = GandivaTypes.Field.newBuilder(); 325 builder.setName(field.getName()); 326 builder.setType(ArrowTypeHelper.arrowTypeToProtobuf(field.getType())); 327 builder.setNullable(field.isNullable()); 328 329 for (Field child : field.getChildren()) { 330 builder.addChildren(ArrowTypeHelper.arrowFieldToProtobuf(child)); 331 } 332 333 return builder.build(); 334 } 335 336 /** 337 * Converts a schema object to a protobuf. 338 * @param schema Schema object to be converted 339 * @return Protobuf representing a schema object 340 */ arrowSchemaToProtobuf(Schema schema)341 public static GandivaTypes.Schema arrowSchemaToProtobuf(Schema schema) throws GandivaException { 342 GandivaTypes.Schema.Builder builder = GandivaTypes.Schema.newBuilder(); 343 344 for (Field field : schema.getFields()) { 345 builder.addColumns(ArrowTypeHelper.arrowFieldToProtobuf(field)); 346 } 347 348 return builder.build(); 349 } 350 } 351