I have a JSON string as below, and when I run the following query, it does not return anything. The JSON is valid, so am I missing something?
SELECT JSON_VALUE(json_content, '$.section_1') FROM messages;
{"section_1":{"section_publish":true,"section_body":"<p><b>Overview<\/b><\/p><p>Launched on 19\/06\/1992, the NUVEEN NEW YORK SELECT TAX-FREE INCOME (NXN) is a passively managed exchange traded fund designed to provide a broad exposure to<\/p>"}}
From the documentation:
The function uses the path expression to evaluate expr and find a scalar JSON value that matches, or satisfies, the path expression.
Your path expression would return a JSON object, not a scalar, I believe. That's an error and the default behavior is to return null. You could try adding an ERROR ON ERROR clause and seeing if that raises an error.
As eaolson stated, JSON_VALUE will only return a SCALAR value. If you want to return the JSON string contained in "section_1" you can use JSON_TABLE while using the keywords FORMAT JSON.
WITH
messages
AS
(SELECT '{"section_1":{"section_publish":true,"section_body":"<p><b>Overview<\/b><\/p><p>Launched on 19\/06\/1992, the NUVEEN NEW YORK SELECT TAX-FREE INCOME (NXN) is a passively managed exchange traded fund designed to provide a broad exposure to<\/p>"}}' AS json_content
FROM DUAL)
SELECT j.*
FROM messages
CROSS JOIN
JSON_TABLE (
json_content,
'$'
COLUMNS section1 FORMAT JSON PATH '$.section_1',
section1_publish PATH '$.section_1.section_publish',
section1_body PATH '$.section_1.section_body') j;
Related
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).
In my hyperledger-composer app with angular front-end I want to send a query to the REST server.
query selectEmployeesByProject {
description: "Select all employees with access to the specified project"
statement:
SELECT org.comp.app.Employee
WHERE (projects CONTAINS [_$project])
ORDER BY [lastName, firstName]
}
Employee is defined as follows:
participant Employee {
o String lastName
o String firstName
--> Project[] projects optional
}
The http-request that is sent is the following:
this.httpClient.get<any[]>(requestURL, {withCredentials: true});
whereby the request url is the following:
http://localhost:4200/api/queries/selectEmployeesByProject?projects=resource:org.comp.app.Project#project1ID
In the console I get the following error message:
Failed to load resource
http://localhost:4200/api/queries/selectEmployeesByProject?projects=resource:org.comp.app.Project#project1ID
the server responded with a status of 400 (Bad Request)
Why is the query not working?
In general, httpRequests to the REST-server work in my app. Even other queries work. However, queries with the "CONTAINS" operator (such as the one above) do not work.
more likely to be
query selectClientsByProjects {
description: "Select all clients with access to a certain project"
statement:
SELECT org.myComp.myApp.Client
WHERE (projects CONTAINS [_$project])
ORDER BY [lastName ASC, firstName ASC]
}
Note: At the time of writing - CouchDB does not allow the ORDER BY clause to contain multiple items of different sort direction (obviously not the case above).
Also - not tested but your http call may need to be:
this.http.get('http://localhost:4200/api/queries/selectClientsByProjects?projects=resource:org.myComp.myApp.Project%231')
(%23 is the ASCII for '#')
You can try it out your definition first anyway (eg. without ORDER BY maybe) etc etc. Note: CONTAINS must match one entry ('array contains an element, with complete string match (above), in any element, in that array)
I am trying to get a list of all connections where the SI_SESSION_USER='xyz'.
When I do a query like
select * from si_infoobjects where si_id='00000', I can see this field in the results with that value (xyz).
When I modify the query to look for that specific field and value, it returns zero rows.
I am using:
select * from si_infoobjects where SI_SESSION_USER='xyz'
What query will return the correct results?
Just a guess here, but si_session_user is probably in the Processing Info bag. So use this:
select *
from ci_infoobjects
where si_processinfo.SI_SESSION_USER='xyz'
Note that that's ci_infoobjects not si_infoobjects, but I assume that's just a typo in your question.
I have a complex dynamic query in Eclipselink with a case expression that involves two different columns, one of VARCHAR2 and one of NVARCHAR2.
It needs to be a case expression, because I also want to be able to sort by that result column, so I can't just query both. In Java, both are just mapped as a String, so you don't even see there's a difference.
For my query, Eclipselink creates the following select expression:
CASE
WHEN (t9.STRINGVALUE IS NOT NULL)
THEN t9.STRINGVALUE
ELSE t10.OTHERSTRINGVALUE
END ,
The criteria code is:
Expression<String> str = firstRoot.get("stringValue");
Expression<String> strExp = cb.<String> selectCase().when(cb.isNotNull(str), str)
.otherwise(otherRoot.<String> get("otherStringValue"));
q.multiselect(..., strExp, ...);
which causes Oracle to fail with ORA-12704: character set mismatch. I'd like to modify the code to result in
cast(t10.OTHERSTRINGVALUE as NVARCHAR2(50),
but I cannot find out how.
I tried a converter on the Entity's field, or a .as(String.class) on the .get()-expressions for both fields.
So the question: is there a way to pass an Oracle type like NVARCHAR2 to the .as() expression? Can I otherwise insert a call to CAST(... as NVARCHAR2) with criteria API? Is there any other way to have it generate custom SQL, because I REALLY cannot rewrite the whole query, just because JPA or EL don't provide for the possibility that you might need some custom SQL...
The only way to do it in criteria API is to create a new PathImpl from the otherRoot. get("otherStringValue") path, passing in an EclipseLink native cast expression as the expression node. something like:
PathImpl path = (PathImpl)otherRoot.<String> get("otherStringValue");
Path castPath = new PathImpl(path, em.getMetamodel(), path.getJavaType(), path.getCurrentNode().cast("NVARCHAR2"), path.getModel());
Expression<String> str = firstRoot.get("stringValue");
Expression<String> strExp = cb.<String> selectCase().when(cb.isNotNull(str), str)
.otherwise(castPath );
q.multiselect(..., strExp, ...);
What does the keyword "value" mean in this statement, and where would I go to learn more?
What happens if I leave out the keyword "value"? In the code below, z is an entity framework class.
string queryString = "SELECT VALUE q from x.zs as q where q.a = #parm;"
ObjectQuery<z> query = context.CreateQuery<z>
(queryString, new ObjectParameter("parmname",parmvalue));
return query.First();
(This is a part of a practice question for an exam).
The above code is in a function that returns a variable of type z.
That is Entity SQL syntax. Value keyword allows only one value to be specified, and does not add a row wrapper.
Read article about SELECT statement in ESQL
Entity SQL supports two variants of the SELECT clause. The first
variant, row select, is identified by the SELECT keyword, and can be
used to specify one or more values that should be projected out.
Because a row wrapper is implicitly added around the values returned,
the result of the query expression is always a multiset of rows.
Each query expression in a row select must specify an alias. If no
alias is specified,Entity SQL attempts to generate an alias by using
the alias generation rules.
The other variant of the SELECT clause, value select, is identified by
the SELECT VALUE keyword. It allows only one value to be specified,
and does not add a row wrapper.
So, if you want to materialize z object from your query, you should use SELECT VALUE syntax (otherwise you will get exception: cast from MaterializedDataRecord to z type is not valid).
Without VALUE keyword you will get set of rows:
string esql = "SELECT q from x.zs as q where q.a = #parm;";
ObjectQuery<DbDataRecord> query = context
.CreateQuery<DbDataRecord>(esql, new ObjectParameter("parm",parmvalue));
var result = query.First();