PL/SQL CREATE OR REPLACE PROCEDURE Using CREATE TABLE Statement - stored-procedures

I am engaged at the moment in some serious PL/SQL programming. The format for creating procedures is
[CREATE [OR REPLACE]]
PROCEDURE procedure_name[(parameter[, parameter]...)]
[AUTHID {DEFINER | CURRENT_USER}] {IS | AS}
[PRAGMA AUTONOMOUS_TRANSACTION;]
[local declarations]
BEGIN
executable statements
[EXCEPTION
exception handlers]
END [name];
and I place executable statements under BEGIN. Why am I not allowed to place a CREATE TABLE statement as an executable statement within a procedure?

Because CREATE TABLE is a DDL statement, and you may not execute DDL statements from PL/SQL (at least not directly).
If (and that's a big if) you really need to do that, you can either use the DBMS_SQL package or EXECUTE IMMEDIATE (easier):
create or replace procedure do_it as
begin
execute immediate 'CREATE TABLE foo(pk number not null)';
end;
But this is usually not necessary. People coming from a SQL Server background often are trained to create lots of temporary tables from their stored procedures - in Oracle, you'd normally use a Global Temporary Table for that.

Related

Execute informix content from file

I need to execute a script (Informix code) in a .sql file for migration purposes. The thing is, I want to load it from a function to be able to use the exception, therefore being able to do a rollback in case of an error.
So, this is the code (still experimenting):
DROP FUNCTION IF EXISTS "informix".SCRIPT_MIGRATION();
CREATE FUNCTION "informix".SCRIPT_MIGRATION()
RETURNS BOOLEAN as RESULT;
DEFINE lv_execute lvarchar(32739);
DEFINE li_errnum, li_eisam INT;
DEFINE lv_errtxt CHAR(200);
ON EXCEPTION SET li_errnum, li_eisam, lv_errtxt
ROLLBACK;
CALL regista_log('script_migration', get_session_user(), li_errnum, lv_errtxt);
RETURN 'f';
END EXCEPTION;
CALL set_isolation_level();
BEGIN;
LET lv_execute = 'LOAD FROM ''C:\Users\Admin\Desktop\ConstaWeb_Stuff\test.sql'' DELIMITER ''+'' INSERT INTO SCRIPT_MIGRATION_TEMP_TABLE;';
DROP TABLE IF EXISTS SCRIPT_MIGRATION_TEMP_TABLE;
CREATE TABLE SCRIPT_MIGRATION_TEMP_TABLE(
STRING_TO_EXECUTE LVARCHAR(31739)
);
EXECUTE IMMEDIATE lv_execute;
COMMIT;
RETURN 't';
END FUNCTION;
CALL SCRIPT_MIGRATION();
That's because we apparently can't execute the load command inside functions. So I'm trying to execute it. But I'm not getting it right, apparently...
The objective here is to execute the script (not a shell command script! it's an Informix script, like creates, loads, unloads, drops...) on a file. I'm open to other ways of doing this.
I'm relatively new to Informix so I'm sure there is still a lot I don't know about it.
As already noted, the LOAD command is not a command recognized by the Informix server. Client products emulate an SQL statement by recognizing the syntax and reading the file and executing appropriate SQL statements. Changing the way you (try to) execute it in a function executing in the server will not help.
Using a shell script instead may help.
If you're migrating an existing Informix database to a new location (machine, version of Informix), then using DB-export and DB-Import may be a good way to go.
The DB-Access command is the 'standard' way to execute scripts from a shell script. You'd need to ensure you set the DBACCNOIGN environment variable to 1. That will then stop if there's an error during the LOAD and rollback the transaction. There's also the DB-Load command, but it will be harder to rollback DDL statements since it does not handle those.
Alternatively, you might find my SQLCMD* program useful — though it too isn't perfect. However, unlike DB-Access, it allows you to control which statements can generate errors that are ignored and which are not (continue [on|off|push|pop]; before and after as appropriate).
With careful packaging, you can use it to create your migration, assuming the DB-Export and DB-Import won't do the job for you automatically.
* You may have to subscribe to the IIUG to get at this. The registration is not onerous, and neither is the email load.

Server opens Stored Procedure like Unicode

As you can see in the image bellow, my SQL Stored Procedures, somehow, my SQL Server opens Procedures like Unicode SPs.
That was not the case before, and I have no idea how this apeared now.
I have around 5.000 stored procedures so there is no chance I can edit it manualy.
My SPs starts from ALTER PROCEDURE , everything before that is somehow added.
Your SP's will still work just fine. This is just the way SQL Server Management Studio scripts the objects when you want to generate ALTER- or CREATE-statements.
To change this behavior, go to Tools > Options > SQL Server Object Explorer > Scripting
Set the option "Include IF NOT EXISTS clause" to "False".
(In other versions of SQL Server Management Studio the option might be called something like "Check for object existence")
As previously answered, changing the scripting option "Include IF NOT EXISTS clause" to false solves the problem. To add context, if this value is true, it has to be scripted by putting the entire Alter Procedure statement in an #statement variable, because the conditional logic associated with the check for existence requires the ALTER PROCEDURE statement be inside a BEGIN/END block, which is not allowed. So Microsoft's workaround is to put the entire ALTER PROCEDURE statement in the #statement variable, which is executed conditionally inside a BEGIN/END block.

optimize the performance of informix stored procudure in asp.net application?

I want to know how to use the equivalent to :
SET ARITHABORT ON
AND
WITH RECOMPILE option
in informix stored procedure ?
SET ARITHABORT ON
Sql Server manual says : Terminates a query when an overflow or
divide-by-zero error occurs during query execution.
At Informix , by default, any error occurred during the execution of any UDR/SP (procedure or function) will trigger an exception and this will be automatically raised at user session level. This will include any arithmetic error.
What you can do inside of SPLs is the inverse , include a treatment to not allow this exception reach the scope of user session.
For this read about ON EXCEPTION
WITH RECOMPILE option
Sql Server manual says : Creating a stored procedure that specifies
the WITH RECOMPILE option in its definition indicates that SQL Server
does not cache a plan for this stored procedure; the stored procedure
is recompiled each time it is executed. Use the WITH RECOMPILE option
when stored procedures take parameters whose values differ widely
between executions of the stored procedure, resulting in different
execution plans to be created each time. Use of this option is
uncommon and causes the stored procedure to execute more slowly,
because the stored procedure must be recompiled each time it is
executed.
At Informix the similar solution is run : update statistics for procedure <your_proc>;
Check the explanation at Informix Manual here

Creating temp table with PID in ESQL/C

I am using ESQL/C code to provide backend support for a UI, connecting to an Informix database. I am creating temp table inside my code. But, I guess that if multiple users use this UI at the same time then temp table might already exist in the database which can create problem. So, can someone suggest if I can create temp table with PID as suffix inside my ESQL/C code
create temp table tabname_PID (name char(10));
In shell script I generally use tabname_$$.
You can create the table with the PID embedded in it, but it isn't necessary. Any temporary table is only visible in the session that creates it, so you can use the same table name in each session (separate but concurrently executing ESQL/C program) without any fear of conflict.
If, despite the reassurances that it is unnecessary, you still want to do it, then you'll have to PREPARE and EXECUTE (or DECLARE, OPEN, FETCH, CLOSE) the statements from a string:
snprintf(sql, sizeof(sql), "CREATE TEMP TABLE tabname_%d(name CHAR(10))", (int)getpid());
EXEC SQL PREPARE s FROM :sql;
EXEC SQL EXECUTE s;
or use EXECUTE IMMEDIATE (which is the obvious winner here):
EXEC SQL EXECUTE IMMEDIATE :sql;
You will also then have to prepare all the queries; one distinct advantage of using the fixed-name temporary table is that you don't have to prepare everything that references the temp table if you don't want to (though there are often advantages to using PREPARE etc).
You don't have to use $$ in shell scripts either, for the same reason — temporary tables are private to a session.

PL/SQL: Passing lexical parameter to a stored procedure

i want to pass a whole sql query as a lexical parameter to a stored procedure and then execute it. Any suggestions how to do that?
you may try this:
create or replace procedure my_proc(pstring IN varchar2)
is
begin
if length(pstring)>0 then
EXECUTE IMMEDIATE pstring;
end if;
end my_proc;
here is the official oracle documentation on dynamic plsql : http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/dynamic.htm#CHDGJEGD
Not sure what you mean by "lexical" parameter but you can pass the SQL query in as a VARCHAR2 then execute it using EXECUTE IMMEDIATE.
What you are trying to do is almost certainly the wrong way to go.
Execute Immediate is to be used with caution because it can a) impose a security risk and b) cause negative effects on performance when many distinct SQL statements are run that way.
However, see here how to insert records using execute immediate. Note that it's essential to use bind variables.
If you want to run a query (as opposed to a DML [insert, update, delete] or a PL/SQL block of code), you can do something like this:
function get_dataset (p_sql_query in varchar2) return sys_refcursor
as
l_returnvalue sys_refcursor;
begin
open l_returnvalue for p_sql_query;
return l_returnvalue;
end get_dataset;
The return value is a "weakly typed" REF CURSOR.
The calling program (whether it is Java, .NET, PL/SQL, whatever) must then process the function result and close the cursor.

Resources