Spring-data-couchbase - running update query - java

Is any possibility to execute N1QL update query using spring-data?
I.e. I have following update query:
"UPDATE USERS USE KEYS $id SET location = $location"
I tried to use couchbaseTemplate.queryN1QL method, but it doesn't work.
Is there any solution of this problem using spring data or even native couchbase java SDK?

the CouchbaseTemplate is more tailored towards Spring Data document's use case, so it expects to run queries that return specific elements and will end up unmarshalled into entities (eg. a User object).
if you want to run a more freeform query, like your update, you can always access the native SDK from the template. In your case:
String paStatement = "UPDATE USERS USE KEYS $id SET location = $location";
JsonObject paramValues = JsonObject.create().put("id", theId).put("location", "theLocation");
N1qlQuery query = N1qlQuery.parametrized(paStatement, paramValues);
template.getCouchbaseBucket().query(query);

I think you can add RETURNING * at the end of your UPDATE statement. It would make the statement returns something. It works for me.

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

Timeout on select query from external service after making an update on the same table

This is such a weird situation. I have Microsoft SQL Server database, app written in java (queries run using javax.persistence.Query) and external service written in C#.
I have a procedure that makes update on table MyTable.
There are only two update statements in this procedure:
UPDATE
MyTable
SET
status = dbo.getStat(id)
WHERE
EXISTS
(
...
)
UPDATE
MyTable
SET
status = 3
WHERE
status = 2
AND EXISTS
(
...
)
EXISTS part is the same for both statements.
In my java app I use following code to launch this procedure:
Query query = em.createNativeQuery(recources.getString("updateStatuses"));
query.setHint("toplink.refresh", "true");
query.setParameter(1, sessId);
query.executeUpdate();
Under updateStatuses I have following sql:
EXEC updateStatusesP ?
After that I select records from this table if they have status equal to 3:
SELECT
id
FROM
MyTable
WHERE
status = 3
AND EXISTS
(
...
)
I iterate through ids and I make a call to external service written in C# which modifies data in db.
The thing is that currently I'm getting a timeout on a select query launched from this external service. It's a query selecting data from MyTable.
If I remove first update statement from my updateStatusesP procedure then it works fine (no timeout). If I modify first query to include "status = " condition in WHERE clause then it also works fine. But without it I get this timeout.
There is a trigger and index on this table. I removed them to check if maybe there is something happening there. No changes.
If I make a direct call to this external service (via postman) then I get correct response. Only when calling it from application code: procedure, select query to select ids and then call to external service - I'm getting a response from this service (with info about timeout) and I can see in db monitoring tool that it didn't go pass first select query launched inside this service.
I don't understand what is happening. I tried putting those updates into transaction and committing it at the end of the procedure but it didn't help. Any ideas?

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

jOOQ addConditions: in SQL question mark appears instead of the value

I would like to launch simple code:
SelectQuery query = dsl.select(field ("id"), field("title")).from("dict.models").getQuery();
if (modelId > 0) query.addConditions(field("model_id", SQLDataType.INTEGER).equal(modelId));
But infortunately in getSQL() I can only see:
select id, title from dict.models where model_id = ?
Where is a mistake?
Thanks.
Query.getSQL() generates the SQL statement as it would be generated if you let jOOQ execute a PreparedStatement - with bind variables. The bind variables can be extracted in the right order via Query.getBindValues()
If you want to inline all bind values into the generated SQL, you have various options through the jOOQ API (all equivalent):
Using Query.getSQL(ParamType) with ParamType.INLINE
Using dsl.renderInlined(QueryPart)
Using StatementType.STATIC_STATEMENT in your Settings

How to create sqlite prepared statement in OrmLite?

Is it possible to create a sqlite prepared statement in OrmLite?
If so, how to bind the query values which may change across different queries.
Is it possible to create a sqlite prepared statement in OrmLite?
You need to RTFM since ORMLite's online documentation is pretty extensive. If you look in the index for "prepared statement" you find out about the QueryBuilder which #Egor pointed out.
how to bind the query values which may change across different queries.
A little further in that section you learn about select arguments which is how you bind query values that change across queries. This is in the index under "arguments to queries".
To quote from the docs here's how you prepare a custom query:
QueryBuilder<Account, String> queryBuilder = dao.queryBuilder();
Where<Account, String> where = queryBuilder.where();
SelectArg selectArg = new SelectArg();
// define our query as 'name = ?'
where.eq("name", selectArg);
// prepare it so it is ready for later query or iterator calls
PreparedQuery<Account> preparedQuery = queryBuilder.prepare();
When you are ready to run the query you set the select argument and issue the query:
selectArg.setValue("foo");
List<Account> accounts = dao.query(preparedQuery);
Later, you can set the select argument to another value and re-run the query:
selectArg.setValue("bar");
accounts = accountDao.query(preparedQuery);

Categories

Resources