Parse SQL Statement and reconstructing after modifications using java - java

Does anyone know how to parse SQL statements, and again build in back using Java? This is required because I would need to add extra columns to WHERE clause based on the some conditions. FOr example, based on the Logon user, I would need to decide whether the user is restricted to see the records like it is restricted outside USA.

use jsqlparser
examples:
CCJSqlParserManager ccjSqlParserManager = new CCJSqlParserManager();
Select statement = (Select) ccjSqlParserManager.parse(new FileReader(path));
PlainSelect plainSelect = (PlainSelect) statement.getSelectBody();
Expression expression = plainSelect.getWhere();

See below example
String sqlstr= "select * from [table name] where [ column 1]='value' or ? "
If( your condition){
sqlstr= sqlstr+" [ column 2]=' value 2'";
}
// Now write your execution statement

Related

How to filter a PostgreSQL table by passing an array of strings in the function

I want to pass an array like [group1, group2, group3] and then filter the Postgres table column groups.
Create or replace function funname(groups text[])
Select *
From tableName
Where groupscolumn #> groups
Also kindly write the function for the same, getting an error while defining character varying [].
It's unclear to me what you want, but maybe you are looking for the ANY operator?
select *
from some_unknown_table
where group_column = any(array_parameter);
This requires that the data type of the group_column and the one of the parameter match. E.g. if group_column is text or varchar the parameter needs to be declare as text[]. If group_column is e.g. an integer, the parameter needs to be declared as integer[]
You can use the unnest function to convert an array in 'table' output and then filter the value that you need, for example:
SELECT * FROM (
SELECT unnest (ARRAY['group1','group2','group3']) AS arr
) AS sub WHERE arr ='group3'
You can use join for groups array and SELECT WHERE group IN groups for filter:
import psycopg2
def filter_groups(group_names):
try:
# connect to BD
connection = psycopg2.connect(
host="host",
user="user",
password="pass",
database="db_name"
)
except Exception as _ex:
print("[INFO] Connection error", _ex)
try:
with connection.cursor() as cursor:
placeholders = ','.join(['%s'] * len(group_names))
rsql = f"SELECT * FROM table_name WHERE groups IN ({placeholders})"
cursor.execute(rsql, group_names)
rows = cursor.fetchall()
cursor.close()
except Exception as _ex:
print("[INFO] Error while working with PostgreSQL", _ex)
if connection:
connection.close()
print("[INFO] PostgreSQL connection closed.")
return rows

Include clause in jooq prepared statement conditionally

Hi I am using JOOQ to build a SQL statement in my java application. I need to include an or clause in my statement under a certain condition and omit under the other.
e.g.
org.jooq.Query ps = select(field("q.*"))
.from(table("QUEUES q"))
.where(field("q.APPLICATION").eq("APP1"));
I then need to unclude an or part to the query depending on some other variable..
org.jooq.Query ps = select(field("q.*"))
.from(table("QUEUES q"))
.where(field("q.APPLICATION").eq("APP1"))
.or(field("q.APPLICATION").eq("APP2"));
I can't figure out how to do this without having two separate statements, one including the or statement and one without. Thanks in advance.
What you want to do is use the extensions of SelectConditionStep which will allow you to break up the query into individual steps and use a flag as a means to attach only one specific extension of SelectConditionStep to the query.
Given your query and a flag (boolean - to separate the extension of SelectConditionStepto be used) called for e.g. checkBothApps.
boolean checkBothApps = false;
org.jooq.SelectJoinStep<R> joinStep = select(field("q.*"))
.from(table("QUEUES q"));
org.jooq.SelectConditionStep<R> conditionStep = joinStep.where(field("q.APPLICATION").eq("APP1"));
if (checkBothApps) {
// This condition will be added to the join step.
joinStep.or(field("q.APPLICATION").eq("APP2"));
}
Edit: Tested code.
Thanks to Koshux
I did it like this...
Condition whereClause = field("q.APPLICATION").eq("APP1");
if(bothApps){
whereClause = whereClause.or(field("q.APPLICATION").eq("APP2"));
}
org.jooq.Query ps = select(field("q.*"))
.from(table("QUEUES q"))
.where(whereClause);

DB2 jdbc execute function error [duplicate]

I'm using the statement below to update/insert some data to a table and, if I run it without parameters, it's fine. However, as soon as I try to execute it using parameters it throws:
SQL0418N - A statement contains a use of an untyped parameter marker, the DEFAULT keyword, or a null value that is not valid.
I've read the error information here, but I'm still struggling with why my statement won't execute.
--This statement works
MERGE Into AB.Testing_Table A
USING (VALUES('TEST', 'P')) B(TEST_ID, "ACTION")
ON (A.TEST_ID = B.TEST_ID)
WHEN NOT MATCHED THEN
INSERT (TEST_ID, "ACTION")
VALUES ('TEST', 'P')
WHEN MATCHED THEN
UPDATE SET TEST_ID = 'TEST'
,"ACTION" = 'P';
--This statement fails with error SQL0418N
MERGE Into AB.Testing_Table A
USING (VALUES(#TEST, #ACTION)) B(TEST_ID, "ACTION")
ON (A.TEST_ID = B.TEST_ID)
WHEN NOT MATCHED THEN
INSERT (TEST_ID, "ACTION")
VALUES (#TEST, #ACTION)
WHEN MATCHED THEN
UPDATE SET TEST_ID = #Test
,"ACTION" = #Action;
Thanks in advance for the help!
Basically, DB2 doesn't know what data types you're sending in on those parameters. I'm guessing you're either on an older version of DB2 (less than 9.7 on Linux/Unix/Windows, or on a Mainframe version older than 10.1), which doesn't do a whole lot of "automatic" type conversion. Or you're sending in NULL values (which still have to be "typed", strange as it sounds).
You can fix the problem by creating your parameter markers as typed parameters (I'm assuming data types here, use what would be appropriate):
MERGE INTO AB.TESTING_TABLE A
USING (VALUES (
CAST(#TEST AS CHAR(4))
,CAST(#ACTION AS CHAR(1))
)) B(TEST_ID, "ACTION")
ON (A.TEST_ID = B.TEST_ID)
WHEN NOT MATCHED THEN
INSERT (TEST_ID, "ACTION")
VALUES (B.TEST_ID, B.ACTION)
WHEN MATCHED THEN
UPDATE SET "ACTION" = B.ACTION
Additionally, since you're using the MERGE, you don't have to use parameters in the UPDATE or INSERT parts, you can refer to the values in the USING table you passed in. Also, since you're matching on TEST_ID, you don't need to include that in your UPDATE statement, since it wouldn't be updated, anyway.

How to bind to IN parameters in Cloud Spanner Java API

Is it possible, using the Google Cloud Spanner Java SDK, to bind to the parameters supplied to the IN portion of a query?
e.g.
List<String> names = new ArrayList<String>();
names.add("Alice");
names.add("Bob");
String sql = "SELECT * FROM people WHERE name IN (#names)";
Statement statement = Statement
.newBuilder(sql)
.bind("names").to(names)
.build();
If we bind names using toStringArray, it errors. And if we set the following:
names = "'Alice','Bob'";
Then the generated SQL is:
SELECT * FROM people WHERE name IN ("'Alice','Bob'")
Note the extra quotations. Any idea how we can do this without %s string substitution to avoid inject attacks?
2 changes to your code:
List<String> names = new ArrayList<String>();
names.add("Alice");
names.add("Bob");
String sql = "SELECT * FROM people WHERE name IN UNNEST(#names)";
Statement statement = Statement
.newBuilder(sql)
.bind("names").toStringArray(names)
.build();
First is to make the condition IN UNNEST as we're going to be binding an array rather than repeated values.
Second is to change to to toStringArray to bind the array as you originally tried.
To better visualize this, the array that you bind is essentially this:
SELECT * FROM people WHERE name IN UNNEST(["Alice", "Bob"])

JAVA: NamedQuery String problem

Hello guys I am having some problems with exact matches while doing a NamedQuery.
I am currently using something like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from Entry e where e.name =:"+ Entry.NAME )
...
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName());
It works for most cases, however I noticed that in case the user pass the file name with an space at the end, the namedQuery ignores that character. For example:
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName()+ " ");
Will return the same result as the query before. Bypassing my 'valid entry' validation. In other words I'd like the query to return no entry at all and treat the error later on.
One workaround I could think of, is to put single quotes surrounding my parameter in the namedQuery, like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from entry e where e.name =':"+ Entry.NAME "'")
However it will trash my code in case the String contains single quotes in it...
Any ideas guys?
I guess this happens because your database field is declared as CHAR(...), and therefore stored values are padded with whitespaces which are not taken into account by = operation.
So, you may either declare your database field as VARCHAR(...) or use a built-in trim function:
query = "select e from Entry e where trim(trailing from e.name) =:"+ Entry.NAME
I did some research in JPA and found out that it does some automatic trimming for CHARs, I am not sure if this behaves the same with Strings, but since it is happening to me... I believe so. The only way to bypass it is by setting some attribute within the session DatabaseLogin object (see http://www.eclipse.org/eclipselink/api/1.1/org/eclipse/persistence/sessions/DatabaseLogin.html#setShouldTrimStrings) .
Well I didn't want to be messing up with the session properties so I decided to make some sort of check and throwing the same exception as the NoResultException catch does in my code.
I basically took the result from the database and compared the field with the String I used:
query.setParameter(Entry.NAME, myEntry.getName());
...
if(!StringUtils.equals(result.getName(), myEntry.getName()){
do a cool throw just like NoResultException Catch
}
I also had to include the Trim function axtavt! This is just to make sure that if the database has a column with trailing spaces and it matches the parameter given by the user, it will be included as a valid answer. For example:
Database entry: Name = "Flavio " - Trimmed with Function = "Flavio".
Parameter passed: Name = "Flavio " - Trimmed by JPA automatic function = "Flavio".
If it isnt trimmed at all it will just Compare "Flavio " with "Flavio", returning NoResult when it was supposed to return that Entry.
Nasty workaround, but as long as there is no other way to stop the auto-trimming we will have to just make use of this sort of things.
Thanks for all the other answers!!

Categories

Resources