PLSQL call procedure from function - stored-procedures

I have a function which is called from a select query, below is the function which works perfect. I want to call the procedure below if boolean = 1 that inserts values into the login table:
create or replace FUNCTION isLoggedIn(x IN VARCHAR2, y IN VARCHAR2)
RETURN number IS
boolean number(1) := 0;
BEGIN
SELECT count(*) into boolean
FROM VIEWLOGIN
WHERE username = x AND password = y;
IF boolean = 1 THEN
PROCDURELOGIN
RETURN boolean;
ELSE
RETURN 0;
END IF;
END;
This is my procedure:
create or replace PROCEDURE PROCDURELOGIN
IS
BEGIN
INSERT INTO "SW3"."LOGIN" (LOGINID, MEMBERID)
VALUES (seqLogin.NEXTVAL, '1');
Commit;
END;
Create view VIEWLOGIN
SELECT firstname, surname, username, password
FROM member
But I get the error when I run the query:
Error starting at line : 1 in command -
SELECT firstname, surname, isLoggedIn(username, password)
FROM VIEWLOGIN
WHERE username = 'fionawalshe' AND password = 'qwertyu8'
Error report -
SQL Error: ORA-14551: cannot perform a DML operation inside a query
ORA-06512: at "SW3.PROCDURELOGIN", line 4
ORA-06512: at "SW3.ISLOGGEDIN", line 10
14551. 00000 - "cannot perform a DML operation inside a query "
*Cause: DML operation like insert, update, delete or select-for-update
cannot be performed inside a query or under a PDML slave.
*Action: Ensure that the offending DML operation is not performed or
use an autonomous transaction to perform the DML operation within
the query or PDML slave.

Oracle clearly says in the error message, what is a problem. Try this:
create or replace PROCEDURE PROCDURELOGIN
IS
pragma autonomous_transaction;
BEGIN
INSERT INTO "SW3"."LOGIN" (LOGINID, MEMBERID)
VALUES (seqLogin.NEXTVAL, '1');
Commit;
END;
By the way, I don't like such procedures and recommend not to use them, if possible.

Related

How to write correct stored procedure in netezza to fetch and display all records from table ? need select procedure

I have written a stored procedure for select operation in netezza db, but its throwing error while I try to execute that stored procedure.
Below is my stored procedure for select operation to fetch and display all records from a table.
#delimiter %%%;
CREATE OR REPLACE PROCEDURE return_result10() RETURNS REFTABLE(tbl)
LANGUAGE NZPLSQL AS
BEGIN_PROC
BEGIN
call * from tbl;
RETURN REFTABLE;
END;
END_PROC;%%%
#delimiter;%%%
I am getting below error as soon as I try to execute this using command ( execute PROCEDURE return_result10(); )
[Code: 1100, SQL State: HY000] ERROR: query "SELECT * from tbl" didn't return a single value
I want a stored procedure to fetch and display all records present in a table in netezza db.

Dynamic Stored Procedure in Oracle

Gurus, I have stored procedure to has to executed on a dynamic table. Here is how the stored procedure looks like.
create or replace PROCEDURE EFX_RECON_UPDATE_SPROC(
FILENAME IN VARCHAR2 ,
SOURCE IN VARCHAR2 )
AS
TABLE_NAME VARCHAR2(200);
query_str VARCHAR2(500);
cnt NUMBER(10);
BEGIN
-- Create dynamic table for each fullfilment system.
TABLE_NAME := SOURCE||'_BRM_OMC_RECON_T';
query_str :='SELECT count(*) from ' || SOURCE || '_BRM_OMC_RECON_T where PROCESSINGFILENAME='''||FILENAME||''';';
EXECUTE IMMEDIATE query_str;
query_str:='MERGE INTO '||TABLE_NAME||' T
USING (
SELECT
ERRORCODE, PROCESSINGFILENAME,
RECORDNUMBER from ERROR_UPLOAD_T
) TMP
ON (T.RECORDNUMBER = TMP.RECORDNUMBER and
T.PROCESSINGFILENAME= TMP.PROCESSINGFILENAME and
T.PROCESSINGFILENAME='''||FILENAME||''')
WHEN MATCHED THEN
UPDATE SET
T.STATUS = ''ERROR'',
T.ERRORSOURCE = ''BRM'',
T.ERRORCODE = TMP.ERRORCODE';
EXECUTE IMMEDIATE query_str;
COMMIT;
END EFX_RECON_UPDATE_SPROC;
I get this error while executing the stored procedure. The problem is with FILENAME and I have enclosed it in ' quot.
ORA-00933: SQL command not properly ended
ORA-06512: at "PIN149.EFX_RECON_UPDATE_SPROC", line 12
According to the error message the problem is on this line:
EXECUTE IMMEDIATE query_str;
It should be:
EXECUTE IMMEDIATE query_str INTO cnt;
And the semicolon should be removed from the SELECT string.
Although the variable cnt is not used elsewhere so I'm not sure what that statement is supposed to accomplish.

Execute Dynamic DDL statement in teradata stored procedure?

How to Execute Dynamic DDL statements IN TERADATA?
CREATE PROCEDURE DROP_INDEXES(IN indexs varchar(1000),IN p_database VARCHAR (8000),IN p_table varchar(8000))
BEGIN
DECLARE L_SQL VARCHAR(400);
SET L_SQL= 'DROP INDEX '||trim(indexs)||' ON '||trim(db_name)|| '.'|| trim(tablename);
EXECUTE IMMEDIATE L_SQL;
END ;
I need to call this child_procedure(DROP_INDEXES) from parent procedure, but during executing of the parent_procedure, after executing this procedure
CALL DROP_INDEXES(indexs,db_name,tablename);
automatically gets exit from the parent_procedure, the next statement is not executing from parent_procedure.
This is the error i'm getting:
Executed as Single statement. Failed [3722 : HY000] SP_DROP_INDEXES:
Only a COMMIT WORK or null statement is legal after a DDL Statement.
Elapsed time = 00:00:00.326
Kindly do help me regarding my issue.
Thanks in advance.
In Teradata each DDL must be committed individually. Your session is running in ANSO mode, thus you need to add ;COMMIT; to the SQL string.
This should work:
SET L_SQL= 'DROP INDEX '||trim(indexs)||' ON '||trim(db_name)|| '.'|| trim(table name) || ';COMMIT;'
Try a different syntax:
REPLACE PROCEDURE DROP_INDEXES(IN indexs varchar(1000), IN p_database VARCHAR (8000),IN p_table varchar(8000))
BEGIN
DECLARE L_SQL VARCHAR(400);
SET L_SQL= 'DROP INDEX '||trim(indexs)||' ON '||trim(p_database)|| '.'|| trim(p_table);
--EXECUTE IMMEDIATE L_SQL;
CALL DBC.SysExecSQL( L_SQL );
END ;
REPLACE PROCEDURE PROC_TEST1 (IN db_name varchar(30),IN tablename varchar(30),IN indexs varchar(30))
BEGIN
CALL DROP_INDEXES(indexs,db_name,tablename);
insert into test2 (charcol) select user;
END;
call proc_test1(DATABASE,'test2','idx_test2');

Call one stored procedure to another stored procedure in DB2

Problem that I was facing is that I have to call one stored procedure from another stored procedure in DB2 database. Kind example that I am giving right below.
I have one stored procedure:
CREATE OR REPLACE PROCEDURE Proc1()
IS
Declare myName in varchar;
BEGIN
Select fname into myName from student where fname='x'; // is returning unique value
-- here call anoher proc2
END;
Now so this proc1 procedure is going to call this proc2 procedure.
Now I have second stored procedure:
CREATE OR REPLACE PROCEDURE Proc2(Name in varchar)
IS
BEGIN
-- do anything
END;
I solved this problem,
So solution is like If we want to execute proc using sql command then syntex is like below,
call Proc2('My Name');
We can use this same approach inside our proc also.
For that we have to follow some steps. Lets say that our above sql call is statement that we want to execute. we are going to convert that statement into String and pass necessary parameter by concating variable values. Then execute statement.
CREATE OR REPLACE PROCEDURE Proc1()
IS
Declare myName in varchar;
-- stmt variable is to execute our proc
STMT VARCHAR(4000);
BEGIN
Select fname into myName from student where fname='x'; // is returning unique value
-- this is our logic
STMT :='call Proc2('||myName||')';
EXECUTE IMMEDIATE STMT;
END;

Executing queries using DAO

I want to execute a list of queries against an Access database using DAO. The "Database.Execute()" method seems suited for this with the remark that it can only execute "action queries", that is queries which don't return a result set (MSDN reference). For queries which return records "Database.OpenRecordset()" can be used. Both methods throw exceptions if the wrong type of query is passed.
Having both action queries and select queries in the list how can I decide upfront which will return records and which will not?
Note that the ADO Execute method can be used regardless of whether or not the query returns a resultset.
But do you really want to execute all 'queries'? What if they contain SQL DDL? Consider you created a PROCEDURE using this SQL DDL code:
CREATE PROCEDURE qryDropMe AS DROP PROCEDURE qryDropMe;
;)
Access maintains a hidden system table called MSysObjects which includes a field (Flags) which stores a value indicating the query type. You could try the following function with each of the query names from your list and use the return value to determine whether to use Database.Execute() or Database.OpenRecordset()
The function requires read permission for MSysObjects. I have heard reports than some Access 2007 users are denied permission to read MSysObjects. However, I haven't encountered that problem with Access 2007.
I tested several query types to determine the Flags values. If one of your queries is a type I didn't test, the function will return the Flags value as unrecognized. You can modify the function to include that Flags type.
The only DDL query I tested was DROP TABLE (Flags = 96).
Also, please be aware that not all "SELECT ... FROM ..." queries are select queries for your purpose (returning a recordset). A query such as "SELECT fields INTO newtable FROM oldtable;" does not return records, and the Access UI classifies it as a Make Table query.
Public Function QueryType(ByVal pQueryName As String) As String
Dim lngFlags As Long
Dim strType As String
Dim strCriteria As String
strCriteria = "[Name] = """ & pQueryName & """ And [Type] = 5"
lngFlags = DLookup("Flags", "MSysObjects", strCriteria)
Select Case lngFlags
Case 0
strType = "Select"
Case 16
strType = "Crosstab"
Case 32
strType = "Delete"
Case 48
strType = "Update"
Case 64
strType = "Append"
Case 80
strType = "Make Table"
Case 96
strType = "Drop Table"
Case 128
strType = "Union"
Case Else
strType = "Flags " & CStr(lngFlags) & " unrecognized"
End Select
QueryType = strType
End Function
Inspired by #HansUp's answer I investigated a bit more the QueryDef structure provided by the DAO interface. The structure has a "Type" property which I can use to differentiate between different query types (MSDN). I ended up with the following implementation:
function TAccessDatabase.SQLExec(AName, AQuery: String): Integer;
var
I: Integer;
QDef: QueryDef;
QDefExists: Boolean;
begin
Result := 0;
// Lookup querydef in the database
QDefExists := False;
for I := 0 to DB.QueryDefs.Count - 1 do
begin
QDef := DB.QueryDefs[I];
if QDef.Name = AName then
begin
QDefExists := True;
break; //-->
end;
end;
// Create query def if it doesn't exists
if not QDefExists then
begin
QDef := DB.CreateQueryDef(AName, AQuery);
// Refresh is required to get the correct QDef.Type_
DB.QueryDefs.Refresh;
end;
// Execute the query only if it is not a SELECT
if QDef.Type_ <> dbQSelect then
begin
db.Execute(AQuery, dbInconsistent);
Result := DB.RecordsAffected;
end;
end;
Thank you all for the helpful answers and remarks.
Why don't you catch the exception thrown and analyse it?
Do you have any way to use a beginTrans/Rollback instruction? You could then send your SQL command, collect the errors, then rollback your transactions, having your database left unchanged.
What about using ADO connection, somewhat smarter than the ADO one, where the connection hold an 'errors' collection and returns some other data like number of records affected?
This information applies to the type of the query. So:
All queries that execute a SELECT ... FROM ... are select queries
All INSERT, UPDATE, DELETE are action queries
You just have to inspect the query sql command text to look if it starts with any of the above keywords and act accordingly.

Resources