Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Most Annoying Error : Use of uninitialized value in concatenation (.) or string at C:\Perl\O

by blackadder (Hermit)
on Jul 15, 2005 at 10:29 UTC ( [id://475165]=perlquestion: print w/replies, xml ) Need Help??

blackadder has asked for the wisdom of the Perl Monks concerning the following question:

Most beloved creatures on God’s earth,…Top of the Morning to you all.

I have the following script;
#! c:/perl/bin/perl.exe -slw use strict; use Win32; use Win32::ODBC; my $DSN = 'ORANGE'; my $DB = new Win32::ODBC($DSN) || die "Error => $!\n"; open (FILE, "$ARGV[0]") || die "\n$!\n"; chomp (my @data=<FILE>); print "\n\nPlease wait......Populating Database\n"; for my $entry (@data) { next if ($entry =~ /^start|^Full/i); my @db_values = split (/,/,$entry); #print "$db_values[0]\n"; $DB->sql("INSERT INTO Files (File_Path, File_Name, Size_Byte, Crea +ted, Modified, Accessed, Type) VALUES ('$db_values[0]','$db_values[5] +','$db_values[1]','$db_values[2]','$db_values[3]','$db_values[4]','$d +b_values[6]')"); } close FILE; $DB->Close; print “\n\nCompleted......Please check $DSN database\n\n”;
This code generated this error;
Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062. Use of uninitialized value in concatenation (.) or string at C:\Perl\O +range\pop_ db.pl line 18, <FILE> line 46062.
And this is the data I am feeding the script;
t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0021LETTER24JAN.doc,29696,1/24/2005,1/24/2005,7/7/2005,SYK0021LETT +ER24JAN.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0021LETTER30JUNE.doc,25088,6/29/2005,6/29/2005,7/7/2005,SYK0021LET +TER30JUNE.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0042LETTER13JAN.doc,25088,1/13/2005,1/13/2005,7/7/2005,SYK0042LETT +ER13JAN.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0099LETTER13APR.doc,29184,4/13/2005,4/13/2005,7/7/2005,SYK0099LETT +ER13APR.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0099LETTER13MAY.doc,29184,5/13/2005,5/13/2005,7/7/2005,SYK0099LETT +ER13MAY.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0099LETTER16JUNE.doc,30208,6/15/2005,6/15/2005,7/7/2005,SYK0099LET +TER16JUNE.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0099LETTER17JUNE.doc,25600,6/16/2005,6/16/2005,7/7/2005,SYK0099LET +TER17JUNE.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0099LETTER20MAY.doc,29696,5/20/2005,5/20/2005,7/7/2005,SYK0099LETT +ER20MAY.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0099LETTER22JUNE.doc,29184,6/21/2005,6/21/2005,7/7/2005,SYK0099LET +TER22JUNE.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0099LETTER27APR.doc,28672,4/27/2005,4/27/2005,7/7/2005,SYK0099LETT +ER27APR.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0100LETTER17JAN.doc,25088,1/17/2005,1/17/2005,7/7/2005,SYK0100LETT +ER17JAN.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0123LETTER07APR.doc,24576,4/7/2005,4/7/2005,7/7/2005,SYK0123LETTER +07APR.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0131LETTER08JUNE.doc,25600,6/8/2005,6/8/2005,7/7/2005,SYK0131LETTE +R08JUNE.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0131LETTER17JAN.doc,29184,1/17/2005,1/17/2005,7/7/2005,SYK0131LETT +ER17JAN.doc,doc t:/uk legal/Sites and Property/Manchester/ADMINISTRATION/LETTERS 2005/ +SYK0131LETTER22APR.doc,29184,4/22/2005,4/22/2005,7/7/2005,SYK0131LETT +ER22APR.doc,doc
I am not really sure – O’ what a surprise – on how can I get rid of this annoying error….Can I relay on your vast knowledge and experience for guidance and a way to remediate this?

Thanking you for your valuable help indeed....Ta!
Blackadder
  • Comment on Most Annoying Error : Use of uninitialized value in concatenation (.) or string at C:\Perl\O
  • Select or Download Code

Replies are listed 'Best First'.
Re: Most Annoying Error : Use of uninitialized value in concatenation (.) or string at C:\Perl\O
by graff (Chancellor) on Jul 15, 2005 at 12:21 UTC
    Grandfather is right. The warning is telling you that you are not checking the contents of @db_values before sending them into an operation where you might not want them to be undef (e.g. inserting a row in a database that contains nothing but null values). It's even telling you which line in the data file is causing the problem.

    An easy way to avoid the warning -- and make sure you only insert rows that have the expected amount of actual data -- would be:

    my @db_values = split (/,/,$entry); next unless ( @db_values == 7 ); ## add this line $DB->sql("INSERT INTO Files ... ");
    You have another symptom of being too trusting: you pass  $ARGV[0] to the open statement without checking to see if the user supplied an arg on the command line.

    In your case (opening a file for input), die would say "No such file or directory" after you get the warning "Use of uninitialized value in open". Oddly enough when I just now tested an open for output with nothing in @ARGV, I got no warning, no error, and no output file -- which makes it a really tricky thing to catch. (That seems like a perl bug, and worthy of a separate thread...)

    Anyway, you should always check input (from users or data files) before using it.

    update: forgot to mention -- are you sure you want to be using DBI to insert stuff into the database? It's very slow and you have to do all the work yourself (which you have not been doing yet) of checking that the values are appropriate before inserting them. I expect that your database engine (whatever it is) has its own tool or method for inserting data from a file, which will run a lot quicker (and value checks are likely to be built-in); note that you can (and should) use perl to condition data in advance if needed, and to run that tool.

      my @db_values = split (/,/,$entry); next unless ( @db_values == 7 ); ## add this line $DB->sql("INSERT INTO Files ... ");

      I don't see how that would work if the array is actually filled with undef's. For example...

      steve@kirk:~$ perl -wle'push @foo, undef for (0..6); print scalar @foo +' 7

      Your code will only work if you don't have 7 entries in the array. It doesn't do any more checking of the data than that. More checks are needed to guarantee it will work.

      A more appropriate question, though, is why the OP is not letting the database do the work for him? jhourcle's entry below suggesting a prepare is probably the best reply here. Let the database do the checks for NULL values then. Simply turning off warnings is not really solving the problem. It's a bit like using duct tape. Its a repair, but not a real fix. Also, there should be a performace boost by not having to repeatedly reparse the insert multiple times.

      Also, regarding the question on an empty $ARGV[0] to open(). I did run into issues, but I had not problems with it die'ing. My problem is that $! wasn't getting populated without using strict on a one-liner. I will open a perlbug for this problem, but I could not see where open was failing to behave as expected. Hopefully, I can get a fix for my problem done this evening.

      steve@kirk:~$ perl -wle'open FOO, undef || die "FOO! $!";' Name "main::FOO" used only once: possible typo at -e line 1. FOO! at -e line 1. steve@kirk:~$ perl -Mstrict -wle'open FOO, undef || die "FOO! $!";' Name "main::FOO" used only once: possible typo at -e line 1. FOO! Bad file descriptor at -e line 1.
        I don't see how that would work if the array is actually filled with undef's.

        The way that split works (with the two argument call as in the OP), an empty or undef input string will yield a list of zero elements, so "scalar @db_values" in that case will be zero. Likewise, if the input string is something like just "a" or "a,,,,,,", split will return a list of just one element (scalar @db_values will be "1"), and so on; trailing separators, if any, are simply truncated.

        It's true that if a line of input text contained a string like ",,,,,,g", split will return a list of 7 elements, the first six of which will be undef. But in that case, it might actually be "right" to create a database record in which the first six fields are null.

        It's also true that more checking of input values, before sending them on to a database, would be prudent, and more efficient ways of inserting database rows are both available and recommended (e.g. using the DB engine's native file import tools).

Re: Most Annoying Error : Use of uninitialized value in concatenation (.) or string at C:\Perl\O
by GrandFather (Saint) on Jul 15, 2005 at 10:59 UTC

    Do you perhaps have a blank line at the end of your input file so that for the last itteration of your loop you get undef for all the field entries?


    Perl is Huffman encoded by design.
      "there is a blank line in the end of input file" this is the exact reason for this kind of warning.
Re: Most Annoying Error : Use of uninitialized value in concatenation (.) or string at C:\Perl\O
by schwern (Scribe) on Jul 16, 2005 at 00:14 UTC

    Use the error message. Use of uninitialized value in concatenation (.) or string at C:\Perl\Orange\pop_db.pl line 18, <FILE> line 46062.

    The key is "line 46062". Perl is telling you that the uninit value is encountered when executing line 18 of your program AND that the last line read from the last opened filehandle (FILE) was 46062. This information would provide useful except that you slurped in the entire file before processing it. Not only wasteful of memory but since everything in the loop happens after you read the whole file they *all* appear to happen at line 46062.

    If you modify your code to process the file a line at a time the warning will identify for you exactly what line in the data is corrupt.

    open (FILE, "$ARGV[0]") || die "\n$!\n"; print "\n\nPlease wait......Populating Database\n"; while(my $entry = <FILE>) { chomp $entry; ...process $entry as normal... } close FILE;
Re: Most Annoying Error : Use of uninitialized value in concatenation (.) or string at C:\Perl\O
by tlm (Prior) on Jul 15, 2005 at 12:29 UTC

    Well, the offending line seems to be the one that starts with $DB->sql. Clearly, some element of @db_values is undefined. If that's OK with you, then do this:

    { no warnings 'uninitialized'; $DB->sql("INSERT INTO Files (File_Path, File_Name, Size_Byte, Cr +eated, Modified, Accessed, Type) VALUES ('$db_values[0]','$db_values[ +5]','$db_values[1]','$db_values[2]','$db_values[3]','$db_values[4]',' +$db_values[6]')"); }
    Alternatively, leave that line as is and instead do something like this:
    my @db_values = map defined( $_ ) ? $_ : '', split (/,/,$entry);

    the lowliest monk

      It would also assume that there were no bad characters in the data being inserted, as there's nothing in the code to escape them.

      In a situation like this, I'd use bind variables, nulls were allowed. I'd use 'em even if nulls weren't allowed, I'd just verify my data before trying the insert:

      my $sth = $DB->prepare( 'INSERT INTO Files ( File_Path, File_Name, Siz +e_Byte, Created, Modified, Accessed, Type ) VALUES ( ?,?,?,?,?,?,? )' + ); foreach my $entry (@data) { next if ($entry =~ /^start|^Full/i); my @db_values = split (/,/,$entry); # do whatever value checking here ... checking for 7 values, etc. $sth->execute( @db_values ); }

      It wouldn't be bad to check for errors after doing an execute, either:

      $sth->execute( @db_values ) or warn $DB->errstr();
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

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

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

    No recent polls found