How to Search from Multiple column in mysql DataBase with java - java

I have follwinig code for search data.
public void advanceSearchMethod(String advanceName, int advanceTpNumber, String advanceAddress, String advanceDescription){
Connection connection=null;
try{
//for connect to database.
connection=(Connection) DriverManager.getConnection("jdbc:mysql://localhost/contactbook","root","time1");
//for communicate with database.
Statement stmt=(Statement)connection.createStatement();
String searchQuery="SELECT * FROM Contacts WHERE Name LIKE '%'"+advanceName+"'%' AND TelePhoneNumber LIKE '"+advanceTpNumber+"%' OR Address LIKE '%'"+advanceAddress+"'%' OR Description LIKE '%'"+advanceDescription+"'%'";
rs=stmt.executeQuery(searchQuery);
contactTableInDefaultForm.setModel(DbUtils.resultSetToTableModel(rs));
}catch(Exception e){
JOptionPane.showMessageDialog(null, "Sorry! Connection Failed");
}
}
No errors in this code.but work catch block. I cannot imagine what I should do. How can I search them?

You have a major bug -- when you build the WHERE clause, you have spurious ' apostrophes after '% opening-quote & wildcard and before %' closing-wildcard & quote.
Your broken code: "WHERE Name LIKE '%'"+advanceName+"'%'"
Corrected: "WHERE Name LIKE '%"+advanceName+"%'"
But the whole code is not good code, at all -- every single thing is wrong with it.
WHERE clauses should be built up only with the conditions you actually need to search on. And should use PreparedStatement and ? bound parameters, rather than building string-literals into the SQL. (You have built a well-known security flaw.)
PhoneNumbers are strings, not integers. The LIKE pattern for TelePhoneNumber doesn't have a starting %.
DB connection should be provided from one class & method, rather than in every method in your application.
Errors in separate operations (getting the connection/ vs. executing the query and reading results) should be checked & reported separately. Exceptions and stacktraces should always be logged (use Log4J) or, at the worst case, output to the console.
The single only thing you got right here, was the variable & parameter naming.
To be honest, you ought to be using Hibernate rather than writing this rickety nonsense.

String searchQuery="SELECT * FROM Contacts WHERE Name LIKE '%'"+advanceName+"'%' AND TelePhoneNumber LIKE '"+advanceTpNumber+"%' OR Address LIKE '%"+advanceAddress+"%' OR Description LIKE '%"+advanceDescription+"%'";
U have added addition single quatation..
Hope this is right answer..

Related

JDBC with H2 and MySQL mode: create procedure fails

Description of code
Database connection
I try to to store Java object locally database without use external database.
For this I use JDBC with H2 via Hibernate :
/**
* #param connection the connection to set
*/
public static void setConnectionHibernate() {
Properties connectionProps = new Properties();
connectionProps.put("user", "sa");
try {
Class.forName("org.h2.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
url = "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MODE=MySQL;";
}
Query
I store the PROCEDURE in String with this code :
static final String CREATE_PROCEDURE_INITPSEUDOS = "CREATE OR REPLACE PROCEDURE init_pseudos (MaxPseudo INT) BEGIN WHILE MaxPseudo >= 0 DO"
+
" INSERT INTO Pseudos (indexPseudo)" +
" VALUES (MaxPseudo);" +
" SET MaxPseudo = MaxPseudo - 1;" +
" END WHILE;" +
" END init_pseudos;";
Query execution
And I execute the statement with this code :
public static void initBaseDonneePseudos() {
try (Connection connection = DriverManager.getConnection(url, connectionProps);
Statement stmt = connection.createStatement()) {
stmt.execute(RequetesSQL.CREATE_TABLE_PSEUDOS);
stmt.execute(RequetesSQL.CREATE_PROCEDURE_INITPSEUDOS);
stmt.execute(RequetesSQL.CREATE_FUNCTION_RECUPEREPSEUDO);
stmt.execute(RequetesSQL.INIT_TABLE_PSEUDOS);
} catch (SQLException e) {
e.printStackTrace();
}
}
Problem
Test
I execute this test to test statement :
#Nested
class BaseDonneeInteractionTest {
#BeforeEach
public void setUp() {
BaseDonnee.setConnectionHibernate();
}
#Test
void testInitBaseDonnee() {
assertDoesNotThrow(() -> BaseDonnee.initBaseDonneePseudos());
}
}
Error
But I obtain this error
I didn't find the problem of the query, anybody have the solution to solve this ?
The "MySQL Compatibility Mode" doesn't make H2 100% compatible with MySQL. It just changes a few things. The documentation lists them:
Creating indexes in the CREATE TABLE statement is allowed using INDEX(..) or KEY(..). Example: create table test(id int primary key, name varchar(255), key idx_name(name));
When converting a floating point number to an integer, the fractional digits are not truncated, but the value is rounded.
ON DUPLICATE KEY UPDATE is supported in INSERT statements, due to this feature VALUES has special non-standard meaning is some contexts.
INSERT IGNORE is partially supported and may be used to skip rows with duplicate keys if ON DUPLICATE KEY UPDATE is not specified.
REPLACE INTO is partially supported.
Spaces are trimmed from the right side of CHAR values.
REGEXP_REPLACE() uses \ for back-references.
Datetime value functions return the same value within a command.
0x literals are parsed as binary string literals.
Unrelated expressions in ORDER BY clause of DISTINCT queries are allowed.
Some MySQL-specific ALTER TABLE commands are partially supported.
TRUNCATE TABLE restarts next values of generated columns.
If value of an identity column was manually specified, its sequence is updated to generate values after inserted.
NULL value works like DEFAULT value is assignments to identity columns.
Referential constraints don't require an existing primary key or unique constraint on referenced columns and create a unique constraint automatically if such constraint doesn't exist.
LIMIT / OFFSET clauses are supported.
AUTO_INCREMENT clause can be used.
YEAR data type is treated like SMALLINT data type.
GROUP BY clause can contain 1-based positions of expressions from the SELECT list.
Unsafe comparison operators between numeric and boolean values are allowed.
That's all. There is nothing about procedures. As #jccampanero pointed out in the other answer, you must use the syntax specific to H2 if you want to create stored procedures.
The problem is that in H2 there are not explicit procedures or functions as you are trying defining.
For that purpose, H2 allows you to create used defined functions instead. Please, consider reed the appropriate documentation.
Basically, you create a user defined function by declaring an ALIAS for a bunch of Java code.
For example, in your use case, your CREATE_PROCEDURE_INITPSEUDOS could look similar to this:
CREATE ALIAS INIT_PSEUDOS AS $$
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
#CODE
void init_pseudos(final Connection conn, final int maxPseudo) throws SQLException {
try (Statement stmt = conn.createStatement()) {
while (maxPseudo >= 0) do {
stmt.execute("INSERT INTO Pseudos (indexPseudo) VALUES (MaxPseudo);");
maxPseudo = maxPseudo - 1;
}
}
}
$$;
Note the following:
As I said, you define a user defined function as Java code. That Java code should be enclosed between two $$ delimiters.
Although I included explicitly some imports, you can use any class in the java.util or java.sql packages in your code. If you want to included explicitly some imports, or if you require classes from other packages than the mentioned, the corresponding imports should be provided right after the first $$ token. In addition, you need to include #CODE the signal H2 where your imports end and your actual Java method starts.
If you need a reference to a Connection to the database in your code, it should be the first argument of your method.
Prefer to raise and not hide exceptions: it will allow your transactions to be committed or rollbacked as a whole appropriately.
You can invoke such a function as usual:
CALL INIT_PSEUDOS (5);
Please, provide the appropriate value for the maxPseudo argument.
Please, consider the provided code as just an example of use: you can improve the code in different ways, like using PreparedStatements instead of Statements for efficiency purposes, checking parameters for nullability, etcetera.
Using H2 as a test database product
Historically, H2 has been used a lot as a test replacement for the actual production database product. But this means you're limiting yourself to the least common denominator between H2 and MySQL, in your case. Including, as others pointed out, the lack of support for stored procedures. You could re-implement all the stored procedures in H2 (very tedious and error prone), or, you could just use testcontainers and run actual integration tests on MySQL directly.
I really think that using H2 as an integration test database is an outdated concept as I've shown in this blog post (unless you're also using H2 in production). You'll be much happier developing and testing everything against MySQL directly!
Using recursive SQL instead
You don't really need that procedure, I think? You probably wrote it to avoid too many round trips to the database for that loop. But you could batch the inserts or generate the following recursive SQL:
INSERT INTO Pseudos (indexPseudo)
WITH RECURSIVE
p (i) AS (
SELECT MaxPseudo
UNION ALL
SELECT i - 1 FROM p WHERE i >= 0
)
SELECT i FROM p;
Now there's no more need to place this in a procedure, you can run the query directly.
Translating your procedure to H2
Just to be complete, for translation of simple procedural logic, jOOQ would offer the feature transparently. You can try it online, here. It's probably overkill, I recommend the other approaches, but perhaps worth a try.
Disclaimer: I work for the company behind jOOQ.

How to replace a string in a string with integer type in java?

I have a requirement. The technology is quite old doesn't support spring at all . It is pure java application with jdbc connection.
Requirement is :
Suppose
select * from employee where empid = <<empid>> and designation = 'Doctor'
I am trying to replace <> with actual int value in java . How I can do it ?
String query = "select * from employee where empid = <<empid>> and designation = 'Doctor'";
if(query.contains("<<empid>>"))
/// Here I want to replace <<empid>> with actual int value in java
Any leads will be helpful
The code you didn't paste, that actually executes the SQL is either [A] a massive security leak that needs serious rewrites, or [B] is using PreparedStatement.
Here's the problem: SQL injection. Creating the SQL string by mixing a template or a bunch of string constants together with a bunch of user input is a security leak. For example, if you try to make SELECT * FROM users WHERE email = 'foo#bar.com' by e.g. String sql = "SELECT * FROM users WHERE email = '" + email + "'";, the problem is, what if the user puts in the web form, in the 'email' field: whatever#foo.com'; DROP TABLE users CASCADE; EXEC 'FORMAT C: /y /force'; --? Then the SQL becomes:
SELECT * FROM users WHERE email = 'whatever#foo.com'; DROP TABLE users CASCADE; EXEC 'FORMAT C: /y /force'; --';
That is legal SQL and you really, really, really don't want your DB engine to execute it.
Each DB engine has its own ideas on what's actually legal, and may do crazy things such as treating curly quotes as real quotes, etc. So, there is no feasible blacklist or whitelist technology you can think of that will properly cover all the bases: You need to ask your DB engine to do this for you, you can't fix this hole yourself.
Java supports this, via java.sql.PreparedStatement. You instead always pass a fully constant SQL string to the engine, and then fill in the blanks, so to speak:
PreparedStatement ps = con.prepareStatement("SELECT * FROM users WHERE email = ?");
ps.setString(1, "foo#whatever.com");
ps.query();
That's how you do it (and add try-with-resources just like you should already be doing here; statements and resultsets are resources you must always close). Even if you call .setString(1, "foo#whatever.com'; DROP TABLE users CASCADE; --"), then it'll simply look for a row in the database that has that mouthful in the email field. It will not delete the entire users table. Security hole eliminated (and this is the only feasible way to eliminate it).
So, check out that code. Is it using preparedstatement? In that case, well, one way or another that code needs to be calling:
ps.setInt(1, 999);
Where ps is the PreparedStatement object created with connection.prepareStatement(...) where ... is either an SQL constant or at least your input string where the <<empid>> was replaced with a question mark and never with any string input from an untrusted source. The 1 in ps.setInt(1, 999) is the position of the question mark (1 = the first question becomes 999), and the 999 is your actual number. It may look like:
if (input instanceof String) {
ps.setString(idx++, (String) input);
} else if (input instanceof Integer) {
ps.setInt(idx++, ((Integer) input).intValue());
} ...
etcetera. If you don't see that, find the setInt invoke and figure out how to get there. If you don't see any setInt, then what you want is not possible without making some updates to this code.
If you don't even see PreparedStatement anywhere in the code, oh dear! Take that server offline right now, research if a security leak has occurred, if this server stored european data you have 72 hours to notify all users if it has or you can't reasonably figure out e.g. by inspecting logs that it hasn't, or you're in breach of the GDPR. Then rewrite that part using PreparedStatement to solve the problem.

How to prevent SQL injection when dealing with dynamic table/column names?

I am using jdbc PreparedStatement for data insertion.
Statement stmt = conn.prepareStatement(
"INESRT INTO" + tablename+ "("+columnString+") VALUES (?,?,?)");
tablename and columnString are something that is dynamically generated.
I've tried to parameterise tablename and columnString but they will just resolve to something like 'tablename' which will violate the syntax.
I've found somewhere online that suggest me to lookup the database to check for valid tablename/columnString, and cache it somewhere(a Hashset perhaps) for another query, but I'm looking for better performance/ quick hack that will solve the issue, perhaps a string validator/ regex that will do the trick.
Have anyone came across this issue and how do you solve it?
I am not a java-guy, so, only a theory.
You can either format dynamically added identifiers or white-list them.
Second option is way better. Because
most developers aren't familiar enough with identifiers to format them correctly. Say, to quote an identifier, which is offered in the first comment, won't make it protected at all.
there could be another attack vector, not entirely an injection, but similar: imagine there is a column in your table, an ordinary user isn't allowed to - say, called "admin". With dynamically built columnString using data coming from the client side, it's piece of cake to forge a privilege escalation.
Thus, to list all the possible (and allowed) variants in your code beforehand, and then to verify entered value against it, would be the best.
As of columnString - is consists of separate column names. Thus, to protect it, one have to verify each separate column name against a white list, and then assemble a final columnString from them.
Create a method that generates the sql string for you:
private static final String template = "insert into %s (%s) values (%s)";
private String buildStmt(String tblName, String ... colNames) {
StringJoiner colNamesJoiner = new StringJoiner(",");
StringJoiner paramsJoiner = new StringJoiner(",");
Arrays.stream(colNames).forEach(colName -> {
colNamesJoiner.add(colName);
paramsJoiner.add("?");
});
return String.format(template, tblName, colNamesJoiner.toString(), paramsJoiner.toString());
}
Then use it...
Statement stmt = conn.prepareStatement(buildStmt(tablename, [your column names]));
As an elaboration on #Anders' answer, don't use the input parameter as the name directly, but keep a properties file (or database table) that maps a set of allowed inputs to actual table names.
That way any invalid name will not lead to valid SQL (and can be caught before any SQL is generated) AND the actual names are never known outside the application, thus making it far harder to guess what would be valid SQL statements.
I think, the best approach is to get table and columns names from database or other non user input, and use parameters in prepared statement for the rest.
There are multiple solutions we can apply.
1) White List Input Validation
String tableName;
switch(PARAM):
case "Value1": tableName = "fooTable";
break;
case "Value2": tableName = "barTable";
break;
...
default : throw new InputValidationException("unexpected value provided for table name");
By doing this input validation on tableName, will allows only specified tables in the query, so it will prevents sql injection attack.
2) Bind your dynamic columnName(s) or tableName(s) with special characters as shown below
eg:
For Mysql : use back codes (`)
Select `columnName ` from `tableName `;
For MSSQL : Use double codes(" or [ ] )
select "columnName" from "tableName"; or
select [columnName] from [tableName];
Note: Before doing this you should sanitize your data with this special characters ( `, " , [ , ] )

Getting MySQLSyntaxErrorException?

I have this code :
String check="SELECT COUNT(*) as check FROM recordstudent WHERE STUDENT_ID="+T_STUDENT_ID+" AND COURSE_ID="+T_COURSE_ID+" AND PACKAGE_ID="+T_PACKAGE_ID+" AND ACTIVITY_ID="+T_ACTIVITY_ID+" AND DATE="+T_DATE+ ";";
rs=myStmt.executeQuery(check);
int ch=0;
while(rs.next()){
ch=Integer.parseInt(rs.getString("check"));
}
if(ch==0)
{
String insertRecord="insert into recordstudent"+
"(STUDENT_ID,COURSE_ID,PACKAGE_ID,ACTIVITY_ID,TEST_NAME,DATE,SCORE,TOTAL_MARKS,PERCENTAGE,CORRECT_ANSWER,TOTAL_QUESTIONS,STUDENT_NAME,SCORE_PER_DIVISION,ATTEMPTS)"+
"VALUES("+
"'"+T_STUDENT_ID+"',"+
"'"+T_COURSE_ID+"',"+
"'"+T_PACKAGE_ID+"',"+
"'"+T_ACTIVITY_ID+"',"+
"'"+T_TEST_NAME+"',"+
"'"+T_DATE+"',"+
"'"+T_SCORE+"',"+
"'"+T_TOTAL_MARKS+"',"+
"'"+T_PERCENTAGE+"',"+
"'"+T_CORRECT_ANSWERS+"',"+
"'"+T_TOTAL_QUESTIONS+"',"+
"'"+T_STUDENT_NAME+"',"+
"'"+T_SCORE_PER_DIVISION+"',"+
"'"+t+"'"
+");";
myStmt.execute(insertRecord);
}
This snippet should insert the data in database only if the ch=0 .But I am getting this error:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
You have an error in your SQL syntax; check the manual that corresponds
to your MySQL server version for the right syntax to use near
'check FROM recordstudent WHERE STUDENT_ID=11 AND COURSE_ID=2 AND PACKAGE_ID=11 A'
at line 1
Can Anyone help me and solve my problem ?
Fundamentally: don't build your SQL this way. I notice that you've put quotes round the values in the "insert" SQL statement - but not in the "select" one. That's the start of the problem - but you shouldn't be including values like this in your SQL to start with. You should use parameterized SQL via PreparedStatement, and set values for the parameters. Benefits:
You can see your actual SQL more easily, so you'll be able to spot syntax errors. (This is basically keeping your code separate from your data.)
(Very important) You won't be open to SQL injection attacks
You won't need to worry about conversion issues for numbers, dates and times etc
There are other problems in your SQL (such as spaces and check being a reserved word in MySQL), but the very first thing you should fix is how you use values. Until you've done that, your code is inviting security problems.
(You should then start using more conventional variable names than T_STUDENT_NAME etc, but that's a different matter.)
check is a reserved word. Surround it with backticks: `check`
Try this
SELECT COUNT(*) as 'check' FROM recordstudent....
instead of
SELECT COUNT(*) as check FROM recordstudent....
I think check is a keyword

Cleanest way to build an SQL string in Java

I want to build an SQL string to do database manipulation (updates, deletes, inserts, selects, that sort of thing) - instead of the awful string concat method using millions of "+"'s and quotes which is unreadable at best - there must be a better way.
I did think of using MessageFormat - but its supposed to be used for user messages, although I think it would do a reasonable job - but I guess there should be something more aligned to SQL type operations in the java sql libraries.
Would Groovy be any good?
First of all consider using query parameters in prepared statements:
PreparedStatement stm = c.prepareStatement("UPDATE user_table SET name=? WHERE id=?");
stm.setString(1, "the name");
stm.setInt(2, 345);
stm.executeUpdate();
The other thing that can be done is to keep all queries in properties file. For example
in a queries.properties file can place the above query:
update_query=UPDATE user_table SET name=? WHERE id=?
Then with the help of a simple utility class:
public class Queries {
private static final String propFileName = "queries.properties";
private static Properties props;
public static Properties getQueries() throws SQLException {
InputStream is =
Queries.class.getResourceAsStream("/" + propFileName);
if (is == null){
throw new SQLException("Unable to load property file: " + propFileName);
}
//singleton
if(props == null){
props = new Properties();
try {
props.load(is);
} catch (IOException e) {
throw new SQLException("Unable to load property file: " + propFileName + "\n" + e.getMessage());
}
}
return props;
}
public static String getQuery(String query) throws SQLException{
return getQueries().getProperty(query);
}
}
you might use your queries as follows:
PreparedStatement stm = c.prepareStatement(Queries.getQuery("update_query"));
This is a rather simple solution, but works well.
For arbitrary SQL, use jOOQ. jOOQ currently supports SELECT, INSERT, UPDATE, DELETE, TRUNCATE, and MERGE. You can create SQL like this:
String sql1 = DSL.using(SQLDialect.MYSQL)
.select(A, B, C)
.from(MY_TABLE)
.where(A.equal(5))
.and(B.greaterThan(8))
.getSQL();
String sql2 = DSL.using(SQLDialect.MYSQL)
.insertInto(MY_TABLE)
.values(A, 1)
.values(B, 2)
.getSQL();
String sql3 = DSL.using(SQLDialect.MYSQL)
.update(MY_TABLE)
.set(A, 1)
.set(B, 2)
.where(C.greaterThan(5))
.getSQL();
Instead of obtaining the SQL string, you could also just execute it, using jOOQ. See
http://www.jooq.org
(Disclaimer: I work for the company behind jOOQ)
One technology you should consider is SQLJ - a way to embed SQL statements directly in Java. As a simple example, you might have the following in a file called TestQueries.sqlj:
public class TestQueries
{
public String getUsername(int id)
{
String username;
#sql
{
select username into :username
from users
where pkey = :id
};
return username;
}
}
There is an additional precompile step which takes your .sqlj files and translates them into pure Java - in short, it looks for the special blocks delimited with
#sql
{
...
}
and turns them into JDBC calls. There are several key benefits to using SQLJ:
completely abstracts away the JDBC layer - programmers only need to think about Java and SQL
the translator can be made to check your queries for syntax etc. against the database at compile time
ability to directly bind Java variables in queries using the ":" prefix
There are implementations of the translator around for most of the major database vendors, so you should be able to find everything you need easily.
I am wondering if you are after something like Squiggle (GitHub). Also something very useful is jDBI. It won't help you with the queries though.
I would have a look at Spring JDBC. I use it whenever I need to execute SQLs programatically. Example:
int countOfActorsNamedJoe
= jdbcTemplate.queryForInt("select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});
It's really great for any kind of sql execution, especially querying; it will help you map resultsets to objects, without adding the complexity of a complete ORM.
I tend to use Spring's Named JDBC Parameters so I can write a standard string like "select * from blah where colX=':someValue'"; I think that's pretty readable.
An alternative would be to supply the string in a separate .sql file and read the contents in using a utility method.
Oh, also worth having a look at Squill: https://squill.dev.java.net/docs/tutorial.html
I second the recommendations for using an ORM like Hibernate. However, there are certainly situations where that doesn't work, so I'll take this opportunity to tout some stuff that i've helped to write: SqlBuilder is a java library for dynamically building sql statements using the "builder" style. it's fairly powerful and fairly flexible.
I have been working on a Java servlet application that needs to construct very dynamic SQL statements for adhoc reporting purposes. The basic function of the app is to feed a bunch of named HTTP request parameters into a pre-coded query, and generate a nicely formatted table of output. I used Spring MVC and the dependency injection framework to store all of my SQL queries in XML files and load them into the reporting application, along with the table formatting information. Eventually, the reporting requirements became more complicated than the capabilities of the existing parameter mapping frameworks and I had to write my own. It was an interesting exercise in development and produced a framework for parameter mapping much more robust than anything else I could find.
The new parameter mappings looked as such:
select app.name as "App",
${optional(" app.owner as "Owner", "):showOwner}
sv.name as "Server", sum(act.trans_ct) as "Trans"
from activity_records act, servers sv, applications app
where act.server_id = sv.id
and act.app_id = app.id
and sv.id = ${integer(0,50):serverId}
and app.id in ${integerList(50):appId}
group by app.name, ${optional(" app.owner, "):showOwner} sv.name
order by app.name, sv.name
The beauty of the resulting framework was that it could process HTTP request parameters directly into the query with proper type checking and limit checking. No extra mappings required for input validation. In the example query above, the parameter named serverId
would be checked to make sure it could cast to an integer and was in the range of 0-50. The parameter appId would be processed as an array of integers, with a length limit of 50. If the field showOwner is present and set to "true", the bits of SQL in the quotes will be added to the generated query for the optional field mappings. field Several more parameter type mappings are available including optional segments of SQL with further parameter mappings. It allows for as complex of a query mapping as the developer can come up with. It even has controls in the report configuration to determine whether a given query will have the final mappings via a PreparedStatement or simply ran as a pre-built query.
For the sample Http request values:
showOwner: true
serverId: 20
appId: 1,2,3,5,7,11,13
It would produce the following SQL:
select app.name as "App",
app.owner as "Owner",
sv.name as "Server", sum(act.trans_ct) as "Trans"
from activity_records act, servers sv, applications app
where act.server_id = sv.id
and act.app_id = app.id
and sv.id = 20
and app.id in (1,2,3,5,7,11,13)
group by app.name, app.owner, sv.name
order by app.name, sv.name
I really think that Spring or Hibernate or one of those frameworks should offer a more robust mapping mechanism that verifies types, allows for complex data types like arrays and other such features. I wrote my engine for only my purposes, it isn't quite read for general release. It only works with Oracle queries at the moment and all of the code belongs to a big corporation. Someday I may take my ideas and build a new open source framework, but I'm hoping one of the existing big players will take up the challenge.
Why do you want to generate all the sql by hand? Have you looked at an ORM like Hibernate Depending on your project it will probably do at least 95% of what you need, do it in a cleaner way then raw SQL, and if you need to get the last bit of performance you can create the SQL queries that need to be hand tuned.
You can also have a look at MyBatis (www.mybatis.org) . It helps you write SQL statements outside your java code and maps the sql results into your java objects among other things.
Google provides a library called the Room Persitence Library which provides a very clean way of writing SQL for Android Apps, basically an abstraction layer over underlying SQLite Database. Bellow is short code snippet from the official website:
#Dao
public interface UserDao {
#Query("SELECT * FROM user")
List<User> getAll();
#Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
#Query("SELECT * FROM user WHERE first_name LIKE :first AND "
+ "last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
#Insert
void insertAll(User... users);
#Delete
void delete(User user);
}
There are more examples and better documentation in the official docs for the library.
There is also one called MentaBean which is a Java ORM. It has nice features and seems to be pretty simple way of writing SQL.
Read an XML file.
You can read it from an XML file. Its easy to maintain and work with.
There are standard STaX, DOM, SAX parsers available out there to make it few lines of code in java.
Do more with attributes
You can have some semantic information with attributes on the tag to help do more with the SQL. This can be the method name or query type or anything that helps you code less.
Maintaince
You can put the xml outside the jar and easily maintain it. Same benefits as a properties file.
Conversion
XML is extensible and easily convertible to other formats.
Use Case
Metamug uses xml to configure REST resource files with sql.
If you put the SQL strings in a properties file and then read that in you can keep the SQL strings in a plain text file.
That doesn't solve the SQL type issues, but at least it makes copying&pasting from TOAD or sqlplus much easier.
How do you get string concatenation, aside from long SQL strings in PreparedStatements (that you could easily provide in a text file and load as a resource anyway) that you break over several lines?
You aren't creating SQL strings directly are you? That's the biggest no-no in programming. Please use PreparedStatements, and supply the data as parameters. It reduces the chance of SQL Injection vastly.

Categories