So, this is looping over a set of records that correspond to a hierarchical data structure stored using the Adjacency Model, printing them out in an indented fashion.
All records are gone through, looking for direct children of a given node, which for each one identified is printed and the function recalled to print its own direct children and so on. Each printing of a nodes children must loop through the entire result set from scratch looking for them, hence why the pointer is set back to 0 prior to calling the function to get its children. After getting its children printed, it needs to reset the pointer to the next record it is supposed to be moving on to. Here is where there's a flaw.
It's incrementing the variable that keeps track of where the pointer should be pointing to, so that it should be pointing to the next record, and then setting the pointer to it. However, upon having processed the last record in the set, the pointer is incremented to one greater than the index of the last item (itself) and therefore trying to set the pointer to it fails. A simple off by one bug.
All you should need to do is switch the order of the last two statements. Set the pointer to the current record, then increment $row. If mysql_fetch_array works how I think it works (I've never messed with setting the index pointer myself), the call to it will itself increment its pointer and fetch the next row, if there is one.
Furthermore, I'd set default values on the root and depth parameters if I were you, it'll make it simpler to use, by just calling traverse($sql);
function traverse($sql, $root = null, $depth = 0)
{
$row = 0;
while ($acat = mysql_fetch_array($sql))
{
if ($acat['parentcat'] == $root)
{
echo "<option value='" . $acat['catID'] . "'>";
$j = 0;
while ($j < $depth) {
echo " ";
$j++;
}
if ($depth > 0) {
echo "-";
}
echo $acat['catname'] . "</option>";
mysql_data_seek($sql, 0);
traverse($sql, $acat['catID'], $depth + 1);
}
mysql_data_seek($sql, $row);
$row++;
}
}