Usage of SQL Server function in SqlExpression in Update query - subsonic

In SubSonic, version 2.2, the following (MSSQL-specific) code fails:
SqlQuery update =
new Update(SomeTable)
.SetExpression(SomeTable.SomeDateTimeColumn).IsEqualTo("GETDATE()")
.Where(SomeTable.IdColumn).IsEqualTo(id);
At this point update.ToString() produces a perfectly legal SQL sentence:
UPDATE [dbo].[SomeTable] SET [SomeDateTime]=GETDATE()
WHERE [dbo].[SomeTable].[ID] = #ID0
update.Execute() however fails with:
{"Failed to convert parameter value from a String to a DateTime."}
at SubSonic.Update.Execute()
Is there any possibility to use sql server functions in expressions?

Ok, I've found a workaround - it is possible to use SQL Server functions outside of InlineQuery. The trick is that you must not use "strongly typed" version of SetExpression that uses TableColumn parameter, but pass column name strings, like this:
SqlQuery update =
new Update(SomeTable)
.SetExpression(SomeTable.Columns.SomeDateTime).IsEqualTo("GETDATE()")
.Where(SomeTable.IdColumn).IsEqualTo(id);
The important part being: SomeTable.Columns.SomeDateTime instead of SomeTable.SomeDateTimeColumn.

For the specific example you've posted you could just do the following:
SqlQuery update = new Update(SomeTable)
.SetExpression(SomeTable.SomeDateTimeColumn).IsEqualTo(DateTime.Now)
.Where(SomeTable.IdColumn).IsEqualTo(id);

Related

Casting Strint to integer in liferay dynamic query

I have been using dynamic query for a project.
Here is an scenario for which I am facing problem.
For a table xyz the column version is stored as varchar (I know it's a poor design, but it's too late to change now) and has values as 9,12.
For the query :
select max(version)
from xyz
where something = 'abc';
I am getting the output as 9 instead of 12.
The dynamic query for the same is:
ClassLoader classLoader = PortletBeanLocatorUtil.getBeanLocator(ClpSerializer.getServletContextName()).getClassLoader();
DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(xyz.class, classLoader);
dynamicQuery.setProjection(ProjectionFactoryUtil.max("version"));
dynamicQuery.add(PropertyFactoryUtil.forName("something").eq("abc"));
List<Object> list = xyzLocalServiceUtil.dynamicQuery(dynamicQuery);
The query which is giving the correct value is :
select max(cast(version as signed))
from xyz
where something = 'abc';
Now, I want it to be in the dynamic query, how can I do that?
I am using liferay-6.2-ce
Try using ProjectionFactoryUtil.sqlProjection method.
That method allows using functions that are executed by SQL engine.
For example, I am using following code in order to get the max length of a string column called 'content':
Projection maxSizeProjection = ProjectionFactoryUtil.sqlProjection(
"max(length(content)) as maxSize", new String[] {"maxSize"},
new Type[] {Type.BIG_DECIMAL});
The same thing can be done with dynamic query criterions using RestrictionsFactoryUtil.sqlRestriction in case you want to use a SQL function in a condition.
In your case try following code:
import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil;
import com.liferay.portal.kernel.dao.orm.Type;
...
Projection maxSizeProjection = ProjectionFactoryUtil.sqlProjection(
"max(cast(version as signed)) as maxVersion",
new String[] {"maxVersion"}, new Type[] {Type.BIG_DECIMAL});
dynamicQuery.setProjection(maxSizeProjection);

How can I call this jOOQ generated function taking a custom bound type?

I originally had the following SQL function:
CREATE FUNCTION resolve_device(query JSONB) RETURNS JSONB...
and the following code calling the method generated by jOOQ:
final JsonArray jsonArray = jooqDWH.select(resolveDevice(queryJson)).fetchOne().value1().getAsJsonArray();
final JsonObject o = jsonArray.get(0).getAsJsonObject();
This worked fine. I needed to return a real device object rather than a JSON blob though, so I changed the SQL function to:
CREATE FUNCTION resolve_device(query JSONB) RETURNS SETOF device...
and the code to:
final ResolveDeviceRecord deviceRecord = jooqDWH.fetchOne(resolveDevice(queryJson));
but I am getting a runtime error:
org.jooq.exception.SQLDialectNotSupportedException: Type class com.google.gson.JsonElement is not supported in dialect DEFAULT
Many other parts of my code continue to work fine with the custom binding I have converting JsonElement to JSONB, but something about the change to this function's signature caused it to stop working.
I tried a few different variants of DSL.field() and DSL.val() to try to force it to be recognized but have not had any luck so far.
This could be a bug in jOOQ or a misconfiguration in your code generator. I'll update my answer once it is clear what went wrong.
Workaround:
Meanwhile, here's a workaround using plain SQL:
// Manually create a data type from your custom JSONB binding first:
final DataType<JsonObject> jsonb = SQLDataType.OTHER.asConvertedDataType(jsonBinding);
// Then, create an explicit bind variable using that data type:
final ResolveDeviceRecord deviceRecord =
jooqDWH.fetchOptional(table("resolve_device({0})", val(queryJson, jsonb)))
.map(r -> r.into(ResolveDeviceRecord.class))
.orElse(null);

Query referencing another query

I can't execute a query in Power Query and the error that throws me is like:
Formula.Firewall: Query XXX references other queries or steps, so it may not directly access a data source. Please rebuild this data combination.
The code within this query is as below:
let
CallToFunction = myFunction,
#"Invoked Function" = CallToFunction(),
Source = Oracle.Database("myServer", [Query="SELECT * FROM myTable WHERE CustomerPK IN (" & #"Invoked Function" & ")"])
in
Source
myFunction is a function that uses a couple of other queries and eventually returns a string of primary keys that I can use to fill in the parenthesis of the WHERE clause of my SQL statement.
When I invoke the function alone it works correctly, so this must be an issue of how to call the function within the last query.
Any ideas?
You need to set the privacy settings of your data sources & workbook.
See https://support.office.com/en-ca/article/Privacy-levels-Power-Query-cc3ede4d-359e-4b28-bc72-9bee7900b540?ui=en-US&rs=en-CA&ad=CA

How do you add elements to a set with DataStax QueryBuilder?

I have a table whose column types are
text, bigint, set<text>
I'm trying to update a single row and add an element to the set using QueryBuilder.
The code that overwrites the existing set looks like this (note this is scala):
val query = QueryBuilder.update("twitter", "tweets")
.`with`(QueryBuilder.set("sinceid", update.sinceID))
.and(QueryBuilder.set("tweets", setAsJavaSet(update.tweets)))
.where(QueryBuilder.eq("handle", update.handle))
I was able to find the actual CQL for adding an element to a set which is:
UPDATE users
SET emails = emails + {'fb#friendsofmordor.org'} WHERE user_id = 'frodo';
But could not find an example using QueryBuilder.
Based off of the CQL I also tried:
.and(QueryBuilder.set("tweets", "tweets"+{setAsJavaSet(update.tweets)}))
But it did not work. Thanks in advance
Use add (add one element at a time) or addAll (more than one any number of element at a time) method to add to a set.
To extend Ananth's answer:
QueryBuilder.add does not support BindMarker. To use BindMarker while adding in set, it is required to use QueryBuilder.addAll only.*
*Just a note, Collections.singleton may come in handy in this regard.
Using #Ananth and #sazzad answers, the code below works:
Session cassandraSession;
UUID uuid;
Long value;
Statement queryAddToSet = QueryBuilder
.update("tableName")
.with(QueryBuilder.addAll("setFieldName", QueryBuilder.bindMarker()))
.where(QueryBuilder.eq("whereFieldName", QueryBuilder.bindMarker()));
PreparedStatement preparedQuery = cassandraSession.prepare(queryAddToSet);
BoundStatement boundQuery = preparedQuery.bind();
boundQuery
.setUUID("whereFieldName", uuid)
.setSet("setFieldName", Collections.singleton(value));
session.execute(boundQuery);

Jira groovy script error

I'm getting groovy records from SQL Table or Function. Example;
String subeKodu = get_sube_kodu_bul(matcher[0][1])
private String get_sube_kodu_bul(String subeAdi) {
def sql = Sql.newInstance("jdbc:jtds:sqlserver://10.xx.xx.xx:1433/DBNAME", "usrname","pass", "net.sourceforge.jtds.jdbc.Driver")
subeAdi = subeAdi.trim()
def row = sql.firstRow("SELECT TOP 1 SUBE_KODU FROM TABLENAME WHERE SUBE_ADI= '${subeAdi}'")
row != null ? (String)row.SUBE_KODU : ''
}
But I am faced with the following error;
WARNING: In Groovy SQL please do not use quotes around dynamic expressions (which start with $) as this means we cannot use a JDBC PreparedStatement and so is a security hole. Groovy has worked around your mistake but the security hole is still there. The expression so far is: SELECT TOP 1 YETKILI FROM TABLENAME WHERE SUBE_ADI = '?'
Groovy is complaining that your code may be vulnerable to a SQL injection attack.
The proper way to do this is with JDBC Prepared Statements. In Groovy, you do this as follows:
sql.firstRow("SELECT TOP 1 SUBE_KODU FROM TABLENAME WHERE SUBE_ADI= ?", [subeAdi])
For more examples of this, see the Groovy SQL tutorial and search for "prepared statements".
Also, don't forget to call close() when you are done.

Resources