Hi Leonel<div><br></div><div>Thanks for your response. I don&#39;t know much about Oracle, but it has been suggested that this approach of calling a stored procedure via SQL won&#39;t work on a database that has security locked down to ensure all database access is via stored procedures. All our production databases are locked down in this way.</div>
<div><br></div><div>I&#39;m told there is a different API call to call a stored procedure directly rather than compile a SQL statement that calls the procedure. I&#39;m guessing, from your suggestion below, that Takusen does not expose this call?</div>
<div><br></div><div>I&#39;ve taken an alternative route. We have our own Haskell to COM bridge (that we hope to release at some point) and I&#39;m using that to talk to ADO, Microsoft&#39;s database API - yes, we are constrained to Windows for this. Initial signs are positive, but I haven&#39;t finished it yet.</div>
<div><br></div><div><br></div><div>Peter<br><br><div class="gmail_quote">On 9 September 2010 06:13, Leonel Fonseca <span dir="ltr">&lt;<a href="mailto:leonelfl@gmail.com">leonelfl@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Hi Peter,<br>
<br>
Yes, from Takusen you can call Oracle stored procedures, functions,<br>
packaged stored procedures or functions, or execute an arbitrary<br>
pl/sql block.<br>
<br>
In the Takusen software release there is a directory called<br>
&quot;Database\Oracle\Test&quot;. There,  Enumerator.lhs, among other code has<br>
these helpers you may want to use:<br>
<br>
<br>
&gt;wrapPLSQLFunc funcname parms =<br>
&gt;  let sqltext = &quot;begin &quot; ++ (head args) ++ &quot; := &quot; ++ funcname<br>
&gt;                         ++ &quot;(&quot; ++ placeholders ++ &quot;); end;&quot;<br>
&gt;      placeholders = concat (intersperse &quot;,&quot; (tail args))<br>
&gt;      args = take (length parms) (map (\n -&gt; &quot;:x&quot; ++ show n) [1..])<br>
&gt;  in  cmdbind sqltext parms<br>
<br>
&gt;wrapPLSQLProc procname parms =<br>
&gt;  let sqltext = &quot;begin &quot; ++ procname<br>
&gt;                         ++ &quot;(&quot; ++ placeholders ++ &quot;); end;&quot;<br>
&gt;      placeholders = concat (intersperse &quot;,&quot; args)<br>
&gt;      args = take (length parms) (map (\n -&gt; &quot;:x&quot; ++ show n) [1..])<br>
&gt;  in  cmdbind sqltext parms<br>
<br>
<br>
Please, be aware of the following points:<br>
<br>
1) If the pl/sql code doesn&#39;t need parameters and has no results, you<br>
can use &quot;execDDL&quot;. (execDML returns a counter of affected rows).<br>
2) If the procedure/function receives parameter, you&#39;ll need to use<br>
&quot;cmdbind&quot; (or similar to &quot;cmdbind&quot;) to pass the parameters.<br>
3) If the pl/sql code returns values, you have this options:<br>
    3.a) The returned value is a reference (cursor): Takusen supports<br>
this very fine. Use &quot;doQuery&quot; or similar.<br>
    3.b) The return value is an scalar value: You can collect the<br>
result with an iteratee, even if it is a single value.<br>
    3.c) The return value is a complex oracle object: As of Takusen<br>
0.8.5 there is no support for table of records of ...<br>
    3.d) The return value is Boolean. You&#39;ll get an error.<br>
<br>
Little examples:<br>
<br>
For case #1:<br>
<br>
&gt; -- Example 1.a:  We set nls_language to  american english.<br>
&gt; set_NlsLang_Eng :: DBM mark Session ()<br>
&gt; set_NlsLang_Eng =  execDDL $ sql<br>
&gt;  &quot;alter session set nls_language=&#39;AMERICAN&#39;&quot;<br>
<br>
&gt; -- Example #1.b: Now we set session language parameter to spanish.<br>
&gt; set_NlsLang_Esp :: DBM mark Session ()<br>
&gt; set_NlsLang_Esp =  execDDL $ sql<br>
&gt;  &quot;alter session set nls_language=&#39;LATIN AMERICAN SPANISH&#39;&quot;<br>
<br>
For case #2:<br>
<br>
&gt; -- Example 2.a: We use database string &quot;concat&quot; function<br>
&gt;concat&#39;      ::  String -&gt; String -&gt; DBM mark Session String<br>
&gt;concat&#39; a b  =   do<br>
&gt;   let ite :: Monad m =&gt; String -&gt; IterAct m String<br>
&gt;       ite v _ = return $ Left v<br>
&gt;       sqlcmd = wrapPLSQLFunc &quot;concat&quot;<br>
&gt;                  [bindP $ Out (&quot;&quot;::String), bindP a, bindP b]<br>
&gt;   doQuery sqlcmd ite undefined<br>
&gt;<br>
&gt; -- later on the program, you&#39;d have...<br>
&gt;     some_string &lt;- concat&#39; &quot;a&quot; &quot;b&quot;<br>
<br>
For case #3:<br>
<br>
&gt; -- Case 3.b: We collect a single scalar value.<br>
&gt; qNlsLang   ::  DBM mark Session [String]<br>
&gt; qNlsLang   =   doQuery s ite []<br>
&gt;  where<br>
&gt;  s   =   &quot;select value from nls_session_parameters \<br>
&gt;          \ where parameter = &#39;NLS_LANGUAGE&#39;&quot;<br>
&gt;  ite ::  (Monad m) =&gt; String -&gt;  IterAct m [String]<br>
&gt;  ite a acc = result&#39; ( a:acc )<br>
<br>
&gt; mostrar_NlsLang  ::  DBM mark Session ()<br>
&gt; mostrar_NlsLang  =   qNlsLang &gt;&gt;= liftIO . print . head<br>
<br>
&gt; -- Another example for Case 3.b<br>
&gt; -- This time we don&#39;t use a list to accumulate results.<br>
&gt; s1 =  sql &quot;select systimestamp from dual&quot;<br>
&gt;<br>
&gt; sysTSasCTQ   ::  DBM mark Session CalendarTime<br>
&gt; sysTSasCTQ    =  do<br>
&gt;<br>
&gt;    let ite :: (Monad m) =&gt; CalendarTime -&gt; IterAct m CalendarTime<br>
&gt;        ite x  _  =  result&#39; x<br>
&gt;<br>
&gt;    t &lt;-  liftIO ( getClockTime &gt;&gt;= toCalendarTime)<br>
&gt;    doQuery s1 ite t<br>
<font color="#888888"><br>
<br>
--<br>
<br>
Leonel Fonseca.<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
</font></blockquote></div><br></div>