Oracle APEX Page item Read Only option which have multiple Conditions - oracle

I am new to Oracle apex.
I have a page with a form that is used to enter data into a table.
For Example there is P_ID, P_NAME, P_ADD_USER, P_VERIFIED_USER, P_SECOND_ID items. I want to make P_SECOND_ID read only based on multiple conditions.
Condition is
IF P_ADD_USER <> :APP_USER AND P_SECOND_ID = ' ' THEN
'P_SECOND_ID should be available to Edit.
ELSE
P_SECOND_ID will be read only.
I tried to use Type = Item!=Value but it is allowing me to add only one condition so is there any option that i can use both conditions and make that ITEM read only.

Condition I'd suggest in such a case is a function that returns a Boolean - if it returns TRUE, something will happen; otherwise, it won't.
So, if you want to make P_SECOND_ID editable if conditions you mentioned are satisfied, then you'd
return not ( :P_ADD_USER <> :APP_USER
and :P_SECOND_ID = ' '
);
Though, did you really want to say :P_SECOND_ID = ' '? Is there a space character in it? Should that, perhaps, be :P_SECOND_ID IS NULL?

SQL Expression allows you to include multiple conditions. You might want to rephrase your requirement to make the item read only ( versus making it editable ) under certain conditions. If I get your requirement right, the condition to make P_SECOND_ID read only is when
:P_ADD_USER = :APP_USER OR :P_SECOND_ID is not NULL
You can use this expression directly in the SQL Expression.

Related

Attempting to prevent SQL injection when referencing an Oracle Package dynamically with JPA

I've gone down a bit of a path and hit a wall with how this could be possibly achieved.
Basically, a query is constructed using JPA and passed to an Oracle DB. On the DB there is a Package, used to generate a reference, and this is dynamically named, based on the environment. This value is user-editable, and stored as a DB property within the application. I don't have any control over the architecture of this.
At a pre-JPA stage, a Query String is generated using the reference value for the Package, which is set as a property (again, I can't change the way this has been designed). I set this up using the Query method setParameter(), like so:
(pseudocode replacing the irrelevant parts for focused context)
String referenceRef = [ reference is fetched from DB properties ];
String queryString = "SELECT ?1 FROM sys.dual";
final Query myQuery = getEntityManager().createNativeQuery( queryString );
myQuery.setParameter( 1, referenceRef );
return myQuery.getSingleResult();
I pretty much did this as a reflex, only to realise (in retrospec, quite obviously) that this won't actually work, as it is escaping the element that should not be escaped...
So, where the referenceRef = "DynamicallyNamedPackage.DoThisDynamicallyNamedThing", the above code will just return "DynamicallyNamedPackage.DoThisDynamicallyNamedThing", as it is obviously making it safe, and the point of doing so is, to a certain extent, the antethesis of what I'm trying to do.
Is it possible to achieve this without creating a whole chunk of additional code? All I can currently think of, as an alternative, is to query dba_procedures for all package objects that match, and using the result of that query to construct the queryString (hence circumnavigating using any user-editable values), but it feels like it's going to be convoluted. This is the alternative, which I am using in lieu of an improvement:
final String verifyReference = "SELECT object_name FROM "
+ "dba_procedures WHERE object_type = 'PACKAGE' AND object_name =?1";
final Query refQuery = getEntityManager().createNativeQuery( verifyReference );
refQuery.setParameter( 1, referenceRef );
final String result = refQuery.getSingleResult();
final String queryString = "SELECT " + result + " FROM sys.dual";
final Query myQuery = getEntityManager().createNativeQuery( queryString );
return myQuery.getSingleResult();
It will essentially look up the user-editable property reference against a list of existing packages, then use the result of that query for building the original reference. It has more null checking and so on involved, and does remove the vulnerability, but feels a bit 'unpolished'.
(As has already been mentioned in the comments, this sort of is designed to need a SQL injection, but needs to prevent "SQL Injection" as a definition of not allowing the DB to be manipulated outside of the design by using an unintended value.)
The Oracle dictionary view all_procedures contains a list of all procedures accessible to the current user.
Specifically in the view there are columns OWNER, OBJECT_NAME (=package name), PROCEDURE_NAME.
You may use this view to sanitize the configured input by simple adding an EXISTS subquery such as:
select
?
from dual where exists (
select null from all_procedures
where
OWNER||'.'||OBJECT_NAME||'.'||PROCEDURE_NAME = upper(?) and
object_type = 'PACKAGE');
You will have to bind twice the same input parameter.
The query returns no data if there is not procedure with the given name, so you may raise an exception.
The query above expects a full qualified stored procedure name, i.e. owner.package.procedure, you'll have to adapt it slightly if you allow unqualified names (without the owner).

Determine whether a SAS dataset is a table or view

I'm trying to determine, given a SAS dataset's name, whether it is a table or view.
The context is that I have a data step where I iterate over a list of dataset names, and if the dataset is a table (and not a view) I'd like to perform a call execute to a sql procedure which drops the table whose name is specified. As it stands now, the code works as intended but throws several warnings of the form
WARNING: File WORK.datasetname.DATA does not exist.
Here is the code I'm using:
data _null_;
set work.ds_list;
tbl_loc = scan(tbl_name,1,'.');
if(tbl_loc = 'WORK') then do;
drop_string = catx(' ',
'proc sql; drop table',
tbl_name,
'; quit;');
call execute (drop_string);
put ' ** Queueing call to drop table ' tbl_name;
end;
run;
So how do I determine from the dataset's name whether it is a view or table?
Thanks!
The function EXIST function will help you here.
if exist(tbl_name,'DATA') then memtype = 'TABLE'; else
if exist(tbl_name,'VIEW') then memtype = 'VIEW';
drop_statements = catx
( ' ',
'proc sql; drop', memtype, tbl_name, '; quit;'
);
From Docs
Syntax
EXIST(member-name <, member-type <, generation>>)
Required Argument
member-name
is a character constant, variable, or expression that specifies the
SAS library member. If member-name is blank or a null string, then
EXIST uses the value of the LAST system variable as the member name.
Optional Arguments
member-type
is a character constant, variable, or expression that specifies the
type of SAS library member. A few common member types include ACCESS,
CATALOG, DATA, and VIEW. If you do not specify a member-type, then the
member type DATA is assumed.
Rather than 'create it' how about using SASHELP.VTABLE to determine if it's a VIEW or DATA.
data temp /view=temp;
set sashelp.class;
run;
data check;
set sashelp.vtable;
where libname='WORK';
run;
Note that the memtype in this case is VIEW. You could probably join your data set to the table as well or do some form of lookup, but a join would be pretty straightforward.
Then once you have the data sets, you can use a PROC DATASETS to drop them all at once rather than one at a time. You don't indicate what initially created this list, but how that list is created is important and could possibly simplify this a lot.
proc datasets lib=work;
delete temp / memtype=view;
run;quit;
so - you'd like to delete all datasets, but not views, from a library?
Simply use the (documented) delete procedure:
proc delete lib=work data=_all_ (memtype=data) ;
run;

case when sum ( condition )= sum (condition) and condition then using db2 system database

Good night, I am working in DB2 and I have been having some troubles making a query with case when
I have to find a way to make a query to define if a record of some category is valid only if the required fields of the relation are required and have been marked as selected, but in this case some registrys are empty and then I must exclude, I have a query like this:
Select (case (sum(category_id) where required='true' and selected='true') = sum(category_id) where required='true' then 'Yes'
else 'no'
from category_table
The problem, is that in some category the required field are all false (it's means do not exist) then I must put a condition like the sum equal to cero, but i always get a syntax error. I have something like this,
Select (case (sum(category_id) where required='true' and selected='true') = sum(category_id) where required='true' and (count(category_id) where required='true' != 0 ) then 'Yes'
else 'no'
from category_table
I have this problem in db2, saddly I can not put the original query hear because the proxy of my work don't le me pass emails to outside or even login at the web page from there.
I would be grateful for any help.
Have you tried using the VALUE function? if no rows will qualify the case conditions then you'll get Zero in the result.

Tuning query with VARCHAR2 column

There is this stored procedure that builds a dynamic query string and then execute it. The sp works fine in development and testing environment, but the DBA of the client company has informed that this query is hitting really hard to the database in production. The IT area has asked us to tune up the query. So far so good, we've moved almost all this sp from building the query string dynamically into a single big query that performs really fast (compared to the old query).
We have found (among other things) that the sp built the where clause of the query string by evaluating if a parameter has a default value or a real value i.e.
IF P_WORKFLOWSTATUS <> 0 THEN
L_SQL := TRIM(L_SQL) || ' AND WORKFLOW.STATUS = ' || TO_CHAR(P_WORKFLOWSTATUS);
END IF;
So we optimized this behavior to
WHERE
...
AND (WORKFLOW.STATUS = P_WORKFLOWSTATUS OR P_WORKFLOWSTATUS = 0)
This kind of change has improved the query that affected numeric columns, but we have found a problem with a VARCHAR2 parameter and column. The current behavior is
--CLIENT.CODE is a VARCHAR2(14) column and there is an unique index for this column.
--The data stored in this field is like 'N0002077123', 'E0006015987' and similar
IF NVL(P_CLIENT_CODE, '') <> '' THEN
L_SQL := TRIM(L_SQL) || ' AND CLIENT.CODE = ''' || P_CLIENT_CODE || '''';
END IF;
We tried to change this to our optimized version of the query by doing
WHERE
...
AND (CLIENT.CODE = P_CLIENT_CODE OR NVL(P_CLIENT_CODE, '') = '')
but this change made the query lost performance. Is there a way to optimize this part of the query or should we turn our big query into a dynamic query (again) just to evaluate if this VARCHAR2 parameter should be added or not into the where clause?
Thanks in advance.
Oracle treats empty strings '' as NULL. So this condition NVL(P_CLIENT_CODE, '') = '' doesn't really make much sense. Moreover it will always be false, because here we are checking equality of NULLs, which is always false. To that end you might and probably should recode that part of the query as:
WHERE
...
AND ( (CLIENT.CODE = P_CLIENT_CODE) OR (CLIENT IS NULL) )
I recommend or to move this varchar2 parameters back to dynamic, or to use the following:
WHERE
...
AND CLIENT.CODE = nvl(P_CLIENT_CODE,CLIENT.CODE)
and be sure you have index on client.code.(Or the table partitioned on client.code, if possible.)
Of course, as it has already been said, you need need to perform correct null checks.
However, the trick is, the difference between
AND (CLIENT.CODE = P_CLIENT_CODE OR NVL(P_CLIENT_CODE, '') = '')
and
AND ( (CLIENT.CODE = P_CLIENT_CODE) OR (CLIENT IS NULL) )
is very unlikely to cause performance problems only by itself. I would even say that query with second clause could perform worse than with the first one, as it will yield true for more rows, resulting in larger result set for consequent joins/orders/filers etc.
I'd bet that adding this clause to your query somehow breaks its optimal execution plan. For instance, having obsolete statistics, the optimizer could make a sub-optimal decision to choose unselective index on client.code instead of others available.
However, it is hard to tell for sure without seeing actual (not the expected one, which you obtain with explain plan command!) execution plan of slow query and your table structure.

EF4.1 LINQ, selecting all results

I am new to LINQ queries and to EF too, I usually work with MySQL and I can't guess how to write really simples queries.
I'd like to select all results from a table. So, I used like this:
ZXContainer db = new ZXContainer();
ViewBag.ZXproperties = db.ZXproperties.All();
But I see that I have to write something inside All(---).
Could someone guide me in how could I do that? And if someone has any good link for references too, I thank so much.
All() is an boolean evaluation performed on all of the elements in a collection (though immediately returns false when it reaches an element where the evaluation is false), for example, you want to make sure that all of said ZXproperties have a certain field set as true:
bool isTrue = db.ZXproperties.All(z => z.SomeFieldName == true);
Which will either make isTrue true or false. LINQ is typically lazy-loading, so if you're calling db.ZXproperties directly, you have access to all of the objects as is, but it isn't quite what you're looking for. You can either load all of the objects at the variable assignment with an .ToList():
ViewBag.ZXproperties = db.ZXproperties.ToList();
or you can use the below expression:
ViewBag.ZXproperties = from s in db.ZXproperties
select s;
Which is really no different than saying:
ViewBag.ZXproperties = db.ZXproperties;
The advantage of .ToList() is that if you are wanting to do multiple calls on this ViewBag.ZXproperties, it will only require the initial database call when it is assigning the variable. Alternatively, if you do any form of queryable action on the data, such as .Where(), you'll have another query performed, which is less than ideal if you already have the data to work with.
To select everything, just skip the .All(...), as ZXproperties allready is a collection.
ZXContainer db = new ZXContainer();
ViewBag.ZXproperties = db.ZXproperties;
You might want (or sometimes even need) to call .ToList() on this collection before use...
You don't use All. Just type
ViewBag.ZXproperties = db.ZXproperties;
or
ViewBag.ZXproperties = db.ZXproperties.ToList();
The All method is used to determine if all items of collection match some condition.
If you just want all of the items, you can just use it directly:
ViewBag.ZXproperties = db.ZXproperties;
If you want this evaluated immediately, you can convert it to a list:
ViewBag.ZXproperties = db.ZXproperties.ToList();
This will force it to be pulled across the wire immediately.
You can use this:
var result = db.ZXproperties.ToList();
For more information on linq see 101 linq sample.
All is some checking on all items and argument in it, called lambda expression.

Resources