Unable to Pass Comma seperated values to Birt Report - java

I am trying to pass a string value which is comma separated to birt report as parameter but failing
Java code
String userlist="\"a\",\"b\",\"c\"";
task.setParameterValue("userlist", userlist);
BeforeOpen has
params["userlist"].value.join("','");
SQL Query is
select * from users where name in (?)
I have already linked data set parameter to report parameter param_1
It's always giving me empty report even though DB table has 3 users. Any advise ?

Know your tools!
In this context: You have to understand SQL and the concept of bind variables, Javascript and BIRT.
Unfortunately every single piece of code you posted is wrong (or at least incomplete).
But you are on the right track: You can modify the SQL text in the beforeOpen event of the database. I'll sketch the idea here:
In your SQL, replace the ? with a placeholder like 'IN-LIST' (such that it is valid SQL).
You should still use the bind variable in the SQL (to avoid pitfalls caused by BIRT's caching mechanism), but in an effective no-op way, e.g. "where ? is not null".
In the beforeOpen event of the data set, you can modify the SQL text:
Get the original SQL text (var query = this.queryText; IIRC).
Split your report parameter into the individual search terms. How exactly to do this depends on your input format. In your example, you are using " around your search terms, which looks overly complicated, unless individual search terms may contain commas. You should now have a list of your search strings, e.g. ["a", "b", "c"].
Convert each term into a valid SQL string literal. Beware of SQL injection attacks, so carefully escape characters like single-quotes! You should now have a list of valid SQL string literals, e.g. ["'a"', "'b'", "'c'"].
Join your list of SQL string literals from 3) into a single string with ", ".
You should now have a string like 'a', 'b', 'c'.
In your query, replace your placeholder string with the string from 4).
Write the modified SQL text back to the DS object: this.queryText = query;
Probably there is also an example somewhere in the mists of the internet.
If you had invested five minutes more, you should have found an existing answer here on stack overflow: How to create a BIRT dataset that accepts multiple (CSV) values that it can be used inside "IN" clause in select statement, the only difference being that you are searching for a list of strings, while that question was about a list of numbers.

Related

Java SQL pattern to find some tables in my database

I'm using database metadata to find some tables in a given schema in database like that:
DatabaseMetaData dbmd = connections.getMetaData();
ResultSet rs = dbmd.getTables(null,"schema_name","table_name_pattern","type");
It works, but my problem is that I only want to find tables that begin with t and three others tables for which I have the exact names:
books_table, froots, and colors.
How can I make a pattern that gives me only these three tables and the tables that begin with t?
I had a similar problem time ago, and the answer is no, you can't do it this way.
The JDBC metadata classes have only very limited functionality.
However, you can query the engine metadata directly. For example you can do:
select *
from pg_catalog.pg_tables
where schemaname = 'public'
and tablename like 't%' or tablename in ('books_table', 'froots', 'colors')
The parameter is interpreted as as wildcard value for a LIKE condition. So to find all tables starting with t use t%.
Quote from the JavaDocs
Some DatabaseMetaData methods take arguments that are String patterns. These arguments all have names such as fooPattern. Within a pattern String, "%" means match any substring of 0 or more characters, and "_" means match any one character.
Note that this is case-sensitive. If you created your tables without quotes (which is what you should be doing) they are stored in lowercase, so t% will work fine.
The last parameter should be a string array with all possible "object types". As you want tables, use {"TABLE"}. Alternatively if you don't care about the "type", you can also pass null
DatabaseMetaData dbmd = connections.getMetaData();
ResultSet rs = dbmd.getTables(null,"schema_name","t%",new String[]{"TABLE"});
You can't however specify multiple OR conditions. If you want to find if other tables exist where you can't use a wildcard, you will have to call getTables() once for each table name.
Another option is to simply get all tables from that schema, then discard those that you don't want while processing the ResultSet. That is most probably faster than using multiple calls to getTables()

Inserting data in cassandra without puting in single quotes using cql java driver

I am having trouble puting those single quotes for ASCII/Timestamp columns and not puting for other types like Int, Decimal, Boolean etc.
The data comes from another db/table, which is a sql.
I have all the column data as string. I don't want to format each column data to check null values and then decide to put quote or not.
Is it possible to pass in insert data value without giving single quotes, using prepared statement or whatever.
If you don't want to write a loader that uses prepared statements (via the CQL driver...which is a good idea), I can think of one other way. To import without using single quotes, you should be able to accomplish this with the COPY FROM CQL3 command (setting the QUOTE parameter to an empty string). If you can dump your RDBMS data to a csv file, you should be able to insert those values into Cassandra like this:
COPY myColumnFamily (colname1,colname2,colname3)
FROM '/home/myUser/rdbmsdata.csv' WITH QUOTE='';
Check out the documentation on the COPY command for more information. Examples can be found here.
EDIT:
I also read the above question and assumed that you did not want a prepared statement-based answer. Since that's obviously not the case, I thought I'd also provide one here (using DataStax's Java CQL driver). Note that this answer is based on my column family and column names from my example above, and assumes that col1 is the (only) primary key.
PreparedStatement statement = session.prepare(
"UPDATE myKeyspace.myColumnFamily " +
"SET col2=?, col3=? " +
"WHERE col1=?");
BoundStatement boundStatement = statement.bind(
strCol2, strCol3, strCol1);
session.execute(boundStatement);
This solution does not require you to encapsulate your string data in single quotes, and has a few added benefits over your String.ReplaceAll:
Allows you to insert values containing single quotes.
Escapes your values, protecting you from CQL-Injection (the lesser-known relative of SQL-Injection).
In CQL, both UPDATE and INSERT add a record if it does not exist and update it if it does (effectively known as an "UPSERT"). Using an UPDATE over an INSERT supports counter columns (if your schema ends up using them).
Prepared statements are faster, because they allow Cassandra to only have to parse the query once, and then re-run that same query with different values.
For more information, check out DataStax's documentation on using prepared statements with the Java Driver.
Finally did it using String.format clubbed with replace
String.format("INSERT INTO xyz_zx(A,B,C,D) VALUES('%s','%s',%s,%s);",(Object[])Strings).replaceAll("'null'","null");

PreparedStatement Update showing error ORA-00927 missing equal sign

I am trying to update the records in database according to data read from an Excel sheet. I have more than 50 columns in db whose column names are stored in an array columnNames[].
I use following code to create the Sql query.
String sqlUpdate= "Update "+tableName+
" set "+columnNames[0]+"=?";
for (int i=1;i<columnCount;i++)
{
sqlUpdate= sqlUpdate+","+columnNames[i]+"=?";
}
sqlUpdate= sqlUpdate+
" where demand_id=?";
the equivalent query obtained to printing it on console is :
Update fulfillment_plan set DEMAND_ID=?,SBU=?,PROJ_DOMAIN=?,JOBCODE=?,INDENT_STATUS=?,JC_CREATED_ON=?,PROJECT_NAME=?,CUSTOMER_NAME=?,GROUP_CUSTOMER=?,US_DEMANDS=?,SUITE_NAME=?,ROLE_NAME=?,LOCATION=?,COUNTRY=?,GEO=?,AREA=?,OPEN_POS=?,PRODUCT=?,DEMAND_TYPE=?,POSITIONS_TO_FULFILL_Q4=?,FULFILLMENT_PLAN_Q4=?,TA_STATUS_Q4=?,POSITIONS_TO_FULFILL_Q3=?,FULFILLMENT_PLAN_Q3=?,TA_STATUS_Q3=?,POSITIONS_TO_FULFILL_Q2=?,FULFILLMENT_PLAN_Q2=?,TA_STATUS_Q2=?,POSITIONS_TO_FULFILL_Q1=?,FULFILLMENT_PLAN_Q1=?,TA_STATUS_Q1=?,NET_ADD_TYPE=?,ESSENTIAL_SKILL=?,SUITE_SKILLS=?,ADDITIONAL_SKILLS=?,POSITIONS_WITH_PROPOSALS=?,POSITIONS_WITHOUT_PROPOSALS=?,DEM_ST_DATE=?,OVER_DUE_STATUS=?,OVERDUE_DAYS=?,LEAD_TIME_DAYS=?,LEAD TIME BUCKET=?,DEM_END_DATE=?,CREATED_ON=?,INDENT_CREATED_ON=?,EBD=?,OPPORTUNITYID=?,LOAD_DATE=?,PROJECT_NUMBER=?,CUSTOMER_NO=?,CUSTOMER_SUB_GEO=?,DEMAND_STATUS=?,ENGAGEMENT_TYPE=?,INVOICE_TYPE=?,INDENT_CLASSIFICATIONS=?,PROJ_STAT=?,EFD_SLA=?,RM_EMP_NAME=?,MONTH=?,QUARTER=?,YEAR=?,ACCOUNT_ID=?,ACCOUNT_TEXT=?,STATUS=? where demand_id=?
Then i have set the values to the '?' and on executing the above prepared statement in am getting the "missing equal sign" error. I have been looking into it for around 3 hours now and am not able to solve it. Kindly help.
I suspect this is due to the LEAD TIME BUCKET column name, which should either have underscores (like the other column names) or be escaped somehow - the spaces within the column name are causing the error. It would be better to have underscores in order to be consistent with your other columns, and to make the SQL simpler.
(I'd also suggest adding spaces within your SQL - e.g. one after every comma - so that the SQL can be reformatted in a text editor by line-breaking on spaces, making it easier to read. I'd have more whitespace in the Java code too, but that's clearly a matter of personal/team preference.)

How to determine if a column name must be referred in quotes in a SQL statement?

I am writing a web service that essentially allows users to submit queries to pre-existing tables in various SQL databases against advertised columns.
I have a PostgreSQL table defined like that:
CREATE TABLE stpg.test (
test integer,
"Test" integer,
"TEST" integer
);
insert into stpg.test values (1,2,3);
To determined the names of the available columns I run the following Java code:
ResultSet rs = dbmd.getColumns(null, "stpg", "test", null);
while (rs.next()) {
System.out.println(rs.getString("COLUMN_NAME"));
}
I get:
test
Test
TEST
If a user submits a query, referring to the columns as they were returned, like
select test, Test, TEST from stpg.test he will get 1 1 1 instead of expected 1 2 3.
Is this a bug?
I know that doing select test, "Test", "TEST" from stpg.testreturns results correctly. But my users would not know that to fetch the values of "capitalized" columns that were defined in quotes they need to use quotes in the query.
Is there a way I could could determine that a column name is case sensitive so that I could report its name in quotes? I need to do that generically against different databases, so JDBC api approach is preferable. I tried using ResultSetMetaData and invoking getColumnName and getColumnLabel but they return the names without the quotes. Calling isCaseSensitive always returns false.
Is there a way I could could determine that a column name is case sensitive so that I could report its name in quotes?
It looks like you are saying that a column name needs to be quoted if it contains any upper-case letters. In that case:
if (!name.equals(name.toLowercase())) {
// needs quoting.
}
But this is moot:
if you just quote all column names, or
if you treat user-supplied column names as case insensitive.
(On the latter point, having column names where case sensitivity matters is probably a bad design. Case sensitivity is certainly not something that you'd want your website users to have to worry about ...)
I tried using ResultSetMetaData and invoking getColumnName and getColumnLabel but they return the names without the quotes.
As they should! The quotes are not part of the column names! They are part of the (Postgres) SQL syntax for identifiers (in general). The name is the stuff within the quotes.
Calling isCaseSensitive always returns false.
To be honest, it is not entirely clear (from the javadoc) what the result of that method means. But it sounds like you might have found a bug in the JDBC driver you are using. (Or maybe you are just mistaken. The code for that implements that method in the current Postgres does consult the column type information ...)
I would suggest to always quote the column names. There is no real reason why you would remove the quotes. And, more importantly, the code to decide whether to quote or not is certainly going to span over 10-15ish lines with no added value. That's about 15 lines of code which can introduce new bugs, typos, conceptual errors.
Just quoting each column is straight-forward and always correct!
Also, regarding to your question if the result of select test, Test, TEST from stpg.test is a bug: It's not. It's the default behaviour of PostgreSQL. All column names (or, db-object names) are always lowered except if they are enclosed in quotes. This also leads us to isCaseSensitive. It is always false because it is not case-sensitive.
A more important note: If you let your users type in SQL queries, you will likely run into other weird problems. You will never know what kind of shenanigans your users type. Either by design or by accident ;)
If this is one of the first times you allow users to enter SQL queries, consider your plan of action carefully! Users type errors, mistakes (full-cartesian products on 5 tables with millions of rows? And only then apply filters?... fun times...), or might even try to play with your DB. If you decide on really doing this, buckle up! :) It all depends on the technical knowledge of you user-base.
Also, in Postgres I find it useful to keep everything lower-cased and user underscores to separate words. Like user_account instead of UserAccount.

fetching records from database based on variable number of inputs from from

I have a form with 8 fields and based on the values entered in them I have have to fetch the records from the DataBase. Now the problem is out of the 8 fields the user may fill any number of fields and that too in any order for example the user may fill fields 1,4 and 6 or he may fill 1 and 7 or he may fill all of them (of course he has to fill at least one field)... Now how will I write a query which will work for any number and order of input parameters? and also because this query will be used in reporting(iReport) I am not allowed to write any code with it , it has to be a SQL query. Any ideas
Thanks
there are a number of ways to do this. I have a blog post about doing something like this in a Microsoft SQL (T-SQL) stored procedure at http://code.scottshipp.com/2013/03/29/tutorial-stored-procedures-with-truly-optional-parameters/ but it is likely that you will want to do something more complex and/or you are not using MS SQL Server. You may have to write the query fragments yourself. My suggestion is to do something like the following:
Once the form is submitted, loop through the various fields in the form, and check if their values are empty or not.
For those that are not empty, add a string containing an appropriate corresponding query fragment to some collections object, like an ArrayList. Do not include "AND" or "OR" directly in this string. If you need to keep track of whether this query fragment gets "AND"ed or "OR"ed with other query fragments, track that in a separate collections object. The "query fragment" I'm talking about is what would show up in the "where __" portion of your SQL query. For instance, say the search was for someone's last name. The query fragment you add is a string that says "lastName='" + lastNameField.value() + "'".
Once you have iterated through all the various fields in the form and have a final collections object full of query fragments, construct the final SQL statement from it. Iterate through your collections object (ArrayList in this example) and connect each one with the appropriate "AND" or "OR". Say your ArrayList has the three fragments "firstName='Joe'", "middleName='Q.'", "lastName='Public'". Use a StringBuilder to keep adding these fragments together into a final where clause: "firstName='Joe' AND middleName='Q.' AND lastName='Public'"...you may want to change these to a "LIKE" style query with wildcard characters.
You now have everything you need to create the final select statement. Issue it to the database and retrieve your results!

Categories