Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Bonjour,
J'ai un souci avec un appel de procédure stockée.
Je suis sous PB12. Ma base de données est sous DB2 V9.
J'ai besoin d'appeler une procédure stockée qui a plusieurs paramètres d'entrée et un paramètre de sortie.
SQL :
CREATE or REPLACE PROCEDURE DBA.NOM_PROC (IN PARAM1 VARCHAR(24), IN PARAM2 VARCHAR(12), IN PARAM3 INTEGER, IN PARAM4 DATE, OUT PARAM5 SMALLINT) SPECIFIC DBA.NOM_PROC MODIFIES SQL DATA LANGUAGE SQL BEGIN (...) END
PB :
DECLARE TEST_NOM_PROC FOR PROCEDURE NOM_PROC @PARAM1= :as_var1, @PARAM2= :as_var2, @PARAM3= :ai_var3, @PARAM4= :ad_var4, @PARAM5= :ai_var5 OUTPUT USING SQLCA; execute TEST_NOM_PROC; if SQLCA.SqlCode = 0 then fetch TEST_NOM_PROC into :ai_var5; close TEST_NOM_PROC; commit; else //Récupération du SQLCA.SQLErrText return -1 end if return 0
Ca ne fonctionne pas. J'ai un SQLCA.SQLCode à -1 et ce message :
[IBM][CLI Driver][DB2/NT64] SQL0104N Une marque inattendue "=" figure à la suite de "NOM_PROC(@PARAM1". Parmi les marques attendues, on trouve : "+". SQLSTATE=42601
Quelqu'un aurait-il une idée SVP ?
Merci d'avance.
Dernière modification par Saria (17-06-2014 08:16:28)
Hors ligne
En C#, c'est OK.
OleDbParameter _Var5; Int32 _Resultat = Int32.MinValue; using (OleDbCommand cmdProcStock = _Connexion.oleConnection.CreateCommand()) { cmdProcStock.CommandType = System.Data.CommandType.Text; cmdProcStock.CommandText = "CALL NOM_PROC (?, ?, ?, ?, ?)"; //Paramètres d'entrée cmdProcStock.Prepare(); cmdProcStock.Parameters.AddWithValue("@PARAM1", _Var1); cmdProcStock.Parameters.AddWithValue("@PARAM2", _Var2); if (!String.IsNullOrEmpty(_Var3)) cmdProcStock.Parameters.AddWithValue("@PARAM3", Convert.ToInt32(_Var3)); else cmdProcStock.Parameters.AddWithValue("@PARAM3", 0); cmdProcStock.Parameters.AddWithValue("@PARAM4", _Var4); //Paramètre de sortie _Var5 = new OleDbParameter("@PARAM5", OleDbType.Integer); _Var5.Direction = ParameterDirection.Output; cmdProcStock.Parameters.Add(_Var5); //Execution et lecture du paramètre de sortie cmdProcStock.ExecuteNonQuery(); _Resultat = Convert.ToInt32(_Var5.Value);
Donc ma procédure fonctionne, c'est l'appel depuis PB que je n'arrive pas à faire fonctionner.
Hors ligne
Si je fais :
DECLARE TEST_NOM_PROC PROCEDURE FOR NOM_PROC( :as_var1, :as_var2, :ai_var3, :ad_var4, :ai_var5) USING SQLCA; execute TEST_CTRL_SOUSCRIPTION ;
J'ai bien un SQLCode à zéro, mais ma variable 5 ne récupère pas le bon résultat (elle reste à 0, alors qu'en C# je récupère bien la valeur 2 avec les mêmes paramètres).
Si je fais :
DECLARE TEST_NOM_PROC PROCEDURE FOR NOM_PROC( :as_var1, :as_var2, :ai_var3, :ad_var4, :ai_var5 OUTPUT) USING SQLCA; execute TEST_CTRL_SOUSCRIPTION ;
J'ai une erreur SQL de syntaxe à cause du mot OUTPUT.
Hors ligne
Tu passes par quel type de driver? Natif, OLE-DB ou ODBC.
Sinon, pour récupérer des paramètres en output, on utilise plutôt la syntaxe comme ceci:
DECLARE TEST_NOM_PROC PROCEDURE FOR NOM_PROC @PARAM1= :as_var1, @PARAM2= :as_var2, @PARAM3= :ai_var3, @PARAM4= :ad_var4 USING SQLCA; execute TEST_NOM_PROC; if SQLCA.SqlCode = 0 then fetch TEST_NOM_PROC into :ai_var5; close TEST_NOM_PROC; commit; else //Récupération du SQLCA.SQLErrText close TEST_NOM_PROC; // Important ici aussi de faire le close return -1 end if return 0
Note:
Hors ligne
Elle passe par ODBC.
Hors ligne
Normalement, la syntaxe avec OUTPUT ou OUT devrait être la bonne. il faut bien s'assurer que les paramètres passés en output sont initialisés auparavant.
Cependant, il faudrait peut-être tester RPCFUNC plutôt que de passer par un DECLARE..EXECUTE..FETCH.
(Note: je n'ai jamais testé DB2)
Hors ligne
Merci.
Effectivement, comme l'a dit mon voisin de bureau, c'est ODBC.
La syntaxe avec les @ ne passait pas, celle avec le OUTPUT non plus.
Je retesterai avec OUT ou avec RPCFUNC dans ce cas.
Mais je n'ai pas trouvé dans l'aide de PB comment fonctionne RPCFUNC.
Hors ligne
Voici le résultat de mes différents tests :
ai_var5 = -1 DECLARE TEST_NOM_PROC PROCEDURE FOR NOM_PROC( :as_var1, :as_var2, :ai_var3, :ad_var4, :ai_var5) USING SQLCA; execute TEST_NOM_PROC ; if SQLCA.SQLCode = 0 then fetch TEST_NOM_PROC into :ai_var5; close TEST_NOM_PROC; commit; else //Récupération du SQLCA.SQLErrText close TEST_NOM_PROC; return -1 end if return 0
Est OK (SQLCA.SQLCode à 0), mais ai_var5 reste à -1 (alors que ma procédure stockée retourne 0, 1, ou 2)
ai_var5 = -1 DECLARE TEST_NOM_PROC PROCEDURE FOR NOM_PROC( :as_var1, :as_var2, :ai_var3, :ad_var4, :ai_var5 output) USING SQLCA; execute TEST_NOM_PROC ; if SQLCA.SQLCode = 0 then fetch TEST_NOM_PROC into :ai_var5; close TEST_NOM_PROC; commit; else //Récupération du SQLCA.SQLErrText close TEST_NOM_PROC; return -1 end if return 0
Est KO (SQLCA.SQLCode à -1, erreur de syntaxe), de même avec OUT à la place de OUTPUT. L'erreur porte sur le OUT ou le OUTPUT.
ai_var5 = -1 DECLARE TEST_NOM_PROC PROCEDURE FOR NOM_PROC @PARAM1 = :as_var1, @PARAM2 = :as_var2, @PARAM3 = :ai_var3, @PARAM4 = :ad_var4 USING SQLCA; execute TEST_NOM_PROC ; if SQLCA.SQLCode = 0 then fetch TEST_NOM_PROC into :ai_var5; close TEST_NOM_PROC; commit; else //Récupération du SQLCA.SQLErrText close TEST_NOM_PROC; return -1 end if return 0
Est KO (SQLCA.SQLCode à -1, erreur de syntaxe). L'erreur porte sur le "@PARAM1 =", il me dit qu'il attend plutôt un "+" ?
Concernant le RPCFUNC, j'ai fait des recherches, mais il faut apparemment créer un UserObject de type Transaction, et d'y définir des fonctions externes (http://pbadonf.fr/forum/viewtopic.php?id=3355).
Je vais tester.
Dernière modification par Saria (28-05-2014 13:34:54)
Hors ligne
Bonjour,
Si je me fie à l'exemple donné dans l'aide Powerbuilder pour Oracle (Oracle DECLARE and EXCUTE), ta déclaration devrait être :
DECLARE TEST_NOM_PROC PROCEDURE FOR NOM_PROC( :as_var1, :as_var2, :ai_var3, :ad_var4) USING SQLCA;
Les paramètres "OUTPUT" ne sont pas à spécifier dans le "DECLARE".
Hors ligne
Ca ne fonctionne pas lorsque je mets seulement 4 arguments dans le DECLARE, il me dit "la procédure ... avec les arguments spécifiés est introuvable."
J'ai testé avec RPCFUNC :
Dans Local External Functions de mon UserObject, j'ai mis :
Subroutine nom_routine( & string param1, & string param2, & integer param3, & date param4, & ref integer param5& ) RPCFUNC ALIAS FOR "DBA.NOM_PROCEDURE";
Ensuite, quelque part dans le code de mon UserObject, j'ai initialisé mes variables et appelé ma routine :
as_var1 = "contenu1" as_var2 = "contenu2" ai_var3 = 1000 ad_var4 = date(2014, 06, 10) ai_var5 = -1 nom_subroutine(as_var1, as_var2, ai_var3, ad_var4, ai_var5);
J'ai en erreur "Transaction not connected".
Dernière modification par Saria (10-06-2014 15:14:13)
Hors ligne
ton userobject est de type hérité de l'objet de base transaction ?
Jette un coup d’œil ici, si ce n'est déjà fait.
http://powerbuilder.hyderabad-colleges. … 6-100.html
Hors ligne
Salut,
As tu essayé en ajoutant le paramètre suivant dans le dbparm de ton profil ODBC : PBNewSPInvocation='Yes'
( Tout en continuant à utiliser ta syntaxe DECLARE TEST_NOM_PROC FOR PROCEDURE NOM_PROC @PARAM1= :as_var1, @PARAM2= :as_var2, @PARAM3= :ai_var3, @PARAM4= :ad_var4, @PARAM5= :ai_var5 OUTPUT USING SQLCA...)
Cdt
Yanis
Hors ligne
Yahoo !!!!!!
str_db_erreur str_err w_erreur_db w_err ai_var5 = -1 if pos(SQLCA.DBParm, "PBNewSPInvocation='Yes'") <= 0 then SQLCA.DBParm+=",PBNewSPInvocation='Yes'" DECLARE TEST_NOM_PROC PROCEDURE FOR DBA.NOM_PROC PARAM1=:as_var1, PARAM2=:as_var2, PARAM3=:ai_var3, PARAM4=:ad_var4, PARAM5=:ai_var5 OUTPUT USING SQLCA; execute TEST_NOM_PROC; if SQLCA.SqlCode = 0 then fetch TEST_NOM_PROC into :ai_var5; close TEST_NOM_PROC; commit; if SQLCA.SqlCode <> 0 then str_err.l_sql_db_code = sqlca.sqldbcode str_err.s_sql_err_text = sqlca.sqlerrtext str_err.s_sql_syntax = 'Erreur : close TEST_NOM_PROC;' openWithParm(w_err, str_err) return -1 end if else str_err.l_sql_db_code = sqlca.sqldbcode str_err.s_sql_err_text = sqlca.sqlerrtext str_err.s_sql_syntax = 'Erreur : execute TEST_NOM_PROC ;' openWithParm(w_err, str_err) close TEST_NOM_PROC; return -1 end if return 0
Ca fonctionne, ai_var5 vaut "1" après le fetch !
Merci !
Dernière modification par Saria (13-06-2014 07:44:51)
Hors ligne
Salut,
Peux tu mettre ton cas à résolu : [RESOLU] dans ton titre?
Cdt
Yanis
Hors ligne
Bonjour,
Finalement, j'ai un nouveau souci.
Il y a d'autres endroits dans le code, qui appellent des procédures stockées, mais "à l'ancienne" (sans le NewSpInvocation). Il n'y a pas le nom du paramètre devant.
DECLARE TEST_IDE PROCEDURE FOR PROC_IDE :as_cod_ide USING SQLCA; execute TEST_IDE ; if SQLCA.SqlCode = 0 then fetch TEST_IDE into :al_int_ide;
Lorsque je ne lance pas mon traitement, tout va bien avec cette autre procédure (appelée assez régulièrement).
Lorsque je lance mon traitement, et que je veux relancer autre chose une fois mon traitement terminé (alors que j'ai bien réinitialisé le DBParm après l'appel à ma procédure), si cette autre chose fait appel à proc_ide, j'ai une erreur :
"CAN NOT FIND PARAMETERS FOR SP PROC_..."
Je n'avais jamais eu cette erreur avant.
J'ai l'impression que d'avoir modifié mon DBParm, il garde en mémoire qu'il faut utiliser la "nouvelle méthode" (NewSpInvocation) même si je l'ai remis comme avant.
Dernière modification par Saria (16-06-2014 14:32:35)
Hors ligne
Par hasard, il ne faut déconnecter et reconnecter la transaction lorsque l'on modifie le DBparm ?
Hors ligne
J'ai tenté de emttre ceci après l'appel à ma procédure stockée :
disconnect using SQLCA; SQLCA.DBParm = ls_contenu_initial_sqlca_dbparm connect using SQLCA;
Mais après avoir fait ça, un peu plus loin, j'ai un
dw_truc.update()
qui plante : Transaction not connected
La DW en question avait été initialisée (setTransObject(SQLCA) dans son constructeur, bien avant l'appel à la procédure stockée.
Dernière modification par Saria (16-06-2014 15:33:01)
Hors ligne
Salut,
Normalement le paramètre est dynamique. Ce qui veut dir qu'il peut être modifié en cours de traitement sans avoir à se déconnecter de la base.
Pourrais tu mettre le code suivant une fois que tu as fait appel à ta proc pour réinitialiser le dbparm.
sqlca.dbparm = "............,PBNewSPInvocation='No',.........."
Cdt
Yanis
Hors ligne
Bonjour,
Effectivement, en forçant à "No" après l'appel à ma procédure stockée, je n'ai plus de souci.
J'arrive à la fois à appeler ma procédure stockée ("nouvelle méthode") et à ne pas casser l'appel aux autres ("ancienne méthode")
Merci beaucoup.
Hors ligne