// Copyright 2023 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include namespace DB::tests { template using Limits = std::numeric_limits; // TODO support unsigned int as the test framework not supports unsigned int so far. class LeadLag : public DB::tests::WindowTest { public: const ASTPtr value_col = col(VALUE_COL_NAME); void initializeContext() override { ExecutorTest::initializeContext(); } template void testInt() { executeFunctionAndAssert( toNullableVec({Limits::max(), Limits::min(), 4, {}, 6, 0, 8, {}}), Lead2(value_col, lit(Field(static_cast(1)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {1, Limits::max(), Limits::min(), 4, 5, 6, 0, 8})}); executeFunctionAndAssert( toNullableVec({{}, 1, Limits::max(), Limits::min(), {}, 5, 6, 0}), Lag2(value_col, lit(Field(static_cast(1)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {1, Limits::max(), Limits::min(), 4, 5, 6, 0, 8})}); } template void testFloat() { executeFunctionAndAssert( toNullableVec({Limits::max(), Limits::min(), 4.4, {}, 6.6, 0, 8.8, {}}), Lead2(value_col, lit(Field(static_cast(1)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec( /*value*/ {1, Limits::max(), Limits::min(), 4.4, 5.5, 6.6, 0, 8.8})}); executeFunctionAndAssert( toNullableVec({{}, 1, Limits::max(), Limits::min(), {}, 5.5, 6.6, 0}), Lag2(value_col, lit(Field(static_cast(1)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec( /*value*/ {1, Limits::max(), Limits::min(), 4.4, 5.5, 6.6, 0, 8.8})}); } }; TEST_F(LeadLag, oneArg) try { executeFunctionAndAssert( toNullableVec({"2", "3", "4", {}, "6", "7", "8", {}}), Lead1(value_col), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({{}, "1", "2", "3", {}, "5", "6", "7"}), Lag1(value_col), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); } CATCH TEST_F(LeadLag, twoArgs) try { // arg2 == 0 executeFunctionAndAssert( toNullableVec({"1", "2", "3", "4", "5", "6", "7", "8"}), Lead2(value_col, lit(Field(static_cast(0)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"1", "2", "3", "4", "5", "6", "7", "8"}), Lag2(value_col, lit(Field(static_cast(0)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); // arg2 < partition_size executeFunctionAndAssert( toNullableVec({"2", "3", "4", {}, "6", "7", "8", {}}), Lead2(value_col, lit(Field(static_cast(1)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"3", "4", {}, {}, "7", "8", {}, {}}), Lead2(value_col, lit(Field(static_cast(2)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"4", {}, {}, {}, "8", {}, {}, {}}), Lead2(value_col, lit(Field(static_cast(3)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({{}, "1", "2", "3", {}, "5", "6", "7"}), Lag2(value_col, lit(Field(static_cast(1)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({{}, {}, "1", "2", {}, {}, "5", "6"}), Lag2(value_col, lit(Field(static_cast(2)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({{}, {}, {}, "1", {}, {}, {}, "5"}), Lag2(value_col, lit(Field(static_cast(3)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); // arg2 >= partition_size executeFunctionAndAssert( toNullableVec({{}, {}, {}, {}, {}, {}, {}, {}}), Lead2(value_col, lit(Field(static_cast(4)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({{}, {}, {}, {}, {}, {}, {}, {}}), Lead2(value_col, lit(Field(static_cast(5)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({{}, {}, {}, {}, {}, {}, {}, {}}), Lag2(value_col, lit(Field(static_cast(4)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({{}, {}, {}, {}, {}, {}, {}, {}}), Lag2(value_col, lit(Field(static_cast(5)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); } CATCH TEST_F(LeadLag, threeArgs) try { // arg2 == 0 executeFunctionAndAssert( toNullableVec({"1", "2", "3", "4", "5", "6", "7", "8"}), Lead3(value_col, lit(Field(static_cast(0))), lit(Field(String("0")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"1", "2", "3", "4", "5", "6", "7", "8"}), Lag3(value_col, lit(Field(static_cast(0))), lit(Field(String("0")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); // arg2 < partition_size executeFunctionAndAssert( toNullableVec({"2", "3", "4", "0", "6", "7", "8", "0"}), Lead3(value_col, lit(Field(static_cast(1))), lit(Field(String("0")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"0", "1", "2", "3", "0", "5", "6", "7"}), Lag3(value_col, lit(Field(static_cast(1))), lit(Field(String("0")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); // arg2 >= partition_size executeFunctionAndAssert( toNullableVec({"0", "0", "0", "0", "0", "0", "0", "0"}), Lead3(value_col, lit(Field(static_cast(4))), lit(Field(String("0")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"0", "0", "0", "0", "0", "0", "0", "0"}), Lead3(value_col, lit(Field(static_cast(5))), lit(Field(String("0")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"0", "0", "0", "0", "0", "0", "0", "0"}), Lag3(value_col, lit(Field(static_cast(4))), lit(Field(String("0")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"0", "0", "0", "0", "0", "0", "0", "0"}), Lag3(value_col, lit(Field(static_cast(5))), lit(Field(String("0")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); // test arg column type executeFunctionAndAssert( toNullableVec({"2", "3", "4", "4", "6", "7", "8", "8"}), Lead3(value_col, lit(Field(static_cast(1))), value_col), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"0", "0", "0", {}, "0", "0", "0", "8"}), Lead3(lit(Field(String("0"))), lit(Field(static_cast(1))), value_col), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", {}, "5", "6", "7", "8"})}); executeFunctionAndAssert( toVec({"0", "0", "1", "1", "0", "0", "1", "1"}), Lead3(lit(Field(String("0"))), lit(Field(static_cast(2))), lit(Field(String("1")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); } CATCH TEST_F(LeadLag, testNull) try { executeFunctionAndAssert( toNullableVec({{}, {}, {}, "aaaaaa", {}, {}, {}, "aaaaaa"}), Lead3(value_col, lit(Field(static_cast(1))), lit(Field(String("aaaaaa")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {{}, {}, {}, {}, {}, {}, {}, {}})}); executeFunctionAndAssert( toNullableVec({"aaaaaa", {}, {}, {}, "aaaaaa", {}, {}, {}}), Lag3(value_col, lit(Field(static_cast(1))), lit(Field(String("aaaaaa")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {{}, {}, {}, {}, {}, {}, {}, {}})}); executeFunctionAndAssert( toNullableVec({"2", "3", "4", {}, "6", "7", "8", {}}), Lead2(value_col, lit(Field(static_cast(1)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({{}, "1", "2", "3", {}, "5", "6", "7"}), Lag2(value_col, lit(Field(static_cast(1)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({{}, {}, {}, {}, {}, {}, {}, {}}), Lead2(value_col, lit(Field(static_cast(1)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {{}, {}, {}, {}, {}, {}, {}, {}})}); executeFunctionAndAssert( toNullableVec({{}, {}, {}, {}, {}, {}, {}, {}}), Lag2(value_col, lit(Field(static_cast(1)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {{}, {}, {}, {}, {}, {}, {}, {}})}); executeFunctionAndAssert( toNullableVec({"aaaaaa", "aaaaaa", {}, {}, "aaaaaa", "aaaaaa", {}, {}}), Lead2(lit(Field(String("aaaaaa"))), lit(Field(static_cast(2)))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {{}, {}, {}, {}, {}, {}, {}, {}})}); executeFunctionAndAssert( toNullableVec({"aaaaaa", "aaaaaa", "aaaaaa", {}, "aaaaaa", "aaaaaa", "aaaaaa", {}}), Lead1(lit(Field(String("aaaaaa")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {{}, {}, {}, {}, {}, {}, {}, {}})}); } CATCH TEST_F(LeadLag, String) try { // normal case executeFunctionAndAssert( toNullableVec({"2", "3", "4", "0", "6", "7", "8", "0"}), Lead3(value_col, lit(Field(static_cast(1))), lit(Field(String("0")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"0", "1", "2", "3", "0", "5", "6", "7"}), Lag3(value_col, lit(Field(static_cast(1))), lit(Field(String("0")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); // blank string executeFunctionAndAssert( toNullableVec({"", "", "", "aaaaaa", "", "", "", "aaaaaa"}), Lead3(value_col, lit(Field(static_cast(1))), lit(Field(String("aaaaaa")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"", "", "", "", "", "", "", ""})}); executeFunctionAndAssert( toNullableVec({"aaaaaa", "", "", "", "aaaaaa", "", "", ""}), Lag3(value_col, lit(Field(static_cast(1))), lit(Field(String("aaaaaa")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"", "", "", "", "", "", "", ""})}); executeFunctionAndAssert( toNullableVec({"2", "3", "4", "", "6", "7", "8", ""}), Lead3(value_col, lit(Field(static_cast(1))), lit(Field(String("")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"", "1", "2", "3", "", "5", "6", "7"}), Lag3(value_col, lit(Field(static_cast(1))), lit(Field(String("")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"1", "2", "3", "4", "5", "6", "7", "8"})}); executeFunctionAndAssert( toNullableVec({"", "", "", "", "", "", "", ""}), Lead3(value_col, lit(Field(static_cast(1))), lit(Field(String("")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"", "", "", "", "", "", "", ""})}); executeFunctionAndAssert( toNullableVec({"", "", "", "", "", "", "", ""}), Lag3(value_col, lit(Field(static_cast(1))), lit(Field(String("")))), {toNullableVec(/*partition*/ {1, 1, 1, 1, 2, 2, 2, 2}), toNullableVec(/*order*/ {1, 2, 3, 4, 5, 6, 7, 8}), toNullableVec(/*value*/ {"", "", "", "", "", "", "", ""})}); } CATCH TEST_F(LeadLag, Int) try { testInt(); testInt(); testInt(); testInt(); } CATCH TEST_F(LeadLag, Float) try { testFloat(); testFloat(); } CATCH // TODO support decimal } // namespace DB::tests