I want to loop through an associative array that represents a table’s columns and values, and call a stored procedure on each iteration that will insert each value into its respective column. The assoc. array and loop looks like this:
public static function update(
int $auctionId,
string $title,
string $description
) : void
{
$new = [
'auction_title' => $title,
'description' => $description
];
foreach ($new as $columnName => $value) {
Database::conn()->callSP('sp_auctions_update', [$auctionId, $columnName, $value]);
}
}
The stored procedure looks like this:
DELIMITER $$
DROP PROCEDURE IF EXISTS sp_auctions_update $$
CREATE PROCEDURE sp_auctions_update(
IN auctionId INT UNSIGNED,
IN columnName,
IN value,
)
SQL SECURITY INVOKER
MODIFIES SQL DATA
BEGIN
UPDATE auctions SET @columnName=@value, WHERE id=@auctionId;
END $$
DELIMITER ;
Is this possible to do? Or is there a better alternative? Many thanks
Advertisement
Answer
do you know what the prepared statement would look like in this instance?
CREATE PROCEDURE sp_auctions_update(
IN auctionId INT UNSIGNED,
IN columnName VARCHAR(64),
IN `value` INT UNSIGNED
)
SQL SECURITY INVOKER
MODIFIES SQL DATA
BEGIN
-- Build SQL query text, insert column name from variable into it
SET @sql := CONCAT('UPDATE auctions SET ', columnName, '=? WHERE id=?;');
-- Reassign parameters values from local variables to user-defined ones
-- because local variables cannot be used in USING
SET @value := `value`;
SET @auctionId := auctionId;
-- Prepare and execute the query
PREPARE stmt FROM @sql;
EXECUTE stmt USING @value, @auctionId;
DEALLOCATE PREPARE stmt;
END
Alternatively you may concat ALL parameters values into the query text:
CREATE PROCEDURE sp_auctions_update(
IN auctionId INT UNSIGNED,
IN columnName VARCHAR(64),
IN `value` INT UNSIGNED
)
SQL SECURITY INVOKER
MODIFIES SQL DATA
BEGIN
-- Build SQL query text, insert parameters from variables into it
SET @sql := CONCAT('UPDATE auctions SET ', columnName, '='', `value`, '' WHERE id=', auctionId, ';');
-- Prepare and execute the query
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Caution.
The columnName
parameter value is inserted into SQL query text as-is – so injection is possible. You must add the code which controls this parameter value. For example you may check that the column with provided name exists in table structure.
Another 2 parameters cannot be a source of injection due to their numeric datatype.