Android SQLite database is locked when pressing power button (screen off) - java

I'm getting a large amount of information from server and loading them in SQLite database (about 4000 rows). I'm using the following code to insert the info:
String DB_PATH = "/data/data/com.example.app.myapplication/databases/";
String DB_NAME = "mydb.sqlite";
SQLiteDatabase sqdb = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
try {
//Getting info
sqdb.beginTransaction();
String[] all_elements = all.split("_");
for (int j = 0; j < all_elements .length; j++) {
if (all_elements [j].length() >= 1) {
m.setLength(0);
m.append("insert into .....the query");
m.append(");");
sqdb.execSQL(m.toString().replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", ""));
changeProgressMessage("Adding element " + String.valueOf(j + 1) + "/" + String.valueOf(all_elements .length));
}
}
sqdb.setTransactionSuccessful();
sqdb.endTransaction();
}
catch (Exception ex)
{
Log.d("Error",ex.toString());
sqdb.setTransactionSuccessful();
sqdb.endTransaction();
}
The point is, when inserting the info, If I press the power button or the screen is off, The app crashes and I get an error saying that the database is locked.
Please note that I'm using another connection to the SQLite database but I'm closing it before using the second one.
db.openDataBase();
String[] array_elements = array.split("_");
for (int i = 0; i < array_elements .length; i++) {
String Details = "";
if (!array_elements [i].isEmpty() && !array_elements [i].equals("")) {
mbuilder.setLength(0);
mbuilder.append(array_elements [i] + ",'" + helper.getdatetime() + "'");
db.insertelements(mbuilder.toString(), "Element");
changeProgressMessage("Element" + String.valueOf(i + 1) + "/" + String.valueOf(array_elements .length) + " inserted");
}
}
db.close();
Any help please ?

Sorry Guys my bad, I was accessing the database in on resume method, so when turning off the screen then turning on, On resume method was called also the database method inside it which explains the crash.

Related

Writing into Oracle database via Java leading to ORA-00604 and ORA-01000

I've got problems at trying to write data into my oracle table.
So, what I'm trying to do is to receive data from TMDB (tmdb.org) and write those into an Oracle table.
Here's my class where all the magic is happening:
public class Movies3 {
public void execute_to_db() throws SQLException, ClassNotFoundException, RuntimeException {
final String url = "jdbc:oracle:thin:#192.168.XXX.XXX:XXX:XXX";
final String user = "TEST2";
final String password = "XXX";
final String table = "TMDB_TEST";
DatabaseConnect db = new DatabaseConnect();
QueryCreateTable_Movies createtable = new QueryCreateTable_Movies();
try {
db.connect(user, password, url);
ResultSet tablelike = db.processQuery(
"SELECT COUNT(table_name) " + "FROM all_tables " + "WHERE table_name = '" + table + "' ");
PreparedStatement insert_ps = db.prepareStatement("INSERT INTO " + table + " "
+ "(TMDB_ID, IMDB_ID, ORIGINAL_TITLE, TITLE_DE, BUDGET, REVENUE, RELEASE_DATE) "
+ "VALUES (?,?,?,?,?,?,?)");
int tablelike_int = 0;
while (tablelike.next())
tablelike_int = tablelike.getInt(1);
if (tablelike_int == 0)
db.processInsert(createtable.create);
else {
TmdbMovies movies = new TmdbApi("XXX").getMovies();
MovieDb latest_movie = movies.getLatestMovie();
int tmdb_max_id = latest_movie.getId();
try {
int id_exist = 0;
for (int i = 1; i < tmdb_max_id; i++) {
ResultSet id_existq = db
.processQuery("SELECT (tmdb_id) FROM " + table + " WHERE tmdb_id = " + i);
while (id_existq.next())
id_exist = id_existq.getInt(1);
if (id_exist == 0) {
try {
MovieDb movie_name_en = movies.getMovie(i, "en");
MovieDb movie_name_de = movies.getMovie(i, "de");
String original_title = movie_name_en.getOriginalTitle();
String title_de = movie_name_de.getTitle();
String imdb_id = movie_name_en.getImdbID();
int budget_en = (int) movie_name_en.getBudget();
int revenue_en = (int) movie_name_en.getRevenue();
String release_date_en = movie_name_en.getReleaseDate();
insert_ps.setInt(1, i);
insert_ps.setString(2, imdb_id);
insert_ps.setString(3, original_title);
insert_ps.setString(4, title_de);
insert_ps.setInt(5, budget_en);
insert_ps.setInt(6, revenue_en);
insert_ps.setString(7, release_date_en);
insert_ps.executeUpdate();
/** Start Output **/
double percent = (i * 100) / tmdb_max_id;
StringBuilder string = new StringBuilder(140);
int percent_int = (int) percent;
long total = (long) tmdb_max_id;
long current = (long) i;
string.append('\r').append(String.join("",
Collections.nCopies(percent_int == 0 ? 2 : 2 - (int) (Math.log10(percent_int)),
" ")))
.append(String.format(" %d%% [", percent_int))
.append(String.join("", Collections.nCopies((percent_int / 2), "=")))
.append('>')
.append(String.join("",
Collections.nCopies((100 / 2) - (percent_int / 2), " ")))
.append(']')
.append(String.join("",
Collections.nCopies(
(int) (Math.log10(total)) - (int) (Math.log10(current)), " ")))
.append(String.format(" %d/%d | TMDB_ID: %d | Movie: %s", current, total, i,
original_title));
System.out.flush();
System.out.print(string);
/** End Output **/
i++;
tmdb_max_id = latest_movie.getId();
} catch (RuntimeException e) {
continue;
} catch (SQLException sqle) {
System.err.println(sqle + " SQL ERROR at movie with ID" + i);
throw sqle;
} finally {
id_existq.close();
insert_ps.close();
tablelike.close();
}
} else
i++;
}
} catch (SQLException sqle2) {
throw sqle2;
} catch (RuntimeException e2) {
throw e2;
} finally {
insert_ps.close();
tablelike.close();
}
}
db.disconnect();
} catch (SQLException sqle_con) {
throw sqle_con;
}
catch (ClassNotFoundException clnf) {
throw clnf;
} finally {
}
}
}
When executing, I receive ORA-00604 and ORA-01000.
Exception in thread "main" java.sql.SQLException: ORA-00604: Fehler auf rekursiver SQL-Ebene 1
ORA-01000: Maximale Anzahl offener Cursor überschritten
ORA-00604: Fehler auf rekursiver SQL-Ebene 1
ORA-01000: Maximale Anzahl offener Cursor überschritten
ORA-01000: Maximale Anzahl offener Cursor überschritten
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:447)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:951)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:513)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:227)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:195)
at oracle.jdbc.driver.T4CStatement.executeForDescribe(T4CStatement.java:876)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1175)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1296)
at oracle.jdbc.driver.OracleStatement.executeQuery(OracleStatement.java:1498)
at oracle.jdbc.driver.OracleStatementWrapper.executeQuery(OracleStatementWrapper.java:406)
at database.DatabaseConnect.processQuery(DatabaseConnect.java:31)
at tmdb_api_to_db.Movies3.execute_to_db(Movies3.java:75)
at tmdb_api_to_db.Main.main(Main.java:22)
I'm pretty sure, that the problem occurs because I got a fallacy with those try-catch-finally constructions - especially when closing my statements - but can't find my mistake and I simply feeling like a dog chasing its tail...
I'm using Eclipse Neon2 on Java 8 and Oracle 11g.
If there is further information needed, I'd be happy to provide.
Please consider that I'm not very experienced and thus be forgiving, if my question hurts any feelings... :)
The error message tranlated into English says
Maximum number of open cursors exceeded
The problem is that you are leaking cursors. One place where this could happen is in the inner for loop.
When the body of
if (id_exist == 0) {
is not executed, the try / finally where you should be closing the ResultSet is never executed. That will leak a cursor. Eventually, Oracle won't let you open any more ...
I'm going to recommend that you read up on the "try with resources" constructed that has been supported by Java since Java 7.
It allows you to write resource cleanup code that is easier to read AND less error prone.
Also, if you find that you have a method where the majority of the code is indented 9 levels deep. That should be a sign to you that you need to refactor it. Seriously, you don't need to do all of that in a single monolithic method. For a start, refactoring your code will make it easier for you (and everyone else) to understand.

Getting SQLite DB data in 2d array and returning in android

I have the below function which I use to query the SQLite Db, put the retrieved records in to an array and return it back.
public String[][] getrecords(){
Log.i("SENDSERVER", "Get Records Called");
SQLiteDatabase sampleDB = this.getReadableDatabase();
Cursor c = sampleDB.rawQuery("SELECT id,welawa,lati,longi FROM " +
TABLE_LOCATIONS + " LIMIT 5", null);
String[][] aryDB = new String[5][4];
int i = 0;
if (c != null ) {
if (c.moveToFirst()) {
do {
String db_id = c.getString(c.getColumnIndex("id"));
String welawa = c.getString(c.getColumnIndex("welawa"));
String latitude = c.getString(c.getColumnIndex("lati"));
String longitude = c.getString(c.getColumnIndex("longi"));
aryDB[i][0] = db_id;
aryDB[i][1] = welawa;
aryDB[i][2] = latitude;
aryDB[i][3] = longitude;
Log.i("SENDSERVER", "Record Added"); //This doesn't get logged
i++;
}while (c.moveToNext());
}
}
Log.i("SENDSERVER", "Return Records");
return aryDB;
}
I try to retrieve the records and use them as below from my service class.
String aryDB[][] = dbh.getrecords();
Log.i("SENDSERVER", "GET DB RECORDS");
int i = 0;
int id = 0;
String welawa = "";
String lati = "";
String longi = "";
while(i < 5){
id = Integer.parseInt(aryDB[i][0]);
welawa = aryDB[i][1];
lati = aryDB[i][2];
longi = aryDB[i][3];
Log.i("SENDSERVERDB", id + " - " + welawa + " - " + lati + " - " + longi);
i++;
}
For some reason the array is not being returned.
My possible guesses are,
1. The defining of the function is wrong. My intention is to return the array.
2. I am getting the db connection / my retrieval code is wrong.
3. Some thing else that my noob brain can't comprehend.
Your help is greatly appreciated guys.
------EDIT
After adding some more logs the app crashes at
Cursor c = sampleDB.rawQuery("SELECT id,welawa,lati,longi FROM " +
TABLE_LOCATIONS + " LIMIT 5", null);
Any issue in my query?
It was a DB issue. Wrong ColumnName used.
The Cursor never returns null when there is no row which the requested conditions, just return a empty Cursor.
You code still has problem when the rawQuery returns 0 rows, cursor won't be null and do while loop will execute at least once.
So there will be problem on this line when the cursor is empty
c.getString(c.getColumnIndex("id"));
Change your code to this:
c.moveToFirst();
while (c.moveToNext())
{
String db_id = c.getString(c.getColumnIndex("id"));
String welawa = c.getString(c.getColumnIndex("welawa"));
String latitude = c.getString(c.getColumnIndex("lati"));
String longitude = c.getString(c.getColumnIndex("longi"));
aryDB[i][0] = db_id;
aryDB[i][1] = welawa;
aryDB[i][2] = latitude;
aryDB[i][3] = longitude;
Log.i("SENDSERVER", "Record Added"); //This doesn't get logged
i++;
}

Getting Exception Index 1 requested, with a size of 1

I am getting exception while fetching data from database in my android project. I am trying to get value of column index 1 from this line of code String ques=c.getString(1);
And this is the code where i am calling database class and trying to fetch database,
try{
c=db.getText(Integer.toString(subid));
if(c==null)
return;
//if(c.getCount()> 0)
//{
//int max=c.getCount();
//int min=0;
Random rn = new Random();
int randomNum = rn.nextInt(max-1) + rowid;
c.moveToPosition(randomNum);
String ques=c.getString(1);
tv.setText(ques+" ");
cans=c.getString(2);
shuffleArray(ans);
int[] a = new int[4];
int j=0;
for (int i = 0; i < ans.length; i++)
{
a[j]=ans[i];
j++;
}
ans1=c.getString(a[0]);
ans2=c.getString(a[1]);
ans3=c.getString(a[2]);
ans4=c.getString(a[3]);
rb1.setText(ans1);
rb2.setText(ans2);
rb3.setText(ans3);
rb4.setText(ans4);
}
catch(Exception e)
{
Toast.makeText(getApplicationContext(), e.getMessage()+"exception", Toast.LENGTH_LONG).show();
}
Snap shot of my database content,
this is my database class,
public Cursor getText(String subId) throws SQLException //here it'll get all rows of subId=1 or whatever the value of subId
{
Cursor mCursor = db.query(true, DATABASE_TABLE, new String[] {
KEY_id, KEY_ques, KEY_correctans, KEY_wrongans1,KEY_wrongans2, KEY_wrongans3},
KEY_subjectid + "=" + " '" + subId + "' " , null,null,null, null,null);
if (mCursor != null)
{
mCursor.moveToFirst();
}
return mCursor;
}
Please help me and hope my question is clear.
Thanks in Advance.
You have an error:
Index 1 requested, with a size of 1
It says, that the size of your cursor is 1 and you know that indexing starts with 0. Therefore, if you write:
String ques = c.getString(1);
you try to get SECOND element, not the first one. If you want to get first element, you have to write:
String ques = c.getString(0);
Remove c.MovetoPosition(randomno);
Instead try this:
c.moveToFirst();
int rw_cnt=c.getCount();
int rndm = ((Math.random())*10000)%rw_cnt); //generates a random no btwn 1 and rw_cnt
for(int i=0;i<rndm;i++) //move cursor rand times
c.moveToNext();
This definitely would be slower than c.moveToPostion(); but it wouldn't make much of a difference unless you have thousands of rows

Getting Exception Index 50 requested, with a size of 50

I am getting exception while fetching data from database. I am trying to get value of column index 1 from this line of code String ques=c.getString(1);
this is the code where i am calling database class and trying to fetch database,
try{
c=db.getText(Integer.toString(subid));
if(c==null)
return;
//if(c.getCount()> 0)
//{
//int max=c.getCount();
//int min=0;
Random rn = new Random();
int randomNum = rn.nextInt(max-1) + rowid;
c.moveToPosition(randomNum);
String ques=c.getString(1);
tv.setText(ques+" ");
cans=c.getString(2);
shuffleArray(ans);
int[] a = new int[4];
int j=0;
for (int i = 0; i < ans.length; i++)
{
a[j]=ans[i];
j++;
}
ans1=c.getString(a[0]);
ans2=c.getString(a[1]);
ans3=c.getString(a[2]);
ans4=c.getString(a[3]);
rb1.setText(ans1);
rb2.setText(ans2);
rb3.setText(ans3);
rb4.setText(ans4);
}
catch(Exception e)
{
Toast.makeText(getApplicationContext(), e.getMessage()+"exception", Toast.LENGTH_LONG).show();
}
Snap shot of my database content,
And this is my database class,
public Cursor getText(String subId) throws SQLException //here it'll get all rows of subId=1 or whatever the value of subId
{
Cursor mCursor = db.query(true, DATABASE_TABLE, new String[] {
KEY_id, KEY_ques, KEY_correctans, KEY_wrongans1,KEY_wrongans2, KEY_wrongans3},
KEY_subjectid + "=" + " '" + subId + "' " , null,null,null, null,null);
if (mCursor != null)
{
mCursor.moveToFirst();
}
return mCursor;
}
As my above details and code, When the value of subId is 1 then it is fetching all the content from the database of subId 1 without any Exception but when i am passing the value of subId=2 then it give CursorIndexOutOfBound: Index 50 requested, with a size of 50 Exception
And when i am passing subId=3 then i am getting Index 49 requested, with a size of 49
Is there any problem in Random number generator or what ?
Actually i am not able to get whats the problem here.
I need help.
Thanks in Advance.
Use space in query " = " actually your column name become "KEY_subjectid=" which is wrong
KEY_subjectid + " =" + " '" + subId + "' " , null,null,null, null,null);
Try generating your random number this way: (I'm assuming c is a Cursor)
int randomNum = rowid + (rn.nextInt() % (c.getCount() - rowid));
Hope this helps :)

Dynamically create print statement in Java

I query a database and get a lot information back that should be presented to the user. In the database I have fields a, b, c, d and e. Now, the user should be able to indicate which of these fields that should be printed on screen (i.e. the user can choose to view only a subset of the data retrieved from the database).
How do I dynamically create a print statement that sometimes prints two of the fields, sometimes four, sometimes three etc. depending on what the user wants?
If all the hard work is already done and you just have a result set to print, then it could be as simple as a succession of calls to System.out.print() for each result and then finish the line with a \n. It can be nested in a FOR loop, so if you have an int with the number of fields to print, just iterate through them.
In a more complicated case when you have a full list where some fields are chosen and others not, then you could use a (slightly) crude method like this:
...
String[] chosenFields = {"Field 1", "Field 2" /*, (et cetera) */};
for (int i = 0; i < numberOfFields; i++)
{
for (int j = 0; j < chosenFields.length; j++)
{
if (fieldsName[i].equals(chosenFields[j]))
System.out.print(fields[i] + " ");
break;
}
}
System.out.println();
...
Sorry about bad indentation; not sure how to sort it on here!
If field names are indeterminate at runtime and you're using Java to execute queries, consider using class ResultSetMetaData to get them.
EDIT:
As an example, here's some of my code which gets all the field names from a table, then creates a tickbox for each, which the user can select or deselect. All the JFrame GUI stuff I've omitted. When the user presses a submit button, the application check each tickbox and constructs an SQL statement to suit the users request.
...
JCheckBox[] jcb;
ResultSetMetaData rsmd;
private void makeCheckBoxes()
{
initConnection(); // Establish connection to MySQL server
try
{
Statement query = connection.createStatement();
ResultSet rs = query.executeQuery("SELECT * FROM client_db;");
rsmd = rs.getMetaData();
noOfColumns = rsmd.getColumnCount();
jcb = new JCheckBox[noOfColumns];
for (int i = 0; i < noOfColumns; i++)
{
jcb[i] = new JCheckBox(rsmd.getColumnName(i + 1));
jpCheckBoxes.add(jcb[i]);
jcb[i].setEnabled(false);
jcbComboBox.addItem(rsmd.getColumnName(i + 1));
}
jcb[0].setSelected(true);
rs.close();
query.close();
connection.close();
}
catch (SQLException e)
{
System.err.println("!> Caught SQLException:\n" + e.getMessage());
System.exit(1);
}
}
...
if (e.getSource() == jbSubmit)
{
String query = "";
initConnection();
if (jtfSearch.getText().isEmpty() == true) // JTextField
{
jtaResults.setText(null); // JTextArea
jtaResults.append("Please enter some search text in the text box above!\n");
return;
}
else
{
int selectedFields;
if (jrbAll.isSelected() == true) // JRadioButton
{
query = "SELECT *";
selectedFields = -1;
}
else
{
query = "SELECT";
selectedFields = 0;
for (int i = 0; i < noOfColumns; i++)
if (jcb[i].isSelected() == true)
{
try
{
if (selectedFields > 0)
query += ",";
query += " " + rsmd.getColumnName(i + 1);
}
catch (SQLException err)
{
System.err.println("!> Caught SQLException:\n" + err.getMessage());
System.exit(1);
}
selectedFields++;
}
}
if (selectedFields == 0)
{
jtaResults.setText(null);
jtaResults.append("No fields were selected!!\n");
return;
}
else
{
query += " FROM client_db WHERE " + jcbComboBox.getSelectedItem() + " LIKE '%" + jtfSearch.getText() + "%'";
if (jcbCurrentClients.isSelected() == true)
query += " AND currentClient LIKE 'y'";
query += ";";
}
}
System.out.println("Query = \"" + query + "\"");
/* Now, print it out in the text area!! */
try
{
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);
ResultSetMetaData rsMetaData = rs.getMetaData();
int columnCount = rsMetaData.getColumnCount();
jtaResults.append("--------------------------------\n");
int noOfResults = 0;
jtaResults.setText(null);
while (rs.next() == true)
{
if (noOfResults > 0)
jtaResults.append("\n");
jtaResults.append("* Search match " + (noOfResults + 1) + ":\n");
for (int i = 0; i < columnCount; i++)
{
jtaResults.append("-> " + rsMetaData.getColumnName(i + 1) + ": " +
rs.getString(i + 1) + "\n");
}
noOfResults++;
}
if (noOfResults == 0)
{
jtaResults.append("No results were returned; please try again with more ambiguous search terms.\n\n");
}
//scroller.setScrollPosition(0, 1048576);
rs.close();
stmt.close();
connection.close();
}
catch (SQLException err)
{
System.err.println("!> Caught SQLException:\n" + err.getMessage());
System.exit(1);
}
}
}
Hopefully this helps. The sustained concatenation to query forms a valid SQL statement based on the fields the user chose. Hopefully a few modifications to this to just print certain fields will help you. The System.out.println() call to print query about two-thirds down is a good place to work from.
The natural way to switch an optional value on or off would be a radiobutton. For 5 fields i.e. an array of 5 radiobuttons.
StringBuffer sb = new StringBuffer (5 * 10);
for (int i = 0; i < 5; ++i)
if (rb[i])
s.append (field[i]).append (" ");
Maybe you're better of only selecting interesting columns from the database? Then a dummy-column is helpful:
sql = new StringBuffer ("SELECT 1 "); // the dummy-column
for (int i = 0; i < 5; ++i)
if (rb[i])
sql.append (", ").append (fieldname[i]);

Categories

Resources