But I closed it...



  • I just spent 2 days tracking down a bug that caused a maximum-number-of-open-cursors-exceeded error from the db.

    A developer who claims 20 years of experience coded the following:

     

       Connection con  = null;
    Statement stmt = null;
    ResultSet rs = null;

    try {
    con = ...;
    stmt = con.prepareStatement(getStatement1());
    rs = stmt.executeQuery();
    ...
    rs.close();

    stmt = con.prepareStatement(getStatement2());
    rs = stmt.executeQuery();
    rs.close();

    } catch (Exception e) {
    ...
    } finally {
    if (rs != null) try { rs.close(); } catch (Exception e) { }
    if (stmt != null) try { stmt.close(); } catch (Exception e) { }
    if (con != null) try { con.close(); } catch (Exception e) { }
    }

    Each query returns a cursor which is retrieved as a ResultSet. The above executes several thousand times. Can you see the leak? Hint: the first statement is not closed before being reassigned to the next statement.

    When I tried to explain it to this guy, he said: But I did close the statement (in the finally block).

    When he finally got it, he replied: So what's the big deal if it leaks some cursors?

    At least it's Friday.



  • :sigh: This is EXACTLY how approximately 90% of our SQL code is ... coded ... at least, when someone deigns to make a finally block.

    Everything in the single finally block is WTF too ... IMO, the Wikipedia article about JDBC shows exactly how to work with it, yet a small minority of our SQL code is configured even close to it.

     



  •  Ha, the old "but i did close it" line.

     I believe someone once asked "so what if it leaks" on the titanic... that turned out well.



  • I'd let you all know my real opinion, it's Friday afternoon and I go home for the weekend in just over an hour, so I can't raise the enthusiasm for withering contempt for a language with indeterminate object lifetimes.

    Seriously, though, he might be one of those people with 20 years' experience where all those 20 years are actually the same year.  Or he might have 20 years' experience mostly in languages with sane assignment-destruction semantics, although the what's-the-big-deal remark makes me suspect otherwise.  (Java is not one of these languages, by the way.  It always amuses me when I see IT trade journalists - and others - writing in an admiring way about Mr Gosling.  I know a guy who used to work with him, and the things my friend has said about Gosling don't bear repeating, but do explain a great deal about why Java is the way it is.)

    See, with sane assignment-destruction semantics, the disappearance of the first prepared statement object (by its reference receiving a new value) would call the destructor immediately, and that would be coded so it closed the cursor and did whatever else it needed to do in order to clean up after itself.  Note that although I normally prefer C++, it isn't the only language with the required semantics, as for example things like Python also do the right thing while simultaneously also having the everything's a reference semantics of Java.

    But what do I know, anyway?



  • .Net's IDisposable pattern along with a using block would also make this error impossible.



  • @Steve The Cynic said:

    Or he might have 20 years' experience mostly in languages with sane assignment-destruction semantics
    That's charitable. It looks to me more like he just doesn't understand what assigning an object to a variable actually does.


    Edit: Had a think about why it seems that way to me, and I think it's because he said "But I closed it" rather than "But I reassigned it" or "But it would have got destroyed there right?". The fact that he said "But I closed it" suggests that he thinks "it" is the same statement all along, somehow ...



  • @token_woman said:

    @Steve The Cynic said:
    Or he might have 20 years' experience mostly in languages with sane assignment-destruction semantics
    That's charitable. It looks to me more like he just doesn't understand what assigning an object to a variable actually does.

    Edit: Had a think about why it seems that way to me, and I think it's because he said "But I closed it" rather than "But I reassigned it" or "But it would have got destroyed there right?". The fact that he said "But I closed it" suggests that he thinks "it" is the same statement all along, somehow ...

    I think your pre-edit remark is saying more or less the same thing as I was - in a language like C++, assigning a value to a variable replaces the current value with another, and in the process calls any code associated with that action, like an operator =() or the destructor of an obect released by a replaced smart pointer.  In Python, giving a new value to a variable destroys (subject to remaining-references semantics, of course) the old object referenced by that variable immediately.  Chuckles-the-code-monkey codes his Java as if that's the case, when it clearly isn't.

    Further, he then defends what he does as if the assignments are merely giving the prepared statement object more work to do (rather than replacing it with another but not cleaning up the old one yet) with the close at the end to tell it, "All done now, go away."  Which of course isn't what happens.  I haven't done more than hardly any Java coding, and I know that this is not how you use Java.  On the other hand, I actually do have 20+ years' experience, and not just the same year 20 times either, and I also know that it is important to understand what your tools do, and what other tools you could use might do instead, because maybe it would be better.  Or maybe it would be worse, but at least you can base the decision on knowledge, not ideology (like the tales told of acquaintances who think git is a magic, divinely inspired thing, the best there is, merely because Linus T had a hand in its creation).  (And no, not because Linus T is an expert in distributed version control, but merely because he is Linus T, creator of an operating system kernel.)

     Anyway, I'm done, it's 6pm on Friday where I am, so I'm getting off the soap box and going home to start my weekend with some nice French wine.



  • @Steve The Cynic said:

    I'd let you all know my real opinion, it's Friday afternoon and I go home for the weekend in just over an hour, so I can't raise the enthusiasm for withering contempt for a language with indeterminate object lifetimes.

    Seriously, though, he might be one of those people with 20 years' experience where all those 20 years are actually the same year.  Or he might have 20 years' experience mostly in languages with sane assignment-destruction semantics, although the what's-the-big-deal remark makes me suspect otherwise.  (Java is not one of these languages, by the way.  It always amuses me when I see IT trade journalists - and others - writing in an admiring way about Mr Gosling.  I know a guy who used to work with him, and the things my friend has said about Gosling don't bear repeating, but do explain a great deal about why Java is the way it is.)

    See, with sane assignment-destruction semantics, the disappearance of the first prepared statement object (by its reference receiving a new value) would call the destructor immediately, and that would be coded so it closed the cursor and did whatever else it needed to do in order to clean up after itself.  Note that although I normally prefer C++, it isn't the only language with the required semantics, as for example things like Python also do the right thing while simultaneously also having the everything's a reference semantics of Java.

    But what do I know, anyway?

    As usual, TRWTF is Java.



  •  @morbiuswilters said:

    As usual, TRWTF is Java.

    While Java has given me a sufficient number of reasons to hate those who designed it, I would argue that, at least in this case, it's not the hammer, but the tool that was using it.



  • @snoofle said:

     @morbiuswilters said:

    As usual, TRWTF is Java.

    While Java has given me a sufficient number of reasons to hate those who designed it, I would argue that, at least in this case, it's not the hammer, but the tool that was using it.

    Why can't it be both? As that cynic guy pointed out, Java's finalize() is obnoxious. Why the hell does it even exist?


  • ♿ (Parody)

    @morbiuswilters said:

    Why can't it be both? As that cynic guy pointed out, Java's finalize() is obnoxious. Why the hell does it even exist?

    I'd say that just because something is a a WTF does not make it the WTF. In this case, there's a simple and obvious and well known way to deal with the WTF-iness of Java's object lifetime and destruction implementation. It's really not that hard. And when the dude still doesn't get it after he's had his nose rubbed in it...



  • @boomzilla said:

    @morbiuswilters said:
    Why can't it be both? As that cynic guy pointed out, Java's finalize() is obnoxious. Why the hell does it even exist?

    I'd say that just because something is a a WTF does not make it the WTF. In this case, there's a simple and obvious and well known way to deal with the WTF-iness of Java's object lifetime and destruction implementation. It's really not that hard. And when the dude still doesn't get it after he's had his nose rubbed in it...

    I prefer to think of it this way: Java is the abstract base class that all WTFs like this inherit from. Java is like the java.lang.Object of the WTF world.



  • @snoofle said:

     
       Connection con  = null;
    Statement stmt = null;
    ResultSet rs = null;

    try {
    ...
    rs.close();
    rs = stmt.executeQuery();
    rs.close();

    } catch (Exception e) {
    ...
    } finally {
    if (rs != null) try { rs.close(); } catch (Exception e) { }
    }

     

    I've used Java, never 'finally', but I think I see another bug. He assigns null to rs. In the loop he assigns a value to rs. In the course of processing he calls rs.close(). Then in the finally clause, he trys to close it again. Won't that usually lead to rs being closed twice? 

     





  • @Steve The Cynic said:

    In Python, giving a new value to a variable destroys (subject to remaining-references semantics, of course) the old object referenced by that variable immediately.

    @The Python Language Reference said:

    Objects are never explicitly destroyed; however, when they become unreachable they may be garbage-collected. [b]An implementation is allowed to postpone garbage collection or omit it altogether[/b] — it is a matter of implementation quality how garbage collection is implemented, as long as no objects are collected that are still reachable.

    CPython implementation detail: CPython currently uses a reference-counting scheme with (optional) delayed detection of cyclically linked garbage, which collects most objects as soon as they become unreachable, but is not guaranteed to collect garbage containing circular references. See the documentation of the gc module for information on controlling the collection of cyclic garbage. Other implementations act differently and CPython may change. [b]Do not depend on immediate finalization of objects when they become unreachable (ex: always close files)[/b].

    Emphasis mine.



  • @Spectre said:

    @Steve The Cynic said:
    In Python, giving a new value to a variable destroys (subject to remaining-references semantics, of course) the old object referenced by that variable immediately.

    @The Python Language Reference said:

    Objects are never explicitly destroyed; however, when they become unreachable they may be garbage-collected. An implementation is allowed to postpone garbage collection or omit it altogether — it is a matter of implementation quality how garbage collection is implemented, as long as no objects are collected that are still reachable.

    CPython implementation detail: CPython currently uses a reference-counting scheme with (optional) delayed detection of cyclically linked garbage, which collects most objects as soon as they become unreachable, but is not guaranteed to collect garbage containing circular references. See the documentation of the gc module for information on controlling the collection of cyclic garbage. Other implementations act differently and CPython may change. Do not depend on immediate finalization of objects when they become unreachable (ex: always close files).

    Emphasis mine.

    This seems overly nit-picky. He already mentioned the circular references thing, which is true of any reference-counting GC. Just avoid circular references in objects you sane destructor behavior from and you're golden.

    The only other thing you have to worry about is the implementation changing from reference counting to something delayed. However, that doesn't seem like a huge deal to me because the Python spec allows a GC to not ever collect garbage, which would create even bigger headaches. Basically: know your GC implementation and what features are important for your code.



  • @morbiuswilters said:

    . Basically: know your GC implementation and what features are important for your code.

     100% correct...Unfortunately 80% of candidates I interview for senior level positions FAIL.



  • @Steve The Cynic said:

    @token_woman said:

    @Steve The Cynic said:
    Or he might have 20 years' experience mostly in languages with sane assignment-destruction semantics
    That's charitable. It looks to me more like he just doesn't understand what assigning an object to a variable actually does.


    Edit: Had a think about why it seems that way to me, and I think it's because he said "But I closed it" rather than "But I reassigned it" or "But it would have got destroyed there right?". The fact that he said "But I closed it" suggests that he thinks "it" is the same statement all along, somehow ...

    I think your pre-edit remark is saying more or less the same thing as I was - in a language like C++, assigning a value to a variable replaces the current value with another, and in the process calls any code associated with that action, like an operator =() or the destructor of an obect released by a replaced smart pointer.  In Python, giving a new value to a variable destroys (subject to remaining-references semantics, of course) the old object referenced by that variable immediately.  Chuckles-the-code-monkey codes his Java as if that's the case, when it clearly isn't.

    Further, he then defends what he does as if the assignments are merely giving the prepared statement object more work to do (rather than replacing it with another but not cleaning up the old one yet) with the close at the end to tell it, "All done now, go away."  Which of course isn't what happens.  I haven't done more than hardly any Java coding, and I know that this is not how you use Java.  On the other hand, I actually do have 20+ years' experience, and not just the same year 20 times either, and I also know that it is important to understand what your tools do, and what other tools you could use might do instead, because maybe it would be better.  Or maybe it would be worse, but at least you can base the decision on knowledge, not ideology (like the tales told of acquaintances who think git is a magic, divinely inspired thing, the best there is, merely because Linus T had a hand in its creation).  (And no, not because Linus T is an expert in distributed version control, but merely because he is Linus T, creator of an operating system kernel.)

     Anyway, I'm done, it's 6pm on Friday where I am, so I'm getting off the soap box and going home to start my weekend with some nice French wine.

    Right, so replace rs = stmt.PrepareStatement with array = new int[5], and that will never leak, right?


Log in to reply