@ConstantFunction.List(list = {
            @ConstantFunction(name = "substring", argTypes = {VARCHAR, INT}, returnType = VARCHAR),
            @ConstantFunction(name = "substring", argTypes = {VARCHAR, INT, INT}, returnType = VARCHAR),
            @ConstantFunction(name = "substr", argTypes = {VARCHAR, INT}, returnType = VARCHAR),
            @ConstantFunction(name = "substr", argTypes = {VARCHAR, INT, INT}, returnType = VARCHAR)
    })
    public static ConstantOperator substring(ConstantOperator value, ConstantOperator... index) {
        Preconditions.checkArgument(index.length == 1 || index.length == 2);

        String string = value.getVarchar();
        /// If index out of bounds, the substring method will throw exception, we need avoid it,
        /// otherwise, the Constant Evaluation will fail.
        /// Besides, the implementation of `substring` function in starrocks includes beginIndex and length,
        /// and the index is start from 1 and can negative, so we need carefully handle it.
        int beginIndex = index[0].getInt() >= 0 ? index[0].getInt() - 1 : string.length() + index[0].getInt();
        int endIndex =
                (index.length == 2) ? Math.min(beginIndex + index[1].getInt(), string.length()) : string.length();

        if (beginIndex < 0 || beginIndex > endIndex) {
            return ConstantOperator.createVarchar("");
        }
        return ConstantOperator.createVarchar(string.substring(beginIndex, endIndex));
    }
@Test
    public void testSubString() {
        assertEquals("ab", ScalarOperatorFunctions.substring(ConstantOperator.createVarchar("abcd"),
                ConstantOperator.createInt(1), ConstantOperator.createInt(2)).getVarchar());
        assertEquals("abcd", ScalarOperatorFunctions.substring(ConstantOperator.createVarchar("abcd"),
                ConstantOperator.createInt(1)).getVarchar());
        assertEquals("cd", ScalarOperatorFunctions.substring(ConstantOperator.createVarchar("abcd"),
                ConstantOperator.createInt(-2)).getVarchar());
        assertEquals("c", ScalarOperatorFunctions.substring(ConstantOperator.createVarchar("abcd"),
                ConstantOperator.createInt(-2), ConstantOperator.createInt(1)).getVarchar());
        assertEquals("abcd", ScalarOperatorFunctions.substring(ConstantOperator.createVarchar("abcd"),
                ConstantOperator.createInt(1), ConstantOperator.createInt(4)).getVarchar());
        assertEquals("abcd", ScalarOperatorFunctions.substring(ConstantOperator.createVarchar("abcd"),
                ConstantOperator.createInt(1), ConstantOperator.createInt(10)).getVarchar());
        assertEquals("cd", ScalarOperatorFunctions.substring(ConstantOperator.createVarchar("abcd"),
                ConstantOperator.createInt(3), ConstantOperator.createInt(4)).getVarchar());
        assertEquals("", ScalarOperatorFunctions.substring(ConstantOperator.createVarchar("abcd"),
                ConstantOperator.createInt(0), ConstantOperator.createInt(2)).getVarchar());
        assertEquals("", ScalarOperatorFunctions.substring(ConstantOperator.createVarchar("abcd"),
                ConstantOperator.createInt(5), ConstantOperator.createInt(2)).getVarchar());

        assertEquals("starrocks", ScalarOperatorFunctions.substring(
                new ConstantOperator("starrockscluster", Type.VARCHAR),
                new ConstantOperator(1, Type.INT),
                new ConstantOperator(9, Type.INT)).getVarchar());

        assertEquals("rocks", ScalarOperatorFunctions.substring(
                new ConstantOperator("starrocks", Type.VARCHAR),
                new ConstantOperator(-5, Type.INT),
                new ConstantOperator(5, Type.INT)).getVarchar());

        assertEquals("s", ScalarOperatorFunctions.substring(
                new ConstantOperator("starrocks", Type.VARCHAR),
                new ConstantOperator(-1, Type.INT),
                new ConstantOperator(8, Type.INT)).getVarchar());

        assertEquals("", ScalarOperatorFunctions.substring(
                new ConstantOperator("starrocks", Type.VARCHAR),
                new ConstantOperator(-100, Type.INT),
                new ConstantOperator(5, Type.INT)).getVarchar());

        assertEquals("", ScalarOperatorFunctions.substring(
                new ConstantOperator("starrocks", Type.VARCHAR),
                new ConstantOperator(0, Type.INT),
                new ConstantOperator(5, Type.INT)).getVarchar());

        assertEquals("", ScalarOperatorFunctions.substring(
                new ConstantOperator("starrocks", Type.VARCHAR),
                new ConstantOperator(-1, Type.INT),
                new ConstantOperator(0, Type.INT)).getVarchar());

        assertEquals("apple", ScalarOperatorFunctions.substring(
                new ConstantOperator("apple", Type.VARCHAR),
                new ConstantOperator(-5, Type.INT),
                new ConstantOperator(5, Type.INT)).getVarchar());

        assertEquals("", ScalarOperatorFunctions.substring(
                new ConstantOperator("starrocks", Type.VARCHAR),
                new ConstantOperator(0, Type.INT)).getVarchar());

        assertEquals("starrocks", ScalarOperatorFunctions.substring(
                new ConstantOperator("starrocks", Type.VARCHAR),
                new ConstantOperator(1, Type.INT)).getVarchar());

        assertEquals("s", ScalarOperatorFunctions.substring(
                new ConstantOperator("starrocks", Type.VARCHAR),
                new ConstantOperator(9, Type.INT)).getVarchar());

        assertEquals("", ScalarOperatorFunctions.substring(
                new ConstantOperator("starrocks", Type.VARCHAR),
                new ConstantOperator(10, Type.INT)).getVarchar());
    }