oracle jdbc driver reports no primary key columns on a table that has a primary key - oracle

This was reported by HibernateTools Reverse Engineering, but it seems to be true.
oracle jdbc driver reports no primary key columns on a table that has a primary key.
#Test
public void checkTable() throws SQLException, IOException {
System.out.println("in check table");
assertNotNull(conn);
Statement s = conn.createStatement();
ResultSet rset = s.executeQuery("select user from dual");
rset.next();
String username = rset.getString(1);
rset.close();
try {
s.execute("drop table " + username + ".x");
} catch (Exception e) {
// nothing it might not exist
}
s.execute("create table " + username + ".x (y number)");
s.execute("alter table x add constraint x_pk primary key (y)");
DatabaseMetaData meta = conn.getMetaData();
final String[] tableTypes = new String[] { "TABLE", "VIEW" };
ResultSet rs = meta.getTables(null, username, "X",tableTypes);
rs.next();
String table = rs.getString("table_name");
System.out.println("table is " + table);
rs.close();
rs = s.executeQuery("select * from user_constraints where table_name = 'X'");
rs.next();
String type = rs.getString("constraint_type");
assertEquals("P",type); // primary key
rs.close();
rs = meta.getPrimaryKeys(null, username, "X");
rs.next();
logger.info("getting pk");
System.out.print("wtf");
int colCount = 0;
while (rs.next()) {
final String pkName = rs.getString("pk_name");
logger.info("pkName: {}", pkName);
int keySeq = rs.getShort("key_seq"); // TODO should probably be column seq
String columnName = rs.getString("column_name");
logger.warn("seq: {}, columnName: {}, keySeq, columnName");
colCount++;
}
System.out.println("colCount: " + colCount);
assertEquals(1,colCount);
}

Related

Retrieve the Columns and Tables of a Database in Postgres

I am working on a Spring MVC project where I need to get the tables and the attributes of a selected Postgres Database and store them in an array as soon as the page loads.
I have currently written the following ajax call through which am able to retrieve the tables and display under the respective database.
VisualEditor.js
drop: function (e, ui) {
var mouseTop = e.clientY;
var mouseLeft = e.clientX;
var dropElem = ui.draggable.attr('class');
droppedElement = ui.helper.clone();
ui.helper.remove();
$(droppedElement).removeAttr("class");
$(droppedElement).draggable({containment: "container"});
jsPlumb.repaint(ui.helper);
//If the dropped Element is a TABLE then->
if (dropElem == "stream ui-draggable ui-draggable-handle") {
var newAgent = $('<div>');
jsPlumb.addEndpoint(newAgent,connectorProperties);
newAgent.attr('id', i).addClass('streamdrop');
var elemType = "table";
$("#container").addClass("disabledbutton");
$("#toolbox").addClass("disabledbutton");
$('#container').append(newAgent);
$.ajax({
type: "post",
url: "http://localhost:8080/controllers/tables",
cache: false,
success: function(response){
if (response !== "{}"){
var array = response.replace("{", "").replace("}", "");
var index = array.indexOf("[") +1;
var stringval = array.split(":");
var stringval2 = array.substring(index,array.indexOf("]")).split(",");
var db_names = new Array();
var table_names = new Array();
var column_names = new Array();
for(var i = 0 ;i < stringval.length-1 ;i++)
{
db_names[i] = eval(stringval[i]);
if(db_names[i]=="testdb"){
var StreamArray = new Array();
}
var listId = "db"+i;
var dropdownId ="mydrpdown"+i;
table_names[i] = new Array();
$("#lot").append(
"<li onclick='myFunction(\""+dropdownId+"\","+i+","+stringval2.length+")' class='list-group-item dropbtn' id='"+listId+"'> " + db_names[i] +
"</li> "+
"<div id='" + dropdownId +"' class='dropdown-content'> " +
"<a onclick='setDatabase(\""+db_names[i]+"\",\""+listId+"\")'> Make This as Default Database</a>"+
"</div>"
);
$("#databaseID").append(
"<option>" + db_names[i] +"</option>"
);
for(var j=0;j < stringval2.length;j++)
{
/**
* Loading the Predefined Databases and Tables of the Connected DB
*/
var table_id= "tableId"+i+j;
if( eval(stringval2[j]) != null){
table_names[i][j] = eval(stringval2[j]);
if(db_names[i]=="testdb")
{
StreamArray[j] = new Array(4);
StreamArray[j][0] = table_names[i][j];
/**
* table_names array values at the moment are:
* customer,department and students
* So the following ajax call should pass each table name to the listTables
* method in the controller and fetch the respective columns of each table
*/
$.ajax({
type: "post",
url: "http://localhost:8080/controllers/listTables/{tablename}",
data: { tablename: table_names[i][j]} ,
cache: false,
success: function(response){
if (response !== "{}"){
var array = response.replace("{", "").replace("}", "");
var index = array.indexOf("[") +1;
var stringval = array.split(":");
var stringval2 = array.substring(index,array.indexOf("]")).split(",");
var db_names = new Array();
var table_names = new Array();
var column_names = new Array();
for(var i = 0 ;i < stringval.length-1 ;i++){
}
}
}
});
}
$("#lot").append(
"<li class='list-group-item'style = 'display:none' id='"+table_id+"'> "+table_names[i][j]+" </li>");
}
}
$("#lot").append(
"</br>");
array = array.slice(array.indexOf("]") +2);
index = array.indexOf("[") +1;
stringval2 = array.substring(index,array.indexOf("]")).split(",");
}
}
},
error: function(xhr, status, error){
alert("Error while loading the query");
}
});
$("property").show();
$(".toolbox-titlex").show();
$(".panel").show();
I have written 2 ajax calls embedded within to get the table_names in the first go and the column_names following that. But am guessing that this is not a very efficient way. But I am not sure how to get both at the same time.
EditorController.java
#RequestMapping(value= "/tables", method = RequestMethod.POST)
public #ResponseBody
String tables(HttpServletRequest request, HttpServletResponse response)
throws Exception {
Map<String, List<String>> alvalues = new HashMap<String, List<String>>();;
String queryString = request.getParameter("query");
// ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Module.xml");
//CustomerDao customerDAO = (CustomerDao) context.getBean("CustomerDao");
alvalues = customerDAO.getAllTables();
Gson gson = new Gson();
String element = gson.toJson(alvalues);
System.out.println(element);
return element;
}
#RequestMapping(value= "/listTables/{tablename}", method = RequestMethod.POST)
public #ResponseBody
String listTables(HttpServletRequest request, HttpServletResponse response,#PathVariable("tablename") String tablename)
throws Exception {
Map<String, List<String>> alvalues = new HashMap<String, List<String>>();;
String queryString = request.getParameter("query");
alvalues = customerDAO.getAllFields(tablename);
Gson gson = new Gson();
String element = gson.toJson(alvalues);
System.out.println(element);
return element;
}
CustomerDAO.java
public Map<String, List<String>> getAllTables();
public Map<String, List<String>> getAllFields(String tablename);
jdbcCustomerDAO.java
public Map<String, List<String>> getAllTables(){
int k = 1;
Map<String, List<String>> map = new HashMap<String, List<String>>();
ArrayList<String> databases = getAllDatabse();
String sql = "SELECT table_name FROM information_schema.tables WHERE table_schema='public'";
Connection conn = null;
for(int i=0;i<=databases.size();i++)
{
try {
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/"+databases.get(i),"postgres", "123");
PreparedStatement ps = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = ps.executeQuery();
ArrayList<String> alvalues = new ArrayList<String>();
while(rs.next()){
alvalues.add(rs.getString(1));
}
map.put(databases.get(i), alvalues);
rs.beforeFirst();
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
String key = entry.getKey();
List<String> values = entry.getValue();
System.out.println("Key = " + key);
System.out.println("Values = " + values + "n");
}
conn.close();
}
catch(Exception e){
System.out.println(e.getMessage());
}
}
return map;
}
public Map<String, List<String>> getAllFields(String tablename){
int k = 1;
Map<String, List<String>> map = new HashMap<String, List<String>>();
ArrayList<String> databases = getAllDatabse();
String sql = "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '"+tablename+"'";
Connection conn = null;
for(int i=0;i<=databases.size();i++)
{
try {
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/"+databases.get(i),"postgres", "123");
PreparedStatement ps = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = ps.executeQuery();
ArrayList<String> alvalues = new ArrayList<String>();
while(rs.next()){
alvalues.add(rs.getString(1));
}
map.put(databases.get(i), alvalues);
rs.beforeFirst();
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
String key = entry.getKey();
List<String> values = entry.getValue();
System.out.println("Key = " + key);
System.out.println("Values = " + values + "n");
}
conn.close();
}
catch(Exception e){
System.out.println(e.getMessage());
}
}
return map;
}
But am not able to get the column names successfully.
Console Log
According to this, the table_names are successfully retrieved but the column names are empty.
INFO : com.postgres.controllers.HomeController - Welcome home! The client locale is en_US.
postgres
postgreside
testdb
Key = postgres
Values = []n
Key = postgreside
Values = [constraints, users, notes, session, projects, databases, tables, columns, index, checksconstraint, additionalproperties, foreignref, primaryref, referenceproperties, department, person]n
Key = postgres
Values = []n
Key = testdb
Values = [customer, department, students]n
Key = postgreside
Values = [constraints, users, notes, session, projects, databases, tables, columns, index, checksconstraint, additionalproperties, foreignref, primaryref, referenceproperties, department, person]n
Key = postgres
Values = []n
Index: 3, Size: 3
{"testdb":["customer","department","students"],"postgreside":["constraints","users","notes","session","projects","databases","tables","columns","index","checksconstraint","additionalproperties","foreignref","primaryref","referenceproperties","department","person"],"postgres":[]}
postgres
postgreside
testdb
postgres
postgreside
testdb
postgres
postgreside
testdb
Key = postgres
Values = []n
Key = postgres
Values = []n
Key = postgres
Values = []n
Key = postgreside
Values = []n
Key = postgres
Values = []n
Key = postgreside
Values = []n
Key = postgres
Values = []n
Key = postgreside
Values = []n
Key = postgres
Values = []n
Key = testdb
Values = []n
Key = postgreside
Values = []n
Key = postgres
Values = []n
Index: 3, Size: 3
{"testdb":[],"postgreside":[],"postgres":[]}
Key = testdb
Values = []n
Key = postgreside
Values = []n
Key = postgres
Values = []n
Index: 3, Size: 3
{"testdb":[],"postgreside":[],"postgres":[]}
Key = testdb
Values = []n
Key = postgreside
Values = []n
Key = postgres
Values = []n
Index: 3, Size: 3
{"testdb":[],"postgreside":[],"postgres":[]}
I would like to have a single method to retrieve the table names and their attributes/columns and store it in the StreamArray so that I don't need to access the DB everytime I need to refer to the related data.
Any suggestions on how I could get the column names and store it in the StreamArray that I've created under the VisualEditor.js will be highly appreciated.
In the general case, you can have more than one database to deal with, more than one schema, and each table name can appear in more than one schema. In your case, there might be more schemas you need to exclude. Or you might decide that only the schema 'public' is relevant. (Be careful with decisions like that.)
select table_catalog, table_schema, table_name, column_name
from information_schema.columns
where table_catalog = 'your_db_name'
and table_schema <> 'information_schema'
and table_schema <> 'pg_catalog'
order by table_catalog, table_schema, table_name, column_name;

Error while trying to load data into hive table

I was able to create a table into hbase using hive now I'm trying to load data into a hive table then overwrite the data into the hbase table :
public class HiveJdbcClient {
private static String driverName = "org.apache.hadoop.hive.jdbc.HiveDriver";
/**
* #param args
* #throws SQLException
**/
public static void main(String[] args) throws SQLException {
try {
Class.forName(driverName);
} catch (ClassNotFoundException e){
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(1);
}
Connection con = DriverManager.getConnection("jdbc:hive://localhost:10000/default", "", "");
Statement stmt = con.createStatement();
String tableNameHive = "hbase_trades";
String tableNameHbase= "trades";
stmt.executeQuery("drop table " + tableNameHive);
ResultSet res = stmt.executeQuery("create table " + tableNameHive + " (key string, value string) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES (\"hbase.columns.mapping\" = \":key,cf1:val\") TBLPROPERTIES (\"hbase.table.name\" = \"trades\")");
String sql = "show tables '" + tableNameHive + "'";
System.out.println("Running: " + sql);
res = stmt.executeQuery(sql);
if (res.next()) {
System.out.println(res.getString(1));
}
sql = "describe " + tableNameHive;
System.out.println("Running: " + sql);
res = stmt.executeQuery(sql);
while (res.next()) {
System.out.println(res.getString(1) + "\t" + res.getString(2));
}
String filepath = "/tmp/test_hive_server.txt";
sql = "load data local inpath '" + filepath + "' into table " + tableNameHive;
System.out.println("Running: " + sql);
res = stmt.executeQuery(sql);
stmt.executeQuery("insert overwrite " + tableNameHbase+"select * from"+tableNameHive);
}
}
and I get the following error:
Running: load data local inpath '/tmp/test_hive_server.txt' into table hbase_trades
Exception in thread "main" java.sql.SQLException: Query returned non-zero code: 10101, cause: FAILED: SemanticException [Error 10101]: A non-native table cannot be used as target for LOAD
at org.apache.hadoop.hive.jdbc.HiveStatement.executeQuery(HiveStatement.java:194)
at com.palmyra.nosql.HiveJdbcClient.main(HiveJdbcClient.java:53)
could someone tell me what's the problem??

Unable to solve Java form of jdbc query with variables

sql3 = "select avg(eff),min(eff),max(eff) from(select ("+baseParam+"/"+denom+"))as eff from ras)as s"; This is query whose output i want.
When i execute the code i get the error stating check your mysql version for syntax. I am using string to store the name of columns. I want to find the efficienccy with respect to 2000 Job_Render i.e. efficiency for each job_render. But what i get is total efficiency of all job_render. when i use the sql syntax with their direct column names. I have commented that query too for the reference. I want to find efficiency of each job render with respect to their 2000 JOBID. Bottom line is i want to find efficiency of 2000 JOBID each whose formula is Job_Render/LC_Final+LC_Preview. I have stored Job_Render in String baseParam and sum of both LC in String Denom. Please help me out.
public class Efficiency {
static final String DB_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_CONNECTION = "jdbc:mysql://localhost:3306/";
static final String DB_USER = "root";
static final String DB_PASSWORD = "root";
static final String dbName = "raas";
public static void main(String[] args) {
try{
effFunc();
}
catch (Exception q){
q.getMessage();
}
}
static void effFunc() throws ClassNotFoundException,SQLException{
Connection conn = null;
// STEP 2: Register JDBC driver
Class.forName(DB_DRIVER);
// STEP 3: Open a connection
System.out.println("Connecting to a selected database...");
conn = DriverManager.getConnection(DB_CONNECTION + dbName, DB_USER,
DB_PASSWORD);
System.out.println("Connected database successfully...");
String baseParam;
//String[] subParam ;
baseParam= "Job_Render";
String sql3="";
String denom="";
final String[] COL={ "LC_Final","LC_Preview"};
denom = "(" + COL[0] + "+" + COL[1] + ")";
Statement stmt = null;
stmt = conn.createStatement();
// sql3 = "select 'Efficiency' Field,avg(eff),min(eff),max(eff) from(select (Job_Render/(LC_Final+LC_Preview))as eff from ras)as s";
sql3 = "select avg(eff),min(eff),max(eff) from(select ("+baseParam+"/"+denom+"))as eff from ras)as s";
System.out.println(sql3);
//
try{
ResultSet res = stmt.executeQuery(sql3);
//System.out.println(res);
while(res.next()){
// String JobID = res.getString("JobID");
// System.out.println("Job ID : " + JobID);
String col1 = res.getString(1);
System.out.println(col1);
double avg = res.getDouble(2);
System.out.println("Average of eff is:"+avg);
double min = res.getDouble(3);
System.out.println("Min of eff is:"+min);
double max = res.getDouble(4);
System.out.println("Max of eff is:"+max);
}}
catch(Exception e){
e.getStackTrace();
System.out.println(e.getMessage());
}
}}
Your code runs the query sql1 which is the empty string,
String sql1="";
// sql1 = "select * from raas.jobs";
ResultSet res = stmt.executeQuery(sql1); // sql1 = ""
should be
ResultSet res = stmt.executeQuery(sql3);
Edit
Then to get the value(s)
String col1 = res.getString(1);
double avg = res.getDouble(2);
double min = res.getDouble(3);
double max = res.getDouble(4);

Comparing very large List<string> with database table via LINQ to Entities

I have a very large list of strings containing GUIDs and a 100,000+ record table in a database with an Entity Framework model in my app.
What' is the most efficient approach to finding all records in a particular dataset where the GUID List is not present?
The following is performing very slowly:
var list= new List<string> { "1", "2", "3" };
return (from t1 in db.Items
where (!list.Contains(t1.GUID))
When I have a lot of parameters (several hundreds or more) to a query I use bulk insert to temporary table and then join it from main table.
My code looks something like this:
private static DataTable FillDataTable(IEnumerable<int> keys) {
var dataTable = new DataTable("Stage");
dataTable.Locale = CultureInfo.CurrentCulture;
dataTable.Columns.Add("Key", typeof(int));
foreach (var key in keys) {
var row = dataTable.NewRow();
row[0] = key;
dataTable.Rows.Add(row);
}
return dataTable;
}
private static void CreateStageTable(SqlConnection connection, string tableName, DataTable dataTable) {
var sql = new StringBuilder();
sql.AppendLine("CREATE TABLE {StageTableName} ( ");
sql.AppendLine(" Key INT NOT NULL ");
sql.AppendLine(") ");
sql.Replace("{StageTableName}", SqlUtilities.QuoteName(tableName));
using (var command = connection.CreateCommand()) {
command.CommandText = sql.ToString();
command.CommandType = CommandType.Text;
command.ExecuteNonQuery();
}
using (var bulkcopy = new SqlBulkCopy(connection)) {
bulkcopy.DestinationTableName = tableName;
bulkcopy.WriteToServer(dataTable);
}
}
public void DoQuery(IEnumerable<int> keys) {
var dataTable = FillDataTable(keys);
using (var connection = new SqlConnection(_connectionString)) {
connection.Open();
CreateStageTable(connection, "#Stage", dataTable);
string sql = "SELECT x " +
"FROM tbl " +
" LEFT JOIN {StageTableName} AS Stage " +
" ON x.Key = Stage.Key "
"WHERE Stage.Key IS NULL";
...
}
}
Don't use a List, use a HashSet<string>, this will give you O(1) lookup ups instead of O(n).

Spring JdbcTemplate query parameters type error: Invalid column type

I use Spring Jdbc Template that way:
public List<User> getUsersForGrid(int rows, int page, String sidx,
String sord) {
int fromRecord = 0;
int toRecord = 0;
toRecord = page * rows;
fromRecord = (page - 1) * rows;
StringBuilder sqlB = new StringBuilder();
sqlB.append("SELECT user_id, username ");
sqlB.append("FROM users ");
sqlB.append("WHERE :fromRecord <= rownum AND rownum <= :toRecord ");
sqlB.append("ORDER BY %s %s ");
String sql = String.format(sqlB.toString(), sidx, sord);
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("fromRecord", fromRecord);
params.addValue("toRecord", toRecord);
List<Map<String, Object>> rsRows = this.jdbcTemplate.queryForList(sql
.toString(),params);
List<User> users = new ArrayList<User>();
for (Map<String, Object> row : rsRows) {
BigDecimal id = (BigDecimal) row.get("user_id");
String username = (String) row.get("username");
User user = new User(id.intValue(), username);
users.add(user);
}
return users;
}
and get java.sql.SQLException: Invalid column type
sidx is column nate("user_id" for example) sord is asc/desc
When pass no params(execute only
sql.append("SELECT user_id, username ");
sql.append("FROM users ");
) everything is OK.
Update: Works with:
sqlB.append("WHERE ? <= rownum AND rownum <= ? ");
and
this.jdbcTemplate.queryForList(sql.toString(),new Object[]{fromRecord, toRecord});
Seems like problem with Spring MapSqlParameterSource and named parameters. I use Spring 3.1.3
DB is Oracle 11.2
describe users;
Name Null Type
------------------------------ -------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
USER_ID NOT NULL NUMBER
USERNAME NOT NULL VARCHAR2(40)
PASSWORD NOT NULL VARCHAR2(20)
ENABLED NOT NULL NUMBER
I think the problem is with your order by clause,
you are trying to dynamically change your order by clause.
Just try
StringBuilder sql = new StringBuilder();
sql.append("SELECT user_id, username ");
sql.append("FROM users ");
sql.append("WHERE :fromRecord <= rownum AND rownum <= :toRecord ");
sql.append("ORDER BY user_id asc ");
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("fromRecord", fromRecord);
params.addValue("toRecord", toRecord);
If the above works, then instead of using the MapSqlParameterSource for changing the order by clause use something like
StringBuilder sql = new StringBuilder();
sql.append("SELECT user_id, username ");
sql.append("FROM users ");
sql.append("WHERE :fromRecord <= rownum AND rownum <= :toRecord ");
sql.append("ORDER BY %s %s ");
//Format the sql string accordingly
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("fromRecord", fromRecord, Types.INTEGER);
params.addValue("toRecord", toRecord, Types.INTEGER);
Hope it helps.
try this
List<Map> rows = getJdbcTemplate().queryForList(sql);
for (Map row : rows) {
BigDecimal id = (BigDecimal) row.get("user_id");
String username = (String) row.get("username");
User user = new User(id.intValue(), username);
users.add(user);
}
ok try
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("fromRecord", fromRecord);
namedParameters.addValue("toRecord", toRecord);
namedParameters.addValue("sidx", sidx);
namedParameters.addValue("sord", sord);
return this.getNamedParameterJdbcTemplate().query(query,
namedParameters, new UserElementMapper());
public class UserMapper implements RowMapper<User> {
public EmailElement mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
emailElement.setID(rs.getInt("user_id"));
emailElement.setUsernameo(rs.getString("username"));
return user;
}
}

Resources