Skip to content

Statement property maxRows incorrectly affects count(*) on table valued functions. #176

@jedvardsson

Description

@jedvardsson

Setting statement property maxRows results in faulty row count on table valued functions.
Below is the output from the supplied test program. The two functions numbers_tf and numbers_itf both return 10 rows. The former is table-valued function while the latter is an inlined version instead.

maxRows(0): select count(*) from dbo.numbers_itf() => 10  OK!
maxRows(5): select count(*) from dbo.numbers_itf() => 10  OK!
maxRows(0): select count(*) from dbo.numbers_tf() => 10  OK!
maxRows(5): select count(*) from dbo.numbers_tf() => 5  FAILED!

As can be seen setting maxRows to 5 changes the count to 5 instead of the expected 10. Clearly this is a bug. MaxRows should only affect the number of rows that the result set returns.

import java.math.BigInteger;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.ThreadLocalRandom;

public class Main {
    public static void main(String[] args) throws SQLException {
        String url = "jdbc:sqlserver://localhost:1433";
        String user = "sa";
        String password = "Test1234!";
        String database = randomName("test_");
        try (
                Connection c = DriverManager.getConnection(url, user, password);
        ) {
            try {
                executeUpdate(c, "create database " + database);
                executeUpdate(c, "use " + database);


                executeUpdate(c, "create function dbo.numbers_itf()\n" +
                        "returns table\n" +
                        "as return\n" +
                        "    select * from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) t(num)\n" +
                        "\n");

                executeUpdate(c, "create function dbo.numbers_tf()\n" +
                        "  returns @result table (\n" +
                        "    num int\n" +
                        "  )\n" +
                        "  as\n" +
                        "  begin\n" +
                        "    insert into @result\n" +
                        "    select * from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) t(num)\n" +
                        "    return\n" +
                        "  end\n" +
                        "\n");


                executeTest(c, 0, "select count(*) from dbo.numbers_itf()", 10);
                executeTest(c, 5, "select count(*) from dbo.numbers_itf()", 10);
                executeTest(c, 0, "select count(*) from dbo.numbers_tf()", 10);
                executeTest(c, 5, "select count(*) from dbo.numbers_tf()", 10);

            } finally {
                executeUpdate(c,"use master");
                executeUpdate(c, "drop database " + database);
            }
        }
    }

    private static int executeUpdate(Connection c, String sql) throws SQLException {
        try (Statement s = c.createStatement()) {
            return s.executeUpdate(sql);
        }
    }

    private static void executeTest(Connection c, int maxRows, String sql, int expected) throws SQLException {
        try (Statement s = c.createStatement()) {
            s.setMaxRows(maxRows);
            s.execute(sql);
            try (ResultSet r = s.getResultSet()) {
                r.next();
                int actual = r.getInt(1);
                System.out.format("maxRows(%d): %s => %d  %s%n", s.getMaxRows(), sql, actual, (actual != expected ? "FAILED!" : "OK!"));
            }
        }
    }

    private static String randomName(String prefix) {
        return prefix + (new BigInteger(40, ThreadLocalRandom.current())).toString(32);
    }

}

Metadata

Metadata

Assignees

Labels

Under ReviewUsed for pull requests under review

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions