Apex 5.1 form page item won't accept a pl/sql function body for default value - oracle-apex-5.1

I get an error message saying my code has a problem when trying to use a pl/sql fucntion body in form item.
Here is my pl/sql function body:
declare
v_name_default varchar2(50);
begin
select name into v_name_default from staff_names where upper(net_id)=:APP_USER;
return v_name_default;
end;
I wonder if perhaps the :APP_USER variable is not allowed -- I am trying to have the default value be the NAME of the individual who is using the form rather than their ID (net_id)
RESOLUTION FOUND:
I was able to resolve the problem. The function body was fine, but the Userid I was pulling from the table was not there. I needed to put some error trapping in my function body to capture those situations. Once I made sure the userid I was testing was in the table, the function worked fine.
Thanks.

Related

Oracle 12c table function to select subset of rows with FOR UPDATE SKIP LOCKED

I have a requirement to return a subset of rows from a table using FOR UPDATE SKIP LOCKED. Based on application parameters this subset may or may not be ordered by a column. I can't use ROWNUM since the numbers are assigned before SKIP LOCKED happens, so using cursors and FETCH ... LIMIT seems to be the way to go.
That works using an anonymous PL/SQL block, but I need to expose the data back to the java application. The most straightforward way would be to use a table function, so I can just do SELECT * FROM table(my_function(<params>)).
I tried a standard table function returning a collection first, but I got the error [902] ORA-00902: invalid datatype. This is roughly what I had in place:
Package specification:
CREATE OR REPLACE PACKAGE ACTIVITY_UTILS AS
TYPE ActivityList IS TABLE OF ACTIVITY_TABLE%ROWTYPE;
FUNCTION activity_batch(batch_size IN INTEGER, order_by_source IN VARCHAR2)
RETURN ActivityList;
END ACTIVITY_UTILS;
Package body:
CREATE OR REPLACE PACKAGE BODY ACTIVITY_UTILS AS
FUNCTION activity_batch(batch_size IN INTEGER, order_by_source IN VARCHAR2)
RETURN ActivityList
IS
batch ActivityList := ActivityList();
selectStatement VARCHAR2(200);
TYPE CursorType IS REF CURSOR;
activitiesCursor CursorType;
BEGIN
IF UPPER(order_by_source) = 'TRUE' THEN
selectStatement := 'SELECT * FROM ACTIVITY_TABLE ORDER BY source FOR UPDATE SKIP LOCKED';
ELSE
selectStatement := 'SELECT * FROM ACTIVITY_TABLE FOR UPDATE SKIP LOCKED';
OPEN activitiesCursor FOR selectStatement;
FETCH activitiesCursor BULK COLLECT INTO batch LIMIT batch_size;
CLOSE activitiesCursor;
RETURN batch;
END activity_batch;
While debugging the ORA-00902 error I ran into this question:
Return collection from packaged function for use in select
My (limited) understanding was I was trying to use a PL/SQL type on plain SQL, which is not allowed. I tried using a pipelined table function, as mentioned in the answer, but then I got the error ORA-14551: cannot perform a DML operation inside a query.
This seemed odd, is SELECT ... FOR UPDATE considered DML? At any rate, I noticed I could workaround this by using pragma autonomous_transaction, but that defeats the purpose of having FOR UPDATE SKIP LOCKED.
My question is, is this requirement achievable at all using functions, or would I have to use a procedure with an OUT parameter?
Option 1: create a function (or procedure) that returns a cursor and let your java application fetch it normally.
Option 2: Use Implicit statement results: in this case your java application can run something like call proc() where proc returns implicit statement results.
PS. It's not a good idea to hide DML under SQL select...

Lazarus DBLookupCombobox can not convert null to int64 for data submission

I have been using Lazarus 2.x with Firebird 3 (via flamerobin) and i try to commit records via TSQLConnection, TSQLQuery, TDataSource in a data module.
I run the following script successfully in order to configure initially DBLookupCombobox, where the records are displayed without any problem.
procedure TForm3.FormCreate(Sender: TObject);
begin
appeals.SQLQuery4.Close;
appeals.SQLQuery4.SQL.Text:='select id,fullname from promoter';
appeals.SQLQuery4.Open;
appeals.DataSource2.DataSet:=appeals.SQLQuery4;
DBLookupComboBox1.ListSource:=appeals.DataSource2;
DBLookupComboBox1.ScrollListDataset:=True;
DBLookupComboBox1.Style:=csDropDownList;
DBLookupComboBox1.KeyField:='id';
DBLookupComboBox1.DataField:='id';
DBLookupComboBox1.ListField:='fullname';
end;
Afterwards i use the following snippet for record submission:
procedure TForm3.Button1Click(Sender: TObject);
begin
appeals.SQLTransaction1.Active:=false;
appeals.SQLQuery1.SQL.Text:='UPDATE appeals set name=:name,date_entry=:entry,date_suspended=:suspended,'+
'date_court=:court,date_judgement=:judgement,promoter_id=:code where id='+IntToStr(row_num);
appeals.SQLQuery1.Params.ParamByName('name').AsString:=Trim(Edit1.Text);
appeals.SQLQuery1.Params.ParamByName('entry').AsDate:=DateTimePicker1.Date;
appeals.SQLQuery1.Params.ParamByName('suspended').AsDate:=IncDay(DateTimePicker1.Date,10);
appeals.SQLQuery1.Params.ParamByName('court').AsDate:=DateTimePicker2.Date;
appeals.SQLQuery1.Params.ParamByName('judgement').AsDate:=IncDay(DateTimePicker2.Date,20);
appeals.SQLQuery1.Params.ParamByName('code').AsInteger:=DBLookupComboBox1.KeyValue;
appeals.SQLTransaction1.StartTransaction;
appeals.SQLQuery1.ExecSQL;
appeals.SQLTransaction1.Commit;
Application.MessageBox('Record submission with success !', 'Information', MB_ICONINFORMATION);
end;
I have also attached the following script in Form Create event without any luck from wiki article.
If (DBLookupComboBox1.KeyValue = Null) And (appeals.SQLQuery4.RecordCount > 0) Then
DBLookupComboBox1.KeyValue := appeals.SQLQuery4.FieldByName('id').AsVariant;
Any idea would help me a lot regarding DBLookupComboBox1.KeyValue where the following error appears!
I would like to update the fields of a table via DBLookupCombobox (foreign key) that loads data from another table, two datetimepickers and edit control.
Regards
I just found that before appeals.SQLTransaction1.Active:=false, i have to store DBLookupComboBox1.KeyValue into a local variable as database connection afterwards is lost and thus there is not any value to DBLookupComboBox1.KeyValue but NULL.
Therefore i have to use that local variable into my SQL query to update the appropriate record.
I should be more careful next time!

Source of parameters in Before Report Trigger in Oracle Report

I am currently working on a migration of oracle reports to another report engine. Therefore I need to know where all the data and parameters are coming from.
There is some "before report trigger" defined that, as far as I already found out, will be called before the data is fetched. Some placeholder columns are set by the function of this trigger. So I will also need to run this code in my migrated report.
The function definition looks like this:
function BeforeReport return boolean is
P_id NUMBER;
P_id2 NUMBER;
P_id3 NUMBER
My question now is: when the reporting engine calls this function before data will be fetched, how does it know what to put into the parameters? Where does this data come from or where is defined, what data will be used here?
I am using Report Builder 12.2.1.3.0
The way you put it, those are not "parameters" but locally declared variables (local to that trigger). Check code that follows; I presume that it might look like
select e.empno
into P_id
from emp e
where ...
or something like that.

Optional Data Input into Spotfire Text Area parameters got from a Oracle Function

I have created a Function from Oralce DB and used it as input to Spotfire report. The reason why i used a function instead of view is because the parameters had some complex logic operations and i was not able to get that done in a view.
Coming to the report i have built. Currently i am using 2 parameters in the function and i am taking both the values from Spotfire text area in Data on Demand mode. So i have set up two 'Input Field' for getting the data. Issue is that unless i enter values for both parameters i wont get the output. My requirement is that i need to add few more parameters for the report which i can but i need to set up the function and the settings in Spotfire such that if 5 parameters are there , if users enters one value for just one parameter report should run for that parameter. I know that parameters set up with complex logis are there but also i need to add additional ones and make sure it works properly. I dont know about proc in case a solution is achievable using that.
I cannot go back to use a view since that wont give me the desired result. Need any ideas or suggestions to implement it. Let me know in case i need to post additional information.
This is how i implemented in oracle :
create or replace function Function_test(p1 varchar2='',p2 varchar2='',p3 varchar2)
return SYS_REFCURSOR as
my_cursor SYS_REFCURSOR;
begin
open my_cursor for
select distinct
x.c1
x.c2
x.c3
from x
where x.c1=p3
and (p1='' or x.c2=p1)
and (p2='' or x.c3=p2);
return my_cursor;
end;
Using a STORED PROCEDURE or a TABLE VALUED FUNCTION will achieve similar results here and you can probably use either one. I understand you can't use a VIEW because VIEWS can't have parameters. I prefer PROCEDURES over VIEWS anyway while working with SPOTFIRE because if you need to add a column or parameter to the PROCEDURE, your INFORMATION LINK on the PROCEDURE will in inherit these changes, whereas using an INFORMATION LINK on a VIEW, the change will not cascade down and you'll need to recreate the INFORMATION LINK all together.
For your case there are a couple of things I would suggest. Since you are trying to make some of the parameters optional, you need to code your FUNCTION or PROCEDURE to accept this. For example, assume one parameter is #param1 and this is accepting input from {$propertyControl1}. To make this optional, you need to instruct users to leave the property control blank if they don't want it to be used to limit the results. Meanwhile, in your FUNCTION or PROCEDURE you need to default it's value to ''. Here is what it could look like using SQL Server, but it should be similar for ORACLE
CREATE FUNCTION dbo.MyFunction (#param1 VARCHAR(256) = '') --default value is blank. Remember don't use NULL since your property control can't be NULL
RETURNS
#returnTBL TABLE(
Column1 datetime,
Column2 int,
Column3 varchar(16))
AS
BEGIN
INSERT INTO #returnTBL (Column1, Column2, Column3)
SELECT
c.C1
c.C2
c.C3
FROM Table2
WHERE #param1 = '' OR c.C3 = #param1 --this returns all rows if the user passes in blank, and filters on it if they pass in a value
RETURN
END
Or, similarly, here is the same logic using a STORED PROCEDURE in SQL Server
CREATE PROCEDURE dbo.MyProcedure(#param1 VARCHAR(256) = '') --default value is blank. Remember don't use NULL since your property control can't be NULL
AS
SELECT
c.C1
c.C2
c.C3
FROM Table2
WHERE #param1 = '' OR c.C3 = #param1 --this returns all rows if the user passes in blank, and filters on it if they pass in a value
GO
Lastly, since you have multiple parameters, I wouldn't have the data on demand automatically refresh. I will have the users click the refresh button to retrieve the data. This will prevent the FUNCTION from being executed each time an individual parameter is change. If a user needs to change 3 of the 5 parameters, you really only want it executed once, versus three times.

ORA-0675:package or function ORG_SPGETTYPE is in an invalid state

PROCEDURE ORG_spGetType
(
v_TypeId IN NUMBER DEFAULT NULL
)
AS
BEGIN
SELECT *
FROM ORG_Type
WHERE TypeId = v_TypeId ;
END;
While Running above proceedure in oracle10g usinq eclipse platform sql editor getting error like "ORA-0675:package or function ORG_SPGETTYPE is in an invalid state"
That's not much of a surprise; that procedure is invalid. When compiling a procedure or any other PL/SQL block you should check whether it's compiled correctly.
If you're compiling on the command line, i.e. in SQL*Plus you can use the SHOW command and use the ERRORS variable, which:
displays the line and column number of the error (LINE/COL) as well as the error itself (ERROR).
After you've compiled the procedure type the following:
show errors
Alternatively, you can use the USER_ERRORS system view which will show you a list of all errors, which the schema you're in can see.
select *
from user_errors
where name = 'ORG_SPGETTYPE'
The actual reason for your error is that you cannot simply SELECT in PL/SQL. If you do you're not giving PL/SQL the ability to use the results of your SELECT statement in any way and so it won't allow you to do so. If you're selecting something you need to do something with it; what that something is is up to you.
There are numerous ways of doing this but let's say the table ORG_TYPE is unique on the column TYPEID and you want to return one column as an OUT parameter. Your procedure would then look like this:
create or replace procedure org_spgettype (
P_typeid in org_type.type_id%type
, P_some_column out org_type.some_column%type
) is
begin
select some_column into P_some_column
from org_type
where typeid = P_typeid;
end;
/
show errors
Please note a number of things:
There doesn't seem to be any need for the DEFAULT NULL if this is your primary key; it can't be NULL so you don't want to allow this possibility.
I've declared your parameters as the type of the column; this enables you to change the column without having to recode everything.
There is so much more to explain about all of this (exceptions for a start) so I would highly recommend taking some basic tutorials first or asking a colleague/friend for help.
You would have a 'compiled with warnings' message when creating the procedure. You can query the user_errors view to see what problems are reported for your peocedure. You will see something like 'PLS-00428: an INTO clause is expected in this SELECT statement', because you are not selecting into something.
The documentation shows how to do that. You need to declare variables to select into. In this case you could declare a rowtype variable:
CREATE OR REPLACE PROCEDURE ORG_spGetType (v_TypeId IN NUMBER DEFAULT NULL) AS
l_org_type org_type%rowtype;
BEGIN
SELECT *
INTO l_org_type
FROM ORG_Type
WHERE TypeId = v_TypeId ;
-- do something with l_org_type
END;
/
Note that this can get a no_data_found exception if there are no matching rows, or too_many_rows if there are multiple matches for the passed ID.
But it isn't clear what you're planning to do with the retrieved data. This currently does nothing at all with it, it's just selected and then forgotten. The name of the procedure suggests you want to return all or part of the data from the table to the caller. If it's only one field value then this should probably be a function rather than a procedure. Or you could add out parameters to put the values into (as Ben shows), or return a refcursor. Depends what you need.
The default null, however, maybe suggests you sometimes expect more than one result, maybe the whole table if no value is passed - though your where clause won't find anything if v_typeid is null.

Resources