-1

This should have at least 3 entries in the array when I view it at a later stage, but it only displays one. I believe this is thee problematic method, any advice?

    String[] getKidsNamebyCid(int cid) {
        String[] out = new String[20];
        try {
            String qry = "SELECT KIDSNAME FROM TBLKIDS WHERE CID = ?";//setting query command
            ps = connect.prepareStatement(qry);//preparing statement
            ps.setInt(1, cid);//setting CID
            ps.executeQuery();//running command
            int i = 0;
            while (ps.getResultSet().next()) {
                out[i] = ps.getResultSet().getString("KIDSNAME");
                i++;
            }
        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return out;
    }
  • 2
    have you debugged your code? – Stultuske Sep 03 '20 at 16:00
  • highschool student here, idk how to do that – Travopticat Sep 03 '20 at 16:02
  • @Stultuske I am sure its this method and its the array thats causing issues, but I can't see why. Within the while loop, I put 2 outputs, one outputs the resultset.getstring, the other outputs the string in out[i]. out[i] is meant to equal the resultset String, but it outputs only null while the getString outputs the correct stuff – Travopticat Sep 03 '20 at 16:04
  • an easy way to mimic the minimal debugging: add a print statement in your while loop, check that way how many elements are added, and what elements are added – Stultuske Sep 03 '20 at 16:04
  • where and how did you add those print statements? – Stultuske Sep 03 '20 at 16:05
  • @Stultuske System.out.println(rs.getString()) and System.out.println(out[i]) just after the i++, rs.getString shows what I want, out[i] doesn't, yet they should be the same thing – Travopticat Sep 03 '20 at 16:09
  • can you add the exact lines you add in the code in your question? Saying rs.getString() doesn't really mean much if you don't have a rs variable. – Stultuske Sep 03 '20 at 16:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/220932/discussion-between-travopticat-and-stultuske). – Travopticat Sep 03 '20 at 16:12
  • Being a highschool student doesn't prevent you from learning how to debug your code. If you don't know how, now would be a great time to learn! Which is what being a student is all about: ***Learning!*** – Andreas Sep 03 '20 at 16:50

2 Answers2

0

The getResultSet() call isn't a getter. That method does things to the DB, and you can't just repeatedly call it; the first time you get a ResultSet object (which you need to close), the second time everything is reset. So don't; you need to call getResultSet() once.

How do I know? By reading. Straight from getResultSet() documentation:

This method should be called only once per result.

Also this code is littered with severe code issues more generally focussed around resources. Resources are objects which aren't -just- a bunch of bits in memory, they represent (and hold open) a 'resource'. In the case of DBs, it's connections to the DB engine. You can't just make resources, you have to always put them in 'guarding' blocks that guarantee the resources are cleaned up. As a consequence, you never want them to be a field unless there's no other way (and then the thing they are a field inside of becomes a resource).

So, the fact that your PreparedStatement is a field? No good. The fact that you call .getResource just like that, unguarded? No good.

Finally, your exception handling is silly. The default act when facing checked exceptions is to just add them to your throws clause. If you can't do that, the right move is throw new RuntimeException("uncaught", e);, not what you did.

executeQuery already returns a resultset. Generally, never call getResultSet*.

Finally, arrays are more or less obsolete; you want collections.

Putting it all together:

    // delete your 'ps' field!

    List<String> getKidsNamebyCid(int cid) throws SQLException {
        var out = new ArrayList<String>();
        String qry = "SELECT KIDSNAME FROM TBLKIDS WHERE CID = ?";
        try (PreparedStatement ps = connect.prepareStatement(qry)) {
            ps.setInt(1, cid);

            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) out.add(rs.getString("KIDSNAME"));
            }
        }
        return out;
    }

*) The PreparedStatement API is extremely unfortunate. The way you interact with a PS is wildly different vs. a Statement (which you should rarely use; you can't add user input to a plain jane Statement), and yet because reasons and history PreparedStatement extends Statement. That means a whole bevy of methods are in PreparedStatements that you should never call. That's unfortunate. There are 2 things to learn here: [1] Java does not break backwards compatibility, even if that means some of the APIs are horrible, and [2] JDBC is not really meant for 'human consumption'. We don't program our CPUs in machine code either, yet machine code exists and will continue to. We use 'machine code' as glue; something library and language developers use as common tongue. So it is with JDBC: It's not meant for you. Use a library with a nice API, like JDBI. This probably goes beyond what your high school curriculum wants, but hey. There's not much to say except: It's on your curriculum and teacher that they're making you work with outmoded tools 'real'** developers don't use.

**) 'real' in the sense of: Is writing code that powers apps that get a lot of dollars and/or eyeballs.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • yeah dude idgaf about this project, it just needs to work, even if it's bare minimum. looking for quick solution considering it's due tomorrow – Travopticat Sep 03 '20 at 16:46
  • *"the first time you get a ResultSet object"* **Wrong.** --- *"the second time everything is reset"* **Wrong.** --- There are other issues with the answer, but so many good points that I won't down-vote the answer, even though I feel I should. – Andreas Sep 03 '20 at 16:49
  • 1
    @Travopticat If you idgaf, why should we idgaf about helping you? You're on the wrong site if you just want free solutions to your school assignments. See [Open letter to students with homework problems](https://softwareengineering.meta.stackexchange.com/q/6166/202153). – Andreas Sep 03 '20 at 17:14
0

You need to learn how PreparedStatement actually works. I highly recommend you follow a tutorial to learn how to use it, then follow the pattern for your own code.

But it's also all in the documentation, so let be quote the various relevant pieces.

The javadoc of executeQuery() says:

Executes the SQL query in this PreparedStatement object and returns the ResultSet object generated by the query.

The code in the question is already wrong at this point, since it **ignores the return value of the executeQuery() call.

In addition, the javadoc of getResultSet() says:

Retrieves the current result as a ResultSet object. This method should be called only once per result.

The code in the question is even more wrong at this point, since it calls getResultSet() repeatedly in a loop.


If you had read the javadoc of the methods you're using, it would have been obvious that something is wrong. As already stated, going through a tutorial would have shown how to do this right. Actually, any web search for examples of executing a query using JDBC would show that.

For extra background information for how it works, the javadoc of execute() says:

Executes the SQL statement in this PreparedStatement object, which may be any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate.

The execute method returns a boolean to indicate the form of the first result. You must call either the method getResultSet or getUpdateCount to retrieve the result; you must call getMoreResults to move to any subsequent result(s).

The javadoc of getMoreResults() says:

Moves to this Statement object's next result, returns true if it is a ResultSet object, and implicitly closes any current ResultSet object(s) obtained with the method getResultSet.

The "return multiple results" is not talking about multiple rows from a single query, but about multiple results from multiple queries. It generally requires the execution of a stored procedure, or a block of SQL code, for this to happen.


This is how to correctly get the multiple rows from the execution of a single SELECT statement:

String qry = "SELECT KIDSNAME FROM TBLKIDS WHERE CID = ?";
try (PreparedStatement ps = connect.prepareStatement(qry)) {
    ps.setInt(1, cid);//setting CID
    try (ResultSet rs = ps.executeQuery()) {
        int i = 0;
        while (rs.next()) {
            out[i] = rs.getString("KIDSNAME");
            i++;
        }
    }
}

If the SQL code in question had returned multiple result sets, you would do it this way:

try (PreparedStatement ps = connect.prepareStatement(qry)) {
    // call ps.setXxx() methods here
    boolean isResultSet = ps.execute();
    while (isResultSet) {
        try (ResultSet rs = ps.getResultSet()) {
            int i = 0;
            while (rs.next()) {
                // call rs.getXxx() methods here
                i++;
            }
        }
        isResultSet = ps.getMoreResults();
    }
}

That is better written using for loops, to keep the loop logic together:

try (PreparedStatement ps = connect.prepareStatement(qry)) {
    // call ps.setXxx() methods here
    for (boolean isResultSet = ps.execute(); isResultSet; isResultSet = ps.getMoreResults()) {
        try (ResultSet rs = ps.getResultSet()) {
            for (int i = 0; rs.next(); i++) {
                // call rs.getXxx() methods here
            }
        }
    }
}
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • I don't see any problem with OP's code and it should work, why I am saying as i did it on my machine and it worked for me. – Sujitmohanty30 Sep 03 '20 at 16:51
  • @Sujitmohanty30 Question code is wrong, because it calls `executeQuery()`, which returns the one-and-only `ResultSet`, but the code **throws that away**. It then calls `getResultSet()` *twice* per iteration of the loop, even though the documentation clearly says to **only call it once** per *result* (not per row of the query). `getResultSet()` is only valid after `execute()` or `getMoreResults()` returns true, and neither of those methods are used. – Andreas Sep 03 '20 at 16:57
  • Regarding returning `ResultSet` agree. But calling inside loop is no problem. see https://docs.oracle.com/javase/tutorial/jdbc/basics/retrieving.html. Still i wonder how it works in my machine without any issue and i could see the result as OP expected. (only if the database has 3 records obviously) – Sujitmohanty30 Sep 03 '20 at 17:00
  • @Sujitmohanty30 Don't confuse the word "result" with a row in the result set of a query. That's not what "result" means here. "Result" refers the the first result available after calling `execute()` and subsequent results available after calling `getMoreResults()`. The result itself is available by calling `getResultSet()` or `getUpdateCount()`, depending on what the `execute()`/`getMoreResults()` method returned. – Andreas Sep 03 '20 at 17:01
  • @Sujitmohanty30 *"calling inside loop is no problem. see ..."* --- I don't see, because that article doesn't call `getResultSet()` at all, so there is no "calling inside loop" going on. --- It might work on your machine because you're using a different JDBC driver. The documentation doesn't say what will happen if you do call it more than once, so it is *undefined* what happens, i.e. different drivers may handle it differently. – Andreas Sep 03 '20 at 17:05
  • my ps.getResultSet() is OUTSIDE my while loop, the rs.getString() is inside. also, if you read one of my top comments, I did 2 outputs, one output was for rs.getString() and another was to output out[i] (both of these outputs after i++) and the rs.getString was returning the multiple rows of values I wanted, whereas the out[i] returned null, as if putting rs.getString into a String[] somehow turned it to null – Travopticat Sep 03 '20 at 17:24
  • @Andreas, I missed the part in OP's code calling `getResultSet` inside loop doesn't make sense and you are right but it should be not be problem as calling `getResultSet` is not equivalent to to `execute` so no matter how many times I call I get the same result set by definition. – Sujitmohanty30 Sep 03 '20 at 17:28
  • @Andreas, it may be my jdbc driver handles the case better way I don't know but your answer is quite long to the actual problem and it doesn't say about problem rather doing it properly only. – Sujitmohanty30 Sep 03 '20 at 17:30
  • @Travopticat You don't even know your own code: *while (**ps.getResultSet()**.next()) { out[i] = **ps.getResultSet()**.getString("KIDSNAME"); i++; }* --- `ps.getResultSet()` is called **2 times** for each iteration of the loop. It is most certainly INSIDE your while loop. --- If you have clarifying information for the question, **edit** the question and add the information. We're not all going to wade through tons of comment to understand the question. The comments are for us to ask for clarity and for you to make sure you understand a comment. The question has to stand on its own. – Andreas Sep 03 '20 at 17:30
  • @Sujitmohanty30 *"no matter how many times I call I get the same result set **by definition**"* --- No, "by definition", i.e. the definition written in the documentation, which is the only real definition, the *"method should be called only **once per result**"*. Any other use is **undefined**, i.e. there is no definition to go by. – Andreas Sep 03 '20 at 17:34
  • @Andreas: Sorry for the word `definition` used wrongly and it should be called once and I completely agree to your point. There is a better explanation found too https://stackoverflow.com/questions/9984468/getresultset-should-be-called-only-once-per-result but still wondering about the problem OP has. with the answer of yours the first block of code changes should solve the problem of OP and if not god knows. Thanks – Sujitmohanty30 Sep 03 '20 at 17:42