ResultSetMetaData getting default value of column - java

I am Using Oracle database.
I want to get default value assign to column using Java JDBC.
But using ResultSetMetaData does not provide any method to get default value of column.
So please tell me any idea.
Thanks in advance.

You can run this query
Select DATA_DEFAULT from USER_TAB_COLUMNS where TABLE_NAME ='MyTable' and COLUMN_NAME = 'MyColumn'

There is no 'getDefaultValue' method on ResultSetMetaData in Java JDBC that I can find.
However the following query works:
SELECT COLUMN_NAME, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS
where table_name='<tablename>' and COLUMN_DEFAULT is not null
Connect to the db in question, or similarly with the db name querying master.

This answer uses DatabaseMetadata rather than ResultSetMetadata, so technically it does not answer the question posed. However, it appears more reliable than a query and still has long-term value for the community at large:
JDBC is there a way to detect if a column has a default?
Example:
Connection connection = ...;
DatabaseMetaData databaseMetaData = connection.getMetaData();
try (ResultSet resultSet = databaseMetaData.getColumns(null, null, "MyTable", "MyColumn")) {
while (resultSet.next()) {
String defaultValue = resultSet.getString("COLUMN_DEF");
// Do something...
}
}

below function Returns the default value of a column.
call it on your ResultSetMetaData
public java.lang.String getDefaultValue(int columnIndex) // or columnName
throws DriverException
like ResultSetMetaData.getDefaultValue(columnNameOrcolumnIndex)

Related

How to refresh table after con.commit() in java?

I am creating a new register in table MY_TABLE using java and then, I am doing a query to obtain the max(id) of that table. However, Java is obtaining the previous one. I mean:
mybean.store(con)
con.commit();
pstm = con.prepareStatement("SELECT MAX (ID) FROM MY_TABLE");
rs = pstm.executeQuery();
while (rs.next()){
id = rs.getString("ID");
System.out.println("id: " +id);
}
Before con.commit(); the table has the max(ID)=3
After com.commit() the table has the max(ID)=4
But I obtain MAX(ID)=3
Can somebody help me to solve this?
You're doing it; if this is returning the wrong result either your DB doesn't contain what you think it contains, or your DB engine is broken (MySQL is often broken, possibly that's the problem. The fix is to not use mysql), or your code is broken. Your snippet contains an error (no semicolon after the first line), so this isn't a straight paste but a modification; generally you should paste precisely the code that is exhibiting the behaviour you don't understand, because if you edit it or try to simplify it without running the simplification, you may have accidentally removed the very thing that would explain what you're observing.
More generally, if all you want is the ID generated for an auto-increment column, this isn't how you do it. You can use statement's .getGeneratedKeys() method to get at these; you may have to pass in Statement.RETURN_GENERATED_KEYS as part of your executeUpdate call.
You do not need a PreparedStatement if you do not have a parametrized query. I would use Statement in this case.
You do not need while (rs.next()) as your query will return a single value. I would use if (rs.next()).
Your query does not have a field called ID and therefore rs.getString("ID") will throw SQLException. You should use rs.getString(1) or use an alias (e.g. maxId in the example shown below) in the query. Also, you should use getInt instead of getString.
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT MAX(ID) AS maxId FROM MY_TABLE");
int id = Integer.MIN_VALUE;
if (rs.next()) {
id = rs.getInt(1);
//id = rs.getInt("maxId");
}
System.out.println(id);

Teradata JDBC not recognizing PreparedStatement parameter as VARCHAR without quotes

I am using JDBC PreparedStatement to query a Teradata database from a web service. My table has a PHONE_NUMBER column, stored as VARCHAR(10). I have always used PreparedStatement setString() to supply the parameter for this column, like below:
String myPhoneNumber = "5551234567";
String sql = "SELECT * FROM MYTABLE " +
"WHERE PHONE_NUMBER = ? ";
PreparedStatement p_stmt = db.getPreparedStatement(sql);
p_stmt.setString(1, myPhoneNumber);
ResultSet rs = db.executeQuery(p_stmt);
It returns correct results, but I noticed the CPU Teradata is using for this query is quite high. According to the EXPLAIN plan, it appears that Teradata is interpreting the myPhoneNumber parameter as a FLOAT, instead of VARCHAR, and so it has to do a data conversion to compare it to the VARCHAR column PHONE_NUMBER. Here is an excerpt of the EXPLAIN plan:
...
MYDATABASE.MYTABLE.PHONE_NUMBER (FLOAT, FORMAT
'-9.99999999999999E-999'))= 5.55123456700000E 009)
So, I came up with the below, which showed a great improvement in CPU usage (99.86% improvement):
String myPhoneNumber = "5551234567";
String sql = "SELECT * FROM MYTABLE " +
"WHERE PHONE_NUMBER = ''||?||'' ";
PreparedStatement p_stmt = db.getPreparedStatement(sql);
p_stmt.setString(1, myPhoneNumber);
ResultSet rs = db.executeQuery(p_stmt);
So my question is why is this necessary? Shouldn't setString tell JDBC to tell Teradata to expect a String/VARCHAR parameter?
Thanks!
Have you tried String myPhoneNumber = "'5551234567'";
Note -- The inclusion of the single quotes to wrap the value.
If you look at the example in the Teradata manuals here, you will see that a Query Band being set the same way as the OP's first example arrives as expected without single quotes wrapping it. It would seem to me this behavior in the first example of the OP is expected.
EDIT
The sample code provided by Teradata for their JDBC driver is using java.sql.PreparedStatment. With this their example program uses setString without any tricks to provide a string value for an INSERT statement. Sample Code If you are not able to replicate that behavior, I would open an incident with the Teradata GSC.

Java PreparedStatement SQL syntax error [duplicate]

This question already has answers here:
Java PreparedStatement complaining about SQL syntax on execute()
(6 answers)
Closed 6 years ago.
This is a really weird error that only started appearing today. When I use a prepared statement with ? for parameters, I get an error, but when I use it without parameters, it works just fine.
Here is the error-causing code:
String table = "files";
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement prep = conn.prepareStatement("SELECT * FROM ?");
prep.setString(1, table);
ResultSet rs = prep.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("file_name"));
}
This produces the following error:
Exception in thread "main" 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 ''files'' at line 1
Also, changing it to the following works just fine:
String table = "files";
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
PreparedStatement prep = conn.prepareStatement("SELECT * FROM " + table);
ResultSet rs = prep.executeQuery();
while(rs.next()) {
System.out.println(rs.getString("file_name"));
}
This doesn't seem to be making a whole lot of sense. Any ideas?
Tried it on another table and got more weired results.
This works and logs the admin in correctly:
String sql = "SELECT * FROM " + ADMIN_AUTH_TABLE + " WHERE " + column + " = '" + hashedPassword + "'";
PreparedStatement prepared = connection.prepareStatement(sql);
The following doesn't cause errors, but returns a message saying that the password entered is incorrect (it's correct - I double triple checked).
String sql = "SELECT * FROM " + ADMIN_AUTH_TABLE + " WHERE ? = ?";
PreparedStatement prepared = connection.prepareStatement(sql);
prepared.setString(1, column);
prepared.setString(2, hashedPassword);
Got it: use ? for values.
Also, the answer here helped.
Bind parameters cannot be used for identifiers in the SQL statement. Only values can supplied through bind placeholders.
This will work:
SELECT foo FROM bar WHERE id = ?
This will not work, because the table name is an identifier
SELECT foo FROM ? WHERE id = 2
You can't supply a column name, because column names are also identifiers.
A statement like this will run, but it may not do what you think it does.
SELECT ? AS foo FROM bar WHERE ? = 0
If we supply values of 'foo' for both placeholders, the query will actually be equivalent to a query containing two string literals:
SELECT 'foo' AS foo FROM bar WHERE 'foo' = 0
MySQL will run that statement, because it's a valid statement (if the table bar exists and we have privileges on it.) That query will return every row in bar (because the predicate in the WHERE clause evaluates to TRUE, independent of the contents of the table.. And we get returned the constant string foo.
It doesn't matter one whit that the string foo happens to match the name of column in our table.
This restriction has to do with how the SQL optimizer operates. We don't need to delve into all the details of the steps (briefly: parsing tokens, performing syntax check, performing semantics check, determining query plan, and then the actual execution of the query plan.)
So here's the short story: The values for bind parameters are supplied too late in that process. They are not supplied until that final step, the execution of the query plan.
The optimizer needs to know which tables and columns are being referenced at earlier stages... for the semantics check, and for developing a query plan. The tables and columns have to be identified to the optimizer. Bind placeholders are "unknowns" at the time the table names and column names are needed.
(That short story isn't entirely accurate; don't take all of that as gospel. But it does explain the reason that bind parameters can't be used for identifiers, like table names and column names.)
tl;dr
Given the particular statement you're running, the only value that can be passed in as a bind parameter would be the "hashedPassword" value. Everything else in that statement has to be in the SQL string.
For example, something like this would work:
String sqltext = "SELECT * FROM mytable WHERE mycolumn = ?";
PreparedStatement prepared = connection.prepareStatement(sqltext);
prepared.setString(1, hashedPassword);
To make other parts of the SQL statement "dynamic" (like the table name and column name) you'd have to handle that in the Java code (using string concatenation.) The contents of that string would need to end up like the contents of the sqltext string (in my example) when it's passed to the prepareStatement method.
The parameters of PreparedStatement should be applied only in parameters that can be used in conditional clauses. The table name is not the case here.
If you have a select where the table name can be applied in the conditional clause you can do it, otherwise you can not.

Using JDBC to read and update each row

I am able to read each line of a query fine, but I would also like to update a field as they are read.
The following code breaks when I add the two rs.update lines.
Connection con = DriverManager.getConnection(url, user, pass);
stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE)
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
amount = rs.getInt("amount");
username = rs.getString("username");
rs.updateString("processed", "true");
rs.updateRow();
}
It would appear I've found my answer:
[SEVERE] com.mysql.jdbc.NotUpdatable: Result Set not updatable (referenced table has no primary keys).This result set must come from a statement that was created with a result set type of ResultSet.CONCUR_UPDATABLE, the query must select only one table, can not use functions and must select all primary keys from that table. See the JDBC 2.1 API Specification, section 5.6 for more details.
It won't hurt to add primary keys to my database, probably the right way to do it anyway.
I added primary key to my database and it works beautifully.
Thanks!

How can I detect a SQL table's existence in Java?

How can I detect if a certain table exists in a given SQL database in Java?
You can use DatabaseMetaData.getTables() to get information about existing tables.
This method works transparently and is independent of the database engine. I think it queries information schema tables behind the scenes.
Edit:
Here is an example that prints all existing table names.
DatabaseMetaData md = connection.getMetaData();
ResultSet rs = md.getTables(null, null, "%", null);
while (rs.next()) {
System.out.println(rs.getString(3));
}
Use java.sql.DatabaseMetaData.getTables(null, null, YOUR_TABLE, null). If the table exists, you will get a ResultSet with one record.
See DatabaseMetaData.getTables
For ALL ANSI-compliant databases:
(mySQL, SQL Server 2005/2008, Oracle, PostgreSQL, SQLLite, maybe others)
select 1 from information_schema.tables where table_name = #tableName
This is not a language-specific, but a database-specific problem. You'd query the metadata in the database for the existence of that particular object.
In SQL Server for instance:
SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[table]')
AND type in (N'U')
Write a query that queries the table/view that will list the tables (this is different depending on DB vendor). Call that from Java.
Googling information_schema.tables will help a lot.
Depending on the DB, you can do (MySQL)
SHOW TABLES
or (Oracle)
SELECT * FROM user_objects WHERE object_type = 'TABLE'
or another thing for SQL Server. Cycle through the results for MySQL or further filter on the Oracle one.
Why not just see if it is in sysobjects (for SQL Server)?
SELECT [name] FROM [sysobjects] WHERE type = 'U' AND [name] = 'TableName'
There is a JDBC feature, database vendor independent - see [java.sql.DatabaseMetaData#getTables()][1]
You can get the DatabaseMetaData instance by calling java.sql.Connection#getMetaData()
[1]: http://java.sun.com/javase/6/docs/api/java/sql/DatabaseMetaData.html#getTables(java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
This is what worked for me for jdbc:derby:
//Create Staff table if it does not exist yet
String tableName = "STAFF";
boolean exists = conn.getMetaData().getTables(null, null, tableName, null).next();
if(!exists){
s = conn.createStatement();
s.execute("create table staff(lastname varchar(30), firstname varchar(30), position varchar(20),salary double,age int)");
System.out.println("Created table " + tableName);
}
Note that tableName has to be all caps.
For MS Access:
Select Count(*) From MSysObjects
Where type=1 And name='your_table_name_here'

Categories