SQLSTATE[HY093]? I can't figure this one out.

I was trying to write a new function after having not worked with SQL in a long time, so I used an existing function as a template to write the new one. It’s a simple enough concept, look for all entries based on a few constraints and return it as an array. First here is the function that works:
[php]
function find_sizes_for_image($index)
{
global $db;
$sth = $db->prepare(‘SELECT sizeID FROM inventory WHERE imageID = :index’);
$sth->bindParam(’:index’,$index,PDO::PARAM_INT);
$sth->execute();
$listcounter=0;
foreach($sth as $entry)
{
$list[$listcounter][‘size’] = $entry[‘sizeID’];
$list[$listcounter][‘desc’] = get_size($entry[‘sizeID’]);
$listcounter++;
}
$sth->closeCursor();
return $list;
}
[/php]

Based on that, I came up with this for the new function:
[php]
function get_calendar($month, $year)
{
global $db;
$sth = $db->prepare(‘SELECT * FROM calendar WHERE date-year = :date-year AND date-month = :date-month’);
$sth->bindParam(’:date-year’,$year,PDO::PARAM_INT);
$sth->bindParam(’:date-month’,$month,PDO::PARAM_INT);
$sth->execute();
$list_counter=0;
foreach($sth as $entry)
{
$list[$list_counter][‘date_year’] = $entry[‘date-year’];
$list[$list_counter][‘date_month’] = $entry[‘date-month’];
$list[$list_counter][‘date_day’] = $entry[‘date-day’];
$list[$list_counter][‘time_start’] = $entry[‘time-start’];
$list[$list_counter][‘time_end’] = $entry[‘time-end’];
if($entry[‘available’] && !$entry[‘reserved’])
{
$list[$list_counter][‘available’] = true;
}
else if(!$entry[‘available’] && $entry[‘reserved’])
{
$list[$list_counter][‘available’] = false;
}
$list[$list_counter][‘info’] = $entry[‘info’];
$list_counter++;
}
$sth->closeCursor();
return $list;
}
[/php]

I’m trying to figure out what the critical difference is. The first one only has one bindParam while the second has two. The first one only gets one value, while the second one gets all the values in the rows selected. Other than that, I don’t know. It’s always hard to come back and write code when you haven’t done it in a year.

Incidentally, the thing fails on the line $sth->execute(); if it makes a difference.

I think I figured it out, you can’t use dashes in param names. I changed them to underscores and that problem went away, although I am still having a problem with this function (nothing gets returned even though there is a single entry in the table that falls into the range that this should pick up).

I can’t find an HY093 error code. Are you positive that is it? Which db server are you using?

I would not use dashes in variable names.

Turn on error reporting and you will know exactly what the problem is.

invalid placeholder names.

The easiest way to find out, is to just check the source code: http://lxr.php.net/xref/PHP_5_3/ext/pdo/pdo_sql_parser.re#49
BINDCHR     = [:][a-zA-Z0-9_]+;

You can use alphanumeric + underscore.


HY093 Invalid parameter number
http://dev.mysql.com/doc/connectors/en/connector-odbc-reference-errorcodes.html

Yeah, it’s confusing because you can use them for table column names, and I was trying to keep them the same to avoid confusion.

Anyway, that problem is resolved, now I just can’t figure out why it never runs through the foreach loop regardless of what’s in the table. The only error returned is at the end where it says it doesn’t know what $list is, which is what would happen if it never enters that loop.

You need to fetch the result set.

[php]$result = $sth->fetchAll();[/php]

Is that because I am using SELECT * in the new function and just selecting by a single column in the first one?

This is what I have now for the function. I have corrected the param names and no longer get the error in the thread title. I have added a fetchAll (also changing the foreach loop appropriately) but it is still not recognizing $list at the end of the function.

[php]
function get_calendar($month, $year)
{
global $db;
$sth = $db->prepare(‘SELECT * FROM calendar WHERE date-year = :date_year AND date-month = :date_month’);
$sth->bindParam(’:date_year’,$year,PDO::PARAM_INT);
$sth->bindParam(’:date_month’,$month,PDO::PARAM_INT);
$sth->execute();
$result = $sth->fetchAll();
$list_counter=0;
foreach($result as $entry)
{
$list[$list_counter][‘date_year’] = $entry[‘date-year’];
$list[$list_counter][‘date_month’] = $entry[‘date-month’];
$list[$list_counter][‘date_day’] = $entry[‘date-day’];
$list[$list_counter][‘time_start’] = $entry[‘time-start’];
$list[$list_counter][‘time_end’] = $entry[‘time-end’];
if($entry[‘available’] && !$entry[‘reserved’])
{
$list[$list_counter][‘available’] = true;
}
else if(!$entry[‘available’] && $entry[‘reserved’])
{
$list[$list_counter][‘available’] = false;
}
$list[$list_counter][‘info’] = $entry[‘info’];
$list_counter++;
}
$sth->closeCursor();
return $list;
}
[/php]

EDIT: And just to make sure I’m not making the mistake somewhere outside of here, the function is called as get_calendar(1,2016), and the table called calendar looks like this (bold for column names)
[table]
[tr]
[td]id[/td][td]date-year[/td][td]date-month[/td][td]date-day[/td][td]available[/td][td]reserved[/td][td]time-start[/td][td]time-end[/td][td]info[/td]
[/tr]
[tr]
[td]0[/td][td]2016[/td][td]1[/td][td]1[/td][td]0[/td][td]1[/td][td]00:00:00[/td][td]23:59:59[/td][td]test[/td]
[/tr]
[/table]

you should instantiate $list as an empty array before the loop. This doesn’t answer why you don’t get any rows returned from the DB, but it makes sure the code works even if you actually have no results.

For the results you never fetch them, you’re trying to loop over the statement handler, which won’t work. Are you really sure the first function works…? If so I didn’t know you could do that.

[php]$list = array();

foreach($sth->fetchAll() as $row)
{
}[/php]

You don’t need to keep track of an index for the loop

[php]$list = array();

foreach($sth->fetchAll() as $row)
{
// Ex
// $entry = array(
// ‘date_year’ => $row[‘date-year’],
// …
// );

// add $row to the $list array
$list[] = $entry;
}

// array(0 => row1, 1 => row2, 2 => row3)[/php]

[hr]

Though really you should just select the data as you want it directly from the DB.

[php]function get_calendar($month, $year)
{
global $db; // globals are evil, should refactor

$sth = $db->prepare(’
SELECT
date-year as date_year,
date-month as date_month,
time-start as time_start,
time-end as time_end,
// I think this should be enough
IF(available AND NOT reserved, true, false) as available,
info
FROM calendar
WHERE date-year = :year AND date-month = :month’);

$sth->bindParam(’:year’,$year,PDO::PARAM_INT);
$sth->bindParam(’:month’,$month,PDO::PARAM_INT);
$sth->execute();

return $sth->fetchAll();
}[/php]

or the syntax I prefer.

[php]function get_calendar($month, $year)
{
global $db; // globals are evil, should refactor

$sth = $db->prepare(’
SELECT
date-year as date_year,
date-month as date_month,
time-start as time_start,
time-end as time_end,
// I think this should be enough
IF(available AND NOT reserved, true, false) as available,
info
FROM calendar
WHERE date-year = ? AND date-month = ?’);

$sth->execute(array($year, $month));
return $sth->fetchAll();
}[/php]

To answer that question about the first block of code in the first post, yes it does work as written. The only thing I can think of is that it’s selecting only from a single column, so each $entry in the foreach only has a single $entry[‘sizeID’] rather than itself being an array with multiple values. I dunno, just the main difference I notice between the two.

I used your second block of code as the basis for this: (I removed one of the columns I was using as it wasn’t needed):
[php]
function get_calendar($month, $year)
{
global $db;
$sth = $db->prepare(‘SELECT * FROM calendar WHERE date-year = :date_year AND date-month = :date_month’);
$sth->bindParam(’:date_year’,$year,PDO::PARAM_INT);
$sth->bindParam(’:date_month’,$month,PDO::PARAM_INT);
$sth->execute();
$list = array();
foreach($sth->fetchAll() as $row)
{
$entry = array(‘date_year’ => $row[‘date-year’], ‘date_month’ => $row[‘date-month’], ‘date_day’ => $row[‘date-day’], ‘time_start’ => $row[‘time-start’], ‘time_end’ => $row[‘time-end’], ‘available’ => $row[‘available’], ‘info’ => $row[‘info’]);
$list[] = $entry;
}
$sth->closeCursor();
return $list;
}
[/php]
Unfortunately, it’s still returning an empty array. :frowning:

EDIT: I’m going to try rewriting this without prepared statements. The function is never called based on user input, so there’s really no need to sanitize the data. That takes out some of the complexity and perhaps that will either make the problem disappear or it will make it easier to find.

Solved! You have to use `` marks around a column name if it has a hyphen and you want to use it the way I was using it. I decided just to get rid of the hyphens in the column names.

Sponsor our Newsletter | Privacy Policy | Terms of Service