Mysql
 sql >> Base de données >  >> RDS >> Mysql

Instruction préparée de procédure stockée MySQL (SQL dynamique) paramétrée

Le EXECUTE l'instruction doit recevoir une liste fixe d'arguments, vous devrez donc préparer et exécuter l'instruction dans un IF/THEN/ELSE bloquer.

IF articlesModule = 1 THEN
    SET @query = ... UNION ...
    PREPARE stmt FROM @query;
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;
ELSE
    SET @query = ...; /* no UNION */
    PREPARE stmt FROM @query;
    EXECUTE stmt USING @searchWordIn, @searchWordIn;
END IF;

Je ne connais aucun moyen de résoudre ce problème dans la portée limitée du langage de procédure stockée MySQL. Pour moi, c'est une autre bonne raison de ne pas utiliser le SQL dynamique dans les procédures stockées.

Vos commentaires :

Je vois... vous pourriez utiliser un CASE déclaration au lieu d'un IF/THEN/ELSE , mais vous avez en fait 2 =128 cas différents potentiels pour les chaînes de requête, car je suppose que l'un de ces 7 modules peut être recherché ou non.

Une alternative qui vous permettrait d'utiliser des paramètres de requête est d'oublier d'utiliser UNION , et à la place, écrivez la procédure de manière à exécuter jusqu'à 7 SELECT distincts les interroge et les renvoie tous sous forme de ensembles de résultats multiples . C'est quelque chose que les procédures stockées sont destinées à faire. Mais vous devez écrire du code dans votre couche PHP pour récupérer chaque ensemble de résultats à tour de rôle. Autrement dit, bouclez sur les ensembles de résultats et, dans cette boucle, bouclez sur les lignes de l'ensemble de résultats actuel. Voir l'exemple sur PDO::nextRowset() ou mysqli::next_result() .

Non, vous n'êtes pas en sécurité si vous faites cela ! Utilisation d'un paramètre de requête en PHP pour transmettre une chaîne à CALL WEBSITE_mainSearch(?) est inutile pour se protéger contre l'injection SQL, si vous concaténez ensuite cette valeur de paramètre dans une autre chaîne à l'intérieur de la procédure et effectuez une analyse et une exécution SQL dynamiques. L'utilisation de paramètres de requête ne rend pas les valeurs de paramètres "sûres", elles séparent simplement ces valeurs de la phase d'analyse SQL.

Vous êtes plus en sécurité si vous utilisez la fonction intégrée de MySQL CITATION() lors de la concaténation des chaînes. QUOTE() fait l'échappement des caractères spéciaux, tout comme mysql_real_escape_string() . Sauf que c'est légèrement différent, car il produit également les guillemets simples délimitant la chaîne, comme PDO::quote() fait.

SET @query = CONCAT(@query, 'SELECT blockName AS itemName, blockPath AS seoName, 
  blockID AS itemID, MATCH(blockName, blockBody) AGAINST (',
  QUOTE(searchWordIn), ') AS relevance, \'block\' AS itemType 
  FROM content_blocks WHERE MATCH(blockName, blockBody) AGAINST (',
  QUOTE(searchWordIn),')') ;

Mise à jour :une autre alternative :utilisez UNION pour ajouter plus de sous-requêtes et compter les modules. Utilisez ensuite un CASE pour exécuter la requête préparée avec un nombre différent de paramètres en fonction du nombre cumulé.

SET @n = 0;
IF articlesModule = 1 THEN
    SET @query = ... UNION ...
    SET @n = @n+1;
END IF;

IF newsModule = 1 THEN
    SET @query = ... UNION ...
    SET @n = @n+1;
END IF;

... and similar for the other 5 modules ...

PREPARE stmt FROM @query;

CASE @n
WHEN 1:
    EXECUTE stmt USING @searchWordIn, @searchWordIn;
WHEN 2:
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;
WHEN 3:
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
      @searchWordIn, @searchWordIn;
WHEN 4:
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
      @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;
WHEN 5:
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
      @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
      @searchWordIn, @searchWordIn;
WHEN 6:
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
      @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
      @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;
WHEN 7:
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
      @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,
      @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn, 
      @searchWordIn, @searchWordIn;
END;