Connecting to Multiple Progress Database using single .p file - openedge

Is there a way to connect to multiple progress database.
In current situation what we do is we use multiple .p files to fetch the data.
Example:
1st program will fetch the data from customer database and using a run command we use to connect to 2nd database.
2nd program we use input parameter to map the value.
My question is, is there a way we can do this in one single program?
Below is the sample program:
/*FIRST Program***/
FIND FIRST customer WHERE customer.cust-id EQ "v456" NO-LOCK NO-ERROR.
IF AVAILABLE customer THEN
RUN /HOME/dbconnect.p(INPUT customer.cust-id, "ACCOUNTS").
RUN /HOME/program-2.p (INPUT customer.cust-id).
/Second Program**/
DEFINE INPUT PARAMETER ipcCust-id AS CHARACTER.
FOR EACH billing WHERE billing.cust-id EQ ipcCust-id NO-LOCK:
DISPLAY billing.DATE.
END.

You can use the CONNECT statement to connect to databases at runtime. You cannot CONNECT and access the newly connected db in the same procedure - the code that uses the new connection must run in a sub-procedure.
You might, for instance, do something like this:
define variable dbList as character no-undo.
define variable i as integer no-undo.
define variable n as integer no-undo.
dbList = "db1,db2,db3".
n = num-entries( dbList ).
do i = 1 to n:
connect value( entry( i, dbList )) no-error.
run "./p1.p".
current-language = current-language. /* forces the r-code cache to be cleared */
disconnect value( entry( i, dbList )) no-error.
end.
and p1.p:
/* p1.p
*/
define variable i as integer no-undo.
for each _field no-lock: /* count the number of fields defined in the schema */
i = i + 1.
end.
display pdbname(1) i.
pause.
p1.p is just a silly little program to demonstrate that the data access is actually coming from 3 distinct databases.
The "current-language = current-language" thing is important if the same procedure will run against several different databases. Without that little nugget the procedure may be cached and it will remember the previous db that it was connected to.
Or if you prefer Stefan's dynamic query approach:
define variable dbList as character no-undo.
define variable i as integer no-undo.
define variable n as integer no-undo.
define variable b as handle no-undo.
define variable q as handle no-undo.
create query q.
dbList = "db1,db2,db3".
n = num-entries( dbList ).
do i = 1 to n:
connect value( entry( i, dbList )) no-error.
create buffer b for table "_field".
q:set-buffers( b ).
q:query-prepare( "preselect each _field no-lock" ).
q:query-open().
display pdbname( 1 ) q:num-results.
pause.
q:query-close.
delete object b.
disconnect value( entry( i, dbList )) no-error.
end.

Is connecting dynamically (inside the .p) a requirement ?
If not, it's probably easier to just connect the databases when launching the program...
(I'm on windows, but should be recognizable)
prowin -pf <path-to>\connect.pf -p <path-to>\program.p
where connect.pf contains:
-db <connection settings for db 1>
-db <connection settings for db 2>
<...>

With static queries, no. You always need to have the database connected before running the .p. With dynamic queries, since there is no reference to the database in the r-code, you can do whatever you want from a single .p.

Related

CREATE FUNCTION throws SQL Error (1064) (42000)

I'm trying to create a stored function in a MariaDB database.
I copied the function I'm trying to create from the MariaDB Docs:
DELIMITER //
CREATE FUNCTION FortyTwo() RETURNS TINYINT DETERMINISTIC
BEGIN
DECLARE x TINYINT;
SET x = 42;
RETURN x;
END
//
DELIMITER ;
Unfortunately, I get the following error:
SQL Error [1064] [42000]: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 3
What baffles me most is that the given code is supposed to resolve the very error code I'm getting according to the MariaDB docs
The solution is to specify a distinct delimiter for the duration of the process, using the DELIMITER command
It turned out, the client I used to issue the command, DBeaver, was causing the trouble.
After switching over to MySqlWorkbench everything worked as expected.
Apparently, DBeaver didn't recognise the delimiters correctly..
I think you may have forgotten to select the database you want this routine to be stored into.
So try adding a use as the first line
use `test`;
DELIMITER //
CREATE FUNCTION FortyTwo() RETURNS TINYINT DETERMINISTIC
BEGIN
DECLARE x TINYINT;
SET x = 42;
RETURN x;
END
//
DELIMITER ;

'procedure' not found (293)

I'm trying to run a procedure on appserver which is set up on localhost.
**'testProc' was not found. (293)
DEFINE VARIABLE hndle AS HANDLE NO-UNDO.
DEFINE VARIABLE tmp AS CHARACTER NO-UNDO.
CREATE SERVER hndle.
PROCEDURE testProc:
DEFINE OUTPUT PARAMETER o_tmp AS CHARACTER INITIAL "HELLO".
END PROCEDURE.
hndle:CONNECT ("-AppService AppServiceName-H localhost").
RUN testProc ON hndle(OUTPUT tmp).
hndle:DISCONNECT ().
DELETE OBJECT hndle.
You can't run internal procedures on an appserver. You have to put the code into its own .p file and run that on the appserver. The .p has to be available in the Propath of the appserver as well.
You're trying to run the internal procedure 'testProc', not the procedure file 'testProc.p'. They have to be two separate files. Create a 'testProc.p' file on your appserver and put your logic in it:
DEFINE OUTPUT PARAMETER o_tmp AS CHARACTER INITIAL "HELLO".
In a separate file, put your code that calls testProc.p:
DEFINE VARIABLE hndle AS HANDLE NO-UNDO.
DEFINE VARIABLE tmp AS CHARACTER NO-UNDO.
CREATE SERVER hndle.
hndle:CONNECT ("-AppService AppServiceName -H localhost").
RUN testProc.p ON hndle(OUTPUT tmp).
hndle:DISCONNECT ().
DELETE OBJECT hndle.
MESSAGE tmp VIEW-AS ALERT-BOX INFORMATION.
Note that your calling program is running testProc.p, not testProc. Run this code and you should get a pop-up message saying "HELLO".

How to define variables in a PL/R (plr) function as parameters for a query inside

I've written a function that queries x,y,z values for creating sections with R.
Now, I want to do that with PL/R, instead of using RStudio.
CREATE OR REPLACE FUNCTION section_graph() RETURNS text AS
'
require(RPostgreSQL)
drv <- dbDriver("PostgreSQL")
con <- dbConnect(drv, host="localhost", user="postgres", password="...", dbname="...", port="5432")
rs <- dbSendQuery(con, "SELECT x,y,z FROM (SELECT (section(1,3)).*) AS foo")
section1 <- fetch(rs, 2000)
dbClearResult(rs)
dbDisconnect(con)
pdf("/tmp/myplot.pdf", width=18, height=9)
plot(section1$y, section1$z, type="l", lwd=1.5, lty=3)
dev.off()
print("done")
'
LANGUAGE 'plr';
Within the dbSendQuery command there is the query SELECT x,y,z FROM (SELECT (section(1,3)).*) AS foo. The paramter 1 represents an ID, the second one is the accuracy of the section (3m).
Now, I want to use my function above like a common PostgreSQL function (e.g. with language 'sql'). That means, a want to define parameters within the function like this:
SELECT x,y,z FROM (SELECT (section($1,$2)).*) AS foo
$1 $2 are the parameters for my function section_graph.
Is this possible with the language 'plr'? I didn't found something helpful.
Obviously there are problems with the double quotes of the query within the function.
Did you try looking at the pl/r documentation? Took me about ten seconds. The parameters are either called arg1 to argN:
CREATE OR REPLACE FUNCTION r_max (integer, integer) RETURNS integer AS '
if (arg1 > arg2)
return(arg1)
else
return(arg2)
' LANGUAGE 'plr' STRICT;
or, PG 8 and above, you can name them:
CREATE OR REPLACE FUNCTION sd(vals float8[]) RETURNS float AS '
sd(vals)
' LANGUAGE 'plr' STRICT;
http://www.joeconway.com/plr/doc/plr-funcs.html
Something else in your code gives me the fear though. Remember, this R code is being called by the Postgres server while executing queries, and you are connecting to, presumably the same Postgres server and executing another query. This looks like a dozen shades of wrong.
The right way to access the DB in PL/R is via the routines outlined in the 'Normal Support' section:
http://www.joeconway.com/plr/doc/plr-spi-rsupport-funcs-normal.html
There are some 'compatibility support' functions that are like the RPostgreSQL package functions:
http://www.joeconway.com/plr/doc/plr-spi-rsupport-funcs-compat.html
but if you require(RPostgreSQL) in your PL/R code you'll probably mask them and your database will disappear up a black hole. Use the 'normal support' routines in PL/R functions.

Passing Optional Arguments in Classic ASP for Stored Procedure

I'm trying to run some stored queries in an Access database from an ASP page. I'd like to use an ADO Command object to run the procedure instead of simply sending a string to the database to execute. My trouble is occurring when I try to create the parameters to send to the stored procedure. I'm using the 'CreateParameter' method of the Command object. It takes 5 optional arguments, of which I only want to use two; name and value (arguments 1 and 5 respectively).
I've tried the following approaches to set up the parameters:
1) Using named arguments
command.Parameters.Append command.CreateParameter name:="name", value:="value"
2) Using named arguments inside brackets
command.Parameters.Append command.CreateParameter(name:="name", value:="value")
3) Leaving out optional parameters I don't need
command.Parameters.Append command.CreateParameter("name", , , , "value")
What is a simple way to achieve what I'm trying to do, and why does my syntax fail in these cases? I'm clearly missing something here!
VBScript doesn't support named arguments with or without brackets. All parameters required to pass (specific or blank) for CreateParameter method of the Command object.
For the section 3 in the question, have a look:
CreateParameter(
name`[optional], <- fits ("name")
type [optional, default = adEmpty], <- NOT fits (type is not empty)
direction[Optional default = adParamInput], <- fits (blank)
size [optional default = 0], <- NOT fits (at least 5 for "value")
value[optional] <- fits ("value")
)
So, you should specify at least type and size for a text valued parameter. Direction is adParamInput already.
Const adVarChar = 200 ' From adovbs.inc or Ado TypeLib
command.Parameters.Append command.CreateParameter("name", adVarChar, , 5, "value")
here is an example that can be followed.
http://www.webconcerns.co.uk/asp/accessqueries/accessqueries.asp
see also
http://bytes.com/topic/asp-classic/answers/628368-running-access-stored-queries-parameters
Remember access uses stored queries not stored procedures so some differences apply. For additional information search for
ASP with Access stored queries using parameters - .net

The use of IN OUT in Ada

Given below is some code in ada
with TYPE_VECT_B; use TYPE_VECT_B;
Package TEST01 is
procedure TEST01
( In_State : IN VECT_B ;
Out_State : IN OUT VECT_B );
function TEST02
( In_State : IN VECT_B ) return Boolean ;
end TEST01;
The TYPE_VECT_B package specification and body is also defined below
Package TYPE_VECT_B is
type VECT_B is array (INTEGER range <>) OF BOOLEAN ;
rounded_data : float ;
count : integer ;
trace : integer ;
end TYPE_VECT_B;
Package BODY TYPE_VECT_B is
begin
null;
end TYPE_VECT_B;
What does the variable In_State and Out_State actually mean? I think In_State means input variable. I just get confused to what actually Out_State means?
An in parameter can be read but not written by the subprogram. in is the default. Prior to Ada 2012, functions were only allowed to have in parameters. The actual parameter is an expression.
An out parameter implies that the previous value is of no interest. The subprogram is expected to write to the parameter. After writing to the parameter, the subprogram can read back what it has written. On exit the actual parameter receives the value written to it (there are complications in this area!). The actual parameter must be a variable.
An in out parameter is like an out parameter except that the previous value is of interest and can be read by the subprogram before assignment. For example,
procedure Add (V : Integer; To : in out Integer; Limited_To : Integer)
is
begin
-- Check that the result wont be too large. This involves reading
-- the initial value of the 'in out' parameter To, which would be
-- wrong if To was a mere 'out' parameter (it would be
-- uninitialized).
if To + V > Limited_To then
To := Limited_To;
else
To := To + V;
end if;
end Add;
Basically, every parameter to a function or procedure has a direction to it. The options are in, out, in out (both), or access. If you don't see one of those, then it defaults to in.
in means data can go into the subroutine from the caller (via the parameter). You are allowed to read from in parameters inside the routine. out means data can come out of the routine that way, and thus you are allowed to assign values to the parameter inside the routine. In general, how the compiler accomplishes the data passing is up to the compiler, which is in accord with Ada's general philosophy of allowing you to specify what you want done, not how you want it done.
access is a special case, and is roughly like putting a "*" in your parameter definition in Cish languages.
The next question folks usually have is "if I pass something large as an in parameter, is it going to push all that data on the stack or something?" The answer is "no", unless your compiler writers are unconsionably stupid. Every Ada compiler I know of under the hood passes objects larger than fit in a machine register by reference. It is the compiler, not the details of your parameter passing mechanisim, that enforces not writing data back out of the routine. Again, you tell Ada what you want done, it figures out the most efficient way to do it.

Resources