Android: SQL Parameter Evaluator for Realm - java

I need to translate SQL statement to Realm (to get record stored in Realm based on SQL statement). I just need to handle SELECT statement with SQL parameters and translate it to Realm. For example:
SELECT * FROM tblCustomer WHERE (Name = 'John Doe' OR Name = 'Joe Black') AND (Postcode = '10013')
I need to evaluate anything after WHERE statement so I can filter and return appropriate records. So, from example above, it is translated to Realm like this
realm.where(tblCustomer.class)
.beginGroup()
.equalTo("Name", "John Doe")
.or()
.equalTo("Name", "Joe Black")
.endGroup()
.beginGroup()
.equalTo("Postcode", "10013")
.endGroup();
I have tried to use Dijsktra's algorithm (Evaluate.java) to evaluate the WHERE parameters, but I am having problem with translating spaces.
I am just wondering, does anyone have algorithms ready to evaluate SQL parameters? If yes, I'll just use your algorithm instead of creating one myself.
Thanks.

Related

Building CosmosDB Query strings with escaping

I want to build a cosmosdb sql query, because I'm using a rest interface, which accepts SQL querys (don't ask why, I can't change that :( )...
Now I want to build that query with some parameters, which affects the WHERE clause.
I think it is a good idea to escape these parameters, to prevent sql injection.
But I just found these way to build a query:
var param = new SqlParameter();
param.add("#test", "here some string to inject");
var query = new SqlQuerySpec("SELECT #test FROM table", param);
Now I could do sql calls to the cosmos's without sql injection. But I don't want this. I just want to get the query string.
But I need the full query from "query". But there seems to be just the method query.getQueryText(). But this just returns the string "SELECT #test FROM table".
Do know a workaround for me? Or maybe just a good package I can use to to my own string escapes.
T
I found the information that this escalation stuff doesn't happen on client site. It happens in the dbms. So I need a rest interface, where I can pass the parameters.
Azure Cosmos DB SQL Like, prepared statements

Couchbase uses wrong indexes with N1QL parameterized queries

I have problems with understanding of way couchbase query plan works.
I use SpringData with Couchbase 4.1 and I provide custom implementation of Couchbase Repository. Inside my custom implememtnation of Couchbase Repository I have below method:
String queryAsString = "SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS FROM MyDatabase WHERE segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1";
JsonObject params = JsonObject.create()
.put(CLASS_VARIABLE, MyClass.class.getCanonicalName())
.put(ID_VARIABLE, segmentId);
N1qlQuery query = N1qlQuery.parameterized(queryAsString, params);
List<MyClass> resultList = couchbaseTemplate.findByN1QL(query, SegmentMembers.class);
return resultList.isEmpty() ? null : resultList.get(0);
In a result, Spring Data produces following json object represented query to Couchbase:
{
"$class":"path/MyClass",
"statement":"SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS from MyDatabase where segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1",
"id":"6592c16a-c8ae-4a74-bc17-7e18bf73b3f8"
}
And the problem is with performance when I execute it via Java and N1QL Rest Api or via cbq consol. For execute this query in cbq I simply replace parameters reference with exact values.
After adding EXPLAIN clause before select statement I mentioned different execution plans. Execution this query as parameterized query via Java Spring Data or N1QL Rest Api I've mentioned that query doesn't use index that I created exactly for this case. Index definiton can be found below:
CREATE INDEX `testMembers` ON MyDatabase `m`(`_class`,`segmentId`,`executionTime`) WHERE (`_class` = "path/MyClass") USING GSI;
So, when I execute query via cbq consol, Couchbase uses my idnex and query performance is very good. But, when I execute this query via N1QL rest api or Java i see that query doesn't use my index. Below you can find part of execution plan that proves this fact:
"~children": [
{
"#operator": "PrimaryScan",
"index": "#primary",
"keyspace": "CSM",
"namespace": "default",
"using": "gsi"
},
So, the question is that the right and legal behavior of couchbase query optimizer? And does it mean that query plan does not take into account real values of parameters? And have I manually put values into query string or exist eny other way to use N1Ql parameterized query with correct index selection?
EDIT
According to shashi raj answer I add N1qlParams.build().adhoc(false) parameter to parameterized N1QL query. This doesn't solve my problem, because I still have performance problem with this query. Moreover, when I print query I see that it is the same as I described earlier. So, my query still wrong analyzed and cause performance decline.
first of all you need to know how N1QL parameterized queries works query should be passed as:
String query= select * from bucketName where _class=$_class and segmentId=$segmentId LIMIT $limit ;
Now the query should be passed as:
N1QL.parameterized(query,jsonObject,N1qlParams.build().adhoc(false));
where jsonObject will have all the placeholder values.
JsonObject jsonObject=JsonObject.create().put("_class","com.entity,user").put("segmentId","12345").put("limit",100);
N1qlParams.build().adhoc(false) is optional since if you want your query to be optimized it will make use of it. It makes use of LRU where it keeps track of previously query entered and it keeps record of it so that next time it doesn't need to parse query and fetch it from previous what we call as prepared statement.
The only problem is couchbase only keeps record of last 5000 queried.
The problem in your case is caused by the fact that you have an index with 'where' clause WHERE ( _class = "path/MyClass"), and at the same time, you passing the _class as a parameter in your query.
Thus, the query optimizer analyzing the parametrized query has no idea that this query might use an index created for _class = "path/MyClass", cause it's _class = $class in a select's where. Pretty simple, right?
So, don't pass any fields mentioned in your index's 'where' as select parameters. Instead, hardcode _class = "path/MyClass" in your select in the same way you did for create index. And everything should be fine.
Here's the ticket in the couchbase issue tracking system about that.
https://issues.couchbase.com/browse/MB-22185?jql=text%20~%20%22parameters%20does%20not%20use%20index%22

Passing clojure vec to POSTGRES IN statement (?)

I'm trying to pass an array of strings to a select statement and I keep getting the error:
org.postgresql.util.PSQLException: Can't infer the SQL type to use for an instance of clojure.lang.PersistentVector. Use setObject() with an explicit Types value to specify the type to use.
I know that the column type is correct, it looks as if passing a vector is the culprit. What is the correct way to do this?
The sql statement is formatted like so:
"SELECT * FROM said_table WHERE item_id IN (?)"
This answer assumes you are using jdbc and not korma or something like it and need to generate the sql directly instead of going through some tool:
the in directive requires you to crate one ? for each item in the list. I end up using this pattern when something else requires me to build the SQL manually:
(let [placeholders (s/join ", " (repeat (count things-go-here) "?"))
query "SELECT * FROM said_table WHERE item_id IN (%s)"]
(exec-raw [(format query placeholders) things-go-here] :results)
....)

extract column names from sql query after where clause

I've a requirement where I need to pull out data from database.
The query is-
SELECT e.Data AS EntityBlob, f.Data AS FpmlBlob
FROM [Trades.InventoryRecord] ir, EntityBlob e, FpmlBlob f
WHERE %s AND uid = e.uid AND uid = f.uid
Here %s is the predicate after where clause which user will input from an html form.
User input will be in this form :
1. TradeDate = '2013-04-05' AND IsLatest = 'TRUE'
2. StreamId= 'IA0015'
3. The query may have IN clause also
Now when this query is rendered I get exception ambigous column streamId or ambigous column IsLatest, as these columns exists in more than one table with same name. So to remove this ambiguity I need to modify the query as - ir.IsLatest or ir.StreamId
To do so by java code, I need to first parse the predicate after where clause, extract column names and insert table name alias- 'ir' before each column name so that the query becomes -
SELECT e.Data AS EntityBlob, f.Data AS FpmlBlob
FROM [Trades.InventoryRecord] ir, EntityBlob e, FpmlBlob f
WHERE ir.TradeDate = '2013-04-05' AND ir.IsLatest = 'TRUE' AND uid = e.uid AND uid = f.uid
what is the best way to parse this predicate, or if there is any other way I can achieve the same result?
My answer to this question is to not parse the user input - there is far too much that can go wrong. It would be a lot better to have a UI with drop downs and buttons for selecting equality, inequality, ranges, in statements, etc. It may seem like more work, but protecting yourself from a SQL injection attack is even more. And even if you are not concerned about malicious SQL injection, then the user still has to get every thing exactly right, or the statement fails.

simpleJDBCTemplate not replacing quoted parameter

I am using simpleJDBCTemplate to insert a value to a postgre database.
String sql "insert into testTable values(:bla, :blah, functionThatTakesAText(':blu'))"
BeanPropertySqlParameterSource namedParameters = new BeanPropertySqlParameterSource(lighting);
simpleJdbcTemplate.update(sql, namedParameters);
Now, the blu parameter is actually a number(the actual sql takes 2 real's ) that is read from a file given by the client.
As a result the database receives something like the following:
insert into testTable values(?, ?, functionThatTakesAText(':blu'))
and fails to replace the :blu parameter as expected.
The current workaround that I'm using is replacing the blu parameter with its value using a regex, but I'm unsure on how safe that is.
How would you solve that?
Spring will skip over anything inside quotes in the SQL (see the skipCommentsAndQuotes() method of NamedParameterUtils), on the basis that anything inside quotes shouldn't be touched.
That makes sense in this context - you would want the prepared statement to say
functionThatTakesAText(?)
rather than
functionThatTakesAText('?')
Try removing the quotes there, and the placeholder should be substituted correctly.

Categories

Resources