EXECUTE и CONCAT внутри хранимой процедуры мешает нормальному fetch-у.

J-Pro

Новичок
EXECUTE и CONCAT внутри хранимой процедуры мешает нормальному fetch-у.

Ребятушки, проблема возникла :(

Значит, для удобства и сокращения написанного, я решил делать выборку из таблиц в хранимых процедурах по различным критериям в одной хранимой процедуре. Выглядит это так:

PHP:
CREATE PROCEDURE `GetAllDiscounts`(IN activitytypeid BIGINT, IN languageid BIGINT)
    NOT DETERMINISTIC
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN

 DECLARE statement VARCHAR(1024);
 DECLARE lang VARCHAR(500);
 DECLARE activitytype VARCHAR(500);

 IF (activitytypeid IS NULL) THEN SET activitytype := ' AND 1=1';
  ELSE SET activitytype := CONCAT(' AND AT.`ActivityTypeID` = ', activitytypeid);
 END IF;

 IF (languageid IS NULL) THEN SET lang := ' AND 1=1';
  ELSE SET lang := CONCAT(' AND D.`LanguageID` = ', languageid);
 END IF;


    SET @statement :=
    CONCAT('SELECT D.`DiscountID`,
            D.`ActivityTypeID`,
            AT.Name,
            AT.Description,
            D.`ArticleName`,
            D.`PathToPhoto`,
            D.`PathToFirstPhoto`,
            D.`Value`,
            D.`OldPrice`,
            D.`NewPrice`,
            D.`StartDate`,
            D.`EndDate`,
            D.`Description`,
            D.`RegisteredOn`,
            D.`UpdatedBy`,
            D.`UpdatedOn`,
            D.`LanguageID`,
            L.Name AS LanguageName,
            L.Initials AS LanguageInitials

    FROM Discounts D
    JOIN ActivityTypes AT ON D.`ActivityTypeID` = AT.`ActivityTypeID`
    JOIN Languages L ON D.LanguageID = L.LanguageID
    WHERE 1 = 1 ', lang, activitytype);
    
    PREPARE stmt FROM @statement;
    EXECUTE stmt;
    
    DEALLOCATE PREPARE stmt;

END;

Раньше же, если писать просто, вот так:

PHP:
CREATE PROCEDURE `GetAllDiscounts`(IN activitytypeid BIGINT, IN languageid BIGINT)
    NOT DETERMINISTIC
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN


    SELECT D.`DiscountID`,
            D.`ActivityTypeID`,
            AT.Name,
            AT.Description,
            D.`ArticleName`,
            D.`PathToPhoto`,
            D.`PathToFirstPhoto`,
            D.`Value`,
            D.`OldPrice`,
            D.`NewPrice`,
            D.`StartDate`,
            D.`EndDate`,
            D.`Description`,
            D.`RegisteredOn`,
            D.`UpdatedBy`,
            D.`UpdatedOn`,
            D.`LanguageID`,
            L.Name AS LanguageName,
            L.Initials AS LanguageInitials

    FROM Discounts D
    JOIN ActivityTypes AT ON D.`ActivityTypeID` = AT.`ActivityTypeID`
    JOIN Languages L ON D.LanguageID = L.LanguageID
    LEFT OUTER JOIN DiscountsTradeCenters DTC ON D.`DiscountID` = DTC.`DiscountID`
    LEFT OUTER JOIN `tradecenters` TC ON DTC.`TradeCenterID` = TC.`TradeCenterID`;

END;
, необходимо было писать условия и несколько раз копипэйстить блок SELECT с разным условием WHEN.

Вызываю я эти процедуры из пхп.

НО, проблема: Первый случай перестал fetch-иться нормально, показывает, что в резалте только названия столбцов, а один раз вообще перемешал как-то все строки, КРОМЕ, опять же, названий столбцов. Т.е. названия одинаковые: ID, Name, а данные в них перемешаны из разных столбцов.
НИЧЕГО НЕ МЕНЯЯ в алгоритме вывода данных из резалтсета, т.е. вообще не прикасаясь к коду php, а просто заменяя хранимую процедуру в первом примере на хранимую процедуру во втором(без EXECUTE), всё работает превосходно, все данные возвращаются.

Хочу отметить, что в консоли, простым CALL оба варианта выше дают одинаковые результаты. Так почему же эти результаты не попадают в stmt?

Кто-то сталкивался с такой проблемой?

Спасибо заранее за ответ.



-~{}~ 02.11.06 15:29:

Народ, помогайте, ищу в нете нигде нет ничего подобного...

Уж не знаю что и делать... Почему так происходит - не пойму... вроде, в SQL-редакторе результаты одинаковые, а тут...

Может, после EXECUTE надо что-то ещё сделать, чтобы всё ок было в пхп?

Код пхп на всякий случай:
PHP:
$procedureCallStatement = "CALL GetAllDiscounts(?, ?)";

$stmt = $mysqli->prepare($procedureCallStatement);
$stmt->bind_param('ii', $activityTypeID, $languageID);
$res = $stmt->execute();

if($res)
{
       $meta = $stmt->result_metadata();
       if(!$meta) return false;

       $retArr = array(array(), array());
       $colNames = array();
       $tmpArray = array();

       while ($field = $meta->fetch_field())
       { // получаем массив названий столбцов

         $names[] = $field->name;
         $colNames[] = $field->name;
       }

       $retArr[0] = $colNames; // первая строка двумерного массива

       // теперь нашими утилитами получаем ассоциативныЕ массивЫ резалт сета
       $j = 1;
       while($assocArr = mps_fetch_assoc($stmt))
       {

               $namesQuan = count($names);

               for($i = 0; $i < $namesQuan; $i++)
               {
                  $tmpArray[$i] = $assocArr[$names[$i]];
               }

               $retArr[$j] = $tmpArray;

               $j++;
      }


}


    // #######################################################################################################
public function mps_fetch_assoc(&$stmt)
{ // Ф-ция для того, чтобы резалт превратить в ассоциативный массив: столбец-данные

	$meta = $stmt->result_metadata();
	$retval[] = &$stmt;
	$tmp;
	$names;

	while ($field = $meta->fetch_field())
	{ // получаем массив названий столбцов
	    $names[] = $field->name;
	}

	$tmp = $names;

	for ($c = 0; $c < count($names); $c++)
	{ // копируем полученные названия столбцов в другой массив ("Id", "Name", .....)
	    $retval[] = &$tmp[$c];
	}



	// Биндим значения столбцов, передавая массив НАЗВАНИЙ ПЕРЕМЕННЫХ, составленный из
	// массива названий столбцов. Т.к. надо: $stmt->bind_result($col1, $col2, $col3, и т.д....);
	call_user_func_array("mysqli_stmt_bind_result", $retval);

	// Если всё прошло успешно, данные получаются фетчем, скидываем их в ассоциативный массив
	if ($stmt->fetch())
	{
	                $assoc_array;
		for ($c = 0; $c < count($names); $c++)
		{
		    $assoc_array[$names[$c]] = $retval[$c + 1];
		}
  	 	
 		return $assoc_array;
	}
	else
	{
	    return FALSE;
	}

}
В итоге получаю $retArr, матрицу, первой строкой которой являются имена столбцов, остальными - данные вернувшейся таблицы.
Но, вот, оставляя код таким же и меняя только процедуру - получаю ошибку... странно...


Жду помощи...

-~{}~ 03.11.06 17:13:

Ребят, неужели никто не встречался с подобными вещами?

Может, кто-то поможет? :(

-~{}~ 06.11.06 13:48:

Жаль, но мне кажется, ответа на мой вопрос никто не знает...

Странно... в PostgreSQL этот вопрос не возникал, а тут... :(
 
Сверху