diff --git a/internal/core/src/common/Types.h b/internal/core/src/common/Types.h index cea451ad90..208d58a668 100644 --- a/internal/core/src/common/Types.h +++ b/internal/core/src/common/Types.h @@ -458,6 +458,7 @@ IsPrimitiveType(proto::schema::DataType type) { case proto::schema::DataType::Double: case proto::schema::DataType::String: case proto::schema::DataType::VarChar: + case proto::schema::DataType::Timestamptz: return true; default: return false; @@ -1045,6 +1046,9 @@ struct fmt::formatter case milvus::proto::schema::DataType::Geometry: name = "Geometry"; break; + case milvus::proto::schema::DataType::Timestamptz: + name = "Timestamptz"; + break; case milvus::proto::schema::DataType::Text: name = "Text"; break; diff --git a/internal/core/src/exec/expression/NullExpr.cpp b/internal/core/src/exec/expression/NullExpr.cpp index 1dc18718de..e0f2dc5c6c 100644 --- a/internal/core/src/exec/expression/NullExpr.cpp +++ b/internal/core/src/exec/expression/NullExpr.cpp @@ -60,6 +60,10 @@ PhyNullExpr::Eval(EvalCtx& context, VectorPtr& result) { result = ExecVisitorImpl(input); break; } + case DataType::TIMESTAMPTZ: { + result = ExecVisitorImpl(input); + break; + } case DataType::VARCHAR: { if (segment_->type() == SegmentType::Growing && !storage::MmapManager::GetInstance() diff --git a/internal/core/src/exec/expression/TimestamptzArithCompareExpr.cpp b/internal/core/src/exec/expression/TimestamptzArithCompareExpr.cpp index 7f7e1e54c8..0763b12f3c 100644 --- a/internal/core/src/exec/expression/TimestamptzArithCompareExpr.cpp +++ b/internal/core/src/exec/expression/TimestamptzArithCompareExpr.cpp @@ -58,7 +58,7 @@ PhyTimestamptzArithCompareExpr::ExecCompareVisitorImplForAll( zeroRightOperand.set_int64_val(0); auto helperExpr = std::make_shared( - expr_->timestamp_column_, + expr_->column_, expr_->compare_op_, proto::plan::ArithOpType::Add, expr_->compare_value_, diff --git a/internal/core/src/exec/expression/TimestamptzArithCompareExpr.h b/internal/core/src/exec/expression/TimestamptzArithCompareExpr.h index 52f213bb74..11fdba4eb0 100644 --- a/internal/core/src/exec/expression/TimestamptzArithCompareExpr.h +++ b/internal/core/src/exec/expression/TimestamptzArithCompareExpr.h @@ -37,8 +37,8 @@ class PhyTimestamptzArithCompareExpr : public SegmentExpr { name, op_ctx, segment, - expr->timestamp_column_.field_id_, - expr->timestamp_column_.nested_path_, + expr->column_.field_id_, + expr->column_.nested_path_, DataType::TIMESTAMPTZ, active_count, batch_size, @@ -57,6 +57,11 @@ class PhyTimestamptzArithCompareExpr : public SegmentExpr { return true; } + std::optional + GetColumnInfo() const override { + return expr_->column_; + } + private: template VectorPtr diff --git a/internal/core/src/expr/ITypeExpr.h b/internal/core/src/expr/ITypeExpr.h index f389752030..047977a424 100644 --- a/internal/core/src/expr/ITypeExpr.h +++ b/internal/core/src/expr/ITypeExpr.h @@ -109,7 +109,7 @@ IsMaterializedViewSupported(const DataType& data_type) { data_type == DataType::INT16 || data_type == DataType::INT32 || data_type == DataType::INT64 || data_type == DataType::FLOAT || data_type == DataType::DOUBLE || data_type == DataType::VARCHAR || - data_type == DataType::STRING; + data_type == DataType::TIMESTAMPTZ || data_type == DataType::STRING; } struct ColumnInfo { @@ -686,7 +686,7 @@ class TimestamptzArithCompareExpr : public ITypeFilterExpr { const proto::plan::Interval& interval, const proto::plan::OpType compare_op, const proto::plan::GenericValue& compare_value) - : timestamp_column_(timestamp_column), + : column_(timestamp_column), arith_op_(arith_op), interval_(interval), compare_op_(compare_op), @@ -696,8 +696,7 @@ class TimestamptzArithCompareExpr : public ITypeFilterExpr { std::string ToString() const override { std::stringstream ss; - ss << "TimestamptzArithCompareExpr:[Column: " - << timestamp_column_.ToString() + ss << "TimestamptzArithCompareExpr:[Column: " << column_.ToString() << ", ArithOp: " << milvus::proto::plan::ArithOpType_Name(arith_op_) << ", Interval: " << interval_.ShortDebugString() << ", CompareOp: " << milvus::proto::plan::OpType_Name(compare_op_) @@ -706,7 +705,7 @@ class TimestamptzArithCompareExpr : public ITypeFilterExpr { } public: - const ColumnInfo timestamp_column_; + const ColumnInfo column_; const proto::plan::ArithOpType arith_op_; const proto::plan::Interval interval_; const proto::plan::OpType compare_op_; diff --git a/internal/core/src/mmap/ChunkedColumn.h b/internal/core/src/mmap/ChunkedColumn.h index b4fee58d5c..ff7c4b541d 100644 --- a/internal/core/src/mmap/ChunkedColumn.h +++ b/internal/core/src/mmap/ChunkedColumn.h @@ -434,6 +434,11 @@ class ChunkedColumn : public ChunkedColumnBase { op_ctx, dst, offsets, count); break; } + case DataType::TIMESTAMPTZ: { + BulkPrimitiveValueAtImpl( + op_ctx, dst, offsets, count); + break; + } case DataType::FLOAT: { BulkPrimitiveValueAtImpl( op_ctx, dst, offsets, count); diff --git a/internal/core/src/mmap/ChunkedColumnGroup.h b/internal/core/src/mmap/ChunkedColumnGroup.h index a9d882228e..a945c72f5b 100644 --- a/internal/core/src/mmap/ChunkedColumnGroup.h +++ b/internal/core/src/mmap/ChunkedColumnGroup.h @@ -469,6 +469,11 @@ class ProxyChunkColumn : public ChunkedColumnInterface { op_ctx, dst, offsets, count); break; } + case DataType::TIMESTAMPTZ: { + BulkPrimitiveValueAtImpl( + op_ctx, dst, offsets, count); + break; + } case DataType::FLOAT: { BulkPrimitiveValueAtImpl( op_ctx, dst, offsets, count); diff --git a/internal/core/src/mmap/ChunkedColumnInterface.h b/internal/core/src/mmap/ChunkedColumnInterface.h index 631ad50df8..8100faac91 100644 --- a/internal/core/src/mmap/ChunkedColumnInterface.h +++ b/internal/core/src/mmap/ChunkedColumnInterface.h @@ -205,7 +205,8 @@ class ChunkedColumnInterface { return data_type == DataType::INT8 || data_type == DataType::INT16 || data_type == DataType::INT32 || data_type == DataType::INT64 || data_type == DataType::FLOAT || data_type == DataType::DOUBLE || - data_type == DataType::BOOL; + data_type == DataType::BOOL || + data_type == DataType::TIMESTAMPTZ; } static bool diff --git a/internal/core/src/segcore/storagev1translator/DefaultValueChunkTranslator.cpp b/internal/core/src/segcore/storagev1translator/DefaultValueChunkTranslator.cpp index 75d48d4a5d..5bb5831b1c 100644 --- a/internal/core/src/segcore/storagev1translator/DefaultValueChunkTranslator.cpp +++ b/internal/core/src/segcore/storagev1translator/DefaultValueChunkTranslator.cpp @@ -81,6 +81,9 @@ DefaultValueChunkTranslator::estimated_byte_size_of_cell( case milvus::DataType::INT64: value_size = sizeof(int64_t); break; + case milvus::DataType::TIMESTAMPTZ: + value_size = sizeof(int64_t); + break; case milvus::DataType::FLOAT: value_size = sizeof(float); break; diff --git a/internal/metastore/model/field.go b/internal/metastore/model/field.go index 256d79f245..e0a0d4e564 100644 --- a/internal/metastore/model/field.go +++ b/internal/metastore/model/field.go @@ -118,7 +118,7 @@ func MarshalFieldModel(field *Field) *schemapb.FieldSchema { IsPartitionKey: field.IsPartitionKey, IsClusteringKey: field.IsClusteringKey, IsFunctionOutput: field.IsFunctionOutput, - DefaultValue: field.DefaultValue, + DefaultValue: proto.Clone(field.DefaultValue).(*schemapb.ValueField), ElementType: field.ElementType, Nullable: field.Nullable, } diff --git a/internal/parser/planparserv2/Plan.g4 b/internal/parser/planparserv2/Plan.g4 index b6cb98b221..d4b33b2cef 100644 --- a/internal/parser/planparserv2/Plan.g4 +++ b/internal/parser/planparserv2/Plan.g4 @@ -1,7 +1,8 @@ grammar Plan; expr: - Identifier (op1=(ADD | SUB) INTERVAL interval_string=StringLiteral)? op2=(LT | LE | GT | GE | EQ | NE) ISO compare_string=StringLiteral # TimestamptzCompare + Identifier (op1=(ADD | SUB) INTERVAL interval_string=StringLiteral)? op2=(LT | LE | GT | GE | EQ | NE) ISO compare_string=StringLiteral # TimestamptzCompareForward + | ISO compare_string=StringLiteral op2=(LT | LE | GT | GE | EQ | NE) Identifier (op1=(ADD | SUB) INTERVAL interval_string=StringLiteral)? # TimestamptzCompareReverse | IntegerConstant # Integer | FloatingConstant # Floating | BooleanConstant # Boolean diff --git a/internal/parser/planparserv2/generated/Plan.interp b/internal/parser/planparserv2/generated/Plan.interp index 86841f90a9..8e23fc1b6d 100644 --- a/internal/parser/planparserv2/generated/Plan.interp +++ b/internal/parser/planparserv2/generated/Plan.interp @@ -135,4 +135,4 @@ expr atn: -[4, 1, 63, 221, 2, 0, 7, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 8, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 30, 8, 0, 10, 0, 12, 0, 33, 9, 0, 1, 0, 3, 0, 36, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 56, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 147, 8, 0, 10, 0, 12, 0, 150, 9, 0, 1, 0, 3, 0, 153, 8, 0, 3, 0, 155, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 162, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 178, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 216, 8, 0, 10, 0, 12, 0, 219, 9, 0, 1, 0, 0, 1, 0, 1, 0, 0, 14, 1, 0, 21, 22, 1, 0, 8, 13, 1, 0, 58, 59, 2, 0, 21, 22, 36, 37, 2, 0, 40, 40, 43, 43, 2, 0, 41, 41, 44, 44, 2, 0, 42, 42, 45, 45, 2, 0, 58, 58, 61, 61, 1, 0, 23, 25, 1, 0, 27, 28, 1, 0, 8, 9, 1, 0, 10, 11, 1, 0, 8, 11, 1, 0, 12, 13, 272, 0, 161, 1, 0, 0, 0, 2, 3, 6, 0, -1, 0, 3, 7, 5, 58, 0, 0, 4, 5, 7, 0, 0, 0, 5, 6, 5, 19, 0, 0, 6, 8, 5, 60, 0, 0, 7, 4, 1, 0, 0, 0, 7, 8, 1, 0, 0, 0, 8, 9, 1, 0, 0, 0, 9, 10, 7, 1, 0, 0, 10, 11, 5, 20, 0, 0, 11, 162, 5, 60, 0, 0, 12, 162, 5, 56, 0, 0, 13, 162, 5, 57, 0, 0, 14, 162, 5, 55, 0, 0, 15, 162, 5, 60, 0, 0, 16, 162, 7, 2, 0, 0, 17, 162, 5, 61, 0, 0, 18, 19, 5, 6, 0, 0, 19, 20, 5, 58, 0, 0, 20, 162, 5, 7, 0, 0, 21, 22, 5, 1, 0, 0, 22, 23, 3, 0, 0, 0, 23, 24, 5, 2, 0, 0, 24, 162, 1, 0, 0, 0, 25, 26, 5, 3, 0, 0, 26, 31, 3, 0, 0, 0, 27, 28, 5, 4, 0, 0, 28, 30, 3, 0, 0, 0, 29, 27, 1, 0, 0, 0, 30, 33, 1, 0, 0, 0, 31, 29, 1, 0, 0, 0, 31, 32, 1, 0, 0, 0, 32, 35, 1, 0, 0, 0, 33, 31, 1, 0, 0, 0, 34, 36, 5, 4, 0, 0, 35, 34, 1, 0, 0, 0, 35, 36, 1, 0, 0, 0, 36, 37, 1, 0, 0, 0, 37, 38, 5, 5, 0, 0, 38, 162, 1, 0, 0, 0, 39, 162, 5, 39, 0, 0, 40, 41, 5, 15, 0, 0, 41, 162, 3, 0, 0, 35, 42, 43, 5, 16, 0, 0, 43, 44, 5, 1, 0, 0, 44, 45, 5, 58, 0, 0, 45, 46, 5, 4, 0, 0, 46, 47, 5, 60, 0, 0, 47, 162, 5, 2, 0, 0, 48, 49, 5, 17, 0, 0, 49, 50, 5, 1, 0, 0, 50, 51, 5, 58, 0, 0, 51, 52, 5, 4, 0, 0, 52, 55, 5, 60, 0, 0, 53, 54, 5, 4, 0, 0, 54, 56, 3, 0, 0, 0, 55, 53, 1, 0, 0, 0, 55, 56, 1, 0, 0, 0, 56, 57, 1, 0, 0, 0, 57, 162, 5, 2, 0, 0, 58, 59, 5, 18, 0, 0, 59, 60, 5, 1, 0, 0, 60, 61, 3, 0, 0, 0, 61, 62, 5, 2, 0, 0, 62, 162, 1, 0, 0, 0, 63, 64, 7, 3, 0, 0, 64, 162, 3, 0, 0, 29, 65, 66, 7, 4, 0, 0, 66, 67, 5, 1, 0, 0, 67, 68, 3, 0, 0, 0, 68, 69, 5, 4, 0, 0, 69, 70, 3, 0, 0, 0, 70, 71, 5, 2, 0, 0, 71, 162, 1, 0, 0, 0, 72, 73, 7, 5, 0, 0, 73, 74, 5, 1, 0, 0, 74, 75, 3, 0, 0, 0, 75, 76, 5, 4, 0, 0, 76, 77, 3, 0, 0, 0, 77, 78, 5, 2, 0, 0, 78, 162, 1, 0, 0, 0, 79, 80, 7, 6, 0, 0, 80, 81, 5, 1, 0, 0, 81, 82, 3, 0, 0, 0, 82, 83, 5, 4, 0, 0, 83, 84, 3, 0, 0, 0, 84, 85, 5, 2, 0, 0, 85, 162, 1, 0, 0, 0, 86, 87, 5, 47, 0, 0, 87, 88, 5, 1, 0, 0, 88, 89, 5, 58, 0, 0, 89, 90, 5, 4, 0, 0, 90, 91, 5, 60, 0, 0, 91, 162, 5, 2, 0, 0, 92, 93, 5, 48, 0, 0, 93, 94, 5, 1, 0, 0, 94, 95, 5, 58, 0, 0, 95, 96, 5, 4, 0, 0, 96, 97, 5, 60, 0, 0, 97, 162, 5, 2, 0, 0, 98, 99, 5, 49, 0, 0, 99, 100, 5, 1, 0, 0, 100, 101, 5, 58, 0, 0, 101, 102, 5, 4, 0, 0, 102, 103, 5, 60, 0, 0, 103, 162, 5, 2, 0, 0, 104, 105, 5, 50, 0, 0, 105, 106, 5, 1, 0, 0, 106, 107, 5, 58, 0, 0, 107, 108, 5, 4, 0, 0, 108, 109, 5, 60, 0, 0, 109, 162, 5, 2, 0, 0, 110, 111, 5, 51, 0, 0, 111, 112, 5, 1, 0, 0, 112, 113, 5, 58, 0, 0, 113, 114, 5, 4, 0, 0, 114, 115, 5, 60, 0, 0, 115, 162, 5, 2, 0, 0, 116, 117, 5, 52, 0, 0, 117, 118, 5, 1, 0, 0, 118, 119, 5, 58, 0, 0, 119, 120, 5, 4, 0, 0, 120, 121, 5, 60, 0, 0, 121, 162, 5, 2, 0, 0, 122, 123, 5, 53, 0, 0, 123, 124, 5, 1, 0, 0, 124, 125, 5, 58, 0, 0, 125, 126, 5, 4, 0, 0, 126, 127, 5, 60, 0, 0, 127, 162, 5, 2, 0, 0, 128, 129, 5, 54, 0, 0, 129, 130, 5, 1, 0, 0, 130, 131, 5, 58, 0, 0, 131, 132, 5, 4, 0, 0, 132, 133, 5, 60, 0, 0, 133, 134, 5, 4, 0, 0, 134, 135, 3, 0, 0, 0, 135, 136, 5, 2, 0, 0, 136, 162, 1, 0, 0, 0, 137, 138, 5, 46, 0, 0, 138, 139, 5, 1, 0, 0, 139, 140, 7, 7, 0, 0, 140, 162, 5, 2, 0, 0, 141, 142, 5, 58, 0, 0, 142, 154, 5, 1, 0, 0, 143, 148, 3, 0, 0, 0, 144, 145, 5, 4, 0, 0, 145, 147, 3, 0, 0, 0, 146, 144, 1, 0, 0, 0, 147, 150, 1, 0, 0, 0, 148, 146, 1, 0, 0, 0, 148, 149, 1, 0, 0, 0, 149, 152, 1, 0, 0, 0, 150, 148, 1, 0, 0, 0, 151, 153, 5, 4, 0, 0, 152, 151, 1, 0, 0, 0, 152, 153, 1, 0, 0, 0, 153, 155, 1, 0, 0, 0, 154, 143, 1, 0, 0, 0, 154, 155, 1, 0, 0, 0, 155, 156, 1, 0, 0, 0, 156, 162, 5, 2, 0, 0, 157, 158, 7, 7, 0, 0, 158, 162, 5, 34, 0, 0, 159, 160, 7, 7, 0, 0, 160, 162, 5, 35, 0, 0, 161, 2, 1, 0, 0, 0, 161, 12, 1, 0, 0, 0, 161, 13, 1, 0, 0, 0, 161, 14, 1, 0, 0, 0, 161, 15, 1, 0, 0, 0, 161, 16, 1, 0, 0, 0, 161, 17, 1, 0, 0, 0, 161, 18, 1, 0, 0, 0, 161, 21, 1, 0, 0, 0, 161, 25, 1, 0, 0, 0, 161, 39, 1, 0, 0, 0, 161, 40, 1, 0, 0, 0, 161, 42, 1, 0, 0, 0, 161, 48, 1, 0, 0, 0, 161, 58, 1, 0, 0, 0, 161, 63, 1, 0, 0, 0, 161, 65, 1, 0, 0, 0, 161, 72, 1, 0, 0, 0, 161, 79, 1, 0, 0, 0, 161, 86, 1, 0, 0, 0, 161, 92, 1, 0, 0, 0, 161, 98, 1, 0, 0, 0, 161, 104, 1, 0, 0, 0, 161, 110, 1, 0, 0, 0, 161, 116, 1, 0, 0, 0, 161, 122, 1, 0, 0, 0, 161, 128, 1, 0, 0, 0, 161, 137, 1, 0, 0, 0, 161, 141, 1, 0, 0, 0, 161, 157, 1, 0, 0, 0, 161, 159, 1, 0, 0, 0, 162, 217, 1, 0, 0, 0, 163, 164, 10, 30, 0, 0, 164, 165, 5, 26, 0, 0, 165, 216, 3, 0, 0, 31, 166, 167, 10, 28, 0, 0, 167, 168, 7, 8, 0, 0, 168, 216, 3, 0, 0, 29, 169, 170, 10, 27, 0, 0, 170, 171, 7, 0, 0, 0, 171, 216, 3, 0, 0, 28, 172, 173, 10, 26, 0, 0, 173, 174, 7, 9, 0, 0, 174, 216, 3, 0, 0, 27, 175, 177, 10, 25, 0, 0, 176, 178, 5, 37, 0, 0, 177, 176, 1, 0, 0, 0, 177, 178, 1, 0, 0, 0, 178, 179, 1, 0, 0, 0, 179, 180, 5, 38, 0, 0, 180, 216, 3, 0, 0, 26, 181, 182, 10, 11, 0, 0, 182, 183, 7, 10, 0, 0, 183, 184, 7, 7, 0, 0, 184, 185, 7, 10, 0, 0, 185, 216, 3, 0, 0, 12, 186, 187, 10, 10, 0, 0, 187, 188, 7, 11, 0, 0, 188, 189, 7, 7, 0, 0, 189, 190, 7, 11, 0, 0, 190, 216, 3, 0, 0, 11, 191, 192, 10, 9, 0, 0, 192, 193, 7, 12, 0, 0, 193, 216, 3, 0, 0, 10, 194, 195, 10, 8, 0, 0, 195, 196, 7, 13, 0, 0, 196, 216, 3, 0, 0, 9, 197, 198, 10, 7, 0, 0, 198, 199, 5, 29, 0, 0, 199, 216, 3, 0, 0, 8, 200, 201, 10, 6, 0, 0, 201, 202, 5, 31, 0, 0, 202, 216, 3, 0, 0, 7, 203, 204, 10, 5, 0, 0, 204, 205, 5, 30, 0, 0, 205, 216, 3, 0, 0, 6, 206, 207, 10, 4, 0, 0, 207, 208, 5, 32, 0, 0, 208, 216, 3, 0, 0, 5, 209, 210, 10, 3, 0, 0, 210, 211, 5, 33, 0, 0, 211, 216, 3, 0, 0, 4, 212, 213, 10, 34, 0, 0, 213, 214, 5, 14, 0, 0, 214, 216, 5, 60, 0, 0, 215, 163, 1, 0, 0, 0, 215, 166, 1, 0, 0, 0, 215, 169, 1, 0, 0, 0, 215, 172, 1, 0, 0, 0, 215, 175, 1, 0, 0, 0, 215, 181, 1, 0, 0, 0, 215, 186, 1, 0, 0, 0, 215, 191, 1, 0, 0, 0, 215, 194, 1, 0, 0, 0, 215, 197, 1, 0, 0, 0, 215, 200, 1, 0, 0, 0, 215, 203, 1, 0, 0, 0, 215, 206, 1, 0, 0, 0, 215, 209, 1, 0, 0, 0, 215, 212, 1, 0, 0, 0, 216, 219, 1, 0, 0, 0, 217, 215, 1, 0, 0, 0, 217, 218, 1, 0, 0, 0, 218, 1, 1, 0, 0, 0, 219, 217, 1, 0, 0, 0, 11, 7, 31, 35, 55, 148, 152, 154, 161, 177, 215, 217] \ No newline at end of file +[4, 1, 63, 230, 2, 0, 7, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 8, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 20, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 39, 8, 0, 10, 0, 12, 0, 42, 9, 0, 1, 0, 3, 0, 45, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 65, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 156, 8, 0, 10, 0, 12, 0, 159, 9, 0, 1, 0, 3, 0, 162, 8, 0, 3, 0, 164, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 171, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 187, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 225, 8, 0, 10, 0, 12, 0, 228, 9, 0, 1, 0, 0, 1, 0, 1, 0, 0, 14, 1, 0, 21, 22, 1, 0, 8, 13, 1, 0, 58, 59, 2, 0, 21, 22, 36, 37, 2, 0, 40, 40, 43, 43, 2, 0, 41, 41, 44, 44, 2, 0, 42, 42, 45, 45, 2, 0, 58, 58, 61, 61, 1, 0, 23, 25, 1, 0, 27, 28, 1, 0, 8, 9, 1, 0, 10, 11, 1, 0, 8, 11, 1, 0, 12, 13, 283, 0, 170, 1, 0, 0, 0, 2, 3, 6, 0, -1, 0, 3, 7, 5, 58, 0, 0, 4, 5, 7, 0, 0, 0, 5, 6, 5, 19, 0, 0, 6, 8, 5, 60, 0, 0, 7, 4, 1, 0, 0, 0, 7, 8, 1, 0, 0, 0, 8, 9, 1, 0, 0, 0, 9, 10, 7, 1, 0, 0, 10, 11, 5, 20, 0, 0, 11, 171, 5, 60, 0, 0, 12, 13, 5, 20, 0, 0, 13, 14, 5, 60, 0, 0, 14, 15, 7, 1, 0, 0, 15, 19, 5, 58, 0, 0, 16, 17, 7, 0, 0, 0, 17, 18, 5, 19, 0, 0, 18, 20, 5, 60, 0, 0, 19, 16, 1, 0, 0, 0, 19, 20, 1, 0, 0, 0, 20, 171, 1, 0, 0, 0, 21, 171, 5, 56, 0, 0, 22, 171, 5, 57, 0, 0, 23, 171, 5, 55, 0, 0, 24, 171, 5, 60, 0, 0, 25, 171, 7, 2, 0, 0, 26, 171, 5, 61, 0, 0, 27, 28, 5, 6, 0, 0, 28, 29, 5, 58, 0, 0, 29, 171, 5, 7, 0, 0, 30, 31, 5, 1, 0, 0, 31, 32, 3, 0, 0, 0, 32, 33, 5, 2, 0, 0, 33, 171, 1, 0, 0, 0, 34, 35, 5, 3, 0, 0, 35, 40, 3, 0, 0, 0, 36, 37, 5, 4, 0, 0, 37, 39, 3, 0, 0, 0, 38, 36, 1, 0, 0, 0, 39, 42, 1, 0, 0, 0, 40, 38, 1, 0, 0, 0, 40, 41, 1, 0, 0, 0, 41, 44, 1, 0, 0, 0, 42, 40, 1, 0, 0, 0, 43, 45, 5, 4, 0, 0, 44, 43, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 46, 1, 0, 0, 0, 46, 47, 5, 5, 0, 0, 47, 171, 1, 0, 0, 0, 48, 171, 5, 39, 0, 0, 49, 50, 5, 15, 0, 0, 50, 171, 3, 0, 0, 35, 51, 52, 5, 16, 0, 0, 52, 53, 5, 1, 0, 0, 53, 54, 5, 58, 0, 0, 54, 55, 5, 4, 0, 0, 55, 56, 5, 60, 0, 0, 56, 171, 5, 2, 0, 0, 57, 58, 5, 17, 0, 0, 58, 59, 5, 1, 0, 0, 59, 60, 5, 58, 0, 0, 60, 61, 5, 4, 0, 0, 61, 64, 5, 60, 0, 0, 62, 63, 5, 4, 0, 0, 63, 65, 3, 0, 0, 0, 64, 62, 1, 0, 0, 0, 64, 65, 1, 0, 0, 0, 65, 66, 1, 0, 0, 0, 66, 171, 5, 2, 0, 0, 67, 68, 5, 18, 0, 0, 68, 69, 5, 1, 0, 0, 69, 70, 3, 0, 0, 0, 70, 71, 5, 2, 0, 0, 71, 171, 1, 0, 0, 0, 72, 73, 7, 3, 0, 0, 73, 171, 3, 0, 0, 29, 74, 75, 7, 4, 0, 0, 75, 76, 5, 1, 0, 0, 76, 77, 3, 0, 0, 0, 77, 78, 5, 4, 0, 0, 78, 79, 3, 0, 0, 0, 79, 80, 5, 2, 0, 0, 80, 171, 1, 0, 0, 0, 81, 82, 7, 5, 0, 0, 82, 83, 5, 1, 0, 0, 83, 84, 3, 0, 0, 0, 84, 85, 5, 4, 0, 0, 85, 86, 3, 0, 0, 0, 86, 87, 5, 2, 0, 0, 87, 171, 1, 0, 0, 0, 88, 89, 7, 6, 0, 0, 89, 90, 5, 1, 0, 0, 90, 91, 3, 0, 0, 0, 91, 92, 5, 4, 0, 0, 92, 93, 3, 0, 0, 0, 93, 94, 5, 2, 0, 0, 94, 171, 1, 0, 0, 0, 95, 96, 5, 47, 0, 0, 96, 97, 5, 1, 0, 0, 97, 98, 5, 58, 0, 0, 98, 99, 5, 4, 0, 0, 99, 100, 5, 60, 0, 0, 100, 171, 5, 2, 0, 0, 101, 102, 5, 48, 0, 0, 102, 103, 5, 1, 0, 0, 103, 104, 5, 58, 0, 0, 104, 105, 5, 4, 0, 0, 105, 106, 5, 60, 0, 0, 106, 171, 5, 2, 0, 0, 107, 108, 5, 49, 0, 0, 108, 109, 5, 1, 0, 0, 109, 110, 5, 58, 0, 0, 110, 111, 5, 4, 0, 0, 111, 112, 5, 60, 0, 0, 112, 171, 5, 2, 0, 0, 113, 114, 5, 50, 0, 0, 114, 115, 5, 1, 0, 0, 115, 116, 5, 58, 0, 0, 116, 117, 5, 4, 0, 0, 117, 118, 5, 60, 0, 0, 118, 171, 5, 2, 0, 0, 119, 120, 5, 51, 0, 0, 120, 121, 5, 1, 0, 0, 121, 122, 5, 58, 0, 0, 122, 123, 5, 4, 0, 0, 123, 124, 5, 60, 0, 0, 124, 171, 5, 2, 0, 0, 125, 126, 5, 52, 0, 0, 126, 127, 5, 1, 0, 0, 127, 128, 5, 58, 0, 0, 128, 129, 5, 4, 0, 0, 129, 130, 5, 60, 0, 0, 130, 171, 5, 2, 0, 0, 131, 132, 5, 53, 0, 0, 132, 133, 5, 1, 0, 0, 133, 134, 5, 58, 0, 0, 134, 135, 5, 4, 0, 0, 135, 136, 5, 60, 0, 0, 136, 171, 5, 2, 0, 0, 137, 138, 5, 54, 0, 0, 138, 139, 5, 1, 0, 0, 139, 140, 5, 58, 0, 0, 140, 141, 5, 4, 0, 0, 141, 142, 5, 60, 0, 0, 142, 143, 5, 4, 0, 0, 143, 144, 3, 0, 0, 0, 144, 145, 5, 2, 0, 0, 145, 171, 1, 0, 0, 0, 146, 147, 5, 46, 0, 0, 147, 148, 5, 1, 0, 0, 148, 149, 7, 7, 0, 0, 149, 171, 5, 2, 0, 0, 150, 151, 5, 58, 0, 0, 151, 163, 5, 1, 0, 0, 152, 157, 3, 0, 0, 0, 153, 154, 5, 4, 0, 0, 154, 156, 3, 0, 0, 0, 155, 153, 1, 0, 0, 0, 156, 159, 1, 0, 0, 0, 157, 155, 1, 0, 0, 0, 157, 158, 1, 0, 0, 0, 158, 161, 1, 0, 0, 0, 159, 157, 1, 0, 0, 0, 160, 162, 5, 4, 0, 0, 161, 160, 1, 0, 0, 0, 161, 162, 1, 0, 0, 0, 162, 164, 1, 0, 0, 0, 163, 152, 1, 0, 0, 0, 163, 164, 1, 0, 0, 0, 164, 165, 1, 0, 0, 0, 165, 171, 5, 2, 0, 0, 166, 167, 7, 7, 0, 0, 167, 171, 5, 34, 0, 0, 168, 169, 7, 7, 0, 0, 169, 171, 5, 35, 0, 0, 170, 2, 1, 0, 0, 0, 170, 12, 1, 0, 0, 0, 170, 21, 1, 0, 0, 0, 170, 22, 1, 0, 0, 0, 170, 23, 1, 0, 0, 0, 170, 24, 1, 0, 0, 0, 170, 25, 1, 0, 0, 0, 170, 26, 1, 0, 0, 0, 170, 27, 1, 0, 0, 0, 170, 30, 1, 0, 0, 0, 170, 34, 1, 0, 0, 0, 170, 48, 1, 0, 0, 0, 170, 49, 1, 0, 0, 0, 170, 51, 1, 0, 0, 0, 170, 57, 1, 0, 0, 0, 170, 67, 1, 0, 0, 0, 170, 72, 1, 0, 0, 0, 170, 74, 1, 0, 0, 0, 170, 81, 1, 0, 0, 0, 170, 88, 1, 0, 0, 0, 170, 95, 1, 0, 0, 0, 170, 101, 1, 0, 0, 0, 170, 107, 1, 0, 0, 0, 170, 113, 1, 0, 0, 0, 170, 119, 1, 0, 0, 0, 170, 125, 1, 0, 0, 0, 170, 131, 1, 0, 0, 0, 170, 137, 1, 0, 0, 0, 170, 146, 1, 0, 0, 0, 170, 150, 1, 0, 0, 0, 170, 166, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 226, 1, 0, 0, 0, 172, 173, 10, 30, 0, 0, 173, 174, 5, 26, 0, 0, 174, 225, 3, 0, 0, 31, 175, 176, 10, 28, 0, 0, 176, 177, 7, 8, 0, 0, 177, 225, 3, 0, 0, 29, 178, 179, 10, 27, 0, 0, 179, 180, 7, 0, 0, 0, 180, 225, 3, 0, 0, 28, 181, 182, 10, 26, 0, 0, 182, 183, 7, 9, 0, 0, 183, 225, 3, 0, 0, 27, 184, 186, 10, 25, 0, 0, 185, 187, 5, 37, 0, 0, 186, 185, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 187, 188, 1, 0, 0, 0, 188, 189, 5, 38, 0, 0, 189, 225, 3, 0, 0, 26, 190, 191, 10, 11, 0, 0, 191, 192, 7, 10, 0, 0, 192, 193, 7, 7, 0, 0, 193, 194, 7, 10, 0, 0, 194, 225, 3, 0, 0, 12, 195, 196, 10, 10, 0, 0, 196, 197, 7, 11, 0, 0, 197, 198, 7, 7, 0, 0, 198, 199, 7, 11, 0, 0, 199, 225, 3, 0, 0, 11, 200, 201, 10, 9, 0, 0, 201, 202, 7, 12, 0, 0, 202, 225, 3, 0, 0, 10, 203, 204, 10, 8, 0, 0, 204, 205, 7, 13, 0, 0, 205, 225, 3, 0, 0, 9, 206, 207, 10, 7, 0, 0, 207, 208, 5, 29, 0, 0, 208, 225, 3, 0, 0, 8, 209, 210, 10, 6, 0, 0, 210, 211, 5, 31, 0, 0, 211, 225, 3, 0, 0, 7, 212, 213, 10, 5, 0, 0, 213, 214, 5, 30, 0, 0, 214, 225, 3, 0, 0, 6, 215, 216, 10, 4, 0, 0, 216, 217, 5, 32, 0, 0, 217, 225, 3, 0, 0, 5, 218, 219, 10, 3, 0, 0, 219, 220, 5, 33, 0, 0, 220, 225, 3, 0, 0, 4, 221, 222, 10, 34, 0, 0, 222, 223, 5, 14, 0, 0, 223, 225, 5, 60, 0, 0, 224, 172, 1, 0, 0, 0, 224, 175, 1, 0, 0, 0, 224, 178, 1, 0, 0, 0, 224, 181, 1, 0, 0, 0, 224, 184, 1, 0, 0, 0, 224, 190, 1, 0, 0, 0, 224, 195, 1, 0, 0, 0, 224, 200, 1, 0, 0, 0, 224, 203, 1, 0, 0, 0, 224, 206, 1, 0, 0, 0, 224, 209, 1, 0, 0, 0, 224, 212, 1, 0, 0, 0, 224, 215, 1, 0, 0, 0, 224, 218, 1, 0, 0, 0, 224, 221, 1, 0, 0, 0, 225, 228, 1, 0, 0, 0, 226, 224, 1, 0, 0, 0, 226, 227, 1, 0, 0, 0, 227, 1, 1, 0, 0, 0, 228, 226, 1, 0, 0, 0, 12, 7, 19, 40, 44, 64, 157, 161, 163, 170, 186, 224, 226] \ No newline at end of file diff --git a/internal/parser/planparserv2/generated/plan_base_visitor.go b/internal/parser/planparserv2/generated/plan_base_visitor.go index 067b8cf12e..a03849c059 100644 --- a/internal/parser/planparserv2/generated/plan_base_visitor.go +++ b/internal/parser/planparserv2/generated/plan_base_visitor.go @@ -71,6 +71,10 @@ func (v *BasePlanVisitor) VisitBoolean(ctx *BooleanContext) interface{} { return v.VisitChildren(ctx) } +func (v *BasePlanVisitor) VisitTimestamptzCompareReverse(ctx *TimestamptzCompareReverseContext) interface{} { + return v.VisitChildren(ctx) +} + func (v *BasePlanVisitor) VisitSTDWithin(ctx *STDWithinContext) interface{} { return v.VisitChildren(ctx) } @@ -79,6 +83,10 @@ func (v *BasePlanVisitor) VisitShift(ctx *ShiftContext) interface{} { return v.VisitChildren(ctx) } +func (v *BasePlanVisitor) VisitTimestamptzCompareForward(ctx *TimestamptzCompareForwardContext) interface{} { + return v.VisitChildren(ctx) +} + func (v *BasePlanVisitor) VisitCall(ctx *CallContext) interface{} { return v.VisitChildren(ctx) } @@ -147,10 +155,6 @@ func (v *BasePlanVisitor) VisitUnary(ctx *UnaryContext) interface{} { return v.VisitChildren(ctx) } -func (v *BasePlanVisitor) VisitTimestamptzCompare(ctx *TimestamptzCompareContext) interface{} { - return v.VisitChildren(ctx) -} - func (v *BasePlanVisitor) VisitInteger(ctx *IntegerContext) interface{} { return v.VisitChildren(ctx) } diff --git a/internal/parser/planparserv2/generated/plan_parser.go b/internal/parser/planparserv2/generated/plan_parser.go index 53d6745098..29099400d8 100644 --- a/internal/parser/planparserv2/generated/plan_parser.go +++ b/internal/parser/planparserv2/generated/plan_parser.go @@ -55,111 +55,115 @@ func planParserInit() { } staticData.PredictionContextCache = antlr.NewPredictionContextCache() staticData.serializedATN = []int32{ - 4, 1, 63, 221, 2, 0, 7, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 8, 8, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 30, 8, 0, 10, 0, - 12, 0, 33, 9, 0, 1, 0, 3, 0, 36, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 4, 1, 63, 230, 2, 0, 7, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 8, 8, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 20, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 3, 0, 56, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 39, 8, 0, 10, 0, 12, 0, 42, 9, 0, + 1, 0, 3, 0, 45, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 65, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 147, 8, 0, 10, 0, - 12, 0, 150, 9, 0, 1, 0, 3, 0, 153, 8, 0, 3, 0, 155, 8, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 3, 0, 162, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 178, 8, 0, 1, 0, 1, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 156, 8, 0, 10, 0, 12, 0, 159, 9, 0, + 1, 0, 3, 0, 162, 8, 0, 3, 0, 164, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, + 0, 171, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 187, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 216, - 8, 0, 10, 0, 12, 0, 219, 9, 0, 1, 0, 0, 1, 0, 1, 0, 0, 14, 1, 0, 21, 22, - 1, 0, 8, 13, 1, 0, 58, 59, 2, 0, 21, 22, 36, 37, 2, 0, 40, 40, 43, 43, - 2, 0, 41, 41, 44, 44, 2, 0, 42, 42, 45, 45, 2, 0, 58, 58, 61, 61, 1, 0, - 23, 25, 1, 0, 27, 28, 1, 0, 8, 9, 1, 0, 10, 11, 1, 0, 8, 11, 1, 0, 12, - 13, 272, 0, 161, 1, 0, 0, 0, 2, 3, 6, 0, -1, 0, 3, 7, 5, 58, 0, 0, 4, 5, - 7, 0, 0, 0, 5, 6, 5, 19, 0, 0, 6, 8, 5, 60, 0, 0, 7, 4, 1, 0, 0, 0, 7, - 8, 1, 0, 0, 0, 8, 9, 1, 0, 0, 0, 9, 10, 7, 1, 0, 0, 10, 11, 5, 20, 0, 0, - 11, 162, 5, 60, 0, 0, 12, 162, 5, 56, 0, 0, 13, 162, 5, 57, 0, 0, 14, 162, - 5, 55, 0, 0, 15, 162, 5, 60, 0, 0, 16, 162, 7, 2, 0, 0, 17, 162, 5, 61, - 0, 0, 18, 19, 5, 6, 0, 0, 19, 20, 5, 58, 0, 0, 20, 162, 5, 7, 0, 0, 21, - 22, 5, 1, 0, 0, 22, 23, 3, 0, 0, 0, 23, 24, 5, 2, 0, 0, 24, 162, 1, 0, - 0, 0, 25, 26, 5, 3, 0, 0, 26, 31, 3, 0, 0, 0, 27, 28, 5, 4, 0, 0, 28, 30, - 3, 0, 0, 0, 29, 27, 1, 0, 0, 0, 30, 33, 1, 0, 0, 0, 31, 29, 1, 0, 0, 0, - 31, 32, 1, 0, 0, 0, 32, 35, 1, 0, 0, 0, 33, 31, 1, 0, 0, 0, 34, 36, 5, - 4, 0, 0, 35, 34, 1, 0, 0, 0, 35, 36, 1, 0, 0, 0, 36, 37, 1, 0, 0, 0, 37, - 38, 5, 5, 0, 0, 38, 162, 1, 0, 0, 0, 39, 162, 5, 39, 0, 0, 40, 41, 5, 15, - 0, 0, 41, 162, 3, 0, 0, 35, 42, 43, 5, 16, 0, 0, 43, 44, 5, 1, 0, 0, 44, - 45, 5, 58, 0, 0, 45, 46, 5, 4, 0, 0, 46, 47, 5, 60, 0, 0, 47, 162, 5, 2, - 0, 0, 48, 49, 5, 17, 0, 0, 49, 50, 5, 1, 0, 0, 50, 51, 5, 58, 0, 0, 51, - 52, 5, 4, 0, 0, 52, 55, 5, 60, 0, 0, 53, 54, 5, 4, 0, 0, 54, 56, 3, 0, - 0, 0, 55, 53, 1, 0, 0, 0, 55, 56, 1, 0, 0, 0, 56, 57, 1, 0, 0, 0, 57, 162, - 5, 2, 0, 0, 58, 59, 5, 18, 0, 0, 59, 60, 5, 1, 0, 0, 60, 61, 3, 0, 0, 0, - 61, 62, 5, 2, 0, 0, 62, 162, 1, 0, 0, 0, 63, 64, 7, 3, 0, 0, 64, 162, 3, - 0, 0, 29, 65, 66, 7, 4, 0, 0, 66, 67, 5, 1, 0, 0, 67, 68, 3, 0, 0, 0, 68, - 69, 5, 4, 0, 0, 69, 70, 3, 0, 0, 0, 70, 71, 5, 2, 0, 0, 71, 162, 1, 0, - 0, 0, 72, 73, 7, 5, 0, 0, 73, 74, 5, 1, 0, 0, 74, 75, 3, 0, 0, 0, 75, 76, - 5, 4, 0, 0, 76, 77, 3, 0, 0, 0, 77, 78, 5, 2, 0, 0, 78, 162, 1, 0, 0, 0, - 79, 80, 7, 6, 0, 0, 80, 81, 5, 1, 0, 0, 81, 82, 3, 0, 0, 0, 82, 83, 5, - 4, 0, 0, 83, 84, 3, 0, 0, 0, 84, 85, 5, 2, 0, 0, 85, 162, 1, 0, 0, 0, 86, - 87, 5, 47, 0, 0, 87, 88, 5, 1, 0, 0, 88, 89, 5, 58, 0, 0, 89, 90, 5, 4, - 0, 0, 90, 91, 5, 60, 0, 0, 91, 162, 5, 2, 0, 0, 92, 93, 5, 48, 0, 0, 93, - 94, 5, 1, 0, 0, 94, 95, 5, 58, 0, 0, 95, 96, 5, 4, 0, 0, 96, 97, 5, 60, - 0, 0, 97, 162, 5, 2, 0, 0, 98, 99, 5, 49, 0, 0, 99, 100, 5, 1, 0, 0, 100, - 101, 5, 58, 0, 0, 101, 102, 5, 4, 0, 0, 102, 103, 5, 60, 0, 0, 103, 162, - 5, 2, 0, 0, 104, 105, 5, 50, 0, 0, 105, 106, 5, 1, 0, 0, 106, 107, 5, 58, - 0, 0, 107, 108, 5, 4, 0, 0, 108, 109, 5, 60, 0, 0, 109, 162, 5, 2, 0, 0, - 110, 111, 5, 51, 0, 0, 111, 112, 5, 1, 0, 0, 112, 113, 5, 58, 0, 0, 113, - 114, 5, 4, 0, 0, 114, 115, 5, 60, 0, 0, 115, 162, 5, 2, 0, 0, 116, 117, - 5, 52, 0, 0, 117, 118, 5, 1, 0, 0, 118, 119, 5, 58, 0, 0, 119, 120, 5, - 4, 0, 0, 120, 121, 5, 60, 0, 0, 121, 162, 5, 2, 0, 0, 122, 123, 5, 53, - 0, 0, 123, 124, 5, 1, 0, 0, 124, 125, 5, 58, 0, 0, 125, 126, 5, 4, 0, 0, - 126, 127, 5, 60, 0, 0, 127, 162, 5, 2, 0, 0, 128, 129, 5, 54, 0, 0, 129, - 130, 5, 1, 0, 0, 130, 131, 5, 58, 0, 0, 131, 132, 5, 4, 0, 0, 132, 133, - 5, 60, 0, 0, 133, 134, 5, 4, 0, 0, 134, 135, 3, 0, 0, 0, 135, 136, 5, 2, - 0, 0, 136, 162, 1, 0, 0, 0, 137, 138, 5, 46, 0, 0, 138, 139, 5, 1, 0, 0, - 139, 140, 7, 7, 0, 0, 140, 162, 5, 2, 0, 0, 141, 142, 5, 58, 0, 0, 142, - 154, 5, 1, 0, 0, 143, 148, 3, 0, 0, 0, 144, 145, 5, 4, 0, 0, 145, 147, - 3, 0, 0, 0, 146, 144, 1, 0, 0, 0, 147, 150, 1, 0, 0, 0, 148, 146, 1, 0, - 0, 0, 148, 149, 1, 0, 0, 0, 149, 152, 1, 0, 0, 0, 150, 148, 1, 0, 0, 0, - 151, 153, 5, 4, 0, 0, 152, 151, 1, 0, 0, 0, 152, 153, 1, 0, 0, 0, 153, - 155, 1, 0, 0, 0, 154, 143, 1, 0, 0, 0, 154, 155, 1, 0, 0, 0, 155, 156, - 1, 0, 0, 0, 156, 162, 5, 2, 0, 0, 157, 158, 7, 7, 0, 0, 158, 162, 5, 34, - 0, 0, 159, 160, 7, 7, 0, 0, 160, 162, 5, 35, 0, 0, 161, 2, 1, 0, 0, 0, - 161, 12, 1, 0, 0, 0, 161, 13, 1, 0, 0, 0, 161, 14, 1, 0, 0, 0, 161, 15, - 1, 0, 0, 0, 161, 16, 1, 0, 0, 0, 161, 17, 1, 0, 0, 0, 161, 18, 1, 0, 0, - 0, 161, 21, 1, 0, 0, 0, 161, 25, 1, 0, 0, 0, 161, 39, 1, 0, 0, 0, 161, - 40, 1, 0, 0, 0, 161, 42, 1, 0, 0, 0, 161, 48, 1, 0, 0, 0, 161, 58, 1, 0, - 0, 0, 161, 63, 1, 0, 0, 0, 161, 65, 1, 0, 0, 0, 161, 72, 1, 0, 0, 0, 161, - 79, 1, 0, 0, 0, 161, 86, 1, 0, 0, 0, 161, 92, 1, 0, 0, 0, 161, 98, 1, 0, - 0, 0, 161, 104, 1, 0, 0, 0, 161, 110, 1, 0, 0, 0, 161, 116, 1, 0, 0, 0, - 161, 122, 1, 0, 0, 0, 161, 128, 1, 0, 0, 0, 161, 137, 1, 0, 0, 0, 161, - 141, 1, 0, 0, 0, 161, 157, 1, 0, 0, 0, 161, 159, 1, 0, 0, 0, 162, 217, - 1, 0, 0, 0, 163, 164, 10, 30, 0, 0, 164, 165, 5, 26, 0, 0, 165, 216, 3, - 0, 0, 31, 166, 167, 10, 28, 0, 0, 167, 168, 7, 8, 0, 0, 168, 216, 3, 0, - 0, 29, 169, 170, 10, 27, 0, 0, 170, 171, 7, 0, 0, 0, 171, 216, 3, 0, 0, - 28, 172, 173, 10, 26, 0, 0, 173, 174, 7, 9, 0, 0, 174, 216, 3, 0, 0, 27, - 175, 177, 10, 25, 0, 0, 176, 178, 5, 37, 0, 0, 177, 176, 1, 0, 0, 0, 177, - 178, 1, 0, 0, 0, 178, 179, 1, 0, 0, 0, 179, 180, 5, 38, 0, 0, 180, 216, - 3, 0, 0, 26, 181, 182, 10, 11, 0, 0, 182, 183, 7, 10, 0, 0, 183, 184, 7, - 7, 0, 0, 184, 185, 7, 10, 0, 0, 185, 216, 3, 0, 0, 12, 186, 187, 10, 10, - 0, 0, 187, 188, 7, 11, 0, 0, 188, 189, 7, 7, 0, 0, 189, 190, 7, 11, 0, - 0, 190, 216, 3, 0, 0, 11, 191, 192, 10, 9, 0, 0, 192, 193, 7, 12, 0, 0, - 193, 216, 3, 0, 0, 10, 194, 195, 10, 8, 0, 0, 195, 196, 7, 13, 0, 0, 196, - 216, 3, 0, 0, 9, 197, 198, 10, 7, 0, 0, 198, 199, 5, 29, 0, 0, 199, 216, - 3, 0, 0, 8, 200, 201, 10, 6, 0, 0, 201, 202, 5, 31, 0, 0, 202, 216, 3, - 0, 0, 7, 203, 204, 10, 5, 0, 0, 204, 205, 5, 30, 0, 0, 205, 216, 3, 0, - 0, 6, 206, 207, 10, 4, 0, 0, 207, 208, 5, 32, 0, 0, 208, 216, 3, 0, 0, - 5, 209, 210, 10, 3, 0, 0, 210, 211, 5, 33, 0, 0, 211, 216, 3, 0, 0, 4, - 212, 213, 10, 34, 0, 0, 213, 214, 5, 14, 0, 0, 214, 216, 5, 60, 0, 0, 215, - 163, 1, 0, 0, 0, 215, 166, 1, 0, 0, 0, 215, 169, 1, 0, 0, 0, 215, 172, - 1, 0, 0, 0, 215, 175, 1, 0, 0, 0, 215, 181, 1, 0, 0, 0, 215, 186, 1, 0, - 0, 0, 215, 191, 1, 0, 0, 0, 215, 194, 1, 0, 0, 0, 215, 197, 1, 0, 0, 0, - 215, 200, 1, 0, 0, 0, 215, 203, 1, 0, 0, 0, 215, 206, 1, 0, 0, 0, 215, - 209, 1, 0, 0, 0, 215, 212, 1, 0, 0, 0, 216, 219, 1, 0, 0, 0, 217, 215, - 1, 0, 0, 0, 217, 218, 1, 0, 0, 0, 218, 1, 1, 0, 0, 0, 219, 217, 1, 0, 0, - 0, 11, 7, 31, 35, 55, 148, 152, 154, 161, 177, 215, 217, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 225, 8, 0, 10, 0, 12, + 0, 228, 9, 0, 1, 0, 0, 1, 0, 1, 0, 0, 14, 1, 0, 21, 22, 1, 0, 8, 13, 1, + 0, 58, 59, 2, 0, 21, 22, 36, 37, 2, 0, 40, 40, 43, 43, 2, 0, 41, 41, 44, + 44, 2, 0, 42, 42, 45, 45, 2, 0, 58, 58, 61, 61, 1, 0, 23, 25, 1, 0, 27, + 28, 1, 0, 8, 9, 1, 0, 10, 11, 1, 0, 8, 11, 1, 0, 12, 13, 283, 0, 170, 1, + 0, 0, 0, 2, 3, 6, 0, -1, 0, 3, 7, 5, 58, 0, 0, 4, 5, 7, 0, 0, 0, 5, 6, + 5, 19, 0, 0, 6, 8, 5, 60, 0, 0, 7, 4, 1, 0, 0, 0, 7, 8, 1, 0, 0, 0, 8, + 9, 1, 0, 0, 0, 9, 10, 7, 1, 0, 0, 10, 11, 5, 20, 0, 0, 11, 171, 5, 60, + 0, 0, 12, 13, 5, 20, 0, 0, 13, 14, 5, 60, 0, 0, 14, 15, 7, 1, 0, 0, 15, + 19, 5, 58, 0, 0, 16, 17, 7, 0, 0, 0, 17, 18, 5, 19, 0, 0, 18, 20, 5, 60, + 0, 0, 19, 16, 1, 0, 0, 0, 19, 20, 1, 0, 0, 0, 20, 171, 1, 0, 0, 0, 21, + 171, 5, 56, 0, 0, 22, 171, 5, 57, 0, 0, 23, 171, 5, 55, 0, 0, 24, 171, + 5, 60, 0, 0, 25, 171, 7, 2, 0, 0, 26, 171, 5, 61, 0, 0, 27, 28, 5, 6, 0, + 0, 28, 29, 5, 58, 0, 0, 29, 171, 5, 7, 0, 0, 30, 31, 5, 1, 0, 0, 31, 32, + 3, 0, 0, 0, 32, 33, 5, 2, 0, 0, 33, 171, 1, 0, 0, 0, 34, 35, 5, 3, 0, 0, + 35, 40, 3, 0, 0, 0, 36, 37, 5, 4, 0, 0, 37, 39, 3, 0, 0, 0, 38, 36, 1, + 0, 0, 0, 39, 42, 1, 0, 0, 0, 40, 38, 1, 0, 0, 0, 40, 41, 1, 0, 0, 0, 41, + 44, 1, 0, 0, 0, 42, 40, 1, 0, 0, 0, 43, 45, 5, 4, 0, 0, 44, 43, 1, 0, 0, + 0, 44, 45, 1, 0, 0, 0, 45, 46, 1, 0, 0, 0, 46, 47, 5, 5, 0, 0, 47, 171, + 1, 0, 0, 0, 48, 171, 5, 39, 0, 0, 49, 50, 5, 15, 0, 0, 50, 171, 3, 0, 0, + 35, 51, 52, 5, 16, 0, 0, 52, 53, 5, 1, 0, 0, 53, 54, 5, 58, 0, 0, 54, 55, + 5, 4, 0, 0, 55, 56, 5, 60, 0, 0, 56, 171, 5, 2, 0, 0, 57, 58, 5, 17, 0, + 0, 58, 59, 5, 1, 0, 0, 59, 60, 5, 58, 0, 0, 60, 61, 5, 4, 0, 0, 61, 64, + 5, 60, 0, 0, 62, 63, 5, 4, 0, 0, 63, 65, 3, 0, 0, 0, 64, 62, 1, 0, 0, 0, + 64, 65, 1, 0, 0, 0, 65, 66, 1, 0, 0, 0, 66, 171, 5, 2, 0, 0, 67, 68, 5, + 18, 0, 0, 68, 69, 5, 1, 0, 0, 69, 70, 3, 0, 0, 0, 70, 71, 5, 2, 0, 0, 71, + 171, 1, 0, 0, 0, 72, 73, 7, 3, 0, 0, 73, 171, 3, 0, 0, 29, 74, 75, 7, 4, + 0, 0, 75, 76, 5, 1, 0, 0, 76, 77, 3, 0, 0, 0, 77, 78, 5, 4, 0, 0, 78, 79, + 3, 0, 0, 0, 79, 80, 5, 2, 0, 0, 80, 171, 1, 0, 0, 0, 81, 82, 7, 5, 0, 0, + 82, 83, 5, 1, 0, 0, 83, 84, 3, 0, 0, 0, 84, 85, 5, 4, 0, 0, 85, 86, 3, + 0, 0, 0, 86, 87, 5, 2, 0, 0, 87, 171, 1, 0, 0, 0, 88, 89, 7, 6, 0, 0, 89, + 90, 5, 1, 0, 0, 90, 91, 3, 0, 0, 0, 91, 92, 5, 4, 0, 0, 92, 93, 3, 0, 0, + 0, 93, 94, 5, 2, 0, 0, 94, 171, 1, 0, 0, 0, 95, 96, 5, 47, 0, 0, 96, 97, + 5, 1, 0, 0, 97, 98, 5, 58, 0, 0, 98, 99, 5, 4, 0, 0, 99, 100, 5, 60, 0, + 0, 100, 171, 5, 2, 0, 0, 101, 102, 5, 48, 0, 0, 102, 103, 5, 1, 0, 0, 103, + 104, 5, 58, 0, 0, 104, 105, 5, 4, 0, 0, 105, 106, 5, 60, 0, 0, 106, 171, + 5, 2, 0, 0, 107, 108, 5, 49, 0, 0, 108, 109, 5, 1, 0, 0, 109, 110, 5, 58, + 0, 0, 110, 111, 5, 4, 0, 0, 111, 112, 5, 60, 0, 0, 112, 171, 5, 2, 0, 0, + 113, 114, 5, 50, 0, 0, 114, 115, 5, 1, 0, 0, 115, 116, 5, 58, 0, 0, 116, + 117, 5, 4, 0, 0, 117, 118, 5, 60, 0, 0, 118, 171, 5, 2, 0, 0, 119, 120, + 5, 51, 0, 0, 120, 121, 5, 1, 0, 0, 121, 122, 5, 58, 0, 0, 122, 123, 5, + 4, 0, 0, 123, 124, 5, 60, 0, 0, 124, 171, 5, 2, 0, 0, 125, 126, 5, 52, + 0, 0, 126, 127, 5, 1, 0, 0, 127, 128, 5, 58, 0, 0, 128, 129, 5, 4, 0, 0, + 129, 130, 5, 60, 0, 0, 130, 171, 5, 2, 0, 0, 131, 132, 5, 53, 0, 0, 132, + 133, 5, 1, 0, 0, 133, 134, 5, 58, 0, 0, 134, 135, 5, 4, 0, 0, 135, 136, + 5, 60, 0, 0, 136, 171, 5, 2, 0, 0, 137, 138, 5, 54, 0, 0, 138, 139, 5, + 1, 0, 0, 139, 140, 5, 58, 0, 0, 140, 141, 5, 4, 0, 0, 141, 142, 5, 60, + 0, 0, 142, 143, 5, 4, 0, 0, 143, 144, 3, 0, 0, 0, 144, 145, 5, 2, 0, 0, + 145, 171, 1, 0, 0, 0, 146, 147, 5, 46, 0, 0, 147, 148, 5, 1, 0, 0, 148, + 149, 7, 7, 0, 0, 149, 171, 5, 2, 0, 0, 150, 151, 5, 58, 0, 0, 151, 163, + 5, 1, 0, 0, 152, 157, 3, 0, 0, 0, 153, 154, 5, 4, 0, 0, 154, 156, 3, 0, + 0, 0, 155, 153, 1, 0, 0, 0, 156, 159, 1, 0, 0, 0, 157, 155, 1, 0, 0, 0, + 157, 158, 1, 0, 0, 0, 158, 161, 1, 0, 0, 0, 159, 157, 1, 0, 0, 0, 160, + 162, 5, 4, 0, 0, 161, 160, 1, 0, 0, 0, 161, 162, 1, 0, 0, 0, 162, 164, + 1, 0, 0, 0, 163, 152, 1, 0, 0, 0, 163, 164, 1, 0, 0, 0, 164, 165, 1, 0, + 0, 0, 165, 171, 5, 2, 0, 0, 166, 167, 7, 7, 0, 0, 167, 171, 5, 34, 0, 0, + 168, 169, 7, 7, 0, 0, 169, 171, 5, 35, 0, 0, 170, 2, 1, 0, 0, 0, 170, 12, + 1, 0, 0, 0, 170, 21, 1, 0, 0, 0, 170, 22, 1, 0, 0, 0, 170, 23, 1, 0, 0, + 0, 170, 24, 1, 0, 0, 0, 170, 25, 1, 0, 0, 0, 170, 26, 1, 0, 0, 0, 170, + 27, 1, 0, 0, 0, 170, 30, 1, 0, 0, 0, 170, 34, 1, 0, 0, 0, 170, 48, 1, 0, + 0, 0, 170, 49, 1, 0, 0, 0, 170, 51, 1, 0, 0, 0, 170, 57, 1, 0, 0, 0, 170, + 67, 1, 0, 0, 0, 170, 72, 1, 0, 0, 0, 170, 74, 1, 0, 0, 0, 170, 81, 1, 0, + 0, 0, 170, 88, 1, 0, 0, 0, 170, 95, 1, 0, 0, 0, 170, 101, 1, 0, 0, 0, 170, + 107, 1, 0, 0, 0, 170, 113, 1, 0, 0, 0, 170, 119, 1, 0, 0, 0, 170, 125, + 1, 0, 0, 0, 170, 131, 1, 0, 0, 0, 170, 137, 1, 0, 0, 0, 170, 146, 1, 0, + 0, 0, 170, 150, 1, 0, 0, 0, 170, 166, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, + 171, 226, 1, 0, 0, 0, 172, 173, 10, 30, 0, 0, 173, 174, 5, 26, 0, 0, 174, + 225, 3, 0, 0, 31, 175, 176, 10, 28, 0, 0, 176, 177, 7, 8, 0, 0, 177, 225, + 3, 0, 0, 29, 178, 179, 10, 27, 0, 0, 179, 180, 7, 0, 0, 0, 180, 225, 3, + 0, 0, 28, 181, 182, 10, 26, 0, 0, 182, 183, 7, 9, 0, 0, 183, 225, 3, 0, + 0, 27, 184, 186, 10, 25, 0, 0, 185, 187, 5, 37, 0, 0, 186, 185, 1, 0, 0, + 0, 186, 187, 1, 0, 0, 0, 187, 188, 1, 0, 0, 0, 188, 189, 5, 38, 0, 0, 189, + 225, 3, 0, 0, 26, 190, 191, 10, 11, 0, 0, 191, 192, 7, 10, 0, 0, 192, 193, + 7, 7, 0, 0, 193, 194, 7, 10, 0, 0, 194, 225, 3, 0, 0, 12, 195, 196, 10, + 10, 0, 0, 196, 197, 7, 11, 0, 0, 197, 198, 7, 7, 0, 0, 198, 199, 7, 11, + 0, 0, 199, 225, 3, 0, 0, 11, 200, 201, 10, 9, 0, 0, 201, 202, 7, 12, 0, + 0, 202, 225, 3, 0, 0, 10, 203, 204, 10, 8, 0, 0, 204, 205, 7, 13, 0, 0, + 205, 225, 3, 0, 0, 9, 206, 207, 10, 7, 0, 0, 207, 208, 5, 29, 0, 0, 208, + 225, 3, 0, 0, 8, 209, 210, 10, 6, 0, 0, 210, 211, 5, 31, 0, 0, 211, 225, + 3, 0, 0, 7, 212, 213, 10, 5, 0, 0, 213, 214, 5, 30, 0, 0, 214, 225, 3, + 0, 0, 6, 215, 216, 10, 4, 0, 0, 216, 217, 5, 32, 0, 0, 217, 225, 3, 0, + 0, 5, 218, 219, 10, 3, 0, 0, 219, 220, 5, 33, 0, 0, 220, 225, 3, 0, 0, + 4, 221, 222, 10, 34, 0, 0, 222, 223, 5, 14, 0, 0, 223, 225, 5, 60, 0, 0, + 224, 172, 1, 0, 0, 0, 224, 175, 1, 0, 0, 0, 224, 178, 1, 0, 0, 0, 224, + 181, 1, 0, 0, 0, 224, 184, 1, 0, 0, 0, 224, 190, 1, 0, 0, 0, 224, 195, + 1, 0, 0, 0, 224, 200, 1, 0, 0, 0, 224, 203, 1, 0, 0, 0, 224, 206, 1, 0, + 0, 0, 224, 209, 1, 0, 0, 0, 224, 212, 1, 0, 0, 0, 224, 215, 1, 0, 0, 0, + 224, 218, 1, 0, 0, 0, 224, 221, 1, 0, 0, 0, 225, 228, 1, 0, 0, 0, 226, + 224, 1, 0, 0, 0, 226, 227, 1, 0, 0, 0, 227, 1, 1, 0, 0, 0, 228, 226, 1, + 0, 0, 0, 12, 7, 19, 40, 44, 64, 157, 161, 163, 170, 186, 224, 226, } deserializer := antlr.NewATNDeserializer(nil) staticData.atn = deserializer.Deserialize(staticData.serializedATN) @@ -1139,6 +1143,106 @@ func (s *BooleanContext) Accept(visitor antlr.ParseTreeVisitor) interface{} { } } +type TimestamptzCompareReverseContext struct { + ExprContext + compare_string antlr.Token + op2 antlr.Token + op1 antlr.Token + interval_string antlr.Token +} + +func NewTimestamptzCompareReverseContext(parser antlr.Parser, ctx antlr.ParserRuleContext) *TimestamptzCompareReverseContext { + var p = new(TimestamptzCompareReverseContext) + + InitEmptyExprContext(&p.ExprContext) + p.parser = parser + p.CopyAll(ctx.(*ExprContext)) + + return p +} + +func (s *TimestamptzCompareReverseContext) GetCompare_string() antlr.Token { return s.compare_string } + +func (s *TimestamptzCompareReverseContext) GetOp2() antlr.Token { return s.op2 } + +func (s *TimestamptzCompareReverseContext) GetOp1() antlr.Token { return s.op1 } + +func (s *TimestamptzCompareReverseContext) GetInterval_string() antlr.Token { return s.interval_string } + +func (s *TimestamptzCompareReverseContext) SetCompare_string(v antlr.Token) { s.compare_string = v } + +func (s *TimestamptzCompareReverseContext) SetOp2(v antlr.Token) { s.op2 = v } + +func (s *TimestamptzCompareReverseContext) SetOp1(v antlr.Token) { s.op1 = v } + +func (s *TimestamptzCompareReverseContext) SetInterval_string(v antlr.Token) { s.interval_string = v } + +func (s *TimestamptzCompareReverseContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *TimestamptzCompareReverseContext) ISO() antlr.TerminalNode { + return s.GetToken(PlanParserISO, 0) +} + +func (s *TimestamptzCompareReverseContext) Identifier() antlr.TerminalNode { + return s.GetToken(PlanParserIdentifier, 0) +} + +func (s *TimestamptzCompareReverseContext) AllStringLiteral() []antlr.TerminalNode { + return s.GetTokens(PlanParserStringLiteral) +} + +func (s *TimestamptzCompareReverseContext) StringLiteral(i int) antlr.TerminalNode { + return s.GetToken(PlanParserStringLiteral, i) +} + +func (s *TimestamptzCompareReverseContext) LT() antlr.TerminalNode { + return s.GetToken(PlanParserLT, 0) +} + +func (s *TimestamptzCompareReverseContext) LE() antlr.TerminalNode { + return s.GetToken(PlanParserLE, 0) +} + +func (s *TimestamptzCompareReverseContext) GT() antlr.TerminalNode { + return s.GetToken(PlanParserGT, 0) +} + +func (s *TimestamptzCompareReverseContext) GE() antlr.TerminalNode { + return s.GetToken(PlanParserGE, 0) +} + +func (s *TimestamptzCompareReverseContext) EQ() antlr.TerminalNode { + return s.GetToken(PlanParserEQ, 0) +} + +func (s *TimestamptzCompareReverseContext) NE() antlr.TerminalNode { + return s.GetToken(PlanParserNE, 0) +} + +func (s *TimestamptzCompareReverseContext) INTERVAL() antlr.TerminalNode { + return s.GetToken(PlanParserINTERVAL, 0) +} + +func (s *TimestamptzCompareReverseContext) ADD() antlr.TerminalNode { + return s.GetToken(PlanParserADD, 0) +} + +func (s *TimestamptzCompareReverseContext) SUB() antlr.TerminalNode { + return s.GetToken(PlanParserSUB, 0) +} + +func (s *TimestamptzCompareReverseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} { + switch t := visitor.(type) { + case PlanVisitor: + return t.VisitTimestamptzCompareReverse(s) + + default: + return t.VisitChildren(s) + } +} + type STDWithinContext struct { ExprContext } @@ -1277,6 +1381,106 @@ func (s *ShiftContext) Accept(visitor antlr.ParseTreeVisitor) interface{} { } } +type TimestamptzCompareForwardContext struct { + ExprContext + op1 antlr.Token + interval_string antlr.Token + op2 antlr.Token + compare_string antlr.Token +} + +func NewTimestamptzCompareForwardContext(parser antlr.Parser, ctx antlr.ParserRuleContext) *TimestamptzCompareForwardContext { + var p = new(TimestamptzCompareForwardContext) + + InitEmptyExprContext(&p.ExprContext) + p.parser = parser + p.CopyAll(ctx.(*ExprContext)) + + return p +} + +func (s *TimestamptzCompareForwardContext) GetOp1() antlr.Token { return s.op1 } + +func (s *TimestamptzCompareForwardContext) GetInterval_string() antlr.Token { return s.interval_string } + +func (s *TimestamptzCompareForwardContext) GetOp2() antlr.Token { return s.op2 } + +func (s *TimestamptzCompareForwardContext) GetCompare_string() antlr.Token { return s.compare_string } + +func (s *TimestamptzCompareForwardContext) SetOp1(v antlr.Token) { s.op1 = v } + +func (s *TimestamptzCompareForwardContext) SetInterval_string(v antlr.Token) { s.interval_string = v } + +func (s *TimestamptzCompareForwardContext) SetOp2(v antlr.Token) { s.op2 = v } + +func (s *TimestamptzCompareForwardContext) SetCompare_string(v antlr.Token) { s.compare_string = v } + +func (s *TimestamptzCompareForwardContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *TimestamptzCompareForwardContext) Identifier() antlr.TerminalNode { + return s.GetToken(PlanParserIdentifier, 0) +} + +func (s *TimestamptzCompareForwardContext) ISO() antlr.TerminalNode { + return s.GetToken(PlanParserISO, 0) +} + +func (s *TimestamptzCompareForwardContext) AllStringLiteral() []antlr.TerminalNode { + return s.GetTokens(PlanParserStringLiteral) +} + +func (s *TimestamptzCompareForwardContext) StringLiteral(i int) antlr.TerminalNode { + return s.GetToken(PlanParserStringLiteral, i) +} + +func (s *TimestamptzCompareForwardContext) LT() antlr.TerminalNode { + return s.GetToken(PlanParserLT, 0) +} + +func (s *TimestamptzCompareForwardContext) LE() antlr.TerminalNode { + return s.GetToken(PlanParserLE, 0) +} + +func (s *TimestamptzCompareForwardContext) GT() antlr.TerminalNode { + return s.GetToken(PlanParserGT, 0) +} + +func (s *TimestamptzCompareForwardContext) GE() antlr.TerminalNode { + return s.GetToken(PlanParserGE, 0) +} + +func (s *TimestamptzCompareForwardContext) EQ() antlr.TerminalNode { + return s.GetToken(PlanParserEQ, 0) +} + +func (s *TimestamptzCompareForwardContext) NE() antlr.TerminalNode { + return s.GetToken(PlanParserNE, 0) +} + +func (s *TimestamptzCompareForwardContext) INTERVAL() antlr.TerminalNode { + return s.GetToken(PlanParserINTERVAL, 0) +} + +func (s *TimestamptzCompareForwardContext) ADD() antlr.TerminalNode { + return s.GetToken(PlanParserADD, 0) +} + +func (s *TimestamptzCompareForwardContext) SUB() antlr.TerminalNode { + return s.GetToken(PlanParserSUB, 0) +} + +func (s *TimestamptzCompareForwardContext) Accept(visitor antlr.ParseTreeVisitor) interface{} { + switch t := visitor.(type) { + case PlanVisitor: + return t.VisitTimestamptzCompareForward(s) + + default: + return t.VisitChildren(s) + } +} + type CallContext struct { ExprContext } @@ -2353,106 +2557,6 @@ func (s *UnaryContext) Accept(visitor antlr.ParseTreeVisitor) interface{} { } } -type TimestamptzCompareContext struct { - ExprContext - op1 antlr.Token - interval_string antlr.Token - op2 antlr.Token - compare_string antlr.Token -} - -func NewTimestamptzCompareContext(parser antlr.Parser, ctx antlr.ParserRuleContext) *TimestamptzCompareContext { - var p = new(TimestamptzCompareContext) - - InitEmptyExprContext(&p.ExprContext) - p.parser = parser - p.CopyAll(ctx.(*ExprContext)) - - return p -} - -func (s *TimestamptzCompareContext) GetOp1() antlr.Token { return s.op1 } - -func (s *TimestamptzCompareContext) GetInterval_string() antlr.Token { return s.interval_string } - -func (s *TimestamptzCompareContext) GetOp2() antlr.Token { return s.op2 } - -func (s *TimestamptzCompareContext) GetCompare_string() antlr.Token { return s.compare_string } - -func (s *TimestamptzCompareContext) SetOp1(v antlr.Token) { s.op1 = v } - -func (s *TimestamptzCompareContext) SetInterval_string(v antlr.Token) { s.interval_string = v } - -func (s *TimestamptzCompareContext) SetOp2(v antlr.Token) { s.op2 = v } - -func (s *TimestamptzCompareContext) SetCompare_string(v antlr.Token) { s.compare_string = v } - -func (s *TimestamptzCompareContext) GetRuleContext() antlr.RuleContext { - return s -} - -func (s *TimestamptzCompareContext) Identifier() antlr.TerminalNode { - return s.GetToken(PlanParserIdentifier, 0) -} - -func (s *TimestamptzCompareContext) ISO() antlr.TerminalNode { - return s.GetToken(PlanParserISO, 0) -} - -func (s *TimestamptzCompareContext) AllStringLiteral() []antlr.TerminalNode { - return s.GetTokens(PlanParserStringLiteral) -} - -func (s *TimestamptzCompareContext) StringLiteral(i int) antlr.TerminalNode { - return s.GetToken(PlanParserStringLiteral, i) -} - -func (s *TimestamptzCompareContext) LT() antlr.TerminalNode { - return s.GetToken(PlanParserLT, 0) -} - -func (s *TimestamptzCompareContext) LE() antlr.TerminalNode { - return s.GetToken(PlanParserLE, 0) -} - -func (s *TimestamptzCompareContext) GT() antlr.TerminalNode { - return s.GetToken(PlanParserGT, 0) -} - -func (s *TimestamptzCompareContext) GE() antlr.TerminalNode { - return s.GetToken(PlanParserGE, 0) -} - -func (s *TimestamptzCompareContext) EQ() antlr.TerminalNode { - return s.GetToken(PlanParserEQ, 0) -} - -func (s *TimestamptzCompareContext) NE() antlr.TerminalNode { - return s.GetToken(PlanParserNE, 0) -} - -func (s *TimestamptzCompareContext) INTERVAL() antlr.TerminalNode { - return s.GetToken(PlanParserINTERVAL, 0) -} - -func (s *TimestamptzCompareContext) ADD() antlr.TerminalNode { - return s.GetToken(PlanParserADD, 0) -} - -func (s *TimestamptzCompareContext) SUB() antlr.TerminalNode { - return s.GetToken(PlanParserSUB, 0) -} - -func (s *TimestamptzCompareContext) Accept(visitor antlr.ParseTreeVisitor) interface{} { - switch t := visitor.(type) { - case PlanVisitor: - return t.VisitTimestamptzCompare(s) - - default: - return t.VisitChildren(s) - } -} - type IntegerContext struct { ExprContext } @@ -3036,15 +3140,15 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { var _alt int p.EnterOuterAlt(localctx, 1) - p.SetState(161) + p.SetState(170) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } - switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 7, p.GetParserRuleContext()) { + switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 8, p.GetParserRuleContext()) { case 1: - localctx = NewTimestamptzCompareContext(p, localctx) + localctx = NewTimestamptzCompareForwardContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx @@ -3069,14 +3173,14 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { var _lt = p.GetTokenStream().LT(1) - localctx.(*TimestamptzCompareContext).op1 = _lt + localctx.(*TimestamptzCompareForwardContext).op1 = _lt _la = p.GetTokenStream().LA(1) if !(_la == PlanParserADD || _la == PlanParserSUB) { var _ri = p.GetErrorHandler().RecoverInline(p) - localctx.(*TimestamptzCompareContext).op1 = _ri + localctx.(*TimestamptzCompareForwardContext).op1 = _ri } else { p.GetErrorHandler().ReportMatch(p) p.Consume() @@ -3095,7 +3199,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { var _m = p.Match(PlanParserStringLiteral) - localctx.(*TimestamptzCompareContext).interval_string = _m + localctx.(*TimestamptzCompareForwardContext).interval_string = _m if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3108,14 +3212,14 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { var _lt = p.GetTokenStream().LT(1) - localctx.(*TimestamptzCompareContext).op2 = _lt + localctx.(*TimestamptzCompareForwardContext).op2 = _lt _la = p.GetTokenStream().LA(1) if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&16128) != 0) { var _ri = p.GetErrorHandler().RecoverInline(p) - localctx.(*TimestamptzCompareContext).op2 = _ri + localctx.(*TimestamptzCompareForwardContext).op2 = _ri } else { p.GetErrorHandler().ReportMatch(p) p.Consume() @@ -3134,7 +3238,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { var _m = p.Match(PlanParserStringLiteral) - localctx.(*TimestamptzCompareContext).compare_string = _m + localctx.(*TimestamptzCompareForwardContext).compare_string = _m if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3142,11 +3246,106 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 2: - localctx = NewIntegerContext(p, localctx) + localctx = NewTimestamptzCompareReverseContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { p.SetState(12) + p.Match(PlanParserISO) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(13) + + var _m = p.Match(PlanParserStringLiteral) + + localctx.(*TimestamptzCompareReverseContext).compare_string = _m + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(14) + + var _lt = p.GetTokenStream().LT(1) + + localctx.(*TimestamptzCompareReverseContext).op2 = _lt + + _la = p.GetTokenStream().LA(1) + + if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&16128) != 0) { + var _ri = p.GetErrorHandler().RecoverInline(p) + + localctx.(*TimestamptzCompareReverseContext).op2 = _ri + } else { + p.GetErrorHandler().ReportMatch(p) + p.Consume() + } + } + { + p.SetState(15) + p.Match(PlanParserIdentifier) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + p.SetState(19) + p.GetErrorHandler().Sync(p) + + if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 1, p.GetParserRuleContext()) == 1 { + { + p.SetState(16) + + var _lt = p.GetTokenStream().LT(1) + + localctx.(*TimestamptzCompareReverseContext).op1 = _lt + + _la = p.GetTokenStream().LA(1) + + if !(_la == PlanParserADD || _la == PlanParserSUB) { + var _ri = p.GetErrorHandler().RecoverInline(p) + + localctx.(*TimestamptzCompareReverseContext).op1 = _ri + } else { + p.GetErrorHandler().ReportMatch(p) + p.Consume() + } + } + { + p.SetState(17) + p.Match(PlanParserINTERVAL) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(18) + + var _m = p.Match(PlanParserStringLiteral) + + localctx.(*TimestamptzCompareReverseContext).interval_string = _m + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + + } else if p.HasError() { // JIM + goto errorExit + } + + case 3: + localctx = NewIntegerContext(p, localctx) + p.SetParserRuleContext(localctx) + _prevctx = localctx + { + p.SetState(21) p.Match(PlanParserIntegerConstant) if p.HasError() { // Recognition error - abort rule @@ -3154,12 +3353,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 3: + case 4: localctx = NewFloatingContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(13) + p.SetState(22) p.Match(PlanParserFloatingConstant) if p.HasError() { // Recognition error - abort rule @@ -3167,12 +3366,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 4: + case 5: localctx = NewBooleanContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(14) + p.SetState(23) p.Match(PlanParserBooleanConstant) if p.HasError() { // Recognition error - abort rule @@ -3180,12 +3379,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 5: + case 6: localctx = NewStringContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(15) + p.SetState(24) p.Match(PlanParserStringLiteral) if p.HasError() { // Recognition error - abort rule @@ -3193,12 +3392,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 6: + case 7: localctx = NewIdentifierContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(16) + p.SetState(25) _la = p.GetTokenStream().LA(1) if !(_la == PlanParserIdentifier || _la == PlanParserMeta) { @@ -3209,12 +3408,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 7: + case 8: localctx = NewJSONIdentifierContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(17) + p.SetState(26) p.Match(PlanParserJSONIdentifier) if p.HasError() { // Recognition error - abort rule @@ -3222,12 +3421,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 8: + case 9: localctx = NewTemplateVariableContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(18) + p.SetState(27) p.Match(PlanParserLBRACE) if p.HasError() { // Recognition error - abort rule @@ -3235,7 +3434,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(19) + p.SetState(28) p.Match(PlanParserIdentifier) if p.HasError() { // Recognition error - abort rule @@ -3243,7 +3442,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(20) + p.SetState(29) p.Match(PlanParserRBRACE) if p.HasError() { // Recognition error - abort rule @@ -3251,12 +3450,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 9: + case 10: localctx = NewParensContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(21) + p.SetState(30) p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule @@ -3264,11 +3463,11 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(22) + p.SetState(31) p.expr(0) } { - p.SetState(23) + p.SetState(32) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -3276,212 +3475,58 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 10: - localctx = NewArrayContext(p, localctx) - p.SetParserRuleContext(localctx) - _prevctx = localctx - { - p.SetState(25) - p.Match(PlanParserT__2) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(26) - p.expr(0) - } - p.SetState(31) - p.GetErrorHandler().Sync(p) - if p.HasError() { - goto errorExit - } - _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 1, p.GetParserRuleContext()) - if p.HasError() { - goto errorExit - } - for _alt != 2 && _alt != antlr.ATNInvalidAltNumber { - if _alt == 1 { - { - p.SetState(27) - p.Match(PlanParserT__3) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(28) - p.expr(0) - } - - } - p.SetState(33) - p.GetErrorHandler().Sync(p) - if p.HasError() { - goto errorExit - } - _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 1, p.GetParserRuleContext()) - if p.HasError() { - goto errorExit - } - } - p.SetState(35) - p.GetErrorHandler().Sync(p) - if p.HasError() { - goto errorExit - } - _la = p.GetTokenStream().LA(1) - - if _la == PlanParserT__3 { - { - p.SetState(34) - p.Match(PlanParserT__3) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - - } - { - p.SetState(37) - p.Match(PlanParserT__4) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - case 11: - localctx = NewEmptyArrayContext(p, localctx) + localctx = NewArrayContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(39) - p.Match(PlanParserEmptyArray) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - - case 12: - localctx = NewExistsContext(p, localctx) - p.SetParserRuleContext(localctx) - _prevctx = localctx - { - p.SetState(40) - p.Match(PlanParserEXISTS) + p.SetState(34) + p.Match(PlanParserT__2) if p.HasError() { // Recognition error - abort rule goto errorExit } } { - p.SetState(41) - p.expr(35) + p.SetState(35) + p.expr(0) } + p.SetState(40) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 2, p.GetParserRuleContext()) + if p.HasError() { + goto errorExit + } + for _alt != 2 && _alt != antlr.ATNInvalidAltNumber { + if _alt == 1 { + { + p.SetState(36) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(37) + p.expr(0) + } - case 13: - localctx = NewTextMatchContext(p, localctx) - p.SetParserRuleContext(localctx) - _prevctx = localctx - { + } p.SetState(42) - p.Match(PlanParserTEXTMATCH) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 2, p.GetParserRuleContext()) if p.HasError() { - // Recognition error - abort rule goto errorExit } } - { - p.SetState(43) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(44) - p.Match(PlanParserIdentifier) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(45) - p.Match(PlanParserT__3) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(46) - p.Match(PlanParserStringLiteral) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(47) - p.Match(PlanParserT__1) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - - case 14: - localctx = NewPhraseMatchContext(p, localctx) - p.SetParserRuleContext(localctx) - _prevctx = localctx - { - p.SetState(48) - p.Match(PlanParserPHRASEMATCH) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(49) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(50) - p.Match(PlanParserIdentifier) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(51) - p.Match(PlanParserT__3) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(52) - p.Match(PlanParserStringLiteral) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - p.SetState(55) + p.SetState(44) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -3490,21 +3535,100 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { if _la == PlanParserT__3 { { - p.SetState(53) + p.SetState(43) p.Match(PlanParserT__3) if p.HasError() { // Recognition error - abort rule goto errorExit } } - { - p.SetState(54) - p.expr(0) - } } { - p.SetState(57) + p.SetState(46) + p.Match(PlanParserT__4) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + + case 12: + localctx = NewEmptyArrayContext(p, localctx) + p.SetParserRuleContext(localctx) + _prevctx = localctx + { + p.SetState(48) + p.Match(PlanParserEmptyArray) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + + case 13: + localctx = NewExistsContext(p, localctx) + p.SetParserRuleContext(localctx) + _prevctx = localctx + { + p.SetState(49) + p.Match(PlanParserEXISTS) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(50) + p.expr(35) + } + + case 14: + localctx = NewTextMatchContext(p, localctx) + p.SetParserRuleContext(localctx) + _prevctx = localctx + { + p.SetState(51) + p.Match(PlanParserTEXTMATCH) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(52) + p.Match(PlanParserT__0) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(53) + p.Match(PlanParserIdentifier) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(54) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(55) + p.Match(PlanParserStringLiteral) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(56) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -3513,31 +3637,73 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 15: - localctx = NewRandomSampleContext(p, localctx) + localctx = NewPhraseMatchContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(58) - p.Match(PlanParserRANDOMSAMPLE) + p.SetState(57) + p.Match(PlanParserPHRASEMATCH) if p.HasError() { // Recognition error - abort rule goto errorExit } } { - p.SetState(59) + p.SetState(58) p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit } } + { + p.SetState(59) + p.Match(PlanParserIdentifier) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } { p.SetState(60) - p.expr(0) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } } { p.SetState(61) + p.Match(PlanParserStringLiteral) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + p.SetState(64) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + _la = p.GetTokenStream().LA(1) + + if _la == PlanParserT__3 { + { + p.SetState(62) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(63) + p.expr(0) + } + + } + { + p.SetState(66) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -3546,62 +3712,20 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 16: - localctx = NewUnaryContext(p, localctx) + localctx = NewRandomSampleContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(63) - - var _lt = p.GetTokenStream().LT(1) - - localctx.(*UnaryContext).op = _lt - - _la = p.GetTokenStream().LA(1) - - if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&206164721664) != 0) { - var _ri = p.GetErrorHandler().RecoverInline(p) - - localctx.(*UnaryContext).op = _ri - } else { - p.GetErrorHandler().ReportMatch(p) - p.Consume() - } - } - { - p.SetState(64) - p.expr(29) - } - - case 17: - localctx = NewJSONContainsContext(p, localctx) - p.SetParserRuleContext(localctx) - _prevctx = localctx - { - p.SetState(65) - _la = p.GetTokenStream().LA(1) - - if !(_la == PlanParserJSONContains || _la == PlanParserArrayContains) { - p.GetErrorHandler().RecoverInline(p) - } else { - p.GetErrorHandler().ReportMatch(p) - p.Consume() - } - } - { - p.SetState(66) - p.Match(PlanParserT__0) + p.SetState(67) + p.Match(PlanParserRANDOMSAMPLE) if p.HasError() { // Recognition error - abort rule goto errorExit } } - { - p.SetState(67) - p.expr(0) - } { p.SetState(68) - p.Match(PlanParserT__3) + p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3620,16 +3744,23 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 18: - localctx = NewJSONContainsAllContext(p, localctx) + case 17: + localctx = NewUnaryContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { p.SetState(72) + + var _lt = p.GetTokenStream().LT(1) + + localctx.(*UnaryContext).op = _lt + _la = p.GetTokenStream().LA(1) - if !(_la == PlanParserJSONContainsAll || _la == PlanParserArrayContainsAll) { - p.GetErrorHandler().RecoverInline(p) + if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&206164721664) != 0) { + var _ri = p.GetErrorHandler().RecoverInline(p) + + localctx.(*UnaryContext).op = _ri } else { p.GetErrorHandler().ReportMatch(p) p.Consume() @@ -3637,19 +3768,27 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(73) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit + p.expr(29) + } + + case 18: + localctx = NewJSONContainsContext(p, localctx) + p.SetParserRuleContext(localctx) + _prevctx = localctx + { + p.SetState(74) + _la = p.GetTokenStream().LA(1) + + if !(_la == PlanParserJSONContains || _la == PlanParserArrayContains) { + p.GetErrorHandler().RecoverInline(p) + } else { + p.GetErrorHandler().ReportMatch(p) + p.Consume() } } - { - p.SetState(74) - p.expr(0) - } { p.SetState(75) - p.Match(PlanParserT__3) + p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3661,6 +3800,18 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(77) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(78) + p.expr(0) + } + { + p.SetState(79) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -3669,35 +3820,23 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 19: - localctx = NewJSONContainsAnyContext(p, localctx) + localctx = NewJSONContainsAllContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(79) + p.SetState(81) _la = p.GetTokenStream().LA(1) - if !(_la == PlanParserJSONContainsAny || _la == PlanParserArrayContainsAny) { + if !(_la == PlanParserJSONContainsAll || _la == PlanParserArrayContainsAll) { p.GetErrorHandler().RecoverInline(p) } else { p.GetErrorHandler().ReportMatch(p) p.Consume() } } - { - p.SetState(80) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(81) - p.expr(0) - } { p.SetState(82) - p.Match(PlanParserT__3) + p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3709,6 +3848,18 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(84) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(85) + p.expr(0) + } + { + p.SetState(86) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -3717,19 +3868,22 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 20: - localctx = NewSTEuqalsContext(p, localctx) + localctx = NewJSONContainsAnyContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(86) - p.Match(PlanParserSTEuqals) - if p.HasError() { - // Recognition error - abort rule - goto errorExit + p.SetState(88) + _la = p.GetTokenStream().LA(1) + + if !(_la == PlanParserJSONContainsAny || _la == PlanParserArrayContainsAny) { + p.GetErrorHandler().RecoverInline(p) + } else { + p.GetErrorHandler().ReportMatch(p) + p.Consume() } } { - p.SetState(87) + p.SetState(89) p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule @@ -3737,15 +3891,11 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(88) - p.Match(PlanParserIdentifier) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } + p.SetState(90) + p.expr(0) } { - p.SetState(89) + p.SetState(91) p.Match(PlanParserT__3) if p.HasError() { // Recognition error - abort rule @@ -3753,15 +3903,11 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(90) - p.Match(PlanParserStringLiteral) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } + p.SetState(92) + p.expr(0) } { - p.SetState(91) + p.SetState(93) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -3770,36 +3916,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 21: - localctx = NewSTTouchesContext(p, localctx) + localctx = NewSTEuqalsContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx - { - p.SetState(92) - p.Match(PlanParserSTTouches) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(93) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(94) - p.Match(PlanParserIdentifier) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } { p.SetState(95) - p.Match(PlanParserT__3) + p.Match(PlanParserSTEuqals) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3807,7 +3929,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(96) - p.Match(PlanParserStringLiteral) + p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3815,6 +3937,30 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(97) + p.Match(PlanParserIdentifier) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(98) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(99) + p.Match(PlanParserStringLiteral) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(100) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -3823,36 +3969,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 22: - localctx = NewSTOverlapsContext(p, localctx) + localctx = NewSTTouchesContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx - { - p.SetState(98) - p.Match(PlanParserSTOverlaps) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(99) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(100) - p.Match(PlanParserIdentifier) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } { p.SetState(101) - p.Match(PlanParserT__3) + p.Match(PlanParserSTTouches) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3860,7 +3982,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(102) - p.Match(PlanParserStringLiteral) + p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3868,6 +3990,30 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(103) + p.Match(PlanParserIdentifier) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(104) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(105) + p.Match(PlanParserStringLiteral) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(106) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -3876,36 +4022,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 23: - localctx = NewSTCrossesContext(p, localctx) + localctx = NewSTOverlapsContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx - { - p.SetState(104) - p.Match(PlanParserSTCrosses) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(105) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(106) - p.Match(PlanParserIdentifier) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } { p.SetState(107) - p.Match(PlanParserT__3) + p.Match(PlanParserSTOverlaps) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3913,7 +4035,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(108) - p.Match(PlanParserStringLiteral) + p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3921,6 +4043,30 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(109) + p.Match(PlanParserIdentifier) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(110) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(111) + p.Match(PlanParserStringLiteral) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(112) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -3929,36 +4075,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 24: - localctx = NewSTContainsContext(p, localctx) + localctx = NewSTCrossesContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx - { - p.SetState(110) - p.Match(PlanParserSTContains) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(111) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(112) - p.Match(PlanParserIdentifier) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } { p.SetState(113) - p.Match(PlanParserT__3) + p.Match(PlanParserSTCrosses) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3966,7 +4088,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(114) - p.Match(PlanParserStringLiteral) + p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -3974,6 +4096,30 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(115) + p.Match(PlanParserIdentifier) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(116) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(117) + p.Match(PlanParserStringLiteral) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(118) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -3982,36 +4128,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 25: - localctx = NewSTIntersectsContext(p, localctx) + localctx = NewSTContainsContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx - { - p.SetState(116) - p.Match(PlanParserSTIntersects) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(117) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(118) - p.Match(PlanParserIdentifier) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } { p.SetState(119) - p.Match(PlanParserT__3) + p.Match(PlanParserSTContains) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -4019,7 +4141,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(120) - p.Match(PlanParserStringLiteral) + p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -4027,6 +4149,30 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(121) + p.Match(PlanParserIdentifier) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(122) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(123) + p.Match(PlanParserStringLiteral) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(124) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -4035,36 +4181,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 26: - localctx = NewSTWithinContext(p, localctx) + localctx = NewSTIntersectsContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx - { - p.SetState(122) - p.Match(PlanParserSTWithin) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(123) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(124) - p.Match(PlanParserIdentifier) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } { p.SetState(125) - p.Match(PlanParserT__3) + p.Match(PlanParserSTIntersects) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -4072,7 +4194,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(126) - p.Match(PlanParserStringLiteral) + p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -4080,6 +4202,30 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(127) + p.Match(PlanParserIdentifier) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(128) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(129) + p.Match(PlanParserStringLiteral) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(130) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -4088,36 +4234,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 27: - localctx = NewSTDWithinContext(p, localctx) + localctx = NewSTWithinContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx - { - p.SetState(128) - p.Match(PlanParserSTDWithin) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(129) - p.Match(PlanParserT__0) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } - { - p.SetState(130) - p.Match(PlanParserIdentifier) - if p.HasError() { - // Recognition error - abort rule - goto errorExit - } - } { p.SetState(131) - p.Match(PlanParserT__3) + p.Match(PlanParserSTWithin) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -4125,7 +4247,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(132) - p.Match(PlanParserStringLiteral) + p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -4133,7 +4255,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(133) - p.Match(PlanParserT__3) + p.Match(PlanParserIdentifier) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -4141,10 +4263,22 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(134) - p.expr(0) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } } { p.SetState(135) + p.Match(PlanParserStringLiteral) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(136) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -4153,12 +4287,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } case 28: - localctx = NewArrayLengthContext(p, localctx) + localctx = NewSTDWithinContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { p.SetState(137) - p.Match(PlanParserArrayLength) + p.Match(PlanParserSTDWithin) if p.HasError() { // Recognition error - abort rule goto errorExit @@ -4174,6 +4308,71 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { p.SetState(139) + p.Match(PlanParserIdentifier) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(140) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(141) + p.Match(PlanParserStringLiteral) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(142) + p.Match(PlanParserT__3) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(143) + p.expr(0) + } + { + p.SetState(144) + p.Match(PlanParserT__1) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + + case 29: + localctx = NewArrayLengthContext(p, localctx) + p.SetParserRuleContext(localctx) + _prevctx = localctx + { + p.SetState(146) + p.Match(PlanParserArrayLength) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(147) + p.Match(PlanParserT__0) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(148) _la = p.GetTokenStream().LA(1) if !(_la == PlanParserIdentifier || _la == PlanParserJSONIdentifier) { @@ -4184,7 +4383,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(140) + p.SetState(149) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -4192,12 +4391,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 29: + case 30: localctx = NewCallContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(141) + p.SetState(150) p.Match(PlanParserIdentifier) if p.HasError() { // Recognition error - abort rule @@ -4205,38 +4404,38 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(142) + p.SetState(151) p.Match(PlanParserT__0) if p.HasError() { // Recognition error - abort rule goto errorExit } } - p.SetState(154) + p.SetState(163) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } _la = p.GetTokenStream().LA(1) - if (int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&4611685674836787274) != 0 { + if (int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&4611685674837835850) != 0 { { - p.SetState(143) + p.SetState(152) p.expr(0) } - p.SetState(148) + p.SetState(157) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } - _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 4, p.GetParserRuleContext()) + _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 5, p.GetParserRuleContext()) if p.HasError() { goto errorExit } for _alt != 2 && _alt != antlr.ATNInvalidAltNumber { if _alt == 1 { { - p.SetState(144) + p.SetState(153) p.Match(PlanParserT__3) if p.HasError() { // Recognition error - abort rule @@ -4244,22 +4443,22 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(145) + p.SetState(154) p.expr(0) } } - p.SetState(150) + p.SetState(159) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } - _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 4, p.GetParserRuleContext()) + _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 5, p.GetParserRuleContext()) if p.HasError() { goto errorExit } } - p.SetState(152) + p.SetState(161) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -4268,7 +4467,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { if _la == PlanParserT__3 { { - p.SetState(151) + p.SetState(160) p.Match(PlanParserT__3) if p.HasError() { // Recognition error - abort rule @@ -4280,7 +4479,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { - p.SetState(156) + p.SetState(165) p.Match(PlanParserT__1) if p.HasError() { // Recognition error - abort rule @@ -4288,12 +4487,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 30: + case 31: localctx = NewIsNullContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(157) + p.SetState(166) _la = p.GetTokenStream().LA(1) if !(_la == PlanParserIdentifier || _la == PlanParserJSONIdentifier) { @@ -4304,7 +4503,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(158) + p.SetState(167) p.Match(PlanParserISNULL) if p.HasError() { // Recognition error - abort rule @@ -4312,12 +4511,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - case 31: + case 32: localctx = NewIsNotNullContext(p, localctx) p.SetParserRuleContext(localctx) _prevctx = localctx { - p.SetState(159) + p.SetState(168) _la = p.GetTokenStream().LA(1) if !(_la == PlanParserIdentifier || _la == PlanParserJSONIdentifier) { @@ -4328,7 +4527,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(160) + p.SetState(169) p.Match(PlanParserISNOTNULL) if p.HasError() { // Recognition error - abort rule @@ -4340,12 +4539,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { goto errorExit } p.GetParserRuleContext().SetStop(p.GetTokenStream().LT(-1)) - p.SetState(217) + p.SetState(226) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } - _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 10, p.GetParserRuleContext()) + _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 11, p.GetParserRuleContext()) if p.HasError() { goto errorExit } @@ -4355,24 +4554,24 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { p.TriggerExitRuleEvent() } _prevctx = localctx - p.SetState(215) + p.SetState(224) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } - switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 9, p.GetParserRuleContext()) { + switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 10, p.GetParserRuleContext()) { case 1: localctx = NewPowerContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(163) + p.SetState(172) if !(p.Precpred(p.GetParserRuleContext(), 30)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 30)", "")) goto errorExit } { - p.SetState(164) + p.SetState(173) p.Match(PlanParserPOW) if p.HasError() { // Recognition error - abort rule @@ -4380,21 +4579,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(165) + p.SetState(174) p.expr(31) } case 2: localctx = NewMulDivModContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(166) + p.SetState(175) if !(p.Precpred(p.GetParserRuleContext(), 28)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 28)", "")) goto errorExit } { - p.SetState(167) + p.SetState(176) var _lt = p.GetTokenStream().LT(1) @@ -4412,21 +4611,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(168) + p.SetState(177) p.expr(29) } case 3: localctx = NewAddSubContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(169) + p.SetState(178) if !(p.Precpred(p.GetParserRuleContext(), 27)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 27)", "")) goto errorExit } { - p.SetState(170) + p.SetState(179) var _lt = p.GetTokenStream().LT(1) @@ -4444,21 +4643,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(171) + p.SetState(180) p.expr(28) } case 4: localctx = NewShiftContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(172) + p.SetState(181) if !(p.Precpred(p.GetParserRuleContext(), 26)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 26)", "")) goto errorExit } { - p.SetState(173) + p.SetState(182) var _lt = p.GetTokenStream().LT(1) @@ -4476,20 +4675,20 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(174) + p.SetState(183) p.expr(27) } case 5: localctx = NewTermContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(175) + p.SetState(184) if !(p.Precpred(p.GetParserRuleContext(), 25)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 25)", "")) goto errorExit } - p.SetState(177) + p.SetState(186) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit @@ -4498,7 +4697,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { if _la == PlanParserNOT { { - p.SetState(176) + p.SetState(185) var _m = p.Match(PlanParserNOT) @@ -4511,7 +4710,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } { - p.SetState(179) + p.SetState(188) p.Match(PlanParserIN) if p.HasError() { // Recognition error - abort rule @@ -4519,21 +4718,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(180) + p.SetState(189) p.expr(26) } case 6: localctx = NewRangeContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(181) + p.SetState(190) if !(p.Precpred(p.GetParserRuleContext(), 11)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 11)", "")) goto errorExit } { - p.SetState(182) + p.SetState(191) var _lt = p.GetTokenStream().LT(1) @@ -4551,7 +4750,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(183) + p.SetState(192) _la = p.GetTokenStream().LA(1) if !(_la == PlanParserIdentifier || _la == PlanParserJSONIdentifier) { @@ -4562,7 +4761,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(184) + p.SetState(193) var _lt = p.GetTokenStream().LT(1) @@ -4580,21 +4779,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(185) + p.SetState(194) p.expr(12) } case 7: localctx = NewReverseRangeContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(186) + p.SetState(195) if !(p.Precpred(p.GetParserRuleContext(), 10)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 10)", "")) goto errorExit } { - p.SetState(187) + p.SetState(196) var _lt = p.GetTokenStream().LT(1) @@ -4612,7 +4811,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(188) + p.SetState(197) _la = p.GetTokenStream().LA(1) if !(_la == PlanParserIdentifier || _la == PlanParserJSONIdentifier) { @@ -4623,7 +4822,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(189) + p.SetState(198) var _lt = p.GetTokenStream().LT(1) @@ -4641,21 +4840,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(190) + p.SetState(199) p.expr(11) } case 8: localctx = NewRelationalContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(191) + p.SetState(200) if !(p.Precpred(p.GetParserRuleContext(), 9)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 9)", "")) goto errorExit } { - p.SetState(192) + p.SetState(201) var _lt = p.GetTokenStream().LT(1) @@ -4673,21 +4872,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(193) + p.SetState(202) p.expr(10) } case 9: localctx = NewEqualityContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(194) + p.SetState(203) if !(p.Precpred(p.GetParserRuleContext(), 8)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 8)", "")) goto errorExit } { - p.SetState(195) + p.SetState(204) var _lt = p.GetTokenStream().LT(1) @@ -4705,21 +4904,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(196) + p.SetState(205) p.expr(9) } case 10: localctx = NewBitAndContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(197) + p.SetState(206) if !(p.Precpred(p.GetParserRuleContext(), 7)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 7)", "")) goto errorExit } { - p.SetState(198) + p.SetState(207) p.Match(PlanParserBAND) if p.HasError() { // Recognition error - abort rule @@ -4727,21 +4926,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(199) + p.SetState(208) p.expr(8) } case 11: localctx = NewBitXorContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(200) + p.SetState(209) if !(p.Precpred(p.GetParserRuleContext(), 6)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 6)", "")) goto errorExit } { - p.SetState(201) + p.SetState(210) p.Match(PlanParserBXOR) if p.HasError() { // Recognition error - abort rule @@ -4749,21 +4948,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(202) + p.SetState(211) p.expr(7) } case 12: localctx = NewBitOrContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(203) + p.SetState(212) if !(p.Precpred(p.GetParserRuleContext(), 5)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 5)", "")) goto errorExit } { - p.SetState(204) + p.SetState(213) p.Match(PlanParserBOR) if p.HasError() { // Recognition error - abort rule @@ -4771,21 +4970,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(205) + p.SetState(214) p.expr(6) } case 13: localctx = NewLogicalAndContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(206) + p.SetState(215) if !(p.Precpred(p.GetParserRuleContext(), 4)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 4)", "")) goto errorExit } { - p.SetState(207) + p.SetState(216) p.Match(PlanParserAND) if p.HasError() { // Recognition error - abort rule @@ -4793,21 +4992,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(208) + p.SetState(217) p.expr(5) } case 14: localctx = NewLogicalOrContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(209) + p.SetState(218) if !(p.Precpred(p.GetParserRuleContext(), 3)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 3)", "")) goto errorExit } { - p.SetState(210) + p.SetState(219) p.Match(PlanParserOR) if p.HasError() { // Recognition error - abort rule @@ -4815,21 +5014,21 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(211) + p.SetState(220) p.expr(4) } case 15: localctx = NewLikeContext(p, NewExprContext(p, _parentctx, _parentState)) p.PushNewRecursionContext(localctx, _startState, PlanParserRULE_expr) - p.SetState(212) + p.SetState(221) if !(p.Precpred(p.GetParserRuleContext(), 34)) { p.SetError(antlr.NewFailedPredicateException(p, "p.Precpred(p.GetParserRuleContext(), 34)", "")) goto errorExit } { - p.SetState(213) + p.SetState(222) p.Match(PlanParserLIKE) if p.HasError() { // Recognition error - abort rule @@ -4837,7 +5036,7 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } { - p.SetState(214) + p.SetState(223) p.Match(PlanParserStringLiteral) if p.HasError() { // Recognition error - abort rule @@ -4850,12 +5049,12 @@ func (p *PlanParser) expr(_p int) (localctx IExprContext) { } } - p.SetState(219) + p.SetState(228) p.GetErrorHandler().Sync(p) if p.HasError() { goto errorExit } - _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 10, p.GetParserRuleContext()) + _alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 11, p.GetParserRuleContext()) if p.HasError() { goto errorExit } diff --git a/internal/parser/planparserv2/generated/plan_visitor.go b/internal/parser/planparserv2/generated/plan_visitor.go index 993eecf786..156325f054 100644 --- a/internal/parser/planparserv2/generated/plan_visitor.go +++ b/internal/parser/planparserv2/generated/plan_visitor.go @@ -55,12 +55,18 @@ type PlanVisitor interface { // Visit a parse tree produced by PlanParser#Boolean. VisitBoolean(ctx *BooleanContext) interface{} + // Visit a parse tree produced by PlanParser#TimestamptzCompareReverse. + VisitTimestamptzCompareReverse(ctx *TimestamptzCompareReverseContext) interface{} + // Visit a parse tree produced by PlanParser#STDWithin. VisitSTDWithin(ctx *STDWithinContext) interface{} // Visit a parse tree produced by PlanParser#Shift. VisitShift(ctx *ShiftContext) interface{} + // Visit a parse tree produced by PlanParser#TimestamptzCompareForward. + VisitTimestamptzCompareForward(ctx *TimestamptzCompareForwardContext) interface{} + // Visit a parse tree produced by PlanParser#Call. VisitCall(ctx *CallContext) interface{} @@ -112,9 +118,6 @@ type PlanVisitor interface { // Visit a parse tree produced by PlanParser#Unary. VisitUnary(ctx *UnaryContext) interface{} - // Visit a parse tree produced by PlanParser#TimestamptzCompare. - VisitTimestamptzCompare(ctx *TimestamptzCompareContext) interface{} - // Visit a parse tree produced by PlanParser#Integer. VisitInteger(ctx *IntegerContext) interface{} diff --git a/internal/parser/planparserv2/parser_visitor.go b/internal/parser/planparserv2/parser_visitor.go index be63a69810..0f451be12b 100644 --- a/internal/parser/planparserv2/parser_visitor.go +++ b/internal/parser/planparserv2/parser_visitor.go @@ -12,11 +12,12 @@ import ( "github.com/milvus-io/milvus-proto/go-api/v2/schemapb" parser "github.com/milvus-io/milvus/internal/parser/planparserv2/generated" "github.com/milvus-io/milvus/pkg/v2/proto/planpb" + "github.com/milvus-io/milvus/pkg/v2/util/funcutil" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) type ParserVisitorArgs struct { - TimezonePreference []string + Timezone string } type ParserVisitor struct { @@ -1920,7 +1921,7 @@ func (v *ParserVisitor) VisitSTDWithin(ctx *parser.STDWithinContext) interface{} } } -func (v *ParserVisitor) VisitTimestamptzCompare(ctx *parser.TimestamptzCompareContext) interface{} { +func (v *ParserVisitor) VisitTimestamptzCompareForward(ctx *parser.TimestamptzCompareForwardContext) interface{} { colExpr, err := v.translateIdentifier(ctx.Identifier().GetText()) identifier := ctx.Identifier().Accept(v) if err != nil { @@ -1952,7 +1953,7 @@ func (v *ParserVisitor) VisitTimestamptzCompare(ctx *parser.TimestamptzCompareCo compareOp := cmpOpMap[ctx.GetOp2().GetTokenType()] - timestamptzInt64, err := parseISOWithTimezone(unquotedCompareStr, v.args.TimezonePreference) + timestamptzInt64, err := funcutil.ValidateAndReturnUnixMicroTz(unquotedCompareStr, v.args.Timezone) if err != nil { return err } @@ -1976,3 +1977,86 @@ func (v *ParserVisitor) VisitTimestamptzCompare(ctx *parser.TimestamptzCompareCo dataType: schemapb.DataType_Bool, } } + +func (v *ParserVisitor) VisitTimestamptzCompareReverse(ctx *parser.TimestamptzCompareReverseContext) interface{} { + colExpr, err := v.translateIdentifier(ctx.Identifier().GetText()) + identifier := ctx.Identifier().GetText() + if err != nil { + return fmt.Errorf("can not translate identifier: %s", identifier) + } + if colExpr.dataType != schemapb.DataType_Timestamptz { + return fmt.Errorf("field '%s' is not a timestamptz datatype", identifier) + } + + arithOp := planpb.ArithOpType_Unknown + interval := &planpb.Interval{} + if ctx.GetOp1() != nil { + arithOp = arithExprMap[ctx.GetOp1().GetTokenType()] + rawIntervalStr := ctx.GetInterval_string().GetText() + unquotedIntervalStr, err := convertEscapeSingle(rawIntervalStr) + if err != nil { + return fmt.Errorf("can not convert interval string: %s", rawIntervalStr) + } + interval, err = parseISODuration(unquotedIntervalStr) + if err != nil { + return err + } + } + + rawCompareStr := ctx.GetCompare_string().GetText() + unquotedCompareStr, err := convertEscapeSingle(rawCompareStr) + if err != nil { + return fmt.Errorf("can not convert compare string: %s", rawCompareStr) + } + + originalCompareOp := cmpOpMap[ctx.GetOp2().GetTokenType()] + + compareOp := reverseCompareOp(originalCompareOp) + + if compareOp == planpb.OpType_Invalid && originalCompareOp != planpb.OpType_Invalid { + return fmt.Errorf("unsupported comparison operator for reverse Timestamptz: %s", ctx.GetOp2().GetText()) + } + + timestamptzInt64, err := funcutil.ValidateAndReturnUnixMicroTz(unquotedCompareStr, v.args.Timezone) + if err != nil { + return err + } + + newExpr := &planpb.Expr{ + Expr: &planpb.Expr_TimestamptzArithCompareExpr{ + TimestamptzArithCompareExpr: &planpb.TimestamptzArithCompareExpr{ + TimestamptzColumn: toColumnInfo(colExpr), + ArithOp: arithOp, + Interval: interval, + CompareOp: compareOp, + CompareValue: &planpb.GenericValue{ + Val: &planpb.GenericValue_Int64Val{Int64Val: timestamptzInt64}, + }, + }, + }, + } + + return &ExprWithType{ + expr: newExpr, + dataType: schemapb.DataType_Bool, + } +} + +func reverseCompareOp(op planpb.OpType) planpb.OpType { + switch op { + case planpb.OpType_LessThan: + return planpb.OpType_GreaterThan + case planpb.OpType_LessEqual: + return planpb.OpType_GreaterEqual + case planpb.OpType_GreaterThan: + return planpb.OpType_LessThan + case planpb.OpType_GreaterEqual: + return planpb.OpType_LessEqual + case planpb.OpType_Equal: + return planpb.OpType_Equal + case planpb.OpType_NotEqual: + return planpb.OpType_NotEqual + default: + return planpb.OpType_Invalid + } +} diff --git a/internal/parser/planparserv2/utils.go b/internal/parser/planparserv2/utils.go index de09a8d905..7c38da27f3 100644 --- a/internal/parser/planparserv2/utils.go +++ b/internal/parser/planparserv2/utils.go @@ -5,7 +5,6 @@ import ( "regexp" "strconv" "strings" - "time" "unicode" "github.com/cockroachdb/errors" @@ -173,6 +172,11 @@ func getTargetType(lDataType, rDataType schemapb.DataType) (schemapb.DataType, e return schemapb.DataType_Geometry, nil } } + if typeutil.IsTimestamptzType(lDataType) { + if typeutil.IsTimestamptzType(rDataType) { + return schemapb.DataType_Timestamptz, nil + } + } if typeutil.IsFloatingType(lDataType) { if typeutil.IsJSONType(rDataType) || typeutil.IsArithmetic(rDataType) { return schemapb.DataType_Double, nil @@ -241,6 +245,9 @@ func castValue(dataType schemapb.DataType, value *planpb.GenericValue) (*planpb. if typeutil.IsStringType(dataType) && IsString(value) { return value, nil } + if typeutil.IsTimestamptzType(dataType) { + return value, nil + } if typeutil.IsBoolType(dataType) && IsBool(value) { return value, nil @@ -630,7 +637,8 @@ func canArithmetic(left, leftElement, right, rightElement schemapb.DataType, rev func canConvertToIntegerType(dataType, elementType schemapb.DataType) bool { return typeutil.IsIntegerType(dataType) || typeutil.IsJSONType(dataType) || - (typeutil.IsArrayType(dataType) && typeutil.IsIntegerType(elementType)) + (typeutil.IsArrayType(dataType) && typeutil.IsIntegerType(elementType)) || + typeutil.IsTimestamptzType(dataType) } func isIntegerColumn(col *planpb.ColumnInfo) bool { @@ -864,31 +872,3 @@ func parseISODuration(durationStr string) (*planpb.Interval, error) { return interval, nil } - -func parseISOWithTimezone(isoString string, preferredZones []string) (int64, error) { - timeZoneOffsetRegex := regexp.MustCompile(`([+-]\d{2}:\d{2}|Z)$`) - // layout for timestamp string without timezone - const layoutForNaiveTime = "2025-01-02T15:04:05.999999999" - if timeZoneOffsetRegex.MatchString(isoString) { // has timezone - t, err := time.Parse(time.RFC3339Nano, isoString) - if err != nil { - return 0, fmt.Errorf("failed to parse timezone-aware string '%s': %w", isoString, err) - } - return t.UnixMicro(), nil - } - for _, zoneName := range preferredZones { - loc, err := time.LoadLocation(zoneName) - if err != nil { - continue - } - t, err := time.ParseInLocation(layoutForNaiveTime, isoString, loc) - if err == nil { - return t.UnixMicro(), nil - } - } - t, err := time.ParseInLocation(layoutForNaiveTime, isoString, time.UTC) - if err != nil { - return 0, fmt.Errorf("failed to parse naive time string '%s' even with UTC fallback: %w", isoString, err) - } - return t.UnixMicro(), nil -} diff --git a/internal/proxy/search_util.go b/internal/proxy/search_util.go index 496f8e79e2..a2936d2aa9 100644 --- a/internal/proxy/search_util.go +++ b/internal/proxy/search_util.go @@ -633,14 +633,6 @@ func parseRankParams(rankParamsPair []*commonpb.KeyValuePair, schema *schemapb.C }, nil } -func parseTimezone(params []*commonpb.KeyValuePair) string { - timezone, err := funcutil.GetAttrByKeyFromRepeatedKV(TimezoneKey, params) - if err != nil { - return "" - } - return timezone -} - func parseTimeFields(params []*commonpb.KeyValuePair) []string { timeFields, err := funcutil.GetAttrByKeyFromRepeatedKV(TimefieldsKey, params) if err != nil { diff --git a/internal/proxy/task.go b/internal/proxy/task.go index 60ff1fafb0..c155d3e1d5 100644 --- a/internal/proxy/task.go +++ b/internal/proxy/task.go @@ -73,7 +73,6 @@ const ( OffsetKey = "offset" LimitKey = "limit" // key for timestamptz translation - TimezoneKey = "timezone" TimefieldsKey = "time_fields" SearchIterV2Key = "search_iter_v2" @@ -417,6 +416,12 @@ func (t *createCollectionTask) PreExecute(ctx context.Context) error { return err } + // Validate timezone + tz, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, t.GetProperties()) + if exist && !funcutil.IsTimezoneValid(tz) { + return merr.WrapErrParameterInvalidMsg("unknown or invalid IANA Time Zone ID: %s", tz) + } + // validate clustering key if err := t.validateClusteringKey(ctx); err != nil { return err @@ -1203,9 +1208,9 @@ func (t *alterCollectionTask) PreExecute(ctx context.Context) error { } } // Check the validation of timezone - err := checkTimezone(t.Properties...) - if err != nil { - return err + userDefinedTimezone, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, t.Properties) + if exist && !funcutil.IsTimezoneValid(userDefinedTimezone) { + return merr.WrapErrParameterInvalidMsg("unknown or invalid IANA Time Zone ID: %s", userDefinedTimezone) } } else if len(t.GetDeleteKeys()) > 0 { key := hasPropInDeletekeys(t.DeleteKeys) diff --git a/internal/proxy/task_database.go b/internal/proxy/task_database.go index 7e4689830d..93730570be 100644 --- a/internal/proxy/task_database.go +++ b/internal/proxy/task_database.go @@ -13,6 +13,7 @@ import ( "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/proto/rootcoordpb" "github.com/milvus-io/milvus/pkg/v2/util/commonpbutil" + "github.com/milvus-io/milvus/pkg/v2/util/funcutil" "github.com/milvus-io/milvus/pkg/v2/util/merr" "github.com/milvus-io/milvus/pkg/v2/util/paramtable" ) @@ -68,7 +69,15 @@ func (cdt *createDatabaseTask) OnEnqueue() error { } func (cdt *createDatabaseTask) PreExecute(ctx context.Context) error { - return ValidateDatabaseName(cdt.GetDbName()) + err := ValidateDatabaseName(cdt.GetDbName()) + if err != nil { + return err + } + tz, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, cdt.GetProperties()) + if exist && !funcutil.IsTimezoneValid(tz) { + return merr.WrapErrParameterInvalidMsg("unknown or invalid IANA Time Zone ID: %s", tz) + } + return nil } func (cdt *createDatabaseTask) Execute(ctx context.Context) error { @@ -267,9 +276,9 @@ func (t *alterDatabaseTask) OnEnqueue() error { func (t *alterDatabaseTask) PreExecute(ctx context.Context) error { if len(t.GetProperties()) > 0 { // Check the validation of timezone - err := checkTimezone(t.Properties...) - if err != nil { - return err + userDefinedTimezone, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, t.Properties) + if exist && !funcutil.IsTimezoneValid(userDefinedTimezone) { + return merr.WrapErrParameterInvalidMsg("unknown or invalid IANA Time Zone ID: %s", userDefinedTimezone) } } _, ok := common.GetReplicateID(t.Properties) diff --git a/internal/proxy/task_delete.go b/internal/proxy/task_delete.go index b458fdd2c4..c4ba8c00e0 100644 --- a/internal/proxy/task_delete.go +++ b/internal/proxy/task_delete.go @@ -301,10 +301,8 @@ func (dr *deleteRunner) Init(ctx context.Context) error { if err != nil { return ErrWithLog(log, "Failed to get collection info", err) } - _, dbTimezone := getDbTimezone(db) - _, colTimezone := getColTimezone(colInfo) - timezonePreference := []string{colTimezone, dbTimezone} - visitorArgs := &planparserv2.ParserVisitorArgs{TimezonePreference: timezonePreference} + colTimezone := getColTimezone(colInfo) + visitorArgs := &planparserv2.ParserVisitorArgs{Timezone: colTimezone} start := time.Now() dr.plan, err = planparserv2.CreateRetrievePlanArgs(dr.schema.schemaHelper, dr.req.GetExpr(), dr.req.GetExprTemplateValues(), visitorArgs) diff --git a/internal/proxy/task_index.go b/internal/proxy/task_index.go index 7bb4a30e2c..8cb5d7b786 100644 --- a/internal/proxy/task_index.go +++ b/internal/proxy/task_index.go @@ -228,6 +228,8 @@ func (cit *createIndexTask) parseIndexParams(ctx context.Context) error { return Params.AutoIndexConfig.ScalarIntIndexType.GetValue() } else if typeutil.IsFloatingType(dataType) { return Params.AutoIndexConfig.ScalarFloatIndexType.GetValue() + } else if typeutil.IsTimestamptzType(dataType) { + return Params.AutoIndexConfig.ScalarTimestampTzIndexType.GetValue() } return Params.AutoIndexConfig.ScalarVarcharIndexType.GetValue() } @@ -427,7 +429,7 @@ func (cit *createIndexTask) parseIndexParams(ctx context.Context) error { } } - // auto fill json path with field name if not specified for json index + // autofill json path with field name if not specified for json index if typeutil.IsJSONType(cit.fieldSchema.DataType) { if _, exist := indexParamsMap[common.JSONPathKey]; !exist { indexParamsMap[common.JSONPathKey] = cit.req.FieldName diff --git a/internal/proxy/task_insert.go b/internal/proxy/task_insert.go index e194bc5302..8dc9d92c2a 100644 --- a/internal/proxy/task_insert.go +++ b/internal/proxy/task_insert.go @@ -243,13 +243,6 @@ func (it *insertTask) PreExecute(ctx context.Context) error { return err } - // trans timestamptz data - _, colTimezone := getColTimezone(colInfo) - err = timestamptzIsoStr2Utc(it.insertMsg.GetFieldsData(), colTimezone) - if err != nil { - return err - } - partitionKeyMode, err := isPartitionKeyMode(ctx, it.insertMsg.GetDbName(), collectionName) if err != nil { log.Warn("check partition key mode failed", zap.String("collectionName", collectionName), zap.Error(err)) diff --git a/internal/proxy/task_query.go b/internal/proxy/task_query.go index 1e1c22a4bb..4694cce1ec 100644 --- a/internal/proxy/task_query.go +++ b/internal/proxy/task_query.go @@ -79,6 +79,7 @@ type queryTask struct { allQueryCnt int64 totalRelatedDataSize int64 mustUsePartitionKey bool + resolvedTimezoneStr string storageCost segcore.StorageCost } @@ -233,9 +234,9 @@ func parseQueryParams(queryParamsPair []*commonpb.KeyValuePair) (*queryParams, e } } - timezoneStr, err := funcutil.GetAttrByKeyFromRepeatedKV(TimezoneKey, queryParamsPair) - if err == nil { - timezone = timezoneStr + timezone, _ = funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, queryParamsPair) + if (timezone != "") && !funcutil.IsTimezoneValid(timezone) { + return nil, merr.WrapErrParameterInvalidMsg("unknown or invalid IANA Time Zone ID: %s", timezone) } extractTimeFieldsStr, err := funcutil.GetAttrByKeyFromRepeatedKV(TimefieldsKey, queryParamsPair) @@ -457,9 +458,16 @@ func (t *queryTask) PreExecute(ctx context.Context) error { t.request.Expr = IDs2Expr(pkField, t.ids) } - _, colTimezone := getColTimezone(colInfo) - timezonePreference := []string{t.queryParams.timezone, colTimezone} - if err := t.createPlanArgs(ctx, &planparserv2.ParserVisitorArgs{TimezonePreference: timezonePreference}); err != nil { + if t.queryParams.timezone != "" { + // validated in queryParams, no need to validate again + t.resolvedTimezoneStr = t.queryParams.timezone + log.Debug("determine timezone from request", zap.String("user defined timezone", t.resolvedTimezoneStr)) + } else { + t.resolvedTimezoneStr = getColTimezone(colInfo) + log.Debug("determine timezone from collection", zap.Any("collection timezone", t.resolvedTimezoneStr)) + } + + if err := t.createPlanArgs(ctx, &planparserv2.ParserVisitorArgs{Timezone: t.resolvedTimezoneStr}); err != nil { return err } t.plan.Node.(*planpb.PlanNode_Query).Query.Limit = t.RetrieveRequest.Limit @@ -666,31 +674,17 @@ func (t *queryTask) PostExecute(ctx context.Context) error { // first page for iteration, need to set up sessionTs for iterator t.result.SessionTs = getMaxMvccTsFromChannels(t.channelsMvcc, t.BeginTs()) } - // Translate timestamp to ISO string - collName := t.request.GetCollectionName() - dbName := t.request.GetDbName() - collID, err := globalMetaCache.GetCollectionID(context.Background(), dbName, collName) - if err != nil { - log.Warn("fail to get collection id", zap.Error(err)) - return err - } - colInfo, err := globalMetaCache.GetCollectionInfo(ctx, dbName, collName, collID) - if err != nil { - log.Warn("fail to get collection info", zap.Error(err)) - return err - } - _, colTimezone := getColTimezone(colInfo) if !t.reQuery { if len(t.queryParams.extractTimeFields) > 0 { log.Debug("extracting fields for timestamptz", zap.Strings("fields", t.queryParams.extractTimeFields)) - err = extractFieldsFromResults(t.result.GetFieldsData(), []string{t.queryParams.timezone, colTimezone}, t.queryParams.extractTimeFields) + err = extractFieldsFromResults(t.result.GetFieldsData(), t.resolvedTimezoneStr, t.queryParams.extractTimeFields) if err != nil { log.Warn("fail to extract fields for timestamptz", zap.Error(err)) return err } } else { log.Debug("translate timestamp to ISO string", zap.String("user define timezone", t.queryParams.timezone)) - err = timestamptzUTC2IsoStr(t.result.GetFieldsData(), t.queryParams.timezone, colTimezone) + err = timestamptzUTC2IsoStr(t.result.GetFieldsData(), t.resolvedTimezoneStr) if err != nil { log.Warn("fail to translate timestamp", zap.Error(err)) return err diff --git a/internal/proxy/task_search.go b/internal/proxy/task_search.go index af10e13a9d..f2c5181f44 100644 --- a/internal/proxy/task_search.go +++ b/internal/proxy/task_search.go @@ -96,6 +96,8 @@ type searchTask struct { functionScore *rerank.FunctionScore rankParams *rankParams + resolvedTimezoneStr string + isIterator bool // we always remove pk field from output fields, as search result already contains pk field. // if the user explicitly set pk field in output fields, we add it back to the result. @@ -286,6 +288,19 @@ func (t *searchTask) PreExecute(ctx context.Context) error { } } + timezone, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, t.request.SearchParams) + if exist { + if !funcutil.IsTimezoneValid(timezone) { + log.Info("get invalid timezone from request", zap.String("timezone", timezone)) + return merr.WrapErrParameterInvalidMsg("unknown or invalid IANA Time Zone ID: %s", timezone) + } + log.Debug("determine timezone from request", zap.String("user defined timezone", timezone)) + } else { + timezone = getColTimezone(collectionInfo) + log.Debug("determine timezone from collection", zap.Any("collection timezone", timezone)) + } + t.resolvedTimezoneStr = timezone + t.resultBuf = typeutil.NewConcurrentSet[*internalpb.SearchResults]() if err = ValidateTask(t); err != nil { @@ -878,32 +893,16 @@ func (t *searchTask) PostExecute(ctx context.Context) error { metrics.ProxyReduceResultLatency.WithLabelValues(strconv.FormatInt(paramtable.GetNodeID(), 10), metrics.SearchLabel).Observe(float64(tr.RecordSpan().Milliseconds())) - // Translate timestamp to ISO string - collName := t.request.GetCollectionName() - dbName := t.request.GetDbName() - collID, err := globalMetaCache.GetCollectionID(context.Background(), dbName, collName) - if err != nil { - log.Warn("fail to get collection id", zap.Error(err)) - return err - } - colInfo, err := globalMetaCache.GetCollectionInfo(ctx, dbName, collName, collID) - if err != nil { - log.Warn("fail to get collection info", zap.Error(err)) - return err - } - _, colTimezone := getColTimezone(colInfo) timeFields := parseTimeFields(t.request.SearchParams) - timezoneUserDefined := parseTimezone(t.request.SearchParams) if timeFields != nil { log.Debug("extracting fields for timestamptz", zap.Strings("fields", timeFields)) - err = extractFieldsFromResults(t.result.GetResults().GetFieldsData(), []string{timezoneUserDefined, colTimezone}, timeFields) + err = extractFieldsFromResults(t.result.GetResults().GetFieldsData(), t.resolvedTimezoneStr, timeFields) if err != nil { log.Warn("fail to extract fields for timestamptz", zap.Error(err)) return err } } else { - log.Debug("translate timstamp to ISO string", zap.String("user define timezone", timezoneUserDefined)) - err = timestamptzUTC2IsoStr(t.result.GetResults().GetFieldsData(), timezoneUserDefined, colTimezone) + err = timestamptzUTC2IsoStr(t.result.GetResults().GetFieldsData(), t.resolvedTimezoneStr) if err != nil { log.Warn("fail to translate timestamp", zap.Error(err)) return err diff --git a/internal/proxy/task_upsert.go b/internal/proxy/task_upsert.go index a95888dbcd..9505f2b2c6 100644 --- a/internal/proxy/task_upsert.go +++ b/internal/proxy/task_upsert.go @@ -1068,17 +1068,6 @@ func (it *upsertTask) PreExecute(ctx context.Context) error { } } - // trans timestamptz data - _, colTimezone := getColTimezone(colInfo) - err = timestamptzIsoStr2Utc(it.insertFieldData, colTimezone) - if err != nil { - return err - } - err = timestamptzIsoStr2Utc(it.req.GetFieldsData(), colTimezone) - if err != nil { - return err - } - it.upsertMsg = &msgstream.UpsertMsg{ InsertMsg: &msgstream.InsertMsg{ InsertRequest: &msgpb.InsertRequest{ diff --git a/internal/proxy/util.go b/internal/proxy/util.go index 629a0f5155..0977a56278 100644 --- a/internal/proxy/util.go +++ b/internal/proxy/util.go @@ -2740,143 +2740,54 @@ func reconstructStructFieldDataForSearch(results *milvuspb.SearchResults, schema results.Results.OutputFields = outputFields } -func hasTimestamptzField(schema *schemapb.CollectionSchema) bool { - for _, field := range schema.Fields { - if field.GetDataType() == schemapb.DataType_Timestamptz { - return true - } +func getColTimezone(colInfo *collectionInfo) string { + timezone, _ := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, colInfo.properties) + if timezone == "" { + timezone = common.DefaultTimezone } - return false + return timezone } -func getDefaultTimezoneVal(props ...*commonpb.KeyValuePair) (bool, string) { - for _, p := range props { - // used in collection or database - if p.GetKey() == common.DatabaseDefaultTimezone || p.GetKey() == common.CollectionDefaultTimezone { - return true, p.Value - } - } - return false, "" -} - -func checkTimezone(props ...*commonpb.KeyValuePair) error { - hasTImezone, timezoneStr := getDefaultTimezoneVal(props...) - if hasTImezone { - _, err := time.LoadLocation(timezoneStr) - if err != nil { - return merr.WrapErrParameterInvalidMsg("invalid timezone, should be a IANA timezone name: %s", err.Error()) - } - } - return nil -} - -func getColTimezone(colInfo *collectionInfo) (bool, string) { - return getDefaultTimezoneVal(colInfo.properties...) -} - -func getDbTimezone(dbInfo *databaseInfo) (bool, string) { - return getDefaultTimezoneVal(dbInfo.properties...) -} - -func timestamptzIsoStr2Utc(columns []*schemapb.FieldData, colTimezone string) error { - naiveLayouts := []string{ - "2006-01-02T15:04:05.999999999", - "2006-01-02T15:04:05", - "2006-01-02 15:04:05.999999999", - "2006-01-02 15:04:05", - } - for _, fieldData := range columns { - if fieldData.GetType() != schemapb.DataType_Timestamptz { - continue - } - - scalarField := fieldData.GetScalars() - if scalarField == nil || scalarField.GetStringData() == nil { - log.Warn("field data is not string data", zap.String("fieldName", fieldData.GetFieldName())) - return merr.WrapErrParameterInvalidMsg("field data is not string data") - } - - stringData := scalarField.GetStringData().GetData() - utcTimestamps := make([]int64, len(stringData)) - - for i, isoStr := range stringData { - var t time.Time - var err error - // parse directly - t, err = time.Parse(time.RFC3339Nano, isoStr) - if err == nil { - utcTimestamps[i] = t.UnixMicro() - continue - } - // no timezone, try to find timezone in collecion -> database level - defaultTZ := "UTC" - if colTimezone != "" { - defaultTZ = colTimezone - } - - location, err := time.LoadLocation(defaultTZ) - if err != nil { - log.Error("invalid timezone", zap.String("timezone", defaultTZ), zap.Error(err)) - return merr.WrapErrParameterInvalidMsg("got invalid default timezone: %s", defaultTZ) - } - var parsed bool - for _, layout := range naiveLayouts { - t, err = time.ParseInLocation(layout, isoStr, location) - if err == nil { - parsed = true - break - } - } - if !parsed { - log.Warn("Can not parse timestamptz string", zap.String("timestamp_string", isoStr)) - return merr.WrapErrParameterInvalidMsg("got invalid timestamptz string: %s", isoStr) - } - utcTimestamps[i] = t.UnixMicro() - } - // Replace data in place - fieldData.GetScalars().Data = &schemapb.ScalarField_TimestamptzData{ - TimestamptzData: &schemapb.TimestamptzArray{ - Data: utcTimestamps, - }, - } - } - return nil -} - -func timestamptzUTC2IsoStr(results []*schemapb.FieldData, userDefineTimezone string, colTimezone string) error { - // Determine the target timezone based on priority: collection -> database -> UTC. - defaultTZ := "UTC" - if userDefineTimezone != "" { - defaultTZ = userDefineTimezone - } else if colTimezone != "" { - defaultTZ = colTimezone - } - - location, err := time.LoadLocation(defaultTZ) +// timestamptzUTC2IsoStr converts Timestamptz (Unix Microsecond) data +// within FieldData results into ISO-8601 strings, applying the correct +// timezone offset and using the optimized format (microsecond precision, no trailing zeros). +func timestamptzUTC2IsoStr(results []*schemapb.FieldData, colTimezone string) error { + location, err := time.LoadLocation(colTimezone) if err != nil { - log.Error("invalid timezone", zap.String("timezone", defaultTZ), zap.Error(err)) - return merr.WrapErrParameterInvalidMsg("got invalid default timezone: %s", defaultTZ) + log.Error("invalid timezone", zap.String("timezone", colTimezone), zap.Error(err)) + return merr.WrapErrParameterInvalidMsg("got invalid default timezone: %s", colTimezone) } for _, fieldData := range results { if fieldData.GetType() != schemapb.DataType_Timestamptz { continue } + scalarField := fieldData.GetScalars() + + // Guard against nil scalars or missing timestamp data if scalarField == nil || scalarField.GetTimestamptzData() == nil { if longData := scalarField.GetLongData(); longData != nil && len(longData.GetData()) > 0 { log.Warn("field data is not Timestamptz data", zap.String("fieldName", fieldData.GetFieldName())) return merr.WrapErrParameterInvalidMsg("field data for '%s' is not Timestamptz data", fieldData.GetFieldName()) } + // Handle the case of an empty field (e.g., all nulls), skip if no data to process. + continue } utcTimestamps := scalarField.GetTimestamptzData().GetData() isoStrings := make([]string, len(utcTimestamps)) + // CORE CHANGE: Use the optimized formatting function for i, ts := range utcTimestamps { + // 1. Convert Unix Microsecond (UTC) to a time.Time object (still in UTC). t := time.UnixMicro(ts).UTC() + + // 2. Adjust the time object to the target location. localTime := t.In(location) - isoStrings[i] = localTime.Format(time.RFC3339Nano) + + // 3. Format using the optimized logic (max 6 digits, no trailing zeros) + isoStrings[i] = funcutil.FormatTimeMicroWithoutTrailingZeros(localTime) } // Replace the TimestamptzData with the new StringData in place. @@ -2918,23 +2829,11 @@ func extractFields(t time.Time, fieldList []string) ([]int64, error) { return extractedValues, nil } -func extractFieldsFromResults(results []*schemapb.FieldData, precedenceTimezone []string, fieldList []string) error { - var targetLocation *time.Location - - for _, tz := range precedenceTimezone { - if tz != "" { - loc, err := time.LoadLocation(tz) - if err != nil { - log.Error("invalid timezone provided in precedence list", zap.String("timezone", tz), zap.Error(err)) - return merr.WrapErrParameterInvalidMsg("got invalid timezone: %s", tz) - } - targetLocation = loc - break // Use the first valid timezone found. - } - } - - if targetLocation == nil { - targetLocation = time.UTC +func extractFieldsFromResults(results []*schemapb.FieldData, timezone string, fieldList []string) error { + targetLocation, err := time.LoadLocation(timezone) + if err != nil { + log.Error("invalid timezone", zap.String("timezone", timezone), zap.Error(err)) + return merr.WrapErrParameterInvalidMsg("got invalid timezone: %s", timezone) } for _, fieldData := range results { diff --git a/internal/proxy/validate_util.go b/internal/proxy/validate_util.go index c7f30b17af..917532aecb 100644 --- a/internal/proxy/validate_util.go +++ b/internal/proxy/validate_util.go @@ -189,11 +189,12 @@ func (v *validateUtil) Validate(data []*schemapb.FieldData, helper *typeutil.Sch case schemapb.DataType_ArrayOfStruct: panic("unreachable, array of struct should have been flattened") case schemapb.DataType_Timestamptz: - // TODO: Add check logic for timestamptz data + if err := v.checkTimestamptzFieldData(field, helper.GetTimezone()); err != nil { + return err + } default: } } - err := v.fillWithValue(data, helper, int(numRows)) if err != nil { return err @@ -465,13 +466,11 @@ func FillWithNullValue(field *schemapb.FieldData, fieldSchema *schemapb.FieldSch if err != nil { return err } - case *schemapb.ScalarField_StringData: sd.StringData.Data, err = fillWithNullValueImpl(sd.StringData.Data, field.GetValidData()) if err != nil { return err } - case *schemapb.ScalarField_ArrayData: sd.ArrayData.Data, err = fillWithNullValueImpl(sd.ArrayData.Data, field.GetValidData()) if err != nil { @@ -568,11 +567,32 @@ func FillWithDefaultValue(field *schemapb.FieldData, fieldSchema *schemapb.Field } case *schemapb.ScalarField_TimestamptzData: + // Basic validation: Check if the length of the validity mask matches the number of rows. if len(field.GetValidData()) != numRows { msg := fmt.Sprintf("the length of valid_data of field(%s) is wrong", field.GetFieldName()) return merr.WrapErrParameterInvalid(numRows, len(field.GetValidData()), msg) } + + // Retrieve the default value, which is usually stored as int64 (UTC microseconds). defaultValue := fieldSchema.GetDefaultValue().GetTimestamptzData() + + // If the int64 default value is 0 (which might happen if it was not fully persisted + // or if the underlying storage is being checked), attempt to fall back to the string value. + if defaultValue == 0 { + strDefaultValue := fieldSchema.GetDefaultValue().GetStringData() + + // If a non-empty string default value exists, perform conversion. + if len(strDefaultValue) != 0 { + // NOTE: The strDefaultValue is guaranteed to be a valid ISO 8601 timestamp string, + // as it was validated during collection schema creation (by checkAndRewriteTimestampTzDefaultValue). + // + // Since the string either contains a UTC offset (e.g., '+08:00') or should be treated + // as UTC/the collection's primary timezone, the 'common.DefaultTimezone' passed here + // as the fallback timezone is generally inconsequential (negligible) + // for the final conversion result in this specific context. + defaultValue, _ = funcutil.ValidateAndReturnUnixMicroTz(strDefaultValue, common.DefaultTimezone) + } + } sd.TimestamptzData.Data, err = fillWithDefaultValueImpl(sd.TimestamptzData.Data, defaultValue, field.GetValidData()) if err != nil { return nil @@ -939,16 +959,6 @@ func (v *validateUtil) checkDoubleFieldData(field *schemapb.FieldData, fieldSche return nil } -func (v *validateUtil) checkTimestamptzFieldData(field *schemapb.FieldData, fieldSchema *schemapb.FieldSchema) error { - data := field.GetScalars().GetTimestamptzData().GetData() - if data == nil && fieldSchema.GetDefaultValue() == nil && !fieldSchema.GetNullable() { - msg := fmt.Sprintf("field '%v' is illegal, array type mismatch", field.GetFieldName()) - return merr.WrapErrParameterInvalid("need long int array", "got nil", msg) - } - // TODO: Additional checks? - return nil -} - func (v *validateUtil) checkArrayElement(array *schemapb.ArrayArray, field *schemapb.FieldSchema) error { switch field.GetElementType() { case schemapb.DataType_Bool: @@ -1140,6 +1150,43 @@ func (v *validateUtil) checkArrayOfVectorFieldData(field *schemapb.FieldData, fi } } +// checkTimestamptzFieldData validates the input string data for a Timestamptz field, +// converts it into UTC Unix Microseconds (int64), and replaces the data in place. +func (v *validateUtil) checkTimestamptzFieldData(field *schemapb.FieldData, timezone string) error { + // 1. Structural Check: Data must be present and must be a string array + scalarField := field.GetScalars() + if scalarField == nil || scalarField.GetStringData() == nil { + log.Warn("timestamptz field data is not string array", zap.String("fieldName", field.GetFieldName())) + return merr.WrapErrParameterInvalidMsg("timestamptz field data must be a string array") + } + + stringData := scalarField.GetStringData().GetData() + utcTimestamps := make([]int64, len(stringData)) + + // 2. Validation and Conversion Loop + for i, isoStr := range stringData { + // Use the centralized parser (funcutil.ParseTimeTz) for validation and parsing. + t, err := funcutil.ParseTimeTz(isoStr, timezone) + if err != nil { + log.Warn("cannot parse timestamptz string", zap.String("timestamp_string", isoStr), zap.Error(err)) + // Use the recommended refined error message structure + const invalidMsg = "invalid timezone name; must be a valid IANA Time Zone ID (e.g., 'Asia/Shanghai' or 'UTC')" + return merr.WrapErrParameterInvalidMsg("got invalid timestamptz string '%s': %s", isoStr, invalidMsg) + } + + // Convert the time object to Unix Microseconds (int64) + utcTimestamps[i] = t.UnixMicro() + } + + // 3. In-Place Data Replacement: Replace StringData with converted TimestamptzData (int64) + field.GetScalars().Data = &schemapb.ScalarField_TimestamptzData{ + TimestamptzData: &schemapb.TimestamptzArray{ + Data: utcTimestamps, + }, + } + return nil +} + func verifyLengthPerRow[E interface{ ~string | ~[]byte }](strArr []E, maxLength int64) (int, bool) { for i, s := range strArr { if int64(len(s)) > maxLength { diff --git a/internal/rootcoord/create_collection_task.go b/internal/rootcoord/create_collection_task.go index 9012766f51..9855daa493 100644 --- a/internal/rootcoord/create_collection_task.go +++ b/internal/rootcoord/create_collection_task.go @@ -153,6 +153,70 @@ func checkGeometryDefaultValue(value string) error { return nil } +// checkAndRewriteTimestampTzDefaultValue processes the collection schema to validate +// and rewrite default values for TIMESTAMPTZ fields. +// +// Background: +// 1. TIMESTAMPTZ default values are initially stored as user-provided ISO 8601 strings +// (in ValueField.GetStringData()). +// 2. Milvus stores TIMESTAMPTZ data internally as UTC microseconds (int64). +// +// Logic: +// The function iterates through all fields of type DataType_Timestamptz. For each field +// with a default value: +// 1. It retrieves the collection's default timezone if no offset is present in the string. +// 2. It calls ValidateAndReturnUnixMicroTz to validate the string (including the UTC +// offset range check) and convert it to the absolute UTC microsecond (int64) value. +// 3. It rewrites the ValueField, setting the LongData field with the calculated int64 +// value, thereby replacing the initial string representation. +func checkAndRewriteTimestampTzDefaultValue(schema *schemapb.CollectionSchema) error { + // 1. Get the collection-level default timezone. + // Assuming common.TimezoneKey and common.DefaultTimezone are defined constants. + timezone, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, schema.GetProperties()) + if !exist { + timezone = common.DefaultTimezone + } + + for _, fieldSchema := range schema.GetFields() { + // Only process TIMESTAMPTZ fields. + if fieldSchema.GetDataType() != schemapb.DataType_Timestamptz { + continue + } + + defaultValue := fieldSchema.GetDefaultValue() + if defaultValue == nil { + continue + } + + // 2. Read the default value as a string (the input format). + // We expect the default value to be set in string_data initially. + stringTz := defaultValue.GetStringData() + if stringTz == "" { + // Skip or handle empty string default values if necessary. + continue + } + + // 3. Validate the string and convert it to UTC microsecond (int64). + // This also performs the critical UTC offset range validation. + utcMicro, err := funcutil.ValidateAndReturnUnixMicroTz(stringTz, timezone) + if err != nil { + // If validation fails (e.g., invalid format or illegal offset), return error immediately. + return err + } + + // 4. Rewrite the default value to store the UTC microsecond (int64). + // By setting ValueField_LongData, the oneof field in the protobuf structure + // automatically switches from string_data to long_data. + defaultValue.Data = &schemapb.ValueField_LongData{ + LongData: utcMicro, + } + + // The original string_data field is now cleared due to the oneof nature, + // and the default value is correctly represented as an int64 microsecond value. + } + return nil +} + func hasSystemFields(schema *schemapb.CollectionSchema, systemFields []string) bool { for _, f := range schema.GetFields() { if funcutil.SliceContain(systemFields, f.GetName()) { @@ -174,6 +238,11 @@ func (t *createCollectionTask) validateSchema(ctx context.Context, schema *schem return err } + // Validate default + if err := checkAndRewriteTimestampTzDefaultValue(schema); err != nil { + return err + } + if err := checkStructArrayFieldSchema(schema.GetStructArrayFields()); err != nil { return err } @@ -383,6 +452,12 @@ func (t *createCollectionTask) prepareSchema(ctx context.Context) error { return err } + // Validate timezone + tz, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, t.Req.GetProperties()) + if exist && !funcutil.IsTimezoneValid(tz) { + return merr.WrapErrParameterInvalidMsg("unknown or invalid IANA Time Zone ID: %s", tz) + } + // Set properties for persistent t.body.CollectionSchema.Properties = t.Req.GetProperties() t.body.CollectionSchema.Version = 0 @@ -472,13 +547,13 @@ func (t *createCollectionTask) Prepare(ctx context.Context) error { } // set collection timezone properties := t.Req.GetProperties() - ok, _ := getDefaultTimezoneVal(properties...) + _, ok := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, properties) if !ok { - ok, defaultTz := getDefaultTimezoneVal(db.Properties...) - if !ok { - defaultTz = "UTC" + dbTz, ok2 := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, db.Properties) + if !ok2 { + dbTz = common.DefaultTimezone } - timezoneKV := &commonpb.KeyValuePair{Key: common.CollectionDefaultTimezone, Value: defaultTz} + timezoneKV := &commonpb.KeyValuePair{Key: common.CollectionDefaultTimezone, Value: dbTz} t.Req.Properties = append(properties, timezoneKV) } diff --git a/internal/rootcoord/ddl_callbacks_alter_collection_properties.go b/internal/rootcoord/ddl_callbacks_alter_collection_properties.go index 56c28c6ad3..42e7d1e4ee 100644 --- a/internal/rootcoord/ddl_callbacks_alter_collection_properties.go +++ b/internal/rootcoord/ddl_callbacks_alter_collection_properties.go @@ -19,6 +19,7 @@ import ( "github.com/milvus-io/milvus/pkg/v2/proto/querypb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message/ce" + "github.com/milvus-io/milvus/pkg/v2/util/funcutil" "github.com/milvus-io/milvus/pkg/v2/util/merr" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) @@ -37,6 +38,12 @@ func (c *Core) broadcastAlterCollectionForAlterCollection(ctx context.Context, r return merr.WrapErrParameterInvalidMsg("can not alter cipher related properties") } + // Validate timezone + tz, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, req.GetProperties()) + if exist && !funcutil.IsTimezoneValid(tz) { + return merr.WrapErrParameterInvalidMsg("unknown or invalid IANA Time Zone ID: %s", tz) + } + isEnableDynamicSchema, targetValue, err := common.IsEnableDynamicSchema(req.GetProperties()) if err != nil { return merr.WrapErrParameterInvalidMsg("invalid dynamic schema property value: %s", req.GetProperties()[0].GetValue()) diff --git a/internal/rootcoord/ddl_callbacks_alter_database.go b/internal/rootcoord/ddl_callbacks_alter_database.go index 3bbad984ba..81c2b63d9d 100644 --- a/internal/rootcoord/ddl_callbacks_alter_database.go +++ b/internal/rootcoord/ddl_callbacks_alter_database.go @@ -33,6 +33,7 @@ import ( "github.com/milvus-io/milvus/pkg/v2/proto/rootcoordpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message/ce" + "github.com/milvus-io/milvus/pkg/v2/util/funcutil" "github.com/milvus-io/milvus/pkg/v2/util/merr" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) @@ -51,6 +52,12 @@ func (c *Core) broadcastAlterDatabase(ctx context.Context, req *rootcoordpb.Alte return merr.WrapErrParameterInvalidMsg("can not alter cipher related properties") } + // Validate timezone + tz, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, req.GetProperties()) + if exist && !funcutil.IsTimezoneValid(tz) { + return merr.WrapErrParameterInvalidMsg("unknown or invalid IANA Time Zone ID: %s", tz) + } + broadcaster, err := startBroadcastWithDatabaseLock(ctx, req.GetDbName()) if err != nil { return err diff --git a/internal/rootcoord/ddl_callbacks_create_database.go b/internal/rootcoord/ddl_callbacks_create_database.go index 2f46efcf0f..c3f7531a10 100644 --- a/internal/rootcoord/ddl_callbacks_create_database.go +++ b/internal/rootcoord/ddl_callbacks_create_database.go @@ -27,9 +27,12 @@ import ( "github.com/milvus-io/milvus/internal/distributed/streaming" "github.com/milvus-io/milvus/internal/metastore/model" "github.com/milvus-io/milvus/internal/util/hookutil" + "github.com/milvus-io/milvus/pkg/v2/common" "github.com/milvus-io/milvus/pkg/v2/proto/etcdpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message/ce" + "github.com/milvus-io/milvus/pkg/v2/util/funcutil" + "github.com/milvus-io/milvus/pkg/v2/util/merr" ) func (c *Core) broadcastCreateDatabase(ctx context.Context, req *milvuspb.CreateDatabaseRequest) error { @@ -54,7 +57,10 @@ func (c *Core) broadcastCreateDatabase(ctx context.Context, req *milvuspb.Create if err != nil { return errors.Wrap(err, "failed to tidy database cipher properties") } - + tz, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, properties) + if exist && !funcutil.IsTimezoneValid(tz) { + return merr.WrapErrParameterInvalidMsg("unknown or invalid IANA Time Zone ID: %s", tz) + } msg := message.NewCreateDatabaseMessageBuilderV2(). WithHeader(&message.CreateDatabaseMessageHeader{ DbName: req.GetDbName(), diff --git a/internal/rootcoord/describe_collection_task.go b/internal/rootcoord/describe_collection_task.go index d5c6e6d22b..630f035e09 100644 --- a/internal/rootcoord/describe_collection_task.go +++ b/internal/rootcoord/describe_collection_task.go @@ -66,6 +66,11 @@ func (t *describeCollectionTask) Execute(ctx context.Context) (err error) { return err } t.Rsp = convertModelToDesc(coll, aliases, db.Name) + // NEW STEP: Convert TIMESTAMPTZ default values back to string format for the user. + err = rewriteTimestampTzDefaultValueToString(t.Rsp) + if err != nil { + return err + } t.Rsp.RequestTime = t.ts return nil } diff --git a/internal/rootcoord/root_coord.go b/internal/rootcoord/root_coord.go index 685e361446..14db9cbf48 100644 --- a/internal/rootcoord/root_coord.go +++ b/internal/rootcoord/root_coord.go @@ -1069,10 +1069,68 @@ func convertModelToDesc(collInfo *model.Collection, aliases []string, dbName str resp.DbId = collInfo.DBID resp.UpdateTimestamp = collInfo.UpdateTimestamp resp.UpdateTimestampStr = strconv.FormatUint(collInfo.UpdateTimestamp, 10) - return resp } +// rewriteTimestampTzDefaultValueToString converts the default_value of TIMESTAMPTZ fields +// in the DescribeCollectionResponse from the internal int64 (UTC microsecond) format +// back to a human-readable, timezone-aware string (RFC3339Nano). +// +// This is necessary because TIMESTAMPTZ default values are stored internally as int64 +// after validation but must be returned to the user as a string, respecting the +// collection's default timezone for display purposes if no explicit offset was stored. +func rewriteTimestampTzDefaultValueToString(resp *milvuspb.DescribeCollectionResponse) error { + if resp.GetSchema() == nil { + return nil + } + + // 1. Determine the target timezone for display. + // This is typically stored in the collection properties. + timezone, exist := funcutil.TryGetAttrByKeyFromRepeatedKV(common.TimezoneKey, resp.GetSchema().GetProperties()) + if !exist { + timezone = common.DefaultTimezone // Fallback to a default, like "UTC" + } + + // 2. Iterate through all fields in the schema. + for _, fieldSchema := range resp.Schema.GetFields() { + // Only process TIMESTAMPTZ fields. + if fieldSchema.GetDataType() != schemapb.DataType_Timestamptz { + continue + } + + defaultValue := fieldSchema.GetDefaultValue() + if defaultValue == nil { + continue + } + + // 3. Check if the default value is stored in the internal int64 (LongData) format. + // If it's not LongData, we assume it's either unset or already a string (which shouldn't happen + // if the creation flow worked correctly). + utcMicro, ok := defaultValue.GetData().(*schemapb.ValueField_LongData) + if !ok { + continue // Skip if not stored as LongData (int64) + } + + ts := utcMicro.LongData + + // 4. Convert the int64 microsecond value back to a timezone-aware string. + tzString, err := funcutil.ConvertUnixMicroToTimezoneString(ts, timezone) + if err != nil { + // In a real system, you might log the error and use the raw int64 as a fallback string, + // but here we'll set a placeholder string to avoid crashing. + tzString = fmt.Sprintf("Error converting timestamp: %v", err) + return errors.Wrap(err, tzString) + } + + // 5. Rewrite the default value field in the response schema. + // The protobuf oneof structure ensures setting one field clears the others. + fieldSchema.GetDefaultValue().Data = &schemapb.ValueField_StringData{ + StringData: tzString, + } + } + return nil +} + func (c *Core) describeCollectionImpl(ctx context.Context, in *milvuspb.DescribeCollectionRequest, allowUnavailable bool) (*milvuspb.DescribeCollectionResponse, error) { if err := merr.CheckHealthy(c.GetStateCode()); err != nil { return &milvuspb.DescribeCollectionResponse{ diff --git a/internal/rootcoord/util.go b/internal/rootcoord/util.go index 563d2905ad..85e9f83145 100644 --- a/internal/rootcoord/util.go +++ b/internal/rootcoord/util.go @@ -399,6 +399,8 @@ func checkFieldSchema(fieldSchemas []*schemapb.FieldSchema) error { if dtype == schemapb.DataType_Geometry { return checkGeometryDefaultValue(fieldSchema.GetDefaultValue().GetStringData()) } + log.Info("czsHaha111", zap.String("type", dtype.String()), zap.String("name", fieldSchema.GetName()), zap.Any("fieldSchema", fieldSchema), + zap.Any("defaultValue", fieldSchema.GetDefaultValue()), zap.Any("type", dtype.String())) errTypeMismatch := func(fieldName, fieldType, defaultValueType string) error { msg := fmt.Sprintf("type (%s) of field (%s) is not equal to the type(%s) of default_value", fieldType, fieldName, defaultValueType) return merr.WrapErrParameterInvalidMsg(msg) @@ -440,17 +442,22 @@ func checkFieldSchema(fieldSchemas []*schemapb.FieldSchema) error { return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Timestamptz") } case *schemapb.ValueField_StringData: - if dtype != schemapb.DataType_VarChar { - return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_VarChar") + if dtype != schemapb.DataType_VarChar && dtype != schemapb.DataType_Timestamptz { + if dtype != schemapb.DataType_VarChar { + return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_VarChar") + } + return errTypeMismatch(fieldSchema.GetName(), dtype.String(), "DataType_Timestamptz") } - maxLength, err := parameterutil.GetMaxLength(fieldSchema) - if err != nil { - return err - } - defaultValueLength := len(fieldSchema.GetDefaultValue().GetStringData()) - if int64(defaultValueLength) > maxLength { - msg := fmt.Sprintf("the length (%d) of string exceeds max length (%d)", defaultValueLength, maxLength) - return merr.WrapErrParameterInvalid("valid length string", "string length exceeds max length", msg) + if dtype == schemapb.DataType_VarChar { + maxLength, err := parameterutil.GetMaxLength(fieldSchema) + if err != nil { + return err + } + defaultValueLength := len(fieldSchema.GetDefaultValue().GetStringData()) + if int64(defaultValueLength) > maxLength { + msg := fmt.Sprintf("the length (%d) of string exceeds max length (%d)", defaultValueLength, maxLength) + return merr.WrapErrParameterInvalid("valid length string", "string length exceeds max length", msg) + } } case *schemapb.ValueField_BytesData: if dtype != schemapb.DataType_JSON { @@ -568,13 +575,3 @@ func nextFieldID(coll *model.Collection) int64 { } return maxFieldID + 1 } - -func getDefaultTimezoneVal(props ...*commonpb.KeyValuePair) (bool, string) { - for _, p := range props { - // used in collection or database - if p.GetKey() == common.DatabaseDefaultTimezone || p.GetKey() == common.CollectionDefaultTimezone { - return true, p.Value - } - } - return false, "" -} diff --git a/internal/storage/utils.go b/internal/storage/utils.go index 1b2754a620..63b12f3548 100644 --- a/internal/storage/utils.go +++ b/internal/storage/utils.go @@ -1600,7 +1600,6 @@ func fillMissingFields(schema *schemapb.CollectionSchema, insertData *InsertData batchRows := int64(insertData.GetRowNum()) allFields := typeutil.GetAllFieldSchemas(schema) - for _, field := range allFields { // Skip function output fields and system fields if field.GetIsFunctionOutput() || field.GetFieldID() < 100 { diff --git a/internal/util/importutilv2/parquet/field_reader.go b/internal/util/importutilv2/parquet/field_reader.go index 442337e4d7..a956b98b49 100644 --- a/internal/util/importutilv2/parquet/field_reader.go +++ b/internal/util/importutilv2/parquet/field_reader.go @@ -215,7 +215,7 @@ func (c *FieldReader) Next(count int64) (any, any, error) { vectors := lo.Flatten(arrayData.([][]int8)) return vectors, nil, nil case schemapb.DataType_Array: - // array has not support default_value + // array has not supported default_value if c.field.GetNullable() { return ReadNullableArrayData(c, count) } diff --git a/internal/util/indexparamcheck/stl_sort_checker.go b/internal/util/indexparamcheck/stl_sort_checker.go index 50a23ffd4f..908d227ba8 100644 --- a/internal/util/indexparamcheck/stl_sort_checker.go +++ b/internal/util/indexparamcheck/stl_sort_checker.go @@ -19,8 +19,9 @@ func (c *STLSORTChecker) CheckTrain(dataType schemapb.DataType, elementType sche } func (c *STLSORTChecker) CheckValidDataType(indexType IndexType, field *schemapb.FieldSchema) error { - if !typeutil.IsArithmetic(field.GetDataType()) && !typeutil.IsStringType(field.GetDataType()) { - return errors.New(fmt.Sprintf("STL_SORT are only supported on numeric or varchar field, got %s", field.GetDataType())) + dataType := field.GetDataType() + if !typeutil.IsArithmetic(dataType) && !typeutil.IsStringType(dataType) && !typeutil.IsTimestamptzType(dataType) { + return errors.New(fmt.Sprintf("STL_SORT are only supported on numeric, varchar or timestamptz field, got %s", field.GetDataType())) } return nil } diff --git a/pkg/common/common.go b/pkg/common/common.go index 28719e3b2f..b051491e8f 100644 --- a/pkg/common/common.go +++ b/pkg/common/common.go @@ -95,6 +95,8 @@ const ( CurrentScalarIndexEngineVersion = int32(2) ) +const DefaultTimezone = "UTC" + // Endian is type alias of binary.LittleEndian. // Milvus uses little endian by default. var Endian = binary.LittleEndian @@ -246,6 +248,7 @@ const ( NamespaceEnabledKey = "namespace.enabled" // timezone releated + TimezoneKey = "timezone" DatabaseDefaultTimezone = "database.timezone" CollectionDefaultTimezone = "collection.timezone" AllowInsertAutoIDKey = "allow_insert_auto_id" diff --git a/pkg/util/funcutil/timestamptz.go b/pkg/util/funcutil/timestamptz.go new file mode 100644 index 0000000000..167a56166c --- /dev/null +++ b/pkg/util/funcutil/timestamptz.go @@ -0,0 +1,200 @@ +package funcutil + +import ( + "bytes" + "fmt" + "strings" + "time" +) + +// Define max/min offset boundaries in seconds for validation, exported for external checks if necessary. +const ( + MaxOffsetSeconds = 14 * 3600 // +14:00 + MinOffsetSeconds = -12 * 3600 // -12:00 +) + +// NaiveTzLayouts is a list of common timestamp formats that lack timezone information. +var NaiveTzLayouts = []string{ + "2006-01-02T15:04:05.999999999", + "2006-01-02T15:04:05", + "2006-01-02 15:04:05.999999999", + "2006-01-02 15:04:05", +} + +// ParseTimeTz is the internal core function for parsing TZ-aware or naive timestamps. +// It includes strict validation for the UTC offset range. +func ParseTimeTz(inputStr string, defaultTimezoneStr string) (time.Time, error) { + // 1. Primary parsing: Attempt to parse a TZ-aware string (RFC3339Nano) + t, err := time.Parse(time.RFC3339Nano, inputStr) + + if err == nil { + // Parsing succeeded (TZ-aware string). Now, perform the strict offset validation. + + // If the string contains an explicit offset (like +99:00), t.Zone() will reflect it. + _, offsetSeconds := t.Zone() + + if offsetSeconds > MaxOffsetSeconds || offsetSeconds < MinOffsetSeconds { + offsetHours := offsetSeconds / 3600 + return time.Time{}, fmt.Errorf("UTC offset hour %d is out of the valid range [%d, %d]", offsetHours, MinOffsetSeconds/3600, MaxOffsetSeconds/3600) + } + + return t, nil + } + + loc, err := time.LoadLocation(defaultTimezoneStr) + if err != nil { + return time.Time{}, fmt.Errorf("invalid default timezone string '%s': %w", defaultTimezoneStr, err) + } + + // 2. Fallback parsing: Attempt to parse a naive string using NaiveTzLayouts + var parsed bool + for _, layout := range NaiveTzLayouts { + // For naive strings, time.ParseInLocation assigns the default location (loc). + parsedTime, parseErr := time.ParseInLocation(layout, inputStr, loc) + if parseErr == nil { + t = parsedTime + parsed = true + break + } + } + + if !parsed { + return time.Time{}, fmt.Errorf("invalid timestamp string: '%s'. Does not match any known format", inputStr) + } + + // No offset validation needed here: The time was assigned the safe defaultTimezoneStr (loc), + // which is already validated via time.LoadLocation. + + return t, nil +} + +// ValidateTimestampTz checks if the timestamp string is valid (TZ-aware or naive + default TZ). +func ValidateTimestampTz(inputStr string, defaultTimezoneStr string) error { + _, err := ParseTimeTz(inputStr, defaultTimezoneStr) + return err +} + +// ValidateAndNormalizeTimestampTz validates the timestamp and normalizes it to a TZ-aware RFC3339Nano string. +func ValidateAndNormalizeTimestampTz(inputStr string, defaultTimezoneStr string) (string, error) { + t, err := ParseTimeTz(inputStr, defaultTimezoneStr) + if err != nil { + return "", err + } + // Normalization: Format the time object to include the timezone offset. + return t.Format(time.RFC3339Nano), nil +} + +// ValidateAndReturnUnixMicroTz validates the timestamp and returns its Unix microsecond (int64) representation. +func ValidateAndReturnUnixMicroTz(inputStr string, defaultTimezoneStr string) (int64, error) { + t, err := ParseTimeTz(inputStr, defaultTimezoneStr) + if err != nil { + return 0, err + } + // UnixMicro() returns the number of microseconds since UTC 1970-01-01T00:00:00Z. + return t.UnixMicro(), nil +} + +// CompareUnixMicroTz compares two timestamp strings at Unix microsecond precision. +// If both strings are valid and represent the same microsecond moment in time, it returns true. +// Note: It assumes the input strings are guaranteed to be valid as per the requirement. +// If not, it will return an error indicating the invalid input. +func CompareUnixMicroTz(ts1 string, ts2 string, defaultTimezoneStr string) (bool, error) { + // 1. Parse the first timestamp + t1, err := ParseTimeTz(ts1, defaultTimezoneStr) + if err != nil { + return false, fmt.Errorf("error parsing first timestamp '%s': %w", ts1, err) + } + + // 2. Parse the second timestamp + t2, err := ParseTimeTz(ts2, defaultTimezoneStr) + if err != nil { + return false, fmt.Errorf("error parsing second timestamp '%s': %w", ts2, err) + } + + // 3. Compare their Unix Microsecond values (int64) + // This automatically compares them based on the UTC epoch, regardless of their original location representation. + return t1.UnixMicro() == t2.UnixMicro(), nil +} + +// ConvertUnixMicroToTimezoneString converts a Unix microsecond timestamp (UTC epoch) +// into a TZ-aware string formatted as RFC3339Nano, adjusted to the target timezone. +func ConvertUnixMicroToTimezoneString(ts int64, targetTimezoneStr string) (string, error) { + loc, err := time.LoadLocation(targetTimezoneStr) + if err != nil { + return "", fmt.Errorf("invalid target timezone string '%s': %w", targetTimezoneStr, err) + } + + // 1. Convert Unix Microsecond (UTC) to a time.Time object (still in UTC). + t := time.UnixMicro(ts).UTC() + + // 2. Adjust the time object to the target location. + localTime := t.In(loc) + + // 3. Format the result. + return localTime.Format(time.RFC3339Nano), nil +} + +// formatTimeMicroWithoutTrailingZeros is an optimized function to format a time.Time +// object. It first truncates the time to microsecond precision (6 digits) and then +// removes all trailing zeros from the fractional seconds part. +// +// Example 1: 2025-03-20T10:30:00.123456000Z -> 2025-03-20T10:30:00.123456Z +// Example 2: 2025-03-20T10:30:00.123000000Z -> 2025-03-20T10:30:00.123Z +// Example 3: 2025-03-20T10:30:00.000000000Z -> 2025-03-20T10:30:00Z +func FormatTimeMicroWithoutTrailingZeros(t time.Time) string { + // 1. Truncate to Microsecond (6 digits max) to ensure we don't exceed the required precision. + tMicro := t.Truncate(time.Microsecond) + + // 2. Format the time using the standard high precision format (RFC3339Nano). + // This results in exactly 9 fractional digits, padded with trailing zeros if necessary. + s := tMicro.Format(time.RFC3339Nano) + + // 3. Locate the key delimiters ('.' and the Timezone marker 'Z' or '+/-'). + dotIndex := strings.LastIndexByte(s, '.') + + // Find the Timezone marker index (Z, +, or -) + tzIndex := len(s) - 1 + for ; tzIndex >= 0; tzIndex-- { + if s[tzIndex] == 'Z' || s[tzIndex] == '+' || s[tzIndex] == '-' { + break + } + } + + // If the format is unexpected, return the original string. + if dotIndex == -1 || tzIndex == -1 { + return s + } + + // 4. Extract and efficiently trim the fractional part using bytes.TrimRight. + + // Slice the fractional part (e.g., "123456000") + fractionalPart := s[dotIndex+1 : tzIndex] + + // Use bytes.TrimRight for efficient removal of trailing '0' characters. + trimmedBytes := bytes.TrimRight([]byte(fractionalPart), "0") + + // 5. Reconstruct the final string based on the trimming result. + + // Case A: The fractional part was entirely zeros (e.g., .000000000) + if len(trimmedBytes) == 0 { + // Remove the '.' and the fractional part, keep the Timezone marker. + // Result: "2025-03-20T10:30:00Z" + return s[:dotIndex] + s[tzIndex:] + } + + // Case B: Fractional part remains (e.g., .123, .123456) + // Recombine: [Time Body] + "." + [Trimmed Fraction] + [Timezone Marker] + // The dot (s[:dotIndex+1]) must be retained here. + return s[:dotIndex+1] + string(trimmedBytes) + s[tzIndex:] +} + +// IsTimezoneValid checks if a given string is a valid, recognized timezone name +// (e.g., "Asia/Shanghai" or "UTC"). +// It utilizes Go's time.LoadLocation function. +func IsTimezoneValid(tz string) bool { + if tz == "" { + return false + } + _, err := time.LoadLocation(tz) + return err == nil +} diff --git a/pkg/util/funcutil/timestamptz_test.go b/pkg/util/funcutil/timestamptz_test.go new file mode 100644 index 0000000000..90cff6577b --- /dev/null +++ b/pkg/util/funcutil/timestamptz_test.go @@ -0,0 +1,629 @@ +package funcutil + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +// TestValidateAndNormalizeTimestampTz tests the function for string validation and normalization. +func TestValidateAndNormalizeTimestampTz(t *testing.T) { + testCases := []struct { + name string + inputStr string + defaultTZ string + expectedOutput string + expectError bool + errorContainsMsg string + }{ + { + name: "Case 1: TZ-aware (UTC)", + inputStr: "2024-10-23T15:30:00Z", + defaultTZ: "Asia/Tokyo", + expectedOutput: "2024-10-23T15:30:00Z", + expectError: false, + }, + { + name: "Case 2: TZ-aware (Offset)", + inputStr: "2024-10-23T15:30:00+05:30", + defaultTZ: "UTC", + expectedOutput: "2024-10-23T15:30:00+05:30", + expectError: false, + }, + { + name: "Case 3: Naive (Apply Default TZ Shanghai)", + inputStr: "2024-10-23 15:30:00", + defaultTZ: "Asia/Shanghai", // Shanghai is UTC+08:00 + expectedOutput: "2024-10-23T15:30:00+08:00", + expectError: false, + }, + { + name: "Case 4: Naive (Apply Default TZ LA)", + inputStr: "2024-10-23 15:30:00.123456", + defaultTZ: "America/Los_Angeles", // LA is UTC-07:00 (PDT for Oct) + expectedOutput: "2024-10-23T15:30:00.123456-07:00", + expectError: false, + }, + { + name: "Case 5: Invalid Format", + inputStr: "23-10-2024 15:30", + defaultTZ: "UTC", + expectedOutput: "", + expectError: true, + errorContainsMsg: "invalid timestamp string", + }, + { + name: "Case 6: Invalid Default Timezone", + inputStr: "2024-10-23T15:30:00Z", + defaultTZ: "Invalid/TZ", + expectedOutput: "", + expectError: true, + errorContainsMsg: "invalid default timezone string", + }, + { + name: "Case 7: Offset Too High (+15:00)", + inputStr: "2024-10-23T15:30:00+15:00", + defaultTZ: "UTC", + expectedOutput: "", + expectError: true, + errorContainsMsg: "UTC offset hour 15 is out of the valid range", + }, + { + name: "Case 8: Offset Too Low (-13:00)", + inputStr: "2024-10-23T15:30:00-13:00", + defaultTZ: "UTC", + expectedOutput: "", + expectError: true, + errorContainsMsg: "UTC offset hour -13 is out of the valid range", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result, err := ValidateAndNormalizeTimestampTz(tc.inputStr, tc.defaultTZ) + + if tc.expectError { + assert.Error(t, err) + if err != nil { + assert.Contains(t, err.Error(), tc.errorContainsMsg) + } + } else { + assert.NoError(t, err) + // Truncate expected output to microsecond for safe comparison + // as time.Time can contain up to nanoseconds, but we test to microsecond precision. + tParsed, _ := time.Parse(time.RFC3339Nano, tc.expectedOutput) + expectedFormatted := tParsed.Truncate(time.Microsecond).Format(time.RFC3339Nano) + + assert.Equal(t, expectedFormatted, result) + } + }) + } +} + +// TestValidateAndReturnUnixMicroTz tests the function for Unix microsecond conversion. +func TestValidateAndReturnUnixMicroTz(t *testing.T) { + // Base time for comparison: 2024-10-23T15:30:00.123456Z (UTC) + // UnixMicro should be the same regardless of input format/timezone if moment is the same. + expectedMicro := int64(1729697400123456) + + testCases := []struct { + name string + inputStr string + defaultTZ string + expectedMicro int64 + expectError bool + }{ + { + name: "Case 1: TZ-aware (UTC)", + inputStr: "2024-10-23T15:30:00.123456Z", + defaultTZ: "Asia/Tokyo", + expectedMicro: expectedMicro, + expectError: false, + }, + { + name: "Case 2: TZ-aware (Offset)", + inputStr: "2024-10-23T23:30:00.123456+08:00", // +8h is 15:30 UTC + defaultTZ: "UTC", + expectedMicro: expectedMicro, + expectError: false, + }, + { + name: "Case 3: Naive (Apply Default TZ Shanghai)", + inputStr: "2024-10-23 23:30:00.123456", // 23:30 Shanghai (UTC+08:00) is 15:30 UTC + defaultTZ: "Asia/Shanghai", + expectedMicro: expectedMicro, + expectError: false, + }, + { + name: "Case 4: Naive (Apply Default TZ LA)", + inputStr: "2024-10-23 08:30:00.123456", // 08:30 LA (PDT, UTC-07:00) is 15:30 UTC + defaultTZ: "America/Los_Angeles", + expectedMicro: expectedMicro, + expectError: false, + }, + { + name: "Case 5: Invalid Offset", + inputStr: "2024-10-23T15:30:00+15:00", + defaultTZ: "UTC", + expectedMicro: 0, + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result, err := ValidateAndReturnUnixMicroTz(tc.inputStr, tc.defaultTZ) + + if tc.expectError { + assert.Error(t, err) + assert.Equal(t, int64(0), result) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.expectedMicro, result) + } + }) + } +} + +// TestCompareUnixMicroTz tests the comparison function. +func TestCompareUnixMicroTz(t *testing.T) { + // Base time for comparison: 2025-10-23T15:30:00Z (Using the current date for realism) + + // These strings all represent the moment 2025-10-23T15:30:00.000000Z + sameTime1 := "2025-10-23T15:30:00Z" + sameTime2 := "2025-10-23T23:30:00+08:00" // Shanghai: 23:30 local -> 15:30 UTC + sameTime3 := "2025-10-23 15:30:00" // Naive time + + // A slightly different moment (1 microsecond later) + differentTime := "2025-10-23T15:30:00.000001Z" + + testCases := []struct { + name string + ts1 string + ts2 string + defaultTZ string + expectedCmp bool + expectError bool + }{ + { + name: "Case 1: Same moment, different explicit TZ format", + ts1: sameTime1, // 15:30 UTC + ts2: sameTime2, // 15:30 UTC + defaultTZ: "UTC", + expectedCmp: true, + expectError: false, + }, + { + name: "Case 2: Same moment, one naive, UTC default TZ needed", + ts1: sameTime1, // 15:30 UTC + ts2: sameTime3, // 15:30 assigned UTC -> 15:30 UTC + defaultTZ: "UTC", + expectedCmp: true, + expectError: false, + }, + { + // FIX FOR DST: On 2025-10-23, New York is in EDT (UTC-04:00). + // To match 15:30 UTC, the naive time (ts2) must be 15:30 + 04:00 = 19:30 local time. + name: "Case 3: Same moment, DST-aware comparison for naive string", + ts1: "2025-10-23T19:30:00-04:00", // 19:30 EDT -> 15:30 UTC + ts2: "2025-10-23 19:30:00", // 19:30 assigned New York (EDT) -> 15:30 UTC + defaultTZ: "America/New_York", + expectedCmp: true, + expectError: false, + }, + { + name: "Case 4: Different moment (1 microsecond difference)", + ts1: sameTime1, + ts2: differentTime, + defaultTZ: "UTC", + expectedCmp: false, + expectError: false, + }, + // Revised Case 5 + { + name: "Case 5: Different naive times under the same default TZ", + ts1: "2025-10-23 10:00:00", // 10:00 assigned LA -> 03:00 UTC + ts2: "2025-10-23 11:00:00", // 11:00 assigned LA -> 04:00 UTC + defaultTZ: "America/Los_Angeles", + expectedCmp: false, // 03:00 UTC != 04:00 UTC + expectError: false, + }, + // New Case 5B: Identical naive strings MUST be equal. + { + name: "Case 5B: Identical naive strings must be equal", + ts1: "2025-10-23 10:00:00", // 10:00 assigned LA -> 03:00 UTC + ts2: "2025-10-23 10:00:00", // 10:00 assigned LA -> 03:00 UTC + defaultTZ: "America/Los_Angeles", + expectedCmp: true, + expectError: false, + }, + { + name: "Case 6: Invalid TS1 (Offset Too High)", + ts1: "2025-10-23T15:30:00+15:00", // Should fail offset check + ts2: sameTime1, + defaultTZ: "UTC", + expectedCmp: false, + expectError: true, + }, + { + name: "Case 7: Invalid TS2 (Bad Format)", + ts1: sameTime1, + ts2: "not a timestamp", + defaultTZ: "UTC", + expectedCmp: false, + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result, err := CompareUnixMicroTz(tc.ts1, tc.ts2, tc.defaultTZ) + + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tc.expectedCmp, result) + } + }) + } +} + +// TestValidateTimestampTz tests the simple validation function. +func TestValidateTimestampTz(t *testing.T) { + testCases := []struct { + name string + inputStr string + defaultTZ string + expectError bool + }{ + { + name: "Case 1: Valid TZ-aware", + inputStr: "2024-10-23T15:30:00Z", + defaultTZ: "UTC", + expectError: false, + }, + { + name: "Case 2: Valid Naive", + inputStr: "2024-10-23 15:30:00", + defaultTZ: "Asia/Shanghai", + expectError: false, + }, + { + name: "Case 3: Invalid Format", + inputStr: "Invalid", + defaultTZ: "UTC", + expectError: true, + }, + { + name: "Case 4: Invalid Offset", + inputStr: "2024-10-23T15:30:00+15:00", + defaultTZ: "UTC", + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := ValidateTimestampTz(tc.inputStr, tc.defaultTZ) + + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +// TestConvertUnixMicroToTimezoneString tests the conversion of Unix Microsecond +// to a TZ-aware RFC3339Nano string. +func TestConvertUnixMicroToTimezoneString2(t *testing.T) { + // Base time for all tests: 2025-03-20T10:30:00.123456Z (UTC) + // This date is chosen to test standard time outside of DST changes. + baseTimeUTC := time.Date(2025, time.March, 20, 10, 30, 0, 123456000, time.UTC) + baseUnixMicro := baseTimeUTC.UnixMicro() // 1710921000123456 (Actual value calculated by Go) + + // DST test date: 2025-10-23T15:30:00.000000Z (UTC) + // New York is in EDT (UTC-04:00) on this date. + dstTimeUTC := time.Date(2025, time.October, 23, 15, 30, 0, 0, time.UTC) + dstUnixMicro := dstTimeUTC.UnixMicro() // 1729697400000000 + + testCases := []struct { + name string + unixMicro int64 + targetTZ string + expectedOutput string + expectError bool + errorContainsMsg string + }{ + // --- Basic Functionality & Precision --- + { + name: "Case 1: Standard conversion to UTC", + unixMicro: baseUnixMicro, + targetTZ: "UTC", + expectedOutput: "2025-03-20T10:30:00.123456Z", + expectError: false, + }, + { + name: "Case 2: Conversion to Asia/Shanghai (+08:00)", + unixMicro: baseUnixMicro, + targetTZ: "Asia/Shanghai", // UTC+08:00 + expectedOutput: "2025-03-20T18:30:00.123456+08:00", + expectError: false, + }, + { + name: "Case 3: Conversion to America/Los_Angeles (PDT on Mar 20)", + unixMicro: baseUnixMicro, + targetTZ: "America/Los_Angeles", + // Corrected Output: 10:30 UTC - 7 hours (PDT) = 03:30 local time + expectedOutput: "2025-03-20T03:30:00.123456-07:00", + expectError: false, + }, + + // --- DST Handling (2025-10-23) --- + { + name: "Case 4: DST active (America/New_York) - UTC-04:00", + unixMicro: dstUnixMicro, + targetTZ: "America/New_York", // EDT = UTC-04:00 on this date + expectedOutput: "2025-10-23T11:30:00-04:00", // 15:30 UTC -> 11:30 local time + expectError: false, + }, + + // --- Error Handling --- + { + name: "Case 5: Invalid Timezone String", + unixMicro: baseUnixMicro, + targetTZ: "Invalid/TZ_Name", + expectedOutput: "", + expectError: true, + errorContainsMsg: "invalid target timezone string", + }, + { + name: "Case 6: UnixMicro 0 (Epoch)", + unixMicro: 0, + targetTZ: "UTC", + expectedOutput: "1970-01-01T00:00:00Z", + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result, err := ConvertUnixMicroToTimezoneString(tc.unixMicro, tc.targetTZ) + + if tc.expectError { + assert.Error(t, err) + if err != nil { + assert.Contains(t, err.Error(), tc.errorContainsMsg) + } + } else { + assert.NoError(t, err) + + // Assert the resulting string can be parsed back and retains microsecond precision + tParsed, parseErr := time.Parse(time.RFC3339Nano, result) + assert.NoError(t, parseErr) + + // Standardize the expected output to ensure nanosecond precision padding is correct + expectedFormatted := tc.expectedOutput + + assert.Equal(t, expectedFormatted, result) + + // Ensure the microsecond value is maintained (conversion consistency check) + assert.Equal(t, tc.unixMicro, tParsed.UnixMicro()) + } + }) + } +} + +// TestFormatTimeMicroWithoutTrailingZerosREVISED tests the custom formatting function +// to ensure it correctly truncates to microsecond and removes trailing zeros. +func TestFormatTimeMicroWithoutTrailingZeros(t *testing.T) { + testCases := []struct { + name string + nanoSeconds int // Nanoseconds part + tzOffsetHours int // TZ Offset in hours + expectedOutput string // Expected final string after cleaning + }{ + { + name: "Case 1: Full Microsecond Precision (No trailing zeros to remove)", + nanoSeconds: 123456000, // .123456 + tzOffsetHours: 8, + expectedOutput: "2025-10-23T00:00:00.123456+08:00", + }, + { + name: "Case 2: Millisecond Precision (Remove 6 trailing zeros)", + nanoSeconds: 123000000, // .123 + tzOffsetHours: 8, + expectedOutput: "2025-10-23T00:00:00.123+08:00", + }, + { + name: "Case 3: Second Precision (Remove all 9 fractional zeros)", + nanoSeconds: 0, // .000000 + tzOffsetHours: 8, + expectedOutput: "2025-10-23T00:00:00+08:00", // Note: The dot is removed. + }, + { + name: "Case 4: Single-digit precision (Remove 8 trailing zeros)", + nanoSeconds: 100000000, // .1 + tzOffsetHours: 0, + expectedOutput: "2025-10-23T00:00:00.1Z", + }, + { + name: "Case 5: Precision beyond microsecond (Truncate first, then remove zeros)", + nanoSeconds: 123456789, // .123456789 -> truncates to .123456 + tzOffsetHours: -7, + expectedOutput: "2025-10-23T00:00:00.123456-07:00", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create a time.Time object for a fixed date/time + tz := time.FixedZone("TEST_TZ", tc.tzOffsetHours*3600) + tInput := time.Date(2025, time.October, 23, 0, 0, 0, tc.nanoSeconds, tz) + + result := FormatTimeMicroWithoutTrailingZeros(tInput) + + assert.Equal(t, tc.expectedOutput, result) + + // Verification: Ensure round-trip parsing still works and yields the correct microsecond value + tParsed, parseErr := time.Parse(time.RFC3339Nano, result) + assert.NoError(t, parseErr) + // Microsecond precision is preserved + assert.Equal(t, tInput.Truncate(time.Microsecond).UnixMicro(), tParsed.UnixMicro()) + }) + } +} + +// funcutil/time_test.go (Updated TestConvertUnixMicroToTimezoneString) + +// TestConvertUnixMicroToTimezoneString tests the conversion of Unix Microsecond +// to a TZ-aware RFC3339Nano string, now including the trailing zero removal logic. +func TestConvertUnixMicroToTimezoneString(t *testing.T) { + // Base time 1: 2025-03-20T10:30:00.123456Z (UTC). Nanoseconds: 123456000 + baseTimeUTC := time.Date(2025, time.March, 20, 10, 30, 0, 123456000, time.UTC) + baseUnixMicro := baseTimeUTC.UnixMicro() // 1710921000123456 + + // Base time 2: 2025-10-23T15:30:00.000000Z (UTC). Nanoseconds: 0 + dstTimeUTC := time.Date(2025, time.October, 23, 15, 30, 0, 0, time.UTC) + dstUnixMicro := dstTimeUTC.UnixMicro() // 1729697400000000 + + testCases := []struct { + name string + unixMicro int64 + targetTZ string + expectedOutput string // NOW CLEANED OF TRAILING ZEROS + expectError bool + errorContainsMsg string + }{ + // --- Basic Functionality & Precision (Using baseUnixMicro - ends in .123456) --- + { + name: "Case 1: Standard conversion to UTC (Microsecond precision)", + unixMicro: baseUnixMicro, + targetTZ: "UTC", + expectedOutput: "2025-03-20T10:30:00.123456Z", // Removed "000" + expectError: false, + }, + { + name: "Case 2: Conversion to Asia/Shanghai (+08:00)", + unixMicro: baseUnixMicro, + targetTZ: "Asia/Shanghai", // UTC+08:00 + expectedOutput: "2025-03-20T18:30:00.123456+08:00", // Removed "000" + expectError: false, + }, + { + // Fix from previous round: 10:30 UTC - 7 hours (PDT) = 03:30 local time. + name: "Case 3: Conversion to America/Los_Angeles (PDT on Mar 20)", + unixMicro: baseUnixMicro, + targetTZ: "America/Los_Angeles", // PDT = UTC-07:00 + expectedOutput: "2025-03-20T03:30:00.123456-07:00", // Removed "000" + expectError: false, + }, + + // --- DST Handling (Using dstUnixMicro - ends in .000000) --- + { + name: "Case 4: DST active (America/New_York) - UTC-04:00 (Second precision)", + unixMicro: dstUnixMicro, + targetTZ: "America/New_York", // EDT = UTC-04:00 on this date + expectedOutput: "2025-10-23T11:30:00-04:00", // Removed all fractional zeros and the dot + expectError: false, + }, + + // --- Custom Test Case: Only Millisecond precision (must remove 3 trailing zeros) --- + { + name: "Case 5: Millisecond precision input", + // Use the calculated value for 2025-03-20T10:30:00.123Z. + // If you were previously using baseUnixMicro, calculate the new value: + // (baseUnixMicro / 1000000) * 1000000 + 123000 + unixMicro: (baseUnixMicro / 1000000 * 1000000) + 123000, + targetTZ: "UTC", + expectedOutput: "2025-03-20T10:30:00.123Z", + expectError: false, + }, + + // --- Error Handling --- + { + name: "Case 6: Invalid Timezone String", + unixMicro: baseUnixMicro, + targetTZ: "Invalid/TZ_Name", + expectedOutput: "", + expectError: true, + errorContainsMsg: "invalid target timezone string", + }, + { + name: "Case 7: UnixMicro 0 (Epoch) - Second precision", + unixMicro: 0, + targetTZ: "UTC", + expectedOutput: "1970-01-01T00:00:00Z", // Removed all fractional zeros and the dot + expectError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result, err := ConvertUnixMicroToTimezoneString(tc.unixMicro, tc.targetTZ) + + if tc.expectError { + assert.Error(t, err) + if err != nil { + assert.Contains(t, err.Error(), tc.errorContainsMsg) + } + } else { + assert.NoError(t, err) + assert.Equal(t, tc.expectedOutput, result) + + // Verify round-trip consistency: the resulting string must parse back + // to the original microsecond value (since no significant digits were lost). + tParsed, parseErr := time.Parse(time.RFC3339Nano, result) + assert.NoError(t, parseErr) + assert.Equal(t, tc.unixMicro, tParsed.UnixMicro()) + } + }) + } +} + +// TestIsTimezoneValid tests the IsTimezoneValid function. +func TestIsTimezoneValid(t *testing.T) { + // Common valid IANA timezone names + validTimezones := []string{ + "UTC", + "Local", + "Asia/Shanghai", + "America/New_York", + "Europe/London", + "Australia/Sydney", + "Etc/GMT+10", + } + + // Common invalid or malformed timezone names + invalidTimezones := []string{ + "", + "GMT+8", + "CST", + "PST", + "Invalid/Zone", + "Asia/Beijingg", + "99:00", + time.FixedZone("MyZone", 3600).String(), // Custom location names (like "MyZone") are not recognized by time.LoadLocation. + } + + // Test valid timezones + for _, tz := range validTimezones { + t.Run("Valid_"+tz, func(t *testing.T) { + if !IsTimezoneValid(tz) { + t.Errorf("IsTimezoneValid(\"%s\") expected true, but got false", tz) + } + }) + } + + // Test invalid timezones + for _, tz := range invalidTimezones { + t.Run("Invalid_"+tz, func(t *testing.T) { + if IsTimezoneValid(tz) { + t.Errorf("IsTimezoneValid(\"%s\") expected false, but got true", tz) + } + }) + } +} diff --git a/pkg/util/paramtable/autoindex_param.go b/pkg/util/paramtable/autoindex_param.go index 6cec0b6f8d..3213b35977 100644 --- a/pkg/util/paramtable/autoindex_param.go +++ b/pkg/util/paramtable/autoindex_param.go @@ -49,15 +49,16 @@ type AutoIndexConfig struct { AutoIndexSearchConfig ParamItem `refreshable:"true"` AutoIndexTuningConfig ParamGroup `refreshable:"true"` - ScalarAutoIndexEnable ParamItem `refreshable:"true"` - ScalarAutoIndexParams ParamItem `refreshable:"true"` - ScalarNumericIndexType ParamItem `refreshable:"true"` - ScalarIntIndexType ParamItem `refreshable:"true"` - ScalarVarcharIndexType ParamItem `refreshable:"true"` - ScalarBoolIndexType ParamItem `refreshable:"true"` - ScalarFloatIndexType ParamItem `refreshable:"true"` - ScalarJSONIndexType ParamItem `refreshable:"true"` - ScalarGeometryIndexType ParamItem `refreshable:"true"` + ScalarAutoIndexEnable ParamItem `refreshable:"true"` + ScalarAutoIndexParams ParamItem `refreshable:"true"` + ScalarNumericIndexType ParamItem `refreshable:"true"` + ScalarIntIndexType ParamItem `refreshable:"true"` + ScalarVarcharIndexType ParamItem `refreshable:"true"` + ScalarBoolIndexType ParamItem `refreshable:"true"` + ScalarFloatIndexType ParamItem `refreshable:"true"` + ScalarJSONIndexType ParamItem `refreshable:"true"` + ScalarGeometryIndexType ParamItem `refreshable:"true"` + ScalarTimestampTzIndexType ParamItem `refreshable:"true"` BitmapCardinalityLimit ParamItem `refreshable:"true"` } @@ -197,7 +198,7 @@ func (p *AutoIndexConfig) init(base *BaseTable) { p.ScalarAutoIndexParams = ParamItem{ Key: "scalarAutoIndex.params.build", Version: "2.4.0", - DefaultValue: `{"int": "HYBRID","varchar": "HYBRID","bool": "BITMAP", "float": "INVERTED", "json": "INVERTED", "geometry": "RTREE"}`, + DefaultValue: `{"int": "HYBRID","varchar": "HYBRID","bool": "BITMAP", "float": "INVERTED", "json": "INVERTED", "geometry": "RTREE", "timestamptz": "STL_SORT"}`, } p.ScalarAutoIndexParams.Init(base.mgr) @@ -262,6 +263,18 @@ func (p *AutoIndexConfig) init(base *BaseTable) { } p.ScalarGeometryIndexType.Init(base.mgr) + p.ScalarTimestampTzIndexType = ParamItem{ + Version: "2.6.0", + Formatter: func(v string) string { + m := p.ScalarAutoIndexParams.GetAsJSONMap() + if m == nil { + return "" + } + return m["timestamptz"] + }, + } + p.ScalarTimestampTzIndexType.Init(base.mgr) + p.BitmapCardinalityLimit = ParamItem{ Key: "scalarAutoIndex.params.bitmapCardinalityLimit", Version: "2.5.0", diff --git a/pkg/util/typeutil/schema.go b/pkg/util/typeutil/schema.go index 99073861ae..a3ff96d381 100644 --- a/pkg/util/typeutil/schema.go +++ b/pkg/util/typeutil/schema.go @@ -344,8 +344,9 @@ type SchemaHelper struct { partitionKeyOffset int clusteringKeyOffset int dynamicFieldOffset int - // include sub fields in StructArrayField + // include sub-fields in StructArrayField allFields []*schemapb.FieldSchema + timezone string } // CreateSchemaHelper returns a new SchemaHelper object @@ -403,9 +404,26 @@ func CreateSchemaHelper(schema *schemapb.CollectionSchema) (*SchemaHelper, error schemaHelper.dynamicFieldOffset = offset } } + + found := false + for _, kv := range schema.GetProperties() { + if kv.Key == common.TimezoneKey { + schemaHelper.timezone = kv.Value + found = true + break + } + } + if !found { + schemaHelper.timezone = common.DefaultTimezone + } return &schemaHelper, nil } +// GetTimezone returns the timezone string associated with the schema. +func (helper *SchemaHelper) GetTimezone() string { + return helper.timezone +} + // GetPrimaryKeyField returns the schema of the primary key func (helper *SchemaHelper) GetPrimaryKeyField() (*schemapb.FieldSchema, error) { if helper.primaryKeyOffset == -1 { @@ -608,8 +626,7 @@ func IsVectorArrayType(dataType schemapb.DataType) bool { func IsIntegerType(dataType schemapb.DataType) bool { switch dataType { case schemapb.DataType_Int8, schemapb.DataType_Int16, - schemapb.DataType_Int32, schemapb.DataType_Int64, - schemapb.DataType_Timestamptz: + schemapb.DataType_Int32, schemapb.DataType_Int64: return true default: return false @@ -624,6 +641,10 @@ func IsGeometryType(dataType schemapb.DataType) bool { return dataType == schemapb.DataType_Geometry } +func IsTimestamptzType(dataType schemapb.DataType) bool { + return dataType == schemapb.DataType_Timestamptz +} + func IsArrayType(dataType schemapb.DataType) bool { return dataType == schemapb.DataType_Array } @@ -677,7 +698,7 @@ func IsVariableDataType(dataType schemapb.DataType) bool { } func IsPrimitiveType(dataType schemapb.DataType) bool { - return IsArithmetic(dataType) || IsStringType(dataType) || IsBoolType(dataType) + return IsArithmetic(dataType) || IsStringType(dataType) || IsBoolType(dataType) || IsTimestamptzType(dataType) } // PrepareResultFieldData construct this slice fo FieldData for final result reduce diff --git a/tests/go_client/testcases/index_test.go b/tests/go_client/testcases/index_test.go index 52ed4a0cf7..deb9ed535a 100644 --- a/tests/go_client/testcases/index_test.go +++ b/tests/go_client/testcases/index_test.go @@ -471,7 +471,7 @@ func TestCreateSortedScalarIndex(t *testing.T) { if field.DataType == entity.FieldTypeBool || field.DataType == entity.FieldTypeJSON || field.DataType == entity.FieldTypeArray { _, err := mc.CreateIndex(ctx, client.NewCreateIndexOption(schema.CollectionName, field.Name, idx)) - require.ErrorContains(t, err, "STL_SORT are only supported on numeric or varchar field") + require.ErrorContains(t, err, "STL_SORT are only supported on numeric, varchar or timestamptz field") } else { idxTask, err := mc.CreateIndex(ctx, client.NewCreateIndexOption(schema.CollectionName, field.Name, idx)) common.CheckErr(t, err, true) @@ -623,7 +623,7 @@ func TestCreateIndexJsonField(t *testing.T) { errMsg string } inxError := []scalarIndexError{ - {index.NewSortedIndex(), "STL_SORT are only supported on numeric or varchar field"}, + {index.NewSortedIndex(), "STL_SORT are only supported on numeric, varchar or timestamptz field"}, {index.NewTrieIndex(), "TRIE are only supported on varchar field"}, } for _, idxErr := range inxError { @@ -649,7 +649,7 @@ func TestCreateUnsupportedIndexArrayField(t *testing.T) { errMsg string } inxError := []scalarIndexError{ - {index.NewSortedIndex(), "STL_SORT are only supported on numeric or varchar field"}, + {index.NewSortedIndex(), "STL_SORT are only supported on numeric, varchar or timestamptz field"}, {index.NewTrieIndex(), "TRIE are only supported on varchar field"}, } diff --git a/tests/python_client/milvus_client/test_milvus_client_index.py b/tests/python_client/milvus_client/test_milvus_client_index.py index 0eeddb9ecc..acb0bcbe76 100644 --- a/tests/python_client/milvus_client/test_milvus_client_index.py +++ b/tests/python_client/milvus_client/test_milvus_client_index.py @@ -851,7 +851,7 @@ class TestMilvusClientJsonPathIndexInvalid(TestMilvusClientV2Base): supported_field_type = "varchar" got_json_suffix = "" if not_supported_varchar_scalar_index == "STL_SORT": - supported_field_type = "numeric or varchar" + supported_field_type = "numeric, varchar or timestamptz" got_json_suffix = ", got JSON" if not_supported_varchar_scalar_index == "BITMAP": supported_field_type = "bool, int, string and array" @@ -1814,4 +1814,4 @@ class TestMilvusClientJsonPathIndexValid(TestMilvusClientV2Base): "json_path": f"{json_field_name}['a'][0]", "index_type": supported_varchar_scalar_index, "field_name": json_field_name, - "index_name": index_name + '/a/0'}) \ No newline at end of file + "index_name": index_name + '/a/0'})