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

Ugh. I got lost in the CGI Action Call thread and wanted to post a question in response to a previous answer from a Monk.Pretty long but you guys always want everything related to problem

Topic is and Update routine suggested in a response. My problem is my update sql is failing due to NULL values in the placeholders as shown in error log below.

I changed values in 5 fields and so clearly that is working Ok since the field differences were detected as expected in the comparison. I don't know why I am getting the NULL's in the placeholders substitutions.

I also posted DBI->trace at bottom. Something I can't make sense of. The session section is a normal part of this.

DBD::mysql::st execute failed: You have an error in your SQL syntax; c +heck the manual that corresponds to your MySQL server version for the + right syntax to use near 'table SET forename = NULL,lastname = NULL, +password = NULL,pin = NULL,position = ' at line 1 at update_tables.cg +i line 664.

Below is sub update

sub update_insert_Record { warn("522 update_insert_Record"); my $post = $query->param("post"); #UPDATE existing record if ($post == 0) { #Fill variables with new update request data (from form) my $id_1 = $query->param("id"); my $user_id_1 = $query->param("user_id"); my $username_1 = $query->param("username"); my $password_1 = $query->param("password"); my $pin_1 = $query->param("pin"); my $position_1 = $query->param("position"); my $forename_1 = $query->param("forename"); my $lastname_1 = $query->param("lastname"); my $business_1 = $query->param("business"); my $address1_1 = $query->param("address1"); my $address2_1 = $query->param("address2"); my $city_1 = $query->param("city"); my $state_1 = $query->param("state"); my $zip_1 = $query->param("zip"); my $email_1 = $query->param("email"); my $phone_home_1 = $query->param("phone_home"); my $phone_cell_1 = $query->param("phone_cell"); my $comments_1 = $query->param("comments"); my $MJ_1 = $query->param("MJ"); my $MD_1 = $query->param("MD"); my $DD_1 = $query->param("DD"); my $DP_1 = $query->param("DP"); my $newData = { id => $id_1, user_id => $user_id_1, username => $username_1, password => $password_1, pin => $pin_1, position => $position_1, forename => $forename_1, lastname => $lastname_1, business => $business_1, address1 => $address1_1, address2 => $address2_1, city => $city_1, state => $state_1, zip => $zip_1, email => $email_1, phone_home => $phone_home_1, phone_cell => $phone_cell_1, comments => $comments_1, MJ => $MJ_1, MD => $MD_1, DD => $DD_1, DP => $DP_1 }; #Declare variables to hold current record data my ($id,$user_id, $username,$password,$pin,$position,$forename,$la +stname,$business,$address1,$address2,$city, $state,$zip,$email,$phone +_home,$phone_cell,$comments,$MJ,$MD,$DD,$DP); #Recover existing values from database and fill variables my $stmt = "SELECT * FROM users WHERE user_id = $user_id_1 ORDER B +Y user_id ASC"; warn("statement = '$stmt'"); my $sth = $dbh->prepare ($stmt) or die "Error Preparing:\n" . $stm +t . "\nDBI returned: \n", $dbh->errstr; DBI->trace(3,$dbitracelog); $sth->execute() or die "Unable to execute query: " . $sth->errstr; + $sth->bind_columns (\$id,\$user_id, \$username,\$password ,\$pin , +\$position ,\$forename ,\$lastname ,\$business ,\$address1 ,\$address +2 ,\$city, \$state ,\$zip ,\$email ,\$phone_home ,\$phone_cell ,\$com +ments ,\$MJ ,\$MD ,\$DD ,\$DP); my $bindResult = $sth->fetchrow_array(); my $oldData = { id => $id, user_id => $user_id, username => $username, password => $password, pin => $pin, position => $position, forename => $forename, lastname => $lastname, business => $business, address1 => $address1, address2 => $address2, city => $city, state => $state, zip => $zip, email => $email, phone_home => $phone_home, phone_cell => $phone_cell, comments => $comments, MJ => $MJ, MD => $MD, DD => $DD, DP => $DP }; my @fields; my @values; # compare old v new for (sort keys %$newData){ if ($newData->{$_} ne $oldData->{$_}){ push @fields,"$_ = ?"; push @values,$newData->{$_}; } } # skip if no change if (@fields == 0){ print "No update required\n"; } else { # build sql my $fields = join ',',@fields; my $stmt = "UPDATE table SET $fields WHERE user_id = ?"; #add id push @values,$user_id; warn("statement = '$stmt'"); # prepare and execute sql # print "$stmt\n(@values)\n"; $sth = $dbh->prepare ($stmt) or die "Error Preparing:\n" . $st +mt . "\nDBI returned: \n", $dbh->errstr; $sth->execute() or die "Unable to execute query: " . $sth->err +str; return; } }

And the DBI->trace(3, log) below

DBI Trace log DBI 1.640-ithread default trace level set to 0x0/3 (pid 27298 pi 1 +c5c010) at update_tables.cgi line 601 via update_tables.cgi line 184 -> execute for DBD::mysql::st (DBI::st=HASH(0x25c0480)~0x2981b48) +thr#1c5c010 -> dbd_st_execute for 297fa00 >- dbd_st_free_result_sets <- dbd_st_free_result_sets RC -1 <- dbd_st_free_result_sets mysql_st_internal_execute MYSQL_VERSION_ID 50558 >parse_params statement SELECT * FROM users WHERE user_id = 23 ORDER B +Y user_id ASC <- dbd_st_execute returning imp_sth->row_num 1 <- execute= 1 at update_tables.cgi line 603 via at update_tables. +cgi line 184 -> bind_columns for DBD::mysql::st (DBI::st=HASH(0x25c0480)~0x2981 +b48 SCALAR(0x2721588) SCALAR(0x27215b8) SCALAR(0x27215e8) SCALAR(0x27 +21618) SCALAR(0x2721648) SCALAR(0x2721678) SCALAR(0x27216a8) SCALAR(0 +x27216d8) SCALAR(0x2721708) SCALAR(0x2721738) SCALAR(0x2721768) SCALA +R(0x2721798) SCALAR(0x27217c8) SCALAR(0x27217f8) SCALAR(0x2721828) SC +ALAR(0x2721858) SCALAR(0x2721888) SCALAR(0x27218b8) SCALAR(0x27218e8) + SCALAR(0x2721918) SCALAR(0x2721948) SCALAR(0x2721978)) thr#1c5c010 1 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 -> dbd_st_FETCH_attrib for 26119d0, key NUM_OF_FIELDS .. FETCH DBI::st=HASH(0x2981b48) 'NUM_OF_FIELDS' = 22 (cached) 1 <- FETCH= 22 at DBI.pm line 1906 via at update_tables.cgi line 18 +4 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 2 <- _async_check= 1 at mysql.pm line 879 via at update_tables.cgi +line 605 1 <- bind_col= 1 at DBI.pm line 1917 via at update_tables.cgi line +184 <- bind_columns= 1 at update_tables.cgi line 605 via at update_ta +bles.cgi line 184 -> fetchrow_array for DBD::mysql::st (DBI::st=HASH(0x25c0480)~0x29 +81b48) thr#1c5c010 -> dbd_st_fetch dbd_st_fetch for 297fa00, chopblanks 0 dbd_st_fetch result set details imp_sth->result=29392a0 mysql_num_fields=22 mysql_num_rows=1 mysql_affected_rows=1 dbd_st_fetch for 297fa00, currow= 1 <- dbd_st_fetch, 22 cols <- fetchrow_array= '1972-10-03' row1 at update_tables.cgi line 608 + via at update_tables.cgi line 184 -> prepare for DBD::mysql::db (DBI::db=HASH(0x276c828)~0x276c630 ' +UPDATE table SET forename = ?,lastname = ?,password = ?,pin = ?,posit +ion = ? WHERE user_id = ?') thr#1c5c010 1 <- _async_check= 1 at mysql.pm line 240 via at update_tables.cgi +line 662 -> dbd_st_prepare MYSQL_VERSION_ID 50558, SQL statement: UPDATE ta +ble SET forename = ?,lastname = ?,password = ?,pin = ?,position = ? W +HERE user_id = ? >- dbd_st_free_result_sets <- dbd_st_free_result_sets RC -1 <- dbd_st_free_result_sets >count_params statement UPDATE table SET forename = ?,lastname = ?,pas +sword = ?,pin = ?,position = ? WHERE user_id = ? <- dbd_st_prepare <- prepare= DBI::st=HASH(0x297f940) at update_tables.cgi line 662 +via at update_tables.cgi line 184 <> DESTROY(DBI::st=HASH(0x25c0480)) ignored for outer handle (inne +r DBI::st=HASH(0x2981b48) has ref cnt 1) -> DESTROY for DBD::mysql::st (DBI::st=HASH(0x2981b48)~INNER) thr# +1c5c010 --> dbd_st_finish >- dbd_st_free_result_sets <- dbd_st_free_result_sets RC -1 <- dbd_st_free_result_sets <-- dbd_st_finish <- DESTROY= undef at update_tables.cgi line 664 via at update_tab +les.cgi line 664 -> execute for DBD::mysql::st (DBI::st=HASH(0x297f940)~0x29823e8) +thr#1c5c010 -> dbd_st_execute for 2981ea8 >- dbd_st_free_result_sets <- dbd_st_free_result_sets RC -1 <- dbd_st_free_result_sets mysql_st_internal_execute MYSQL_VERSION_ID 50558 >parse_params statement UPDATE table SET forename = ?,lastname = ?,pas +sword = ?,pin = ?,position = ? WHERE user_id = ? Binding parameters: UPDATE table SET forename = NULL,lastname = NULL,p +assword = NULL,pin = NULL,position = NULL WHERE user_id = NULL --> do_error You have an error in your SQL syntax; check the manual that correspond +s to your MySQL server version for the right syntax to use near 'tabl +e SET forename = NULL,lastname = NULL,password = NULL,pin = NULL,posi +tion = ' at line 1 error 1064 recorded: You have an error in your SQL + syntax; check the manual that corresponds to your MySQL server versi +on for the right syntax to use near 'table SET forename = NULL,lastna +me = NULL,password = NULL,pin = NULL,position = ' at line 1 <-- do_error IGNORING ERROR errno 1064 <- dbd_st_execute returning imp_sth->row_num 18446744073709551614 !! ERROR: 1064 'You have an error in your SQL syntax; check the ma +nual that corresponds to your MySQL server version for the right synt +ax to use near 'table SET forename = NULL,lastname = NULL,password = +NULL,pin = NULL,position = ' at line 1' (err#0) <- execute= undef at update_tables.cgi line 664 via at update_tab +les.cgi line 184 <> DESTROY(DBI::st=HASH(0x297f940)) ignored for outer handle (inne +r DBI::st=HASH(0x29823e8) has ref cnt 1) -> DESTROY for DBD::mysql::st (DBI::st=HASH(0x29823e8)~INNER) thr# +1c5c010 Freeing 6 parameters, bind 0 fbind 0 ERROR: 1064 'You have an error in your SQL syntax; check the ma +nual that corresponds to your MySQL server version for the right synt +ax to use near 'table SET forename = NULL,lastname = NULL,password = +NULL,pin = NULL,position = ' at line 1' (err#0) <- DESTROY= undef at update_tables.cgi line 664 via at update_tab +les.cgi line 664 !! The ERROR '1064' was CLEARED by call to do method -> do for DBD::mysql::db (DBI::db=HASH(0x276c828)~0x276c630 'INSER +T INTO sessions (id, a_session) VALUES(?, ?) ON DUPLICATE KEY UPDATE +a_session = ?' undef 'e220ca233bcc2555ed2e6ca7ac75e8bc' '$D = {'_SESS +ION_ID' => 'e220ca233bcc2555ed2e6ca7ac75e8bc','_SESSION_ATIME' => 152 +1989277,'user_id' => 15000,'_SESSION_REMOTE_ADDR' => '72.168.128.150' +,'_SESSION_CTIME' => 1521989277};;$D' '$D = {'_SESSION_ID' => 'e220ca +233bcc2555ed2e6ca7ac75e8bc','_SESSION_ATIME' => 1521989277,'user_id' +=> 15000,'_SESSION_REMOTE_ADDR' => '72.168.128.150','_SESSION_CTIME' +=> 1521989277};;$D') thr#1c5c010 mysql.xs do() use_server_side_prepare 0, async 0 mysql_st_internal_execute MYSQL_VERSION_ID 50558 >parse_params statement INSERT INTO sessions (id, a_session) VALUES(?, + ?) ON DUPLICATE KEY UPDATE a_session = ? Binding parameters: INSERT INTO sessions (id, a_session) VALUES('e220c +a233bcc2555ed2e6ca7ac75e8bc', '$D = {\'_SESSION_ID\' => \'e220ca233bc +c2555ed2e6ca7ac75e8bc\',\'_SESSION_ATIME\' => 1521989277,\'user_id\' +=> 15000,\'_SESSION_REMOTE_ADDR\' => \'72.168.128.150\',\'_SESSION_CT +IME\' => 1521989277};;$D') ON DUPLICATE KEY UPDATE a_session = '$D = +{\'_SESSION_ID\' => \'e220ca233bcc2555ed2e6ca7ac75e8bc\',\'_SESSION_A +TIME\' => 1521989277,\'user_id\' => 15000,\'_SESSION_REMOTE_ADDR\' => + \'72.168.128.150\',\'_SESSION_CTIME\' => 1521989277};;$D' <- do= 1 at mysql.pm line 50 via at Session.pm line 251 -> ping for DBD::mysql::db (DBI::db=HASH(0x276c828)~0x276c630) thr +#1c5c010 <- ping= 1 at DBI.pm line 136 via at update_tables.cgi line 664 -> FETCH for DBD::mysql::db (DBI::db=HASH(0x276c630)~INNER 'AutoCo +mmit') thr#1c5c010 <- FETCH= '' at DBI.pm line 141 via at update_tables.cgi line 664 -> commit for DBD::mysql::db (DBI::db=HASH(0x276c828)~0x276c630) t +hr#1c5c010 <- commit= 1 at DBI.pm line 141 via at update_tables.cgi line 664 -- DBI::END ($@: , $!: ) -> disconnect_all for DBD::mysql::dr (DBI::dr=HASH(0x2759650)~0x21 +433a8) thr#1c5c010 <- disconnect_all= (not implemented) at DBI.pm line 756 via at up +date_tables.cgi line 664 ! <> DESTROY(DBI::st=HASH(0x297f3a0)) ignored for outer handle (inne +r DBI::st=HASH(0x297f220) has ref cnt 1) ! -> DESTROY for DBD::mysql::st (DBI::st=HASH(0x297f220)~INNER) thr# +1c5c010 Freeing 1 parameters, bind 0 fbind 0 ! <- DESTROY= undef during global destruction ! -> ping for DBD::mysql::db (DBI::db=HASH(0x276c828)~0x276c630) thr +#1c5c010 ! <- ping= 1 at DBI.pm line 136 via at update_tables.cgi line 0 dur +ing global destruction ! -> FETCH for DBD::mysql::db (DBI::db=HASH(0x276c630)~INNER 'AutoCo +mmit') thr#1c5c010 ! <- FETCH= '' at DBI.pm line 141 via at update_tables.cgi line 0 d +uring global destruction ! -> commit for DBD::mysql::db (DBI::db=HASH(0x276c828)~0x276c630) t +hr#1c5c010 ! <- commit= 1 at DBI.pm line 141 via at update_tables.cgi line 0 d +uring global destruction ! -> DESTROY in DBD::_::common for DBD::mysql::dr (DBI::dr=HASH(0x21 +433a8)~INNER) thr#1c5c010 ! <- DESTROY= undef during global destruction >> DESTROY DBI::db=HASH(0x276c630) clearing 1 CachedKids ! -> DESTROY for DBD::mysql::db (DBI::db=HASH(0x276c630)~INNER) thr# +1c5c010 imp_dbh->pmysql: 275aa30 ! <- DESTROY= undef during global destruction ! <> DESTROY for DBI::dr=HASH(0x2759650) ignored (inner handle gone) -> DBI->connect(, , ****, HASH(0x250fe20)) ! <> DESTROY for DBI::db=HASH(0x276c828) ignored (inner handle gone)

Replies are listed 'Best First'.
SQL Error
by hippo (Archbishop) on Mar 25, 2018 at 15:37 UTC
    You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'table SET forename = NULL,lastname = NULL,password = NULL,pin = NULL,position = ' at line 1 error 1064

    Your table isn't called "table" because that's a reserved word.

Re: New CGI Action Call
by tultalk (Monk) on Mar 25, 2018 at 15:37 UTC

    Perhaps "@values" belongs in execute

    $sth->execute(@values) or die "Unable to execute query: " . $sth->err +str;

      That got past the NULL hump

      [Sun Mar 25 10:45:52 2018] update_tables.cgi: DBD::mysql::st execute f +ailed: You have an error in your SQL syntax; check the manual that co +rresponds to your MySQL server version for the right syntax to use ne +ar 'table SET business = 'Jackson Group',forename = 'Louis',lastname += 'Jackson',pas' at line 1 at update_tables.cgi line 664.

      pas is part of password = 'ZZZZZZZZ' and 2 other fields missing from the 6 I changed.

        And the call from the darkness

        <- dbd_st_free_result_sets <-- dbd_st_finish <- DESTROY= undef at update_tables.cgi line 662 via at update_tab +les.cgi line 662 -> execute for DBD::mysql::st (DBI::st=HASH(0x2bbb330)~0x2bbddd8 ' +Jackson Group' 'Louis' 'Jackson' 'ZZZZZZxxxxxxxx' 'CCCCCCCC' '3' 23) +thr#1e97010 Called: dbd_bind_ph Called: dbd_bind_ph Called: dbd_bind_ph Called: dbd_bind_ph Called: dbd_bind_ph Called: dbd_bind_ph Called: dbd_bind_ph -> dbd_st_execute for 2bbd898 >- dbd_st_free_result_sets <- dbd_st_free_result_sets RC -1 <- dbd_st_free_result_sets mysql_st_internal_execute MYSQL_VERSION_ID 50558 >parse_params statement UPDATE table SET business = ?,forename = ?,las +tname = ?,password = ?,pin = ?,position = ? WHERE user_id = ? Binding parameters: UPDATE table SET business = 'Jackson Group',forena +me = 'Louis',lastname = 'Jackson',password = 'ZZZZZZxxxxxxxx',pin = ' +CCCCCCCC',position = '3' WHERE user_id = '23' --> do_error You have an error in your SQL syntax; check the manual that correspond +s to your MySQL server version for the right syntax to use near 'tabl +e SET business = 'Jackson Group',forename = 'Louis',lastname = 'Jacks +on',pas' at line 1 error 1064 recorded: You have an error in your SQL + syntax; check the manual that corresponds to your MySQL server versi +on for the right syntax to use near 'table SET business = 'Jackson Gr +oup',forename = 'Louis',lastname = 'Jackson',pas' at line 1

        Looks like the dynamically created SQL statement is correct

        Why it is chopped off??Who knows

Re: New CGI Action Call
by Anonymous Monk on Mar 26, 2018 at 12:54 UTC
    I'd say a big part of your problem is that you are vastly over-thinking this thing. With code this (unnecessarily) complicated, bugs are inevitable. Just put the values into a hash – probably, the GET/POST parameters are already available as a hash – and get rid of the slew of discrete variables. You could rewrite this whole thing into a half-dozen lines of code, tops, and then you could see the problems. One of the most-basic considerations, of course, is that a browser typically sends only those values that have changed. If you populate a form field with a value and don't change that value, it might not come back in the return stream.
      One of the most-basic considerations, of course, is that a browser typically sends only those values that have changed. If you populate a form field with a value and don't change that value, it might not come back in the return stream.

      I really wonder where in the HTTP / CGI specification this User-Agent behaviour would be specified, since I've never seen nor even heard of this behaviour until now. I do a bit of web and browser automation and don't know of any test suites or code that looks for such cases.

      Can you please point out this weird behaviour either in the specifications or in example cases of browsers and pages on which that happens?

      I will ignore such advice until you show actual code/data.

      …a browser typically sends only those values that have changed.

      Mostly just putting a pin in this for my own record keeping. But I will say that anyone who posts here that six lines of code, TOPS!, could help and does not then proceed to write those lines of code is the antithesis of what I think this place should be.