@SqlNullable @Description("extract query parameter from url") @ScalarFunction @LiteralParameters({"x", "y"}) @SqlType("varchar(x)") public static Slice urlExtractParameter( @SqlType("varchar(x)") Slice url, @SqlType("varchar(y)") Slice parameterName) { URI uri = parseUrl(url); if ((uri == null) || (uri.getQuery() == null)) { return null; } Slice query = slice(uri.getQuery()); String parameter = parameterName.toStringUtf8(); Iterable<String> queryArgs = QUERY_SPLITTER.split(query.toStringUtf8()); for (String queryArg : queryArgs) { Iterator<String> arg = ARG_SPLITTER.split(queryArg).iterator(); if (arg.next().equals(parameter)) { if (arg.hasNext()) { return utf8Slice(arg.next()); } // first matched key is empty return Slices.EMPTY_SLICE; } } // no key matched return null; }
@ScalarFunction(value = "at_time_zone", hidden = true) @SqlType(TimestampWithTimeZoneType.class) public static long timestampAtTimeZone( @SqlType(TimestampWithTimeZoneType.class) long timestampWithTimeZone, @SqlType(VarcharType.class) Slice zoneId) { return packDateTimeWithZone(unpackMillisUtc(timestampWithTimeZone), zoneId.toStringUtf8()); }
@Nullable private static URI parseUrl(Slice url) { try { return new URI(url.toStringUtf8()); } catch (URISyntaxException e) { return null; } }
@Description("escape a string for use in URL query parameter names and values") @ScalarFunction @LiteralParameters({"x", "y"}) @Constraint(variable = "y", expression = "min(2147483647, x * 12)") @SqlType("varchar(y)") public static Slice urlEncode(@SqlType("varchar(x)") Slice value) { Escaper escaper = UrlEscapers.urlFormParameterEscaper(); return slice(escaper.escape(value.toStringUtf8())); }
private static Object nativeContainerToOrcValue(Type type, Object nativeValue) { if (nativeValue == null) { return null; } if (type instanceof DecimalType) { BigInteger unscaledValue; DecimalType decimalType = (DecimalType) type; if (decimalType.isShort()) { unscaledValue = BigInteger.valueOf((long) nativeValue); } else { unscaledValue = Decimals.decodeUnscaledValue((Slice) nativeValue); } return HiveDecimal.create(unscaledValue, decimalType.getScale()); } if (type.getJavaType() == boolean.class) { return nativeValue; } if (type.getJavaType() == long.class) { return nativeValue; } if (type.getJavaType() == double.class) { return nativeValue; } if (type.getJavaType() == Slice.class) { Slice slice = (Slice) nativeValue; return type instanceof VarcharType ? slice.toStringUtf8() : slice.getBytes(); } if (isArrayType(type)) { Block arrayBlock = (Block) nativeValue; Type elementType = type.getTypeParameters().get(0); List<Object> list = new ArrayList<>(); for (int i = 0; i < arrayBlock.getPositionCount(); i++) { list.add( nativeContainerToOrcValue( elementType, getNativeContainerValue(elementType, arrayBlock, i))); } return list; } if (isMapType(type)) { Block mapBlock = (Block) nativeValue; Type keyType = type.getTypeParameters().get(0); Type valueType = type.getTypeParameters().get(1); Map<Object, Object> map = new HashMap<>(); for (int i = 0; i < mapBlock.getPositionCount(); i += 2) { Object key = nativeContainerToOrcValue(keyType, getNativeContainerValue(keyType, mapBlock, i)); Object value = nativeContainerToOrcValue( valueType, getNativeContainerValue(valueType, mapBlock, i + 1)); map.put(key, value); } return map; } throw new PrestoException(INTERNAL_ERROR, "Unimplemented type: " + type); }
@Description("unescape a URL-encoded string") @ScalarFunction @LiteralParameters("x") @SqlType("varchar(x)") public static Slice urlDecode(@SqlType("varchar(x)") Slice value) { try { return slice(URLDecoder.decode(value.toStringUtf8(), UTF_8.name())); } catch (UnsupportedEncodingException e) { throw new AssertionError(e); } catch (IllegalArgumentException e) { throw new PrestoException(INVALID_FUNCTION_ARGUMENT, e); } }
public static Expression toExpression(Object object, Type type) { requireNonNull(type, "type is null"); if (object instanceof Expression) { return (Expression) object; } if (object == null) { if (type.equals(UNKNOWN)) { return new NullLiteral(); } return new Cast(new NullLiteral(), type.getTypeSignature().toString(), false, true); } checkArgument( Primitives.wrap(type.getJavaType()).isInstance(object), "object.getClass (%s) and type.getJavaType (%s) do not agree", object.getClass(), type.getJavaType()); if (type.equals(BIGINT)) { return new LongLiteral(object.toString()); } if (type.equals(DOUBLE)) { Double value = (Double) object; // WARNING: the ORC predicate code depends on NaN and infinity not appearing in a tuple // domain, so // if you remove this, you will need to update the TupleDomainOrcPredicate if (value.isNaN()) { return new FunctionCall(new QualifiedName("nan"), ImmutableList.<Expression>of()); } else if (value.equals(Double.NEGATIVE_INFINITY)) { return ArithmeticUnaryExpression.negative( new FunctionCall(new QualifiedName("infinity"), ImmutableList.<Expression>of())); } else if (value.equals(Double.POSITIVE_INFINITY)) { return new FunctionCall(new QualifiedName("infinity"), ImmutableList.<Expression>of()); } else { return new DoubleLiteral(object.toString()); } } if (type instanceof VarcharType) { if (object instanceof String) { object = Slices.utf8Slice((String) object); } if (object instanceof Slice) { Slice value = (Slice) object; int length = SliceUtf8.countCodePoints(value); if (length == ((VarcharType) type).getLength()) { return new StringLiteral(value.toStringUtf8()); } return new Cast( new StringLiteral(value.toStringUtf8()), type.getDisplayName(), false, true); } throw new IllegalArgumentException( "object must be instance of Slice or String when type is VARCHAR"); } if (type.equals(BOOLEAN)) { return new BooleanLiteral(object.toString()); } if (object instanceof Block) { SliceOutput output = new DynamicSliceOutput(((Block) object).getSizeInBytes()); BlockSerdeUtil.writeBlock(output, (Block) object); object = output.slice(); // This if condition will evaluate to true: object instanceof Slice && !type.equals(VARCHAR) } if (object instanceof Slice) { // HACK: we need to serialize VARBINARY in a format that can be embedded in an expression to // be // able to encode it in the plan that gets sent to workers. // We do this by transforming the in-memory varbinary into a call to // from_base64(<base64-encoded value>) FunctionCall fromBase64 = new FunctionCall( new QualifiedName("from_base64"), ImmutableList.of( new StringLiteral(VarbinaryFunctions.toBase64((Slice) object).toStringUtf8()))); Signature signature = FunctionRegistry.getMagicLiteralFunctionSignature(type); return new FunctionCall(new QualifiedName(signature.getName()), ImmutableList.of(fromBase64)); } Signature signature = FunctionRegistry.getMagicLiteralFunctionSignature(type); Expression rawLiteral = toExpression(object, FunctionRegistry.typeForMagicLiteral(type)); return new FunctionCall(new QualifiedName(signature.getName()), ImmutableList.of(rawLiteral)); }