in reply to Re^3: CGI Action call
in thread CGI Action call

Hi

The "user"in this case is the administrator and logged on as such.

That aside your point is well taken.

I don't dee that placeholders would be needed below but can you use multiple place holders as in the below code?

if ($kind == 2){ #previous record $stmt = "SELECT * FROM users WHERE user_id < (SELECT MAX(user_id) FR +OM users WHERE user_id < $rowpointer) ORDER BY user_id DESC LIMIT 1"; } if ($kind == 3){ #next record $stmt = "SELECT * FROM users WHERE user_id > (SELECT MIN(user_id) F +ROM users WHERE user_id > $rowpointer) ORDER BY user_id ASC LIMIT 1"; }

I know there is better way through MySQL but not there yet

Replies are listed 'Best First'.
Re^5: CGI Action call
by Corion (Patriarch) on Mar 12, 2018 at 20:25 UTC

    Yes, as is documented in DBI.

    Also, your SQL seems faulty to me as the "previous record" seems to skip users:

    create table users ( user_id integer not null primary key, name varcha +r(16) ); insert into users values (1,'Fred'); insert into users values (2,'Barney'); insert into users values (3,'Wilma'); insert into users values (4,'Betty'); insert into users values (5,'Pebbles'); SELECT * FROM users WHERE user_id < (SELECT MAX(user_id) FROM users WHERE user_id < 4) ORDER BY user_id DESC LIMIT 1

    (SQL fiddle)

    This suggests that the "previous" entry for "Betty" (user id 4) is "Barney" (user id 2), and not user id 3 as I would expect.

    The same, but inverse holds for the other SQL.

      I have a form with a navigator control I made. Works fine except when I want to scroll with a different order in place.

      The 4 SQL statements work fine in PHPAdmin. I issue an "alter table users order by lastname asc and the table is so ordered. Shows as such in browse. I execute the various SQL statements below and the returned records are as expected. next, next, previous, beginning and end. The ORDER remains in place.

      On the form I search for last name and set the alter table based on the search selected. This all works as intended per my logging. When I try to scroll the records with the navigator it is returning records based on the user_id order. I tried correcting this by reasserting the alter table again with each scroll but to no avail.

      Don't understand why the process works in PHP MyAdmin but not with my code.

      #==================================== #Navigation navigate_Records Buttons 1-4 # 1 Beginning # 2 Previous # 3 Next # 4 End sub navigate_Records { my $kind = $query->param('kind'); my $rowpointer = $query->param('searchterm'); my ($sth, $stmt); my @row; warn("Entered update_tables.cgi Open Database return First Record +with action: = '$action'"); warn("Search Parameter = '$kind'"); warn("rowpointer = '$rowpointer'"); my $minrowpointer; my $maxrowpointer; my $searchfield; warn("sortindex = '$sortindex'"); #Set by selection in search_Rec +ords if (!$sortindex) { $sortindex = 0; } if ($sortindex == 0){ $searchfield = 'user_id'; $minrowpointer = 1; $maxrowpointer = 14999; } elsif ($sortindex == 1) { $searchfield = 'lastname'; $minrowpointer = 'a%'; $maxrowpointer = 'z%'; } elsif ($sortindex == 2) { $searchfield = 'business'; $minrowpointer = 'a%'; $maxrowpointer = 'z%'; } #kind 0 & 3 ok with direct hard coded SQL if ($kind == 0){ #beginning record Tested Good $stmt= "SELECT * FROM ( SELECT * FROM users WHERE $searchfield + <= ? AND $searchfield >= ? ORDER BY $searchfield ASC LIMIT 1 ) sub O +RDER BY $searchfield ASC"; # example user_id # $stmt = "SELECT * FROM ( SELECT * FROM users WHERE user_id <= + 14999 AND user_id >= 1 ORDER BY user_id ASC LIMIT 1 ) sub ORDER BY u +ser_id ASC"; #Works fine hard coded #example lastname SELECT * FROM ( SELECT * FROM users WHERE la +stname <='z%' AND lastname >= 'a%'ORDER BY lastname ASC LIMIT 1 ) sub + ORDER BY lastname ASC #Works fine hard coded #example business SELECT * FROM ( SELECT * FROM users WHERE bu +siness <='z%' AND business >= 'a%'ORDER BY business ASC LIMIT 1 ) sub + ORDER BY business ASC } if ($kind == 1){ #previous record Tested Good $stmt = "SELECT * FROM users WHERE $searchfield <= (SELECT MAX +($searchfield) FROM users WHERE $searchfield < ?) ORDER BY $searchfie +ld DESC LIMIT 1"; } if ($kind == 2){ #next record Tested Good $stmt = "SELECT * FROM users WHERE $searchfield >= (SELECT MIN +($searchfield) FROM users WHERE $searchfield > ?) ORDER BY $searchfie +ld ASC LIMIT 1"; } if ($kind == 3){ #Last record Tested Good $stmt = "SELECT * FROM ( SELECT * FROM users WHERE $searchfiel +d <= ? AND $searchfield >= ? ORDER BY $searchfield DESC LIMIT 1 ) sub + ORDER BY $searchfield ASC"; #example user_id # $stmt = "SELECT * FROM ( SELECT * FROM users WHERE user_id <= +14999 AND user_id >= 1 ORDER BY user_id DESC LIMIT 1 ) sub ORDER BY u +ser_id ASC"; #Works fine hard coded #example lastname SELECT * FROM ( SELECT * FROM users WHERE la +stname >='z%' AND lastname >= 'a%'ORDER BY user_id DESC LIMIT 1 ) sub + ORDER BY lastname ASC #Works fine hard coded #example business SELECT * FROM ( SELECT * FROM users WHERE bu +siness >='z%' AND business >= 'a%'ORDER BY business DESC LIMIT 1 ) su +b ORDER BY business ASC } warn("statement = '$stmt'"); $sth = $dbh->prepare ($stmt) or die "Error Preparing:\n" . $stmt . + "\nDBI returned: \n", $dbh->errstr; # warn("'$maxrowpointer' '$minrowpointer' '$searchfield' '$rowpoint +er'"); if (($kind == 0) || ($kind == 3)){ warn("kind = '$kind' maxrowpointer = '$maxrowpointer' minrowpo +inter = '$minrowpointer'"); $sth->execute ($maxrowpointer,$minrowpointer) or die "Unable to + execute query: " . $sth->errstr; } elsif (($kind == 1) || ($kind == 2)){ warn("kind = '$kind' rowpointer = '$rowpointer'"); $sth->execute($rowpointer) or die "Unable to execute query: " . + $sth->errstr; } my $navResult = $sth->fetchrow_hashref(); warn("navResult = '$navResult'"); my $count = $sth->rows; warn("count = '$count'"); if ($count == 0) { my %navFail = ( Count => $count); my $json = JSON->new; $json->canonical(1); $json = encode_json(\%navFail); print "Content-Type: application/json\n\n"; print $json; warn("Finished print 0 count $json"); exit(1); } else { warn("count = '$count'"); my $json = JSON->new; $json->canonical(1); $json = encode_json($navResult); print "Content-Type: application/json\n\n"; print $json; warn("Finished print $json"); exit(0); } }

      More code

      #Search Records & Return Found 3 buttons # 0 Member ID # 1 Last Name # 2 Business Name #elsif ($action eq "search_Records") sub search_Records { warn("Entered search_Records"); my $kind = $query->param('kind'); my $searchterm = $query->param('searchterm'); my $result; warn("searchterm = '$searchterm'"); my $searchfield = ""; if ($kind == 0) { $searchfield = 'user_id'; } if ($kind == 1) { $searchfield = 'lastname'; } if ($kind == 2) { $searchfield = 'business'; } $sortindex = $kind; restoreOrder($kind); #Sort Index For The Three Kinds Of ORDER Supposed to be global. warn("sortindex = '$sortindex'"); warn("searchfield = '$searchfield'"); $stmt = "SELECT * FROM users WHERE $searchfield = ? ORDER BY ? ASC +"; # my $stmt = "SELECT * FROM users WHERE user_id = 15 ORDER BY user_ +id ASC"; warn("statement = '$stmt'"); $sth = $dbh->prepare ($stmt) or die "Error Preparing:\n" . $stmt . + "\nDBI returned: \n", $dbh->errstr; $sth->execute($searchterm, $searchfield) or die "Unable to execute + query: " . $sth->errstr; # $sth->execute() or die "Unable to execute query: " . $sth->errstr +; my $searchResult = $sth->fetchrow_hashref(); my $count = $sth->rows; warn("count = '$count'"); if ($count == 0) { warn("Failed Search: '$searchfield' equal to '$searchterm' "); my %searchFail = ( SearchError => $kind); my $json = JSON->new; $json->canonical(1); $json = encode_json(\%searchFail); print "Content-Type: application/json\n\n"; print $json; warn("Finished print 0 count $json"); exit(1); } #{"SearchError":0} Good else { warn("count = '$count'"); my $json = JSON->new; $json->canonical(1); $json = encode_json($searchResult); print "Content-Type: application/json\n\n"; print $json; warn("Finished print $json"); exit(0); } }

      And yet more code

      #================================== #Set up "order by clause" depending on searchfield sub restoreOrder{ my $searchIndex = shift; if ($searchIndex == 0) { $searchfield = "user_id"; } elsif ($searchIndex == 1) { $searchfield = "lastname"; } elsif ($searchIndex == 1) { $searchfield = "business"; } warn("in restoreOrder index = '$searchIndex'"); my $stmt = "alter table users order by $searchfield asc"; 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; + }

        Why use sub selects here

        SELECT * FROM users WHERE $searchfield <= ( SELECT MAX($searchfield) FROM users WHERE $searchfield < ?) ORDER BY $searchfield DESC LIMIT 1

        instead of the simpler

        SELECT * FROM users WHERE $searchfield < ? ORDER BY $searchfield DESC LIMIT 1
        poj
        alter table users order by lastname asc

        I don't think that this is how SQL works. In fact, I'm surprised that such a statement parses at all and doesn't raise an error.

        In SQL, tables don't have any kind of order that you can change. SELECT statements have an order clause and if you want to have a specific order, you need to specify that in every SELECT statement.

      That may be. I threw it together and locked it to return related to fixed row number for testing other parts.

      Another to-do

      Need some insight. Have been staring at this since last night. Placeholder issue

      if ($kind == 3){ #Last record $stmt = "SELECT * FROM ( SELECT * FROM users WHERE ? <= ? AND +? >= ? ORDER BY ? ASC LIMIT 1 ) sub ORDER BY ? ASC"; #example user_id # $stmt = "SELECT * FROM ( SELECT * FROM users WHERE user_id <= +14999 AND user_id >= 1 ORDER BY user_id DESC LIMIT 1 ) sub ORDER BY u +ser_id ASC"; #Works fine hard coded

      placeholder substitution

      $sth = $dbh->prepare ($stmt) or die "Error Preparing:\n" . $stmt . + "\nDBI returned: \n", $dbh->errstr; warn("'$searchfield' '$maxrowpointer' '$searchfield' '$minrowpoint +er' '$searchfield' '$searchfield'"); #verified correct values in var +iables at this point $sth->execute ($searchfield, $maxrowpointer,$searchfield,$minrowpo +inter, $searchfield, $searchfield) or die "Unable to execute query: " + . $sth->errstr; my $refresult = $sth->fetchrow_hashref(); my $count = $sth->rows;

      This works fine with hard coded vaues instead of placeholders and also testing MySQL directly. count = 1 When running with the placeholders, count = 0

      Result with hard code JSON output below

      {"DD":"2019-01-30","DP":"2018-12-31","MD":"120.00","MJ":"2018-01-30"," +address1":"1471 Meeks Rd","address2":null,"business":"JZ Electroplating","city":"Warran","comments":"This is a test entry","email":"jze@yahoo.com","forename":"John","id":57,"lastname":"Z +inzer","password":"1234","phone_cell":"517-240-1004","phone_home":"51 +7-233- 4378","pin":"JbwmZ","position":"General Member","state":"MI","user_id" +:19,"username":"bwm19","zip":"45789-2334"}

        What is the value of $searchfield? You don't show it to us so we have to guess. This makes it much harder to provide you concise help. Please adjust your debugging process and tell us what you see/output instead of making us guess.

        My guess is that $searchfield contains the string id or some other string that you want to be interpreted as column name.

        Did you read the section about placeholders in DBI?

        Most likely, you skipped over the part where it tells you where placeholders can be used:

        Placeholders, also called parameter markers, are used to indicate values in a database statement that will be supplied later, ...
        With most drivers, placeholders can't be used for any element of a statement that would prevent the database server from validating the statement and creating a query execution plan for it.

        Naturally, you can't supply the name of a column as a placeholder because the database can't validate your statement before seeing the column name.

        What happens instead is that your database treats all placeholders as values and never compares the columns but just values of the placeholders.