Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Re^2: Perl Not returning SQL query result

by afoken (Chancellor)
on May 12, 2021 at 20:33 UTC ( [id://11132519]=note: print w/replies, xml ) Need Help??


in reply to Re: Perl Not returning SQL query result
in thread Perl Not returning SQL query result

my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","","",{RaiseError = +> 1}) or die "Couldn't connect to database: " . DBI->errstr;

If $dbh is zero, then the connect failed!

Um, no. If $dbh ever becomes 0 in that two lines, something very unexpected has happened in perl, i.e. you have triggered a serious bug and/or corrupted memory. (Or you simply have redefined die to return 0 instead of dieing.)

Yes, I'm bean counting again. Sorry.

First, DBI->connect() is documented to return undef on error, a database handle object if the connection succeeds. It should never return 0 at all, or anything else than undef or a blessed reference (i.e. an object).

Second, 0 and undef are two very different values, and while they are treated the same on the left-hand side of or (as a boolean FALSE value), they are not generally exchangeable.

Side note: Around DBI, there is also the special zero value 0E0 that is treated by perl as a boolean TRUE value, returned by execute() and similar methods (do(), execute_array(), execute_for_fetch()) to indicate success with zero rows affected. Some of the core functions (fcntl, ioctl, msgctl, semctl, shmctl, sysseek) return the special value 0 but true for a very similar purpose. That special value is excempt from warning complaints about improper numeric conversions (documented in ioctl).

Third, should DBI->connect() return undef, 0 or any other value that evaluates to FALSE in boolean context, the right-hand side of or will be executed and die will prevent any assignment to $dbh by either exiting the interpreter or by jumping out of a surrounding eval block. So, $dbh starts unassigned, but will never be assigned 0 (unless you have redefined die to return 0).

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Replies are listed 'Best First'.
Re^3: Perl Not returning SQL query result
by Marshall (Canon) on May 12, 2021 at 22:09 UTC
    Yes, I'm bean counting again. Sorry. No worries!...Let's get the details right! These threads have a way of relentlessly getting the exact details right.

    Ok, the code that I showed will work. 0 and undef are treated the same in this logic, but I did misspeak. I accept your point! My post updated. I was correct in saying, "I may have made a mistake which the other Monks will quickly point out."

    Yes, the string "0 but true" is hard coded into Perl from ancient times and will evaluate to 0 when used in a numeric context (and no warning will be issued, even if use warnings; is in effect).

    The DBI doesn't use that nowadays. The DBI will return the string "0E0" which evaluates to "True" in a logical context (it is a non-null string), but zero in a numeric context. Yes, this is the DBI's version of "true, but zero rows affected." This value cannot be returned by a SELECT SQL statement, but can be returned by say an ALTER.

    In the code shown, if the SELECT does not return any data, the array_ref will be a reference to an array with zero elements. There was another thread recently where this was discussed at length and the specific point that the returned scalar value from execute() won't work for a SELECT.

    I am not quite sure about your Third point. If the DB connect fails, this code will DIE. The idea of an eval{} block was not under consideration here. The OP was asking some very basic questions and I tried (perhaps not successfully) to give a simple "roadmap".

    But yes, in the context of an Oracle DB with username and password, there should be some way to recover and get better credentials. In the SQLite world, there is no username or password. Connect will fail if 1) wrong file name, 2)wrong path to that file name, or 3)wrong permissions or perhaps 4) corrupt DB file. I copied my connect code from a program that is in its 6th year of production. In this code, the user doesn't have anything to say about things. If the code that this is in bombs, there is a serious problem that my Perl code cannot fix.

    Update: SQLite is an amazing critter. It generates some journal files as it works. It is possible for that thing to recover itself to a known ACID state even after a serious event like power fail. I have never personally seen (4) corrupt DB file because SQLite is much better at recovery than you might think. But I have communicated with others who have seen this.

    https://en.wikipedia.org/wiki/ACID

      I am not quite sure about your Third point. If the DB connect fails, this code will DIE. The idea of an eval{} block was not under consideration here. The OP was asking some very basic questions and I tried (perhaps not successfully) to give a simple "roadmap".

      Well, once I start bean-counting, it's hard to stop. ;-)

      C:\Users\alex>perl -Mstrict -w -E "sub false { 0 } my $x=false or die +'Died'; say 'not reached';" Died at -e line 1.

      $x will never be assigned, because perl dies before it could assign the result of the or operation. That's what happens in your code, and I could have stopped here.

      BUT, in beancounting mode, there may be an eval around the assignment, not shown in the posting. Yes, this is beyond basic use of perl.

      C:\Users\alex>perl -MWin32 -E "sub false { 0 } eval { my $x=false or d +ie 'Died'; say 'not reached'; 1 } or Win32::MsgBox(qq[$@]);"

      That example aborts, but the last thing it does before is to display a message box contaning "Died at -e line 1.". That does not make much sense when hacking a one-liner in a console window. But it becomes really useful when perl is started by something like a self-extracting archive or simply a non-console application. Without that messagebox, you would just see a console window flashing into existance and disappear again, and you had no chance to see a useful error message. I used that trick almost two decades ago, see Re^3: How do you distribute your Perl application to your customers?.

      C:\Users\alex>perl -Mstrict -w -E "BEGIN { *CORE::GLOBAL::die=sub { 'I + am evil' } } sub false { 0 } my $x=false or die 'Died'; say 'not rea +ched';" not reached

      And that silly example demonstrates that one can redefine die so it does not die. Just to make people really, really angry.


      A little extra:

      Quick, don't think, just answer for yourself: What does that example print out?

      C:\Users\alex>perl -Mstrict -w -E "BEGIN { *CORE::GLOBAL::die=sub { 'I + am evil' } } sub false { 0 } my $x=false or die 'Died'; say 'not rea +ched, $x=',$x;"

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
        EDIT: after writing all that up and posting, I re-read your final paragraphs, and realized you said basically the same thing.

        So ignore all the original detail in the spoiler

        I don't see any big issue here.

        I will mention something that is very useful about die messages. If you put a trailing \n, like "some message\n", that will suppress the details like line number, etc. I write different code for a sysop versus Windows user. For the inexperienced, usually a simple "what can I do about it?" message works best and extra detail just confuses them.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11132519]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (4)
As of 2024-04-23 07:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found