/** * Creates a string in a specfied character set. * * @param value String constant, must not be null * @param charsetName Name of the character set, may be null * @param collation Collation, may be null * @throws IllegalCharsetNameException If the given charset name is illegal * @throws UnsupportedCharsetException If no support for the named charset is available in this * instance of the Java virtual machine * @throws RuntimeException If the given value cannot be represented in the given charset */ public NlsString(String value, String charsetName, SqlCollation collation) { assert value != null; if (null != charsetName) { charsetName = charsetName.toUpperCase(); this.charsetName = charsetName; String javaCharsetName = SqlUtil.translateCharacterSetName(charsetName); if (javaCharsetName == null) { throw new UnsupportedCharsetException(charsetName); } this.charset = Charset.forName(javaCharsetName); CharsetEncoder encoder = charset.newEncoder(); // dry run to see if encoding hits any problems try { encoder.encode(CharBuffer.wrap(value)); } catch (CharacterCodingException ex) { throw RESOURCE.charsetEncoding(value, javaCharsetName).ex(); } } else { this.charsetName = null; this.charset = null; } this.collation = collation; this.value = value; }
/** * Creates a literal like X'ABAB' from an array of bytes. * * @param bytes Contents of binary literal * @param pos Parser position * @return Binary string literal */ public static SqlBinaryStringLiteral createBinaryString(byte[] bytes, SqlParserPos pos) { BitString bits; try { bits = BitString.createFromBytes(bytes); } catch (NumberFormatException e) { throw SqlUtil.newContextException(pos, RESOURCE.binaryLiteralInvalid()); } return new SqlBinaryStringLiteral(bits, pos); }
/** * Transforms this literal (which must be of type character) into a new one in which 4-digit * Unicode escape sequences have been replaced with the corresponding Unicode characters. * * @param unicodeEscapeChar escape character (e.g. backslash) for Unicode numeric sequences; 0 * implies no transformation * @return transformed literal */ public SqlLiteral unescapeUnicode(char unicodeEscapeChar) { if (unicodeEscapeChar == 0) { return this; } assert SqlTypeUtil.inCharFamily(getTypeName()); NlsString ns = (NlsString) value; String s = ns.getValue(); StringBuilder sb = new StringBuilder(); int n = s.length(); for (int i = 0; i < n; ++i) { char c = s.charAt(i); if (c == unicodeEscapeChar) { if (n > (i + 1)) { if (s.charAt(i + 1) == unicodeEscapeChar) { sb.append(unicodeEscapeChar); ++i; continue; } } if ((i + 5) > n) { throw SqlUtil.newContextException( getParserPosition(), RESOURCE.unicodeEscapeMalformed(i)); } final String u = s.substring(i + 1, i + 5); final int v; try { v = Integer.parseInt(u, 16); } catch (NumberFormatException ex) { throw SqlUtil.newContextException( getParserPosition(), RESOURCE.unicodeEscapeMalformed(i)); } sb.append((char) (v & 0xFFFF)); // skip hexits i += 4; } else { sb.append(c); } } ns = new NlsString(sb.toString(), ns.getCharsetName(), ns.getCollation()); return new SqlCharStringLiteral(ns, getParserPosition()); }
/** @pre SqlTypeUtil.sameNamedType(argTypes[0], (argTypes[1])) */ public RelDataType inferReturnType(SqlOperatorBinding opBinding) { final RelDataType argType0 = opBinding.getOperandType(0); final RelDataType argType1 = opBinding.getOperandType(1); if (!(SqlTypeUtil.inCharOrBinaryFamilies(argType0) && SqlTypeUtil.inCharOrBinaryFamilies(argType1))) { Util.pre( SqlTypeUtil.sameNamedType(argType0, argType1), "SqlTypeUtil.sameNamedType(argTypes[0], argTypes[1])"); } SqlCollation pickedCollation = null; if (SqlTypeUtil.inCharFamily(argType0)) { if (!SqlTypeUtil.isCharTypeComparable(opBinding.collectOperandTypes().subList(0, 2))) { throw opBinding.newError( RESOURCE.typeNotComparable( argType0.getFullTypeString(), argType1.getFullTypeString())); } pickedCollation = SqlCollation.getCoercibilityDyadicOperator( argType0.getCollation(), argType1.getCollation()); assert null != pickedCollation; } // Determine whether result is variable-length SqlTypeName typeName = argType0.getSqlTypeName(); if (SqlTypeUtil.isBoundedVariableWidth(argType1)) { typeName = argType1.getSqlTypeName(); } RelDataType ret; ret = opBinding .getTypeFactory() .createSqlType(typeName, argType0.getPrecision() + argType1.getPrecision()); if (null != pickedCollation) { RelDataType pickedType; if (argType0.getCollation().equals(pickedCollation)) { pickedType = argType0; } else if (argType1.getCollation().equals(pickedCollation)) { pickedType = argType1; } else { throw Util.newInternal("should never come here"); } ret = opBinding .getTypeFactory() .createTypeWithCharsetAndCollation( ret, pickedType.getCharset(), pickedType.getCollation()); } return ret; }
/** * Returns the long value of this literal. * * @param exact Whether the value has to be exact. If true, and the literal is a fraction (e.g. * 3.14), throws. If false, discards the fractional part of the value. * @return Long value of this literal */ public long longValue(boolean exact) { switch (typeName) { case DECIMAL: case DOUBLE: BigDecimal bd = (BigDecimal) value; if (exact) { try { return bd.longValueExact(); } catch (ArithmeticException e) { throw SqlUtil.newContextException( getParserPosition(), RESOURCE.numberLiteralOutOfRange(bd.toString())); } } else { return bd.longValue(); } default: throw Util.unexpected(typeName); } }