2010-09-11 5 views
1

Je veux créer une procédure stockée comme ceci:Est-il possible de passer le nom de la table en tant que paramètre dans Oracle?

PROCEDURE P_CUSTOMER_UPDATE 
    (
     pADSLTable IN Table, 
     pAccountname IN NVARCHAR2, 
     pStatus IN NUMBER, 
     pNote IN NVARCHAR2, 
     pEmail IN NVARCHAR2, 
     pMobi IN NVARCHAR2, 
     pServiceTypeID IN NUMBER, 
     pDate IN DATE 
) 
    IS 
    BEGIN 
     UPDATE pADSLTable 
     SET STATUS = pStatus, NOTE = pNote, EMAIL = pEmail, MOBI = pMobi, SERVICETYPE_ID = pServiceTypeID, ACTIVATION_DATE = pDate 
     WHERE ACCOUNT_NAME = pAccountname; 
    END; 

Bien sûr, Oracle ne me laisse pas faire ça. Y a-t-il un moyen de contourner ce problème? Merci beaucoup.

Répondre

11

Vous avez plusieurs tables différentes avec exactement les mêmes noms de colonnes et types de données? Ça sent le design douteux. De toute façon, nous ne pouvons pas utiliser les variables comme objets de base de données dans un SQL simple comme ça. Nous devons utiliser le SQL dynamique.

PROCEDURE P_CUSTOMER_UPDATE 
    (
     pADSLTable IN USER_TABLES.table_name%type, 
     pAccountname IN NVARCHAR2, 
     pStatus IN NUMBER, 
     pNote IN NVARCHAR2, 
     pEmail IN NVARCHAR2, 
     pMobi IN NVARCHAR2, 
     pServiceTypeID IN NUMBER, 
     pDate IN DATE 
) 
    IS 
    BEGIN 
     execute immediate 
      'UPDATE '||pADSLTable 
      ||' SET STATUS = :1, NOTE = :2, EMAIL = :3, MOBI = :4, SERVICETYPE_ID = :5, ACTIVATION_DATE = :6' 
      ||' WHERE ACCOUNT_NAME = :7' 
     using pStatus, pNote, pEmail, pMobi, pServiceTypeID, pDate, pAccountname; 
    END; 

Une raison pour éviter l'utilisation de SQL dynamique est qu'il est ouvert à l'abus. Les personnes malveillantes peuvent utiliser les paramètres pour tenter de contourner notre sécurité. C'est ce qu'on appelle l'injection SQL. Je pense que les gens surestiment l'importance de l'injection SQL. Ce n'est pas automatiquement une menace. Par exemple, si la procédure est une procédure privée dans un paquet (c'est-à-dire non déclaré dans la spécification), il est peu probable que quelqu'un la piratera.

Mais il est judicieux de prendre des précautions. DBMS_ASSERT est un package introduit dans Oracle 10g pour intercepter les tentatives d'attaques par injection SQL. Il ce cas, il serait intéressant de l'utiliser pour valider le nom de la table passé

.... 
'UPDATE '|| DBMS_ASSERT.simple_sql_name(pADSLTable) 
.... 

Cela empêcherait quiconque passant 'pay_table set salary = salary * 10 where id = 1234 --' comme paramètre de nom de la table. Une autre raison d'éviter le SQL dynamique est qu'il est plus difficile de corriger et de déboguer. La syntaxe de l'instruction réelle n'est vérifiée qu'à l'exécution. Il est bon d'avoir une suite complète de tests unitaires qui valident toutes les entrées passées, pour s'assurer que la procédure ne déclenche pas une exception de syntaxe.

Enfin, un tel SQL dynamique n'apparaît pas dans les vues telles que ALL_DEPENDENCIES. Cela rend plus difficile l'analyse d'impact et la localisation de tous les programmes utilisant une table ou une colonne donnée.

+0

DBMS_ASSERT n'est pas documenté dans 10gR2, bien qu'il soit présent. Merci de l'avoir signalé. –

1

Oui, il est natif SQL dynamique:

EXECUTE IMMEDIATE 'UPDATE ' || pADSLTable || 
    'SET STATUS = :1, NOTE = :2, EMAIL = :3, MOBI = :4, SERVICETYPE_ID = :5, ACTIVATION_DATE = :6 WHERE ACCOUNT_NAME = :7 ' 
    USING pStatus, pNote, pEmail, pMobi, pServiceTypeId, pDate, pAccountname; 

Performance et la vérification des erreurs ne sont pas aussi bon (pas de syntaxe de compilation et de validation du schéma). Méfiez-vous de l'injection SQL. Donc, si vous n'avez que quelques tables à choisir, pensez à utiliser une construction if/then/else avec toutes les options à la place.

0

Vous pouvez utiliser toutes sortes d'instructions DDL à l'aide de SQL dynamique. Vous pouvez passer des noms d'objets de base de données différents en tant que paramètres ou les manipuler dans des variables.

Questions connexes