it's possible to execute a string as a SQL query in C and get the result? I'm trying to compile this code:
EXEC SQL
EXECUTE IMMEDIATE : sql_formula INTO :sql_prec_desconto_mp;
But I've this error:
Error at line 10548, column 35 in file
D:\syncs\AIX\fuentes\funcn\niv2\src\rutin as.pc
EXECUTE IMMEDIATE : sql_formula INTO :sql_prec_desconto_mp;
PCC-S-02201, Encountered the symbol "INTO" when expecting one of the
following:
; ( [ . ++ -- ->
How can I get the result of the SQL query? If I remove the INTO clause I can compile without errors.
Thanks in advance.
That format is described in the documentation:
To prepare and execute a DELETE, INSERT, or UPDATE statement or a PL/SQL block containing no host variables.
You aren't doing one of those DML types, and those don't recognise INTO. When you run a dynamic SQL query without an INTO the query is never actually executed (see the note in the docs).
The quickest way that immediately comes to mind to do what I think you want, is to prepare a cursor and fetch the result:
EXEC SQL PREPARE stmt FROM :sql_formula;
EXEC SQL DECLARE cur CURSOR FOR stmt;
EXEC SQL OPEN cur;
EXEC SQL FETCH cur INTO :sql_prec_desconto_mp;
Related
The following DECLARE fails:
PREPARE stmt(bigint) AS SELECT ...;
DECLARE crs CURSOR FOR stmt;
According to https://www.postgresql.org/docs/9.6/static/sql-declare.html,
stmt has to be either SELECT or VALUES command.
I use PREPARE statement in a latency-critical section of the code in which thousands of quick queries are emitted. Parsing and generating a query plan each time would be performance killer. However, in some rare cases the query can return millions of records and the result doesn't fit into memory.
Is there a way to declare a cursor for prepared statement in PostgreSQL? If not, are there any workarounds?
https://www.postgresql.org/docs/9.1/static/ecpg-commands.html#ECPG-EXECUTING
This can be done through ECPG C library in c code.
One can create prepared statement in C code as:
EXEC SQL PREPARE stmt1 FROM "SELECT oid,datname FROM pg_database WHERE oid > ?";
and then create cursor for that statement as:
EXEC SQL DECLARE foo_bar CURSOR FOR stmt1;
fetch result form cursor within infinite loop.
EXEC SQL OPEN foo_bar USING 100;
while(1){
EXEC SQL FETCH NEXT FROM foo_bar INTO :dboid, :dbname;
}
This is available with 9.1 version of postgresql.
I have been trying to prepare a Fetch statement in db2 as below
Stmt = %trim('FETCH EXSQCRS INTO ?');
EXEC SQL PREPARE SQLSTMT2 FROM :STMT ;
EXSQCRS is a cursor.
But this is failing with -104 error. Any clue on how to write this?
FETCH isn't a statement that can be prepared. It's simply an executable statement. See Actions allowed on SQL statements
You need to read up on Embedded SQL programming
Simple example with dynamic SQL
D EMPNUM S 6A
D NAME S 15A
D STMT S 500A INZ('SELECT LASTNAME -
D FROM CORPDATA.EMPLOYEE WHERE -
D EMPNO = ?')
//************************************************************
// Prepare STMT as initialized in declare section *
//************************************************************
/FREE
EXEC SQL
PREPARE S1 FROM :STMT;
//
//************************************
// Declare Cursor for STMT *
//************************************
EXEC SQL
DECLARE C1 CURSOR FOR S1;
//
//****************************************************
// Assign employee number to use in select statement *
//****************************************************
EMPNUM = '000110';
//*********************
// Open Cursor *
//*********************
EXEC SQL
OPEN C1 USING :EMPNUM;
//
//**********************************************
// Fetch record and put value of *
// LASTNAME into NAME *
//**********************************************
EXEC SQL
FETCH C1 INTO :NAME;
You can't prepare the fetch. You can prepare the SQL statement that is used to define the cursor though. So it would look like this:
dcl-s stmt Varchar(256) Inz('');
exec sql declare S1 statement;
exec sql declare C1 cursor for S1;
stmt = 'select * from customer where cusno = ?';
exec sql prepare S1 from :stmt;
exec sql open C1 using :customerNumber;
exec sql fetch C1 into :customerDS;
dow %subst(sqlstate:1:2) = '00'
or %subst(sqlstate:1:2) = '01';
... process it here ...
exec sql fetch C1 into :customerDS;
enddo;
exec sql close C1;
Note there is no error checking here. You really want to do that on all executable sql statements. Note also that the exec sql declare ... statements are not executable. Not even the declare C1 cursor. I will usually put my sql in their own procedures. The prepare and open will go in one procedure, the fetch in another, and the close in another.
Some notes about using procedures and local variables with embedded sql. When using static cursors, you need to put the declare in the same procedure as the open because the host variables are in the declare statement, and they need to be the same variables in scope when you do the open. That is because the declare is totally commented out, and generates no code. It is not executable. The host variables appear in the code generated for the open in this case.
With prepared cursors, you do not need to put the declare in the same procedure as the open like you do with static cursors. That is because the host variables that are bound to parameter markers in the prepared statement appear in the open statement. The declare can be up at the head of the program with the global declarations. It is a global declaration after all regardless of where the declare is physically located. I like to explicitly declare my prepared statements even though you don't have to. I put them up with the cursor declarations.
I generally will have the fetch procedure return a boolean (indicator), or a record count so that I don't have to repeat the call in the code. The fetch is indeed repeated here just because I did not use procedures.
And finally, the one exception I have with testing errors is that I do not test for an error after the close because the only error that will throw is that the cursor isn't open which is not an error in my mind, it is what I want the state of the cursor to be when I am finished with it.
I have the following stored procedure:
CREATE PROCEDURE SQLTEST()
LANGUAGE SQL
BEGIN ATOMIC
DECLARE SQLCMD VARCHAR(1024);
FOR v AS cur1 CURSOR FOR SELECT ID, CMD from COMMANDTBL
DO
SET SQLCMD= v.CMD;
"CALL" SQLCMD;
END FOR;
END?
The COMMANDTBL has the columns ID and CMD of which CMD has SQL Commands.
CMD is 1024 VARCHAR.
In this test they are 2 inserts for another table
INSERT INTO TARGETTBL(TARGET, TARINT) VALUES ('TEST', 100);
INSERT INTO TARGETTBL(TARGET, TARINT) VALUES ('TEST2', 200);
for example.
My problem is the "CALL" part. I have DB2 v9.7 but it would be great if there was a solution running on lower versions as well.
I have not found any pointers on how to run this and a simple EXEC or EXECUTE does not work.
Thank you for your help.
TheVagabond
You need to prepare and execute the statements because they are deemed "dynamic SQL".
PREPARE myStmt FROM SQLCMD;
EXECUTE myStmt;
This question already has answers here:
How do I conditionally create a stored procedure in SQL Server?
(11 answers)
Closed 7 years ago.
I'm writing a db update script which basically retrieve the current version number from the database then create a number of stored procedure if the version is valid. If the current version does not match the expected version then it should skip executing the code.
However I run into a problem when I write the script because CREATE PROCEDURE has to be the first statement in a batch, so it's not possible for me to insert if .. else statement before the create procedure statement.
I've also tried using GOTO but to no avail because GOTO doesn't span across multiple batches. Same thing applies to RETURN and RAISEERROR - the rest of the code will still execute.
Sample script:
IF #Version = '1.0' --doesn't work
BEGIN
CREATE PROCEDURE dbo.uspCreateAccount
AS BEGIN
--The rest of the code goes here
END
END
Can anyone provide some insight on this?
You can accomplish this using the exec functionality.
IF #Version = '1.0'
BEGIN
--Drop it if it already exists
IF OBJECT_ID('uspCreateAccount', 'P') IS NOT NULL
EXEC ('DROP PROCEDURE uspCreateAccount')
--Recreate it.
EXEC('
CREATE PROCEDURE uspCreateAccount
AS BEGIN
--The rest of the code goes here
END
')
END
You can use exec to run a SQL command in a new scope. The following snippet will run even when dbo.YourProc already exists, because the SQL command inside exec() will never be parsed in that case.
if not exists (select * from sys.procedures where name = 'YourProc')
exec ('create procedure dbo.YourProc as select 1 as a')
go
alter procedure dbo.YourProc
as
select ...
This construct creates an empty stub procedure if the procedure does not exist. If the procedure exists, it runs alter. So it preserves rights that have been granted on the procedure.
Can we declare and open a cursor for UPDATE query also or is it only for SELECT queries?
EXEC SQL PREPARE S FROM :query;
EXEC SQL DECLARE C CURSOR FOR S;
DbUtilT::set_bind_variables(bind_dp,¶mList);
EXEC SQL OPEN C USING DESCRIPTOR bind_dp;
EXEC SQL WHENEVER NOT FOUND GOTO end_update_loop;
EXEC SQL FETCH C USING DESCRIPTOR bind_dp;
EXEC SQL COMMIT WORK;
Is this fine? Or should we use cursor only for SELECT statments then how do we execute UPDATE queries?
If query is something like:
SELECT id FROM mytable WHERE ... FOR UPDATE OF id
then you can do:
...
EXEC SQL FETCH C USING DESCRIPTOR bind_dp;
EXEC SQL UPDATE mytable SET id = <something> WHERE CURRENT OF C;
I'm not quite sure what you mean though; you don't have to use a cursor to do an update, you can do:
EXEC SQL UPDATE mytable SET id = <something> WHERE ...;
... or the equivalent prepared statement.
Have I completely misunderstood the question?