如果您对com.facebook.presto.sql.tree.TimestampLiteral的实例源码感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解com.facebook.presto
如果您对com.facebook.presto.sql.tree.TimestampLiteral的实例源码感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解com.facebook.presto.sql.tree.TimestampLiteral的实例源码的各种细节,此外还有关于com.facebook.presto.spi.type.TimestampType的实例源码、com.facebook.presto.sql.tree.AliasedRelation的实例源码、com.facebook.presto.sql.tree.BooleanLiteral的实例源码、com.facebook.presto.sql.tree.Cast的实例源码的实用技巧。
本文目录一览:- com.facebook.presto.sql.tree.TimestampLiteral的实例源码
- com.facebook.presto.spi.type.TimestampType的实例源码
- com.facebook.presto.sql.tree.AliasedRelation的实例源码
- com.facebook.presto.sql.tree.BooleanLiteral的实例源码
- com.facebook.presto.sql.tree.Cast的实例源码
com.facebook.presto.sql.tree.TimestampLiteral的实例源码
@Override protected Type visitTimestampLiteral(TimestampLiteral node,StackableAstVisitorContext<AnalysisContext> context) { try { parseTimestampLiteral(session.getTimeZoneKey(),node.getValue()); } catch (Exception e) { throw new SemanticException(INVALID_LIteraL,node,"'%s' is not a valid timestamp literal",node.getValue()); } Type type; if (timestampHasTimeZone(node.getValue())) { type = TIMESTAMP_WITH_TIME_ZONE; } else { type = TIMESTAMP; } expressionTypes.put(node,type); return type; }
private Object getobject(Literal literal){ Object value = null; if(literal instanceof LongLiteral) value = ((LongLiteral)literal).getValue(); else if(literal instanceof BooleanLiteral) value = ((BooleanLiteral)literal).getValue(); else if(literal instanceof DoubleLiteral) value = ((DoubleLiteral)literal).getValue(); else if(literal instanceof StringLiteral) value = ((StringLiteral)literal).getValue(); else if(literal instanceof TimeLiteral) value = ((TimeLiteral)literal).getValue(); else if(literal instanceof TimestampLiteral) value = ((TimestampLiteral)literal).getValue(); return value; }
@Override protected RowExpression visitTimestampLiteral(TimestampLiteral node,Void context) { long value; if (types.get(node).equals(TIMESTAMP_WITH_TIME_ZONE)) { value = parseTimestampWithTimeZone(timeZoneKey,node.getValue()); } else { // parse in time zone of client value = parseTimestampWithoutTimeZone(timeZoneKey,node.getValue()); } return constant(value,types.get(node)); }
@Override protected Long visitTimestampLiteral(TimestampLiteral node,ConnectorSession session) { try { return parseTimestampLiteral(session.getTimeZoneKey(),node.getValue()); } }
@Override public Node visitTypeConstructor(sqlbaseParser.TypeConstructorContext context) { String type = context.identifier().getText(); String value = unquote(context.STRING().getText()); if (type.equalsIgnoreCase("time")) { return new TimeLiteral(getLocation(context),value); } if (type.equalsIgnoreCase("timestamp")) { return new TimestampLiteral(getLocation(context),value); } return new GenericLiteral(getLocation(context),type,value); }
@Test public void testLiterals() throws Exception { assertExpression("TIME" + " 'abc'",new TimeLiteral("abc")); assertExpression("TIMESTAMP" + " 'abc'",new TimestampLiteral("abc")); assertExpression("INTERVAL '33' day",new IntervalLiteral("33",Sign.POSITIVE,IntervalField.DAY,Optional.empty())); assertExpression("INTERVAL '33' day to second",Optional.of(IntervalField.SECOND))); }
@Override protected String visitTimestampLiteral(TimestampLiteral node,Void context) { return "TIMESTAMP '" + node.getValue() + "'"; }
@Override protected String visitTimestampLiteral(TimestampLiteral node,StackableAstVisitorContext<Integer> indent) { return "TIMESTAMP '" + node.getValue() + "'"; }
@Override protected String visitTimestampLiteral(TimestampLiteral node,Boolean unmangleNames) { return "TIMESTAMP '" + node.getValue() + "'"; }
@Override protected String visitTimestampLiteral(TimestampLiteral node,Boolean unmangleNames) { return "TIMESTAMP '" + node.getValue() + "'"; }
com.facebook.presto.spi.type.TimestampType的实例源码
public static JDBCType jdbcType(Type type) { if (type.equals(BooleanType.BOOLEAN)) { return JDBCType.BOOLEAN; } if (type.equals(BigintType.BIGINT) || type.equals(TimestampType.TIMESTAMP)) { return JDBCType.BIGINT; } if (type.equals(DoubleType.DOUBLE)) { return JDBCType.DOUBLE; } if (type.equals(DateType.DATE)) { return JDBCType.INTEGER; } if (type.equals(VarcharType.VARCHAR)) { return JDBCType.VARBINARY; } return null; }
private static ColumnStats doComputeColumnStats(OrcReader orcReader,long columnId,Type type) throws IOException { int columnIndex = columnIndex(orcReader.getColumnNames(),columnId); OrcRecordReader reader = orcReader.createRecordReader(ImmutableMap.of(columnIndex,type),OrcPredicate.TRUE,UTC,new AggregatedMemoryContext()); if (type.equals(BooleanType.BOOLEAN)) { return indexBoolean(type,reader,columnIndex,columnId); } if (type.equals(BigintType.BIGINT) || type.equals(DateType.DATE) || type.equals(TimestampType.TIMESTAMP)) { return indexLong(type,columnId); } if (type.equals(DoubleType.DOUBLE)) { return indexDouble(type,columnId); } if (type.equals(VarcharType.VARCHAR)) { return indexString(type,columnId); } return null; }
@Test public void testAddFieldToTimestamp() { assertFunction("date_add('millisecond',3," + TIMESTAMP_LIteraL + ")",TimestampType.TIMESTAMP,toTimestamp(TIMESTAMP.plusMillis(3))); assertFunction("date_add('second',toTimestamp(TIMESTAMP.plusSeconds(3))); assertFunction("date_add('minute',toTimestamp(TIMESTAMP.plusMinutes(3))); assertFunction("date_add('hour',toTimestamp(TIMESTAMP.plusHours(3))); assertFunction("date_add('day',toTimestamp(TIMESTAMP.plusDays(3))); assertFunction("date_add('week',toTimestamp(TIMESTAMP.plusWeeks(3))); assertFunction("date_add('month',toTimestamp(TIMESTAMP.plusMonths(3))); assertFunction("date_add('quarter',toTimestamp(TIMESTAMP.plusMonths(3 * 3))); assertFunction("date_add('year',toTimestamp(TIMESTAMP.plusYears(3))); assertFunction("date_add('millisecond'," + WEIRD_TIMESTAMP_LIteraL + ")",TIMESTAMP_WITH_TIME_ZONE,toTimestampWithTimeZone(WEIRD_TIMESTAMP.plusMillis(3))); assertFunction("date_add('second',toTimestampWithTimeZone(WEIRD_TIMESTAMP.plusSeconds(3))); assertFunction("date_add('minute',toTimestampWithTimeZone(WEIRD_TIMESTAMP.plusMinutes(3))); assertFunction("date_add('hour',toTimestampWithTimeZone(WEIRD_TIMESTAMP.plusHours(3))); assertFunction("date_add('day',toTimestampWithTimeZone(WEIRD_TIMESTAMP.plusDays(3))); assertFunction("date_add('week',toTimestampWithTimeZone(WEIRD_TIMESTAMP.plusWeeks(3))); assertFunction("date_add('month',toTimestampWithTimeZone(WEIRD_TIMESTAMP.plusMonths(3))); assertFunction("date_add('quarter',toTimestampWithTimeZone(WEIRD_TIMESTAMP.plusMonths(3 * 3))); assertFunction("date_add('year',toTimestampWithTimeZone(WEIRD_TIMESTAMP.plusYears(3))); }
@Override public long getLong(int field) { checkState(!closed,"cursor is closed"); try { Type type = getType(field); if (type.equals(BigintType.BIGINT)) { return resultSet.getLong(field + 1); } if (type.equals(DateType.DATE)) { // JDBC returns a date using a timestamp at midnight in the JVM timezone long localMillis = resultSet.getDate(field + 1).getTime(); // Convert it to a midnight in UTC long utcMillis = ISOChronology.getInstance().getZone().getMillisKeepLocal(UTC,localMillis); // convert to days return TimeUnit.MILLISECONDS.toDays(utcMillis); } if (type.equals(TimeType.TIME)) { Time time = resultSet.getTime(field + 1); return UTC_CHRONOLOGY.millisOfDay().get(time.getTime()); } if (type.equals(TimestampType.TIMESTAMP)) { Timestamp timestamp = resultSet.getTimestamp(field + 1); return timestamp.getTime(); } throw new PrestoException(INTERNAL_ERROR,"Unhandled type for long: " + type.getTypeSignature()); } catch (sqlException e) { throw handlesqlException(e); } }
@Test public void testFromUnixTime() { DateTime dateTime = new DateTime(2001,1,22,4,5,DATE_TIME_ZONE); double seconds = dateTime.getMillis() / 1000.0; assertFunction("from_unixtime(" + seconds + ")",toTimestamp(dateTime)); dateTime = new DateTime(2001,888,DATE_TIME_ZONE); seconds = dateTime.getMillis() / 1000.0; assertFunction("from_unixtime(" + seconds + ")",toTimestamp(dateTime)); }
@Test public void testLocale() { Locale locale = Locale.JAPAnesE; Session localeSession = testSessionBuilder() .setTimeZoneKey(TIME_ZONE_KEY) .setLocale(locale) .build(); FunctionAssertions localeAssertions = new FunctionAssertions(localeSession); String dateTimeLiteral = "TIMESTAMP '2001-01-09 13:04:05.321'"; localeAssertions.assertFunction("date_format(" + dateTimeLiteral + ",'%a')",VARCHAR,"火"); localeAssertions.assertFunction("date_format(" + dateTimeLiteral + ",'%W')","火曜日"); localeAssertions.assertFunction("date_format(" + dateTimeLiteral + ",'%p')","午後"); localeAssertions.assertFunction("date_format(" + dateTimeLiteral + ",'%r')","01:04:05 午後"); localeAssertions.assertFunction("date_format(" + dateTimeLiteral + ",'%b')","1"); localeAssertions.assertFunction("date_format(" + dateTimeLiteral + ",'%M')","1月"); localeAssertions.assertFunction("format_datetime(" + dateTimeLiteral + ",'EEE')","火"); localeAssertions.assertFunction("format_datetime(" + dateTimeLiteral + ",'EEEE')","火曜日"); localeAssertions.assertFunction("format_datetime(" + dateTimeLiteral + ",'a')","午後"); localeAssertions.assertFunction("format_datetime(" + dateTimeLiteral + ",'MMM')","1"); localeAssertions.assertFunction("format_datetime(" + dateTimeLiteral + ",'MMMM')","1月"); localeAssertions.assertFunction("date_parse('2013-05-17 12:35:10 午後','%Y-%m-%d %h:%i:%s %p')",toTimestamp(new DateTime(2013,17,12,35,10,DATE_TIME_ZONE),localeSession)); localeAssertions.assertFunction("date_parse('2013-05-17 12:35:10 午前',localeSession)); localeAssertions.assertFunction("parse_datetime('2013-05-17 12:35:10 午後','yyyy-MM-dd hh:mm:ss a')",toTimestampWithTimeZone(new DateTime(2013,DATE_TIME_ZONE))); localeAssertions.assertFunction("parse_datetime('2013-05-17 12:35:10 午前','yyyy-MM-dd hh:mm:ss aaa')",DATE_TIME_ZONE))); }
public static ObjectInspector getRowColumnInspector(Type type) { if (type.equals(BooleanType.BOOLEAN)) { return writableBooleanObjectInspector; } if (type.equals(BigintType.BIGINT)) { return writableLongObjectInspector; } if (type.equals(DoubleType.DOUBLE)) { return writableDoubleObjectInspector; } if (type.equals(VarcharType.VARCHAR)) { return writableStringObjectInspector; } if (type.equals(VarbinaryType.VARBINARY)) { return writableBinaryObjectInspector; } if (type.equals(DateType.DATE)) { return writableDateObjectInspector; } if (type.equals(TimestampType.TIMESTAMP)) { return writableTimestampObjectInspector; } if (isArrayType(type) || isMapType(type) || isRowType(type)) { return getJavaObjectInspector(type); } throw new IllegalArgumentException("unsupported type: " + type); }
@Override public void setField(Block block,int position) { long millisUtc = TimestampType.TIMESTAMP.getLong(block,position); value.setTime(millisUtc); rowInspector.setStructFieldData(row,field,value); }
private void assertTimestamp(String projection,int year,int month,int day,int hour,int minutes,int seconds) { FUNCTION_ASSERTIONS.assertFunction( projection,toTimestamp(new DateTime(year,month,day,hour,minutes,seconds,DATE_TIME_ZONE))); }
private Type getType(String typeName) { log.debug("Get type " + typeName); typeName = typeName.toLowerCase(); // check if type is varchar(xx) Pattern vcpattern = Pattern.compile("varchar\\(\\s*(\\d+)\\s*\\)"); Matcher vcmatcher = vcpattern.matcher(typeName); if (vcmatcher.find()) { String vlen = vcmatcher.group(1); if (!vlen.isEmpty()) { return VarcharType.createVarcharType(Integer.parseInt(vlen)); } return UnkNownType.UNKNowN; } // check if type is char(xx) Pattern cpattern = Pattern.compile("char\\(\\s*(\\d+)\\s*\\)"); Matcher cmatcher = cpattern.matcher(typeName); if (cmatcher.find()) { String clen = cmatcher.group(1); if (!clen.isEmpty()) { return CharType.createCharType(Integer.parseInt(clen)); } return UnkNownType.UNKNowN; } // check if type is decimal(precision,scale) Pattern dpattern = Pattern.compile("decimal\\((\\d+)\\s*,?\\s*(\\d*)\\)"); Matcher dmatcher = dpattern.matcher(typeName); if (dmatcher.find()) { String dprecision = dmatcher.group(1); String dscale = dmatcher.group(2); if (dprecision.isEmpty()) { return UnkNownType.UNKNowN; } if (dscale.isEmpty()) { return DecimalType.createDecimalType(Integer.parseInt(dprecision)); } return DecimalType.createDecimalType(Integer.parseInt(dprecision),Integer.parseInt(dscale)); } switch (typeName) { case "boolean": return BooleanType.BOOLEAN; case "tinyint": return tinyintType.tinyint; case "smallint": return SmallintType.SMALLINT; case "integer": return IntegerType.INTEGER; case "bigint": return BigintType.BIGINT; case "real": return RealType.REAL; case "double": return DoubleType.DOUBLE; case "date": return DateType.DATE; case "time": return TimeType.TIME; case "timestamp": return TimestampType.TIMESTAMP; default: return UnkNownType.UNKNowN; } }
@Test public void testLocalTimestamp() { functionAssertions.assertFunction("localtimestamp",toTimestamp(session.getStartTime())); }
@Test public void testTruncateTimestamp() { DateTime result = TIMESTAMP; result = result.withMillisOfSecond(0); assertFunction("date_trunc('second',toTimestamp(result)); result = result.withSecondOfMinute(0); assertFunction("date_trunc('minute',toTimestamp(result)); result = result.withMinuteOfHour(0); assertFunction("date_trunc('hour',toTimestamp(result)); result = result.withHourOfDay(0); assertFunction("date_trunc('day',toTimestamp(result)); result = result.withDayOfMonth(20); assertFunction("date_trunc('week',toTimestamp(result)); result = result.withDayOfMonth(1); assertFunction("date_trunc('month',toTimestamp(result)); result = result.withMonthOfYear(7); assertFunction("date_trunc('quarter',toTimestamp(result)); result = result.withMonthOfYear(1); assertFunction("date_trunc('year',toTimestamp(result)); result = WEIRD_TIMESTAMP; result = result.withMillisOfSecond(0); assertFunction("date_trunc('second',toTimestampWithTimeZone(result)); result = result.withSecondOfMinute(0); assertFunction("date_trunc('minute',toTimestampWithTimeZone(result)); result = result.withMinuteOfHour(0); assertFunction("date_trunc('hour',toTimestampWithTimeZone(result)); result = result.withHourOfDay(0); assertFunction("date_trunc('day',toTimestampWithTimeZone(result)); result = result.withDayOfMonth(20); assertFunction("date_trunc('week',toTimestampWithTimeZone(result)); result = result.withDayOfMonth(1); assertFunction("date_trunc('month',toTimestampWithTimeZone(result)); result = result.withMonthOfYear(7); assertFunction("date_trunc('quarter',toTimestampWithTimeZone(result)); result = result.withMonthOfYear(1); assertFunction("date_trunc('year',toTimestampWithTimeZone(result)); }
@Test public void testDateParse() { assertFunction("date_parse('2013','%Y')",DATE_TIME_ZONE))); assertFunction("date_parse('2013-05','%Y-%m')",DATE_TIME_ZONE))); assertFunction("date_parse('2013-05-17','%Y-%m-%d')",DATE_TIME_ZONE))); assertFunction("date_parse('2013-05-17 12:35:10','%Y-%m-%d %h:%i:%s')",DATE_TIME_ZONE))); assertFunction("date_parse('2013-05-17 12:35:10 PM',DATE_TIME_ZONE))); assertFunction("date_parse('2013-05-17 12:35:10 AM',DATE_TIME_ZONE))); assertFunction("date_parse('2013-05-17 00:35:10','%Y-%m-%d %H:%i:%s')",DATE_TIME_ZONE))); assertFunction("date_parse('2013-05-17 23:35:10',23,DATE_TIME_ZONE))); assertFunction("date_parse('abc 2013-05-17 fff 23:35:10 xyz','abc %Y-%m-%d fff %H:%i:%s xyz')",DATE_TIME_ZONE))); assertFunction("date_parse('2013 14','%Y %y')",toTimestamp(new DateTime(2014,DATE_TIME_ZONE))); assertFunction("date_parse('1998 53','%x %v')",toTimestamp(new DateTime(1998,28,DATE_TIME_ZONE))); assertFunction("date_parse('1.1','%s.%f')",toTimestamp(new DateTime(1970,100,DATE_TIME_ZONE))); assertFunction("date_parse('1.01',DATE_TIME_ZONE))); assertFunction("date_parse('1.2006',200,DATE_TIME_ZONE))); assertFunction("date_parse('0','%k')",DATE_TIME_ZONE))); }
public static ObjectInspector getJavaObjectInspector(Type type) { if (type.equals(BooleanType.BOOLEAN)) { return javaBooleanObjectInspector; } else if (type.equals(BigintType.BIGINT)) { return javaLongObjectInspector; } else if (type.equals(DoubleType.DOUBLE)) { return javaDoubleObjectInspector; } else if (type.equals(VarcharType.VARCHAR)) { return writableStringObjectInspector; } else if (type.equals(VarbinaryType.VARBINARY)) { return javaByteArrayObjectInspector; } else if (type.equals(DateType.DATE)) { return javaDateObjectInspector; } else if (type.equals(TimestampType.TIMESTAMP)) { return javaTimestampObjectInspector; } else if (isArrayType(type)) { return ObjectInspectorFactory.getStandardListObjectInspector(getJavaObjectInspector(type.getTypeParameters().get(0))); } else if (isMapType(type)) { ObjectInspector keyObjectInspector = getJavaObjectInspector(type.getTypeParameters().get(0)); ObjectInspector valueObjectInspector = getJavaObjectInspector(type.getTypeParameters().get(1)); return ObjectInspectorFactory.getStandardMapObjectInspector(keyObjectInspector,valueObjectInspector); } else if (isRowType(type)) { return ObjectInspectorFactory.getStandardStructObjectInspector( type.getTypeSignature().getParameters().stream() .map(parameter -> parameter.getNamedTypeSignature().getName()) .collect(toList()),type.getTypeParameters().stream() .map(HiveWriteUtils::getJavaObjectInspector) .collect(toList())); } throw new IllegalArgumentException("unsupported type: " + type); }
public static FieldSetter createFieldSetter(SettableStructObjectInspector rowInspector,Object row,StructField field,Type type) { if (type.equals(BooleanType.BOOLEAN)) { return new BooleanFieldSetter(rowInspector,row,field); } if (type.equals(BigintType.BIGINT)) { return new BigintFieldBuilder(rowInspector,field); } if (type.equals(DoubleType.DOUBLE)) { return new DoubleFieldSetter(rowInspector,field); } if (type.equals(VarcharType.VARCHAR)) { return new VarcharFieldSetter(rowInspector,field); } if (type.equals(VarbinaryType.VARBINARY)) { return new BinaryFieldSetter(rowInspector,field); } if (type.equals(DateType.DATE)) { return new DateFieldSetter(rowInspector,field); } if (type.equals(TimestampType.TIMESTAMP)) { return new TimestampFieldSetter(rowInspector,field); } if (isArrayType(type)) { return new ArrayFieldSetter(rowInspector,type.getTypeParameters().get(0)); } if (isMapType(type)) { return new MapFieldSetter(rowInspector,type.getTypeParameters().get(0),type.getTypeParameters().get(1)); } if (isRowType(type)) { return new RowFieldSetter(rowInspector,type.getTypeParameters()); } throw new IllegalArgumentException("unsupported type: " + type); }
private static void serializePrimitive(BlockBuilder builder,Object object,PrimitiveObjectInspector inspector) { requireNonNull(builder,"parent builder is null"); if (object == null) { builder.appendNull(); return; } switch (inspector.getPrimitiveCategory()) { case BOOLEAN: BooleanType.BOOLEAN.writeBoolean(builder,((BooleanObjectInspector) inspector).get(object)); return; case BYTE: BigintType.BIGINT.writeLong(builder,((ByteObjectInspector) inspector).get(object)); return; case SHORT: BigintType.BIGINT.writeLong(builder,((ShortObjectInspector) inspector).get(object)); return; case INT: BigintType.BIGINT.writeLong(builder,((IntObjectInspector) inspector).get(object)); return; case LONG: BigintType.BIGINT.writeLong(builder,((LongObjectInspector) inspector).get(object)); return; case FLOAT: DoubleType.DOUBLE.writeDouble(builder,((FloatObjectInspector) inspector).get(object)); return; case DOUBLE: DoubleType.DOUBLE.writeDouble(builder,((DoubleObjectInspector) inspector).get(object)); return; case STRING: VarcharType.VARCHAR.writeSlice(builder,Slices.utf8Slice(((StringObjectInspector) inspector).getPrimitiveJavaObject(object))); return; case DATE: DateType.DATE.writeLong(builder,formatDateAsLong(object,(DateObjectInspector) inspector)); return; case TIMESTAMP: TimestampType.TIMESTAMP.writeLong(builder,formatTimestampAsLong(object,(TimestampObjectInspector) inspector)); return; case BINARY: VARBINARY.writeSlice(builder,Slices.wrappedBuffer(((BinaryObjectInspector) inspector).getPrimitiveJavaObject(object))); return; } throw new RuntimeException("UnkNown primitive type: " + inspector.getPrimitiveCategory()); }
protected void checkCursor(RecordCursor cursor,List<TestColumn> testColumns,int numRows) throws IOException { for (int row = 0; row < numRows; row++) { assertTrue(cursor.advanceNextPosition()); for (int i = 0,testColumnsSize = testColumns.size(); i < testColumnsSize; i++) { TestColumn testColumn = testColumns.get(i); Object fieldFromCursor; Type type = HiveType.valueOf(testColumn.getobjectInspector().getTypeName()).getType(TYPE_MANAGER); if (cursor.isNull(i)) { fieldFromCursor = null; } else if (BOOLEAN.equals(type)) { fieldFromCursor = cursor.getBoolean(i); } else if (BIGINT.equals(type)) { fieldFromCursor = cursor.getLong(i); } else if (DOUBLE.equals(type)) { fieldFromCursor = cursor.getDouble(i); } else if (VARCHAR.equals(type)) { fieldFromCursor = cursor.getSlice(i); } else if (VARBINARY.equals(type)) { fieldFromCursor = cursor.getSlice(i); } else if (DateType.DATE.equals(type)) { fieldFromCursor = cursor.getLong(i); } else if (TimestampType.TIMESTAMP.equals(type)) { fieldFromCursor = cursor.getLong(i); } else if (isstructuralType(type)) { fieldFromCursor = cursor.getobject(i); } else { throw new RuntimeException("unkNown type"); } if (fieldFromCursor == null) { assertEquals(null,testColumn.getExpectedValue(),String.format("Expected null for column %s",testColumn.getName())); } else if (testColumn.getobjectInspector().getTypeName().equals("float") || testColumn.getobjectInspector().getTypeName().equals("double")) { assertEquals((double) fieldFromCursor,(double) testColumn.getExpectedValue(),EPSILON); } else if (testColumn.getobjectInspector().getCategory() == Category.PRIMITIVE) { assertEquals(fieldFromCursor,String.format("Wrong value for column %s",testColumn.getName())); } else { Block expected = (Block) testColumn.getExpectedValue(); Block actual = (Block) fieldFromCursor; assertBlockEquals(actual,expected,testColumn.getName())); } } } }
com.facebook.presto.sql.tree.AliasedRelation的实例源码
@Override protected List<QuerySource> visitRelation(Relation node,QueryState state){ if(node instanceof Join){ return node.accept(this,state); }else if( node instanceof SampledRelation){ state.addException("Sampled relations are not supported"); return null; }else if( node instanceof AliasedRelation){ AliasedRelation ar = (AliasedRelation)node; state.setkeyvalue("table_alias",ar.getAlias()); List<QuerySource> relations = ar.getRelation().accept(this,state); for(QuerySource rr : relations) rr.setAlias(ar.getAlias()); return relations; }else if( node instanceof QueryBody){ return node.accept(this,state); }else{ state.addException("Unable to parse node because it has an unkNown type :"+node.getClass()); return null; } }
@Override protected RelationType visitAliasedRelation(AliasedRelation relation,AnalysisContext context) { RelationType child = process(relation.getRelation(),context); // todo this check should be inside of TupleDescriptor.withAlias,but the exception needs the node object if (relation.getColumnNames() != null) { int totalColumns = child.getVisibleFieldCount(); if (totalColumns != relation.getColumnNames().size()) { throw new SemanticException(MISMATCHED_COLUMN_ALIASES,relation,"Column alias list has %s entries but '%s' has %s columns available",relation.getColumnNames().size(),relation.getAlias(),totalColumns); } } RelationType descriptor = child.withAlias(relation.getAlias(),relation.getColumnNames()); analysis.setoutputDescriptor(relation,descriptor); return descriptor; }
@Override protected Void visitAliasedRelation(AliasedRelation node,Integer indent) { process(node.getRelation(),indent); builder.append(' ') .append(formatName(node.getAlias())); appendaliasColumns(builder,node.getColumnNames()); return null; }
@Override protected RelationPlan visitAliasedRelation(AliasedRelation node,Void context) { RelationPlan subPlan = process(node.getRelation(),context); RelationType outputDescriptor = analysis.getoutputDescriptor(node); return new RelationPlan(subPlan.getRoot(),outputDescriptor,subPlan.getoutputSymbols(),subPlan.getSampleWeight()); }
@Override protected Void visitAliasedRelation(AliasedRelation node,indent); builder.append(' ') .append(node.getAlias()); appendaliasColumns(builder,node.getColumnNames()); return null; }
@Override public Node visitAliasedRelation(sqlbaseParser.AliasedRelationContext context) { Relation child = (Relation) visit(context.relationPrimary()); if (context.identifier() == null) { return child; } return new AliasedRelation(getLocation(context),child,context.identifier().getText(),getColumnAliases(context.columnAliases())); }
@Override protected Void visitAliasedRelation(AliasedRelation node,node.getColumnNames()); return null; }
public static Relation aliased(Relation relation,String alias,List<String> columnAliases) { return new AliasedRelation(relation,alias,columnAliases); }
com.facebook.presto.sql.tree.BooleanLiteral的实例源码
@Override public PhysicalOperation visitProject(ProjectNode node,LocalExecutionPlanContext context) { PlanNode sourceNode; Expression filterExpression; if (node.getSource() instanceof FilterNode) { FilterNode filterNode = (FilterNode) node.getSource(); sourceNode = filterNode.getSource(); filterExpression = filterNode.getPredicate(); } else { sourceNode = node.getSource(); filterExpression = BooleanLiteral.TRUE_LIteraL; } List<Symbol> outputSymbols = node.getoutputSymbols(); return visitScanFilterandProject(context,node.getId(),sourceNode,filterExpression,node.getAssignments(),outputSymbols); }
private PlanNode rewriteFilterSource(FilterNode filterNode,PlanNode source,Symbol rowNumberSymbol,int upperBound) { ExtractionResult extractionResult = fromPredicate(Metadata,session,filterNode.getPredicate(),types); TupleDomain<Symbol> tupleDomain = extractionResult.getTupleDomain(); if (!isEqualRange(tupleDomain,rowNumberSymbol,upperBound)) { return new FilterNode(filterNode.getId(),source,filterNode.getPredicate()); } // Remove the row number domain because it is absorbed into the node Map<Symbol,Domain> newDomains = tupleDomain.getDomains().get().entrySet().stream() .filter(entry -> !entry.getKey().equals(rowNumberSymbol)) .collect(toMap(Map.Entry::getKey,Map.Entry::getValue)); // Construct a new predicate TupleDomain<Symbol> newTupleDomain = TupleDomain.withColumnDomains(newDomains); Expression newPredicate = ExpressionUtils.combineConjuncts( extractionResult.getRemainingExpression(),toPredicate(newTupleDomain)); if (newPredicate.equals(BooleanLiteral.TRUE_LIteraL)) { return source; } return new FilterNode(filterNode.getId(),newPredicate); }
/** * Extracts the literal value from an expression (if expression is supported) * @param expression * @param state * @return a Long,Boolean,Double or String object */ private Object getLiteralValue(Expression expression,QueryState state){ if(expression instanceof LongLiteral) return ((LongLiteral)expression).getValue(); else if(expression instanceof BooleanLiteral) return ((BooleanLiteral)expression).getValue(); else if(expression instanceof DoubleLiteral) return ((DoubleLiteral)expression).getValue(); else if(expression instanceof StringLiteral) return ((StringLiteral)expression).getValue(); else if(expression instanceof ArithmeticUnaryExpression){ ArithmeticUnaryExpression unaryExp = (ArithmeticUnaryExpression)expression; Sign sign = unaryExp.getSign(); Number num = (Number)getLiteralValue(unaryExp.getValue(),state); if(sign == Sign.MINUS){ if(num instanceof Long) return -1*num.longValue(); else if(num instanceof Double) return -1*num.doubleValue(); else { state.addException("Unsupported numeric literal expression encountered : "+num.getClass()); return null; } } return num; } else if(expression instanceof FunctionCall){ FunctionCall fc = (FunctionCall)expression; if(fc.getName().toString().equals("Now")) return new Date(); else state.addException("Function '"+fc.getName()+"' is not supported"); }else if(expression instanceof CurrentTime){ CurrentTime ct = (CurrentTime)expression; if(ct.getType() == CurrentTime.Type.DATE) return new LocalDate().toDate(); else if(ct.getType() == CurrentTime.Type.TIME) return new Date(new LocalTime(DateTimeZone.UTC).getMillisOfDay()); else if(ct.getType() == CurrentTime.Type.TIMESTAMP) return new Date(); else if(ct.getType() == CurrentTime.Type.LOCALTIME) return new Date(new LocalTime(DateTimeZone.UTC).getMillisOfDay()); else if(ct.getType() == CurrentTime.Type.LOCALTIMESTAMP) return new Date(); else state.addException("CurrentTime function '"+ct.getType()+"' is not supported"); }else state.addException("Literal type "+expression.getClass().getSimpleName()+" is not supported"); return null; }
private Object getobject(Literal literal){ Object value = null; if(literal instanceof LongLiteral) value = ((LongLiteral)literal).getValue(); else if(literal instanceof BooleanLiteral) value = ((BooleanLiteral)literal).getValue(); else if(literal instanceof DoubleLiteral) value = ((DoubleLiteral)literal).getValue(); else if(literal instanceof StringLiteral) value = ((StringLiteral)literal).getValue(); else if(literal instanceof TimeLiteral) value = ((TimeLiteral)literal).getValue(); else if(literal instanceof TimestampLiteral) value = ((TimestampLiteral)literal).getValue(); return value; }
private Object getLiteralValue(Expression expression) throws sqlException{ if(expression instanceof LongLiteral) return ((LongLiteral)expression).getValue(); else if(expression instanceof BooleanLiteral) return ((BooleanLiteral)expression).getValue(); else if(expression instanceof DoubleLiteral) return ((DoubleLiteral)expression).getValue(); else if(expression instanceof StringLiteral) return ((StringLiteral)expression).getValue(); throw new sqlException("Unsupported literal type: "+expression); }
@Override public PlanNode visitFilter(FilterNode node,RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getSource()); Expression canonicalized = canonicalizeExpression(node.getPredicate()); if (canonicalized.equals(BooleanLiteral.TRUE_LIteraL)) { return source; } return new FilterNode(node.getId(),canonicalized); }
@Override public PlanNode optimize(PlanNode plan,Session session,Map<Symbol,Type> types,SymbolAllocator symbolAllocator,PlanNodeIdAllocator idAllocator) { requireNonNull(plan,"plan is null"); requireNonNull(session,"session is null"); requireNonNull(types,"types is null"); requireNonNull(idAllocator,"idAllocator is null"); return SimplePlanRewriter.rewriteWith(new Rewriter(symbolAllocator,idAllocator,Metadata,sqlParser,session),plan,BooleanLiteral.TRUE_LIteraL); }
@Override public PlanNode visitPlan(PlanNode node,RewriteContext<Expression> context) { PlanNode rewrittenNode = context.defaultRewrite(node,BooleanLiteral.TRUE_LIteraL); if (!context.get().equals(BooleanLiteral.TRUE_LIteraL)) { // Drop in a FilterNode b/c we cannot push our predicate down any further rewrittenNode = new FilterNode(idAllocator.getNextId(),rewrittenNode,context.get()); } return rewrittenNode; }
@Override public PlanNode visitTableScan(TableScanNode node,RewriteContext<Expression> context) { Expression predicate = simplifyExpression(context.get()); if (!BooleanLiteral.TRUE_LIteraL.equals(predicate)) { return new FilterNode(idAllocator.getNextId(),node,predicate); } return node; }
@Override public PlanNode visitTableScan(TableScanNode node,RewriteContext<Void> context) { if (node.getLayout().isPresent()) { return node; } return planTableScan(node,BooleanLiteral.TRUE_LIteraL); }
@Test public void testJoinPrecedence() { assertStatement("SELECT * FROM a CROSS JOIN b LEFT JOIN c ON true",simpleQuery( selectList(new AllColumns()),new Join( Join.Type.LEFT,new Join( Join.Type.CROSS,new Table(Qualifiedname.of("a")),new Table(Qualifiedname.of("b")),Optional.empty() ),new Table(Qualifiedname.of("c")),Optional.of(new JoinOn(BooleanLiteral.TRUE_LIteraL))))); assertStatement("SELECT * FROM a CROSS JOIN b NATURAL JOIN c CROSS JOIN d NATURAL JOIN e",new Join( Join.Type.INNER,new Join( Join.Type.INNER,new Join( Join.Type.CROSS,Optional.empty() ),Optional.of(new NaturalJoin())),new Table(Qualifiedname.of("d")),new Table(Qualifiedname.of("e")),Optional.of(new NaturalJoin())))); }
@Override protected String visitBooleanLiteral(BooleanLiteral node,Void context) { return String.valueOf(node.getValue()); }
@Override protected String visitBooleanLiteral(BooleanLiteral node,StackableAstVisitorContext<Integer> indent) { return String.valueOf(node.getValue()); }
@Override protected IComparison visitExpression(Expression node,QueryState state) { if( node instanceof LogicalBinaryExpression){ LogicalBinaryExpression boolExp = (LogicalBinaryExpression)node; IComparison left = boolExp.getLeft().accept(this,state); IComparison right = boolExp.getRight().accept(this,state); return new BooleanComparison(left,right,boolExp.getType() == Type.AND); }else if( node instanceof ComparisonExpression){ ComparisonExpression compareExp = (ComparisonExpression)node; Column column = new SelectParser().visitExpression(compareExp.getLeft(),state); Column leftCol = state.getheading().getColumnByLabel(column.getLabel()); if(leftCol == null){ state.addException("Having reference "+column+" not found in SELECT clause"); return null; } // right hand side is a concrete literal to compare with if(compareExp.getRight() instanceof Literal){ Object value; if(compareExp.getRight() instanceof LongLiteral) value = ((LongLiteral)compareExp.getRight()).getValue(); else if(compareExp.getRight() instanceof BooleanLiteral) value = ((BooleanLiteral)compareExp.getRight()).getValue(); else if(compareExp.getRight() instanceof DoubleLiteral) value = ((DoubleLiteral)compareExp.getRight()).getValue(); else if(compareExp.getRight() instanceof StringLiteral) value = ((StringLiteral)compareExp.getRight()).getValue(); else { state.addException("Unable to get value from "+compareExp.getRight()); return null; } return new SimpleComparison(leftCol,compareExp.getType(),(Number)value); // right hand side refers to another column } else if(compareExp.getRight() instanceof DereferenceExpression || compareExp.getRight() instanceof QualifiednameReference){ String col2; if(compareExp.getLeft() instanceof DereferenceExpression){ // parse columns like 'reference.field' col2 = SelectParser.visitDereferenceExpression((DereferenceExpression)compareExp.getRight()); }else{ col2 = ((QualifiednameReference)compareExp.getRight()).getName().toString(); } col2 = heading.findOriginal(state.originalsql(),col2,"having.+","\\W"); Column rightCol = state.getheading().getColumnByLabel(col2); if(rightCol == null){ state.addException("column "+col2+" not found in SELECT clause"); return null; } return new SimpleComparison(leftCol,rightCol); }else { // unkNown right hand side so state.addException("Unable to get value from "+compareExp.getRight()); return null; } }else if( node instanceof NotExpression){ state.addException("NOT is currently not supported,use '<>' instead"); }else{ state.addException("Unable to parse "+node+" ("+node.getClass().getName()+") is not a supported expression"); } return null; }
@Override protected RowExpression visitBooleanLiteral(BooleanLiteral node,Void context) { return constant(node.getValue(),BOOLEAN); }
@Override protected Object visitBooleanLiteral(BooleanLiteral node,ConnectorSession session) { return node.getValue(); }
@Override protected Object visitBooleanLiteral(BooleanLiteral node,Object context) { return node.equals(BooleanLiteral.TRUE_LIteraL); }
@Override public PlanWithProperties visitTableScan(TableScanNode node,Context context) { return planTableScan(node,BooleanLiteral.TRUE_LIteraL,context); }
private PlanWithProperties planTableScan(TableScanNode node,Expression predicate,Context context) { // don't include non-deterministic predicates Expression deterministicPredicate = stripNonDeterministicConjuncts(predicate); DomainTranslator.ExtractionResult decomposedPredicate = DomainTranslator.fromPredicate( Metadata,deterministicPredicate,symbolAllocator.getTypes()); TupleDomain<ColumnHandle> simplifiedConstraint = decomposedPredicate.getTupleDomain() .transform(node.getAssignments()::get) .intersect(node.getCurrentConstraint()); Map<ColumnHandle,Symbol> assignments = ImmutableBiMap.copyOf(node.getAssignments()).inverse(); Expression constraint = combineConjuncts( deterministicPredicate,DomainTranslator.toPredicate(node.getCurrentConstraint().transform(assignments::get))); // Layouts will be returned in order of the connector's preference List<TableLayoutResult> layouts = Metadata.getLayouts( session,node.getTable(),new Constraint<>(simplifiedConstraint,bindings -> !shouldPrune(constraint,bindings)),Optional.of(node.getoutputSymbols().stream() .map(node.getAssignments()::get) .collect(toImmutableSet()))); if (layouts.isEmpty()) { return new PlanWithProperties( new ValuesNode(idAllocator.getNextId(),node.getoutputSymbols(),ImmutableList.of()),ActualProperties.undistributed()); } // Filter out layouts that cannot supply all the required columns layouts = layouts.stream() .filter(layoutHasAllNeededOutputs(node)) .collect(toList()); checkState(!layouts.isEmpty(),"No usable layouts for %s",node); List<PlanWithProperties> possiblePlans = layouts.stream() .map(layout -> { TableScanNode tableScan = new TableScanNode( node.getId(),Optional.of(layout.getLayout().getHandle()),simplifiedConstraint.intersect(layout.getLayout().getPredicate()),Optional.ofNullable(node.getoriginalConstraint()).orElse(predicate)); PlanWithProperties result = new PlanWithProperties(tableScan,deriveProperties(tableScan,ImmutableList.of())); Expression resultingPredicate = combineConjuncts( DomainTranslator.toPredicate(layout.getUnenforcedConstraint().transform(assignments::get)),stripDeterministicConjuncts(predicate),decomposedPredicate.getRemainingExpression()); if (!BooleanLiteral.TRUE_LIteraL.equals(resultingPredicate)) { return withDerivedProperties( new FilterNode(idAllocator.getNextId(),result.getNode(),resultingPredicate),ImmutableList.of())); } return result; }) .collect(toList()); return pickPlan(possiblePlans,context); }
private PlanNode planTableScan(TableScanNode node,Expression predicate) { DomainTranslator.ExtractionResult decomposedPredicate = DomainTranslator.fromPredicate( Metadata,predicate,symbolAllocator.getTypes()); TupleDomain<ColumnHandle> simplifiedConstraint = decomposedPredicate.getTupleDomain() .transform(node.getAssignments()::get) .intersect(node.getCurrentConstraint()); List<TableLayoutResult> layouts = Metadata.getLayouts( session,bindings -> true),Optional.of(ImmutableSet.copyOf(node.getAssignments().values()))); if (layouts.isEmpty()) { return new ValuesNode(idAllocator.getNextId(),ImmutableList.of()); } TableLayoutResult layout = layouts.get(0); TableScanNode result = new TableScanNode( node.getId(),Optional.ofNullable(node.getoriginalConstraint()).orElse(predicate)); Map<ColumnHandle,Symbol> assignments = ImmutableBiMap.copyOf(node.getAssignments()).inverse(); Expression resultingPredicate = combineConjuncts( decomposedPredicate.getRemainingExpression(),DomainTranslator.toPredicate(layout.getUnenforcedConstraint().transform(assignments::get))); if (!BooleanLiteral.TRUE_LIteraL.equals(resultingPredicate)) { return new FilterNode(idAllocator.getNextId(),result,resultingPredicate); } return result; }
@Override public PlanNode visitTableScan(TableScanNode node,RewriteContext<Context> context) { return planTableScan(node,context.get()); }
@Override protected ExtractionResult visitBooleanLiteral(BooleanLiteral node,Boolean complement) { boolean value = complement ? !node.getValue() : node.getValue(); return new ExtractionResult(value ? TupleDomain.all() : TupleDomain.none(),TRUE_LIteraL); }
@Override protected Type visitBooleanLiteral(BooleanLiteral node,StackableAstVisitorContext<AnalysisContext> context) { expressionTypes.put(node,BOOLEAN); return BOOLEAN; }
@Test public void testTableScan() throws Exception { // Effective predicate is True if there is no effective predicate Map<Symbol,ColumnHandle> assignments = Maps.filterKeys(scanAssignments,Predicates.in(ImmutableList.of(A,B,C,D))); PlanNode node = new TableScanNode( newId(),DUAL_TABLE_HANDLE,ImmutableList.copyOf(assignments.keySet()),assignments,Optional.empty(),TupleDomain.all(),null); Expression effectivePredicate = EffectivePredicateExtractor.extract(node,TYPES); Assert.assertEquals(effectivePredicate,BooleanLiteral.TRUE_LIteraL); node = new TableScanNode( newId(),TupleDomain.none(),null); effectivePredicate = EffectivePredicateExtractor.extract(node,FALSE_LIteraL); node = new TableScanNode( newId(),TupleDomain.withColumnDomains(ImmutableMap.of(scanAssignments.get(A),Domain.singleValue(BIGINT,1L))),TYPES); Assert.assertEquals(normalizeConjuncts(effectivePredicate),normalizeConjuncts(equals(number(1L),AE))); node = new TableScanNode( newId(),TupleDomain.withColumnDomains(ImmutableMap.of( scanAssignments.get(A),1L),scanAssignments.get(B),2L))),normalizeConjuncts(equals(number(2L),BE),equals(number(1L),BooleanLiteral.TRUE_LIteraL); }
@Override public Node visitBooleanValue(sqlbaseParser.BooleanValueContext context) { return new BooleanLiteral(getLocation(context),context.getText()); }
@Override protected String visitBooleanLiteral(BooleanLiteral node,Boolean unmangleNames) { return String.valueOf(node.getValue()); }
@Override protected String visitBooleanLiteral(BooleanLiteral node,Boolean unmangleNames) { return String.valueOf(node.getValue()); }
com.facebook.presto.sql.tree.Cast的实例源码
@Override public Type visitCast(Cast node,StackableAstVisitorContext<AnalysisContext> context) { Type type = typeManager.getType(parseTypeSignature(node.getType())); if (type == null) { throw new SemanticException(TYPE_MISMATCH,node,"UnkNown type: " + node.getType()); } if (type.equals(UNKNowN)) { throw new SemanticException(TYPE_MISMATCH,"UNKNowN is not a valid type"); } Type value = process(node.getExpression(),context); if (!value.equals(UNKNowN)) { try { functionRegistry.getCoercion(value,type); } catch (OperatorNotFoundException e) { throw new SemanticException(TYPE_MISMATCH,"Cannot cast %s to %s",value,type); } } expressionTypes.put(node,type); return type; }
@Override protected RowExpression visitCast(Cast node,Void context) { RowExpression value = process(node.getExpression(),context); if (node.isSafe()) { return call(tryCastSignature(types.get(node),value.getType()),types.get(node),value); } return call(castSignature(types.get(node),value); }
@Override public Object visitCast(Cast node,Object context) { Object value = process(node.getExpression(),context); if (value instanceof Expression) { return new Cast((Expression) value,node.getType(),node.isSafe()); } // hack!!! don't optimize CASTs for types that cannot be represented in the sql AST // Todo: this will not be an issue when we migrate to RowExpression tree for this,which allows arbitrary literals. if (optimize && !FunctionRegistry.isSupportedLiteralType(expressionTypes.get(node))) { return new Cast(toExpression(value,expressionTypes.get(node.getExpression())),node.isSafe()); } if (value == null) { return null; } Type type = Metadata.getType(parseTypeSignature(node.getType())); if (type == null) { throw new IllegalArgumentException("Unsupported type: " + node.getType()); } Signature operator = Metadata.getFunctionRegistry().getCoercion(expressionTypes.get(node.getExpression()),type); try { return invoke(session,Metadata.getFunctionRegistry().getScalarFunctionImplementation(operator),ImmutableList.of(value)); } catch (RuntimeException e) { if (node.isSafe()) { return null; } throw e; } }
@VisibleForTesting @NotNull public static Expression createFailureFunction(RuntimeException exception,Type type) { requireNonNull(exception,"Exception is null"); String failureInfo = JsonCodec.jsonCodec(FailureInfo.class).toJson(Failures.toFailure(exception).toFailureInfo()); FunctionCall jsonParse = new FunctionCall(Qualifiedname.of("json_parse"),ImmutableList.of(new StringLiteral(failureInfo))); FunctionCall failureFunction = new FunctionCall(Qualifiedname.of("fail"),ImmutableList.of(jsonParse)); return new Cast(failureFunction,type.getTypeSignature().toString()); }
@Override public String visitCast(Cast node,Void context) { return (node.isSafe() ? "TRY_CAST" : "CAST") + "(" + process(node.getExpression(),context) + " AS " + node.getType() + ")"; }
@Override public String visitCast(Cast node,StackableAstVisitorContext<Integer> indent) { return (node.isSafe() ? "TRY_CAST" : "CAST") + "(" + process(node.getExpression(),indent) + " AS " + node.getType() + ")"; }
@Override protected Boolean visitCast(Cast node,Void context) { return process(node.getExpression(),context); }
@Override public Node visitCast(sqlbaseParser.CastContext context) { boolean isTryCast = context.TRY_CAST() != null; return new Cast(getLocation(context),(Expression) visit(context.expression()),getType(context.type()),isTryCast); }
@Override public String visitCast(Cast node,Boolean unmangleNames) { return (node.isSafe() ? "TRY_CAST" : "CAST") + "(" + process(node.getExpression(),unmangleNames) + " AS " + node.getType() + ")"; }
private static void assertCast(String type,String expected) { assertExpression("CAST(null AS " + type + ")",new Cast(new NullLiteral(),expected)); }
@Override public String visitCast(Cast node,unmangleNames) + " AS " + node.getType() + ")"; }
我们今天的关于com.facebook.presto.sql.tree.TimestampLiteral的实例源码的分享已经告一段落,感谢您的关注,如果您想了解更多关于com.facebook.presto.spi.type.TimestampType的实例源码、com.facebook.presto.sql.tree.AliasedRelation的实例源码、com.facebook.presto.sql.tree.BooleanLiteral的实例源码、com.facebook.presto.sql.tree.Cast的实例源码的相关信息,请在本站查询。
本文标签: