I've rawQuery which requires comma separated string but according to the documentation here, the second argument should be an array:
An array of dynamic, untrusted strings to SQL-escape and inject within the SQL string using the appropriate template syntax for this model's database. (If you have no dynamic values to inject, then just use an empty array here.)
var rawQuery = 'SELECT * FROM "user" WHERE "user"."email" IN ($1)';
User.query(rawQuery, ['a#a.com', 'b#b.com'], function (err, rawResult) {
if (err) { return res.serverError(err); }
return res.ok(rawResult.rows);
});
How can I make this query work without passing a variable through an array? I can directly add the variable like this
var rawQuery = 'SELECT * FROM "user" WHERE "user"."email" IN (' + foo +')';
But it will be prone to SQL injection attack.
To run the query directly without using the parameter injection mode, you need to remove SQL command especial characters, otherwise you will be prune to injection attacks, as you said.
There are packages that do that for you:
the most popular are npm: sql-escape and npm sqlstring
They will add escape characters to any especial character into your string:
var escape = require('sql-escape');
var result = escape('my sweet "string"');
//result: 'my sweet \\"string\\"'
Related
I'm using flutter with graphql/client library.
I'm trying to create a string for a gql query that has a where condition:
const getUsers = """
query getUsers(\$nameToSearch: String!) {
users(where: {name: {_ilike: %\$nameToSearch%}}) {
id
name
}
}
""";
the problem is that I don't know how to insert the '%' symbol in that string... the example is wrong and I tried all the combinations.
Online I found only basic examples that doesn't use the '%' symbol
What is the correct syntax?
just store you value inside another variable and then use that variable with ${variable} inside the graphql query it will help you
Consider below code:
const items = await Item.query().where(
"type",
"like",
raw("'??'", [`%${term}%`])
);
I'm not getting any errors with the code above, but the database returns an empty result set. The created SQL query is below:
select "items".* from "items" where type LIKE '%"mobiles"%'
Please look at the like mobiles in the above SQL '%"mobiles"%' "" are treated as part of the value and returns an empty result set.
How can avoid "" in the query above?
Edit: Please note that I'm using ObjectionJS as well which uses Knex.
?? are supposed to be used for a column name.
I've 2 suggestions for you,
use the query without raw at all,
const items = await Item.query().where('type', 'like', `%${term}%`);
use single ?,
const items = await Item.query().where('type', 'like', raw("'?'", [`%${term}%`]));
I have a JPA/Hibernate entity which has a JSONB column (using https://github.com/vladmihalcea/hibernate-types ) for storing a list of strings. This works fine so far.
#TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
#Type(type = "jsonb")
#Column(name = "TAGS", columnDefinition = "jsonb")
private List<String> tags;
Now I want to check if another string is contained in the list of strings.
I can do this by writing a native query and use the #> operator from Postgres. Because of other reasons (the query is more complex) I do not want to go in that direction. My current approach is calling the jsonb_contains method in a Spring Data specification (since the operator is just alias to this function), e.g. jsonb_contains('["tag1", "tag2", "tag3"]','["tag1"]'). What I am struggling with is, getting the second parameter right.
My initial approach is to also use a List of Strings.
public static Specification<MyEntity> hasTag(String tag) {
return (root, query, cb) -> {
if (StringUtils.isEmpty(tag)) {
return criteriaBuilder.conjunction();
}
Expression<Boolean> expression = criteriaBuilder.function("jsonb_contains",
Boolean.class,
root.get("tags"),
criteriaBuilder.literal(List.of(tag)));
return criteriaBuilder.isTrue(expression);
};
}
This results in the following error.
Caused by: org.postgresql.util.PSQLException: ERROR: function jsonb_contains(jsonb, character varying) does not exist
Hinweis: No function matches the given name and argument types. You might need to add explicit type casts.
Position: 375
It does know that root.get("tags") is mapped to JSONB but for the second parameter it does not. How can I get this right? Is this actually possible?
jsonb_contains(jsob, jsonb) parameters must be jsonb type.
You can not pass a Java String as a parameter to the function.
You can not do casting in Postgresql via JPA Criteria.
Using JSONObject or whatever does not help because Postgresql sees it as
bytea type.
There are 2 possible solutions:
Solution 1
Create jsonb with jsonb_build_object(text[]) function and send it to jsonb_contains(jsonb, jsonb) function:
public static Specification<MyEntity> hasTag(String tag) {
// get List of key-value: [key1, value1, key2, value2...]
List<Object> tags = List.of(tag);
// create jsonb from array list
Expression<?> jsonb = criteriaBuilder.function(
"jsonb_build_object",
Object.class,
cb.literal(tags)
);
Expression<Boolean> expression = criteriaBuilder.function(
"jsonb_contains",
Boolean.class,
root.get("tags"),
jsonb
);
return criteriaBuilder.isTrue(expression);
}
Solution 2
Create custom function in your Postgresql and use it in Java:
SQL:
CREATE FUNCTION jsonb_contains_as_text(a jsonb, b text)
RETURNS BOOLEAN AS $$
SELECT CASE
WHEN a #> b::jsonb THEN TRUE
ELSE FALSE
END;$$
LANGUAGE SQL IMMUTABLE STRICT;
Java Code:
public static Specification<MyEntity> hasTag(String tag) {
Expression<Boolean> expression = criteriaBuilder.function(
"jsonb_contains_as_text",
Boolean.class,
root.get("tags"),
criteriaBuilder.literal(tag)
);
return criteriaBuilder.isTrue(expression);
}
I think that the reason is that you pass the varchar as the second param. jsonb_contains() requires two jsonb params.
To check a jsonb array contains all/any values from a string array you need to use another operators: ?& or ?|.
The methods bindings for them in PSQL 9.4 are: jsonb_exists_all and jsonb_exists_any correspondingly.
In your PSQL version, you could check it by the following command:
select * from pg_operator where oprname = '?&'
I'm powering a search bar via AJAX that passes a selected filter (radio button) that relates to a database column and a search string for whatever is entered in the search bar. The scala/play/anorm code I am using is this:
def searchDB(searchString: String, filter: String): List[DatabaseResult] = {
DB.withConnection { implicit c =>
SQL(
"""
SELECT name, email, emailsecondary, picture, linkedin, title, company, companylink, companydesc, location, github, stackoverflow, twitter, blog
FROM mailinglistperson
WHERE {filter} LIKE '%{searchString}%'
""").on(
'filter -> filter,
'searchString -> searchString
).as(databaseResultParser.*)
}
}
When I run a query on the database (PostgreSQL) using psql that is isomorphic to the above anorm code, it returns 2 results, i.e.:
select id, name, email from mailinglistperson where company like '%kixer%';
But the anorm code returns 0 results when passed the exact same values (I've verified the values via println's)
EDIT: When I switch the anorm code to use String Interpolation I get:
[error] - play.core.server.netty.PlayDefaultUpstreamHandler - Cannot invoke the action
java.lang.RuntimeException: No parameter value for placeholder: 3
EDIT2: I also tried passing the '%...%' along with searchString into LIKE and still got 0 results.
There are two issues - the name of the column, and the filter value
As for the filter value: You have to omit the single ticks in the SQL command, and you should pass the placeholder "%" in the argument. The ticks are handled automatically in case of a string.
As for the column name: It's like a string parameter, so again ticks are handled automatically as well:
[debug] c.j.b.PreparedStatementHandle - select ... from ... where 'filter' like '%aaa%'
One solution: Use normal string interpolation s"""... $filter ...""".
All together:
SQL(
s"""
SELECT name, email, ...
FROM mailinglistperson
WHERE $filter LIKE {searchString}
""").on(
'searchString -> "%" + searchString + "%"
).as(databaseResultParser.*)
but that should be accompanied by a check before, something like
val validColumns = List("name", "email")
if (validColumns.contains(filter)) == false) {
throw new IllegalArgumentException("...")
}
to guard against SQL injection.
Update
As pointed out by cchantep: If Anorm >= 2.4 is used, one can use mixed interpolation (both for column names and values):
SQL"... WHERE #$filter LIKE $searchString"
In this case it's partially safe against SQL injection: that only covers the values, and not the column name.
Update 2
As for logging the SQL statements, see Where to see the logged sql statements in play2?
But as you are using PostgreSQL I suggest the definitive source: The PostgreSQL log: In postgresql.conf:
log_statement = 'all' # none, ddl, mod, all
then you will see in the PostgreSQL log file something like this:
LOG: select * from test50 where name like $1
DETAIL: Parameter: $1 = '%aaa'
I am trying to insert a vertex with orientjs(previously oriento) query builder. My class has a link type property pointing to another class.
I know I can get it to work with a raw query string but I would love to use the query builder.
Here is what I've tried so far :
db.insert()
.into('VertexClassName')
.set({"prop":"value", "linkProperty":"33:1289287"})
db.insert()
.into('VertexClassName')
.set({"prop":"value", "linkProperty":"#33:1289287"})
I get the following error :
Error on saving record in cluster #13
Am I setting properties in the right way ?
Could the error be related to somtehing else ?
I have sucessfully ran an insert query in the cluster #13 with a raw query string in the studio...
According to the official documentation it seems that the problem might be at the end of your statement
db.insert().into('VertexClassName')
.set({"prop":"value", "linkProperty":"33:1289287"}).one()
.then(function (data) {
// callback
});
Check if your code works adding one() to the pipe line
EDITED: I found this method in orientjs.
db.create('VERTEX', 'V')
.set({
key: 'value',
foo: 'bar'
})
.one()
.then(function (vertex) {
console.log('created vertex', vertex);
});
When using Tinkerpop API they recommend using createVertex instead of insert, because createVertex is intended for graphs and insert for Documents... Could you try with the create() method instead?
I am using SQL and it worked.
sql = "INSERT INTO Station set linked = (select from LinkedClass where LinkedProb = 'value'), prop = 'value'"
OrientVertex vertex = new OrientVertex();
vertex = graph.command(new OCommandSQL(sql)).execute();
I don't think that's possible unless you've added a proper field with the right type 'Link' in your schema. (which I rarely do).
Now instead of having the right 'link' type inserted you can do the opposite, store is as a String, and leverage the query functions to use it correctly:
db.insert().into('table').set({prop: '#15:14'}).one();
And it will be converted as String (which is a bit sad) but then you can use that in your queries:
SELECT eval(prop) FROM table;
And it will be 'eval'-ed to a Node RecordID that you can directly use and call functions like expand() on.
For example:
SELECT name FROM (SELECT expand(eval(prop)) FROM table);
Will eval the node stored in the insert(), grab the node, expand it and collect its name property.