SQLite and Android Exception - android

I am facing problem in android application i want to create database with following script.
CREATE TABLE IF NOT EXISTS events (
_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
source_device_id INT,
timestamp INT NOT NULL,
processed BOOLEAN DEFAULT FALSE,
event_type TINYINT NOT NULL,
payload BLOB);
CREATE INDEX IF NOT EXISTS events_unprocessed ON events (processed, _id);
and my android code is
public void onCreate(SQLiteDatabase db) {
InputStream schemaStream = context.getResources().openRawResource(R.raw.logdb_schema);
Scanner schemaScanner = new Scanner(schemaStream, "UTF-8");
schemaScanner.useDelimiter(";");
Log.i(TAG, "Creating database");
try {
db.beginTransaction();
while (schemaScanner.hasNext()) {
String statement = schemaScanner.next();
Log.d(TAG, "Creating database: " + statement);
db.execSQL(statement);
}
db.setTransactionSuccessful();
}
finally {
db.endTransaction();
}
}
Its not working its generating run-time exception:
android.database.sqlite.SQLiteException: not an error:

I had this problem because of whitespace after the last semicolon in my schema. My java code was executing that whitespace as a separate query.
On Froyo it complains, on Ice Cream Sandwich it doesn't cause a problem.

My guess would that you are using a BOOLEAN & TINYINT type which are not supported. You need to use INTEGER instead

Related

Android SQLite check if table exist [duplicate]

I have an android app that needs to check if there's already a record in the database, and if not, process some things and eventually insert it, and simply read the data from the database if the data does exist. I'm using a subclass of SQLiteOpenHelper to create and get a rewritable instance of SQLiteDatabase, which I thought automatically took care of creating the table if it didn't already exist (since the code to do that is in the onCreate(...) method).
However, when the table does NOT yet exist, and the first method ran upon the SQLiteDatabase object I have is a call to query(...), my logcat shows an error of "I/Database(26434): sqlite returned: error code = 1, msg = no such table: appdata", and sure enough, the appdata table isn't being created.
Any ideas on why?
I'm looking for either a method to test if the table exists (because if it doesn't, the data's certainly not in it, and I don't need to read it until I write to it, which seems to create the table properly), or a way to make sure that it gets created, and is just empty, in time for that first call to query(...)
EDIT
This was posted after the two answers below:
I think I may have found the problem. I for some reason decided that a different SQLiteOpenHelper was supposed to be created for each table, even though both access the same database file. I think refactoring that code to only use one OpenHelper, and creating both tables inside it's onCreate may work better...
Try this one:
public boolean isTableExists(String tableName, boolean openDb) {
if(openDb) {
if(mDatabase == null || !mDatabase.isOpen()) {
mDatabase = getReadableDatabase();
}
if(!mDatabase.isReadOnly()) {
mDatabase.close();
mDatabase = getReadableDatabase();
}
}
String query = "select DISTINCT tbl_name from sqlite_master where tbl_name = '"+tableName+"'";
try (Cursor cursor = mDatabase.rawQuery(query, null)) {
if(cursor!=null) {
if(cursor.getCount()>0) {
return true;
}
}
return false;
}
}
I know nothing about the Android SQLite API, but if you're able to talk to it in SQL directly, you can do this:
create table if not exists mytable (col1 type, col2 type);
Which will ensure that the table is always created and not throw any errors if it already existed.
Although there are already a lot of good answers to this question, I came up with another solution that I think is more simple. Surround your query with a try block and the following catch:
catch (SQLiteException e){
if (e.getMessage().contains("no such table")){
Log.e(TAG, "Creating table " + TABLE_NAME + "because it doesn't exist!" );
// create table
// re-run query, etc.
}
}
It worked for me!
This is what I did:
/* open database, if doesn't exist, create it */
SQLiteDatabase mDatabase = openOrCreateDatabase("exampleDb.db", SQLiteDatabase.CREATE_IF_NECESSARY,null);
Cursor c = null;
boolean tableExists = false;
/* get cursor on it */
try
{
c = mDatabase.query("tbl_example", null,
null, null, null, null, null);
tableExists = true;
}
catch (Exception e) {
/* fail */
Log.d(TAG, tblNameIn+" doesn't exist :(((");
}
return tableExists;
Yep, turns out the theory in my edit was right: the problem that was causing the onCreate method not to run, was the fact that SQLiteOpenHelper objects should refer to databases, and not have a separate one for each table. Packing both tables into one SQLiteOpenHelper solved the problem.
// #param db, readable database from SQLiteOpenHelper
public boolean doesTableExist(SQLiteDatabase db, String tableName) {
Cursor cursor = db.rawQuery("select DISTINCT tbl_name from sqlite_master where tbl_name = '" + tableName + "'", null);
if (cursor != null) {
if (cursor.getCount() > 0) {
cursor.close();
return true;
}
cursor.close();
}
return false;
}
sqlite maintains sqlite_master table containing information of all tables and indexes in database.
So here we are simply running SELECT command on it, we'll get cursor having count 1 if table exists.
You mentioned that you've created an class that extends SQLiteOpenHelper and implemented the onCreate method. Are you making sure that you're performing all your database acquire calls with that class? You should only be getting SQLiteDatabase objects via the SQLiteOpenHelper#getWritableDatabase and getReadableDatabase otherwise the onCreate method will not be called when necessary. If you are doing that already check and see if th SQLiteOpenHelper#onUpgrade method is being called instead. If so, then the database version number was changed at some point in time but the table was never created properly when that happened.
As an aside, you can force the recreation of the database by making sure all connections to it are closed and calling Context#deleteDatabase and then using the SQLiteOpenHelper to give you a new db object.
Kotlin solution, based on what others wrote here:
fun isTableExists(database: SQLiteDatabase, tableName: String): Boolean {
database.rawQuery("select DISTINCT tbl_name from sqlite_master where tbl_name = '$tableName'", null)?.use {
return it.count > 0
} ?: return false
}
public boolean isTableExists(String tableName) {
boolean isExist = false;
Cursor cursor = db.rawQuery("select DISTINCT tbl_name from sqlite_master where tbl_name = '" + tableName + "'", null);
if (cursor != null) {
if (cursor.getCount() > 0) {
isExist = true;
}
cursor.close();
}
return isExist;
}
no such table exists: error is coming because once you create database with one table after that whenever you create table in same database it gives this error.
To solve this error you must have to create new database and inside the onCreate() method you can create multiple table in same database.
Important condition is IF NOT EXISTS to check table is already exist or not in database
like...
String query = "CREATE TABLE IF NOT EXISTS " + TABLE_PLAYER_PHOTO + "("
+ KEY_PLAYER_ID + " TEXT,"
+ KEY_PLAYER_IMAGE + " TEXT)";
db.execSQL(query);
i faced that and deal with it by try catch as simple as that i do what i want in table if it not exist will cause error so catch it by exceptions and create it :)
SQLiteDatabase db=this.getWritableDatabase();
try{
db.execSQL("INSERT INTO o_vacations SELECT * FROM vacations");
db.execSQL("DELETE FROM vacations");
}catch (SQLiteException e){
db.execSQL("create table o_vacations (id integer primary key ,name text ,vacation text,date text,MONTH text)");
db.execSQL("INSERT INTO o_vacations SELECT * FROM vacations");
db.execSQL("DELETE FROM vacations");
}
.....
Toast t = Toast.makeText(context, "try... " , Toast.LENGTH_SHORT);
t.show();
Cursor callInitCheck = db.rawQuery("select count(*) from call", null);
Toast t2a = Toast.makeText(context, "count rows " + callInitCheck.getCount() , Toast.LENGTH_SHORT);
t2a.show();
callInitCheck.moveToNext();
if( Integer.parseInt( callInitCheck.getString(0)) == 0) // if no rows then do
{
// if empty then insert into call
.....

SQLite Update / Replace Table Android

I have an app that gets JSON data from a server. I then put the parsed data into the android SQLite database and use the data as needed. This all works great, however, I am unable to find a method to update the whole table.
The scenario would be that this Json Data feed gets updated every week on the server. I have two Questions:
What am I missing or what is the method for updating the SQLite table? (currently this just duplicates the data)
public void updateTable(Product product){
SQLiteDatabase db = this.getWritableDatabase();
try{
ContentValues values = new ContentValues();
values.put(KEY_TYPE_NAME, product.getmProductTypeName());
// more columns here...
db.update(TABLE_NAME, values, null,null);
db.close();
}catch(Exception e){
Log.e("error:",e + "in updateData method")
}
What is an ideal system for updating the data? Would it be silly and bad practice to just call the method when connected to internet?
Related Code in "Main Activity":
handler = new DBHandler(this);
NetworkUtils utils = new NetworkUtils(MainActivity.this);
if (handler.getProductCount() == 0 && utils.isConnectingToInternet()) {
new JsonDataParse().execute();
}`
Related Code "DBhandler" Activity:
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(DROP_TABLE);
onCreate(db);
}
String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + KEY_TYPE_NAME + " TEXT" + ")"
That is basically my CREATE TABLE String format. I just condensed to because it has 16 columns.
This is the code I added to only delete the stored data only if there was data:
if(handler.getProductCount() == 0) {
}else{
handler.deleteData();
}
Then I just just added the delete the method as suggested:
public void deleteData() {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, "1", null);
}
I'm not sure what you mean by "update the whole table". It sounds to me like you just need to delete the data in the table and then use your current method to add the new data. To delete the contents you can use:
db.delete(TABLE_NAME, "1", null);
Then call your existing method to re-populate the table from the server.
What is an ideal system for updating the data? Would it be silly and bad practice to just call the method when connected to internet?
No it wouldn't be bad practice. That makes sense, as you'll only be able to reach the server if you're connected to the internet anyway.

Insert null in Sqlite table

I am trying to figure how to insert a null value into an SQLite table in Android.
This is the table:
"create table my table (_id integer primary key autoincrement, " +
"deviceAddress text not null unique, " +
"lookUpKey text , " +
"deviceName text , " +
"contactName text , " +
"playerName text , " +
"playerPhoto blob " +
");";
I wanted to use a simple Insert command via execSQL but since one of the values is a blob I can't do it (I think).
So, I am using a standard db.Insert command.
How do I make one of the values null?
If I just skip it in the ContentValues object will it automatically put a null value in the column?
You can use ContentValues.putNull(String key) method.
Yes, you can skip the field in ContentValues and db.insert will set it NULL.
Also you can use the other way:
ContentValues cv = new ContentValues();
cv.putNull("column1");
db.insert("table1", null, cv);
this directrly sets "column1" NULL. Also you can use this way in update statement.
I think you can skip it but you can also put null, just make sure that when you first create the Database, you don't declare the column as "NOT NULL".
In your insert query string command, you can insert null for the value you want to be null. This is C# as I don't know how you set up database connections for Android, but the query would be the same, so I've given it for illustrative purposes I'm sure you could equate to your own:
SQLiteConnection conn = new SQLiteConnection(SQLiteConnString());
// where SQLiteConnString() is a function that returns this string with the path of the SQLite DB file:
// String.Format("Data Source={0};Version=3;New=False;Compress=True;", filePath);
try
{
using (SQLiteCommand cmd = conn.CreateCommand()
{
cmd.CommandText = "INSERT INTO MyTable (SomeColumn) VALUES (null)";
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
// do something with ex.ToString() or ex.Message
}

In android, sqlite text field is retrieved using getBlob, not getString

I am attempting to make an android application with a pre-populated database. When learning about how to go about this, I came across this article http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/ , which basically takes an existing sqlite database and streams it into the correct location on the android device. The data I had was dealt with in ruby, so I grabbed the sqlite gem, and created a database like so.
db = SQLite3::Database.new( "cards.db" )
db.execute("CREATE TABLE android_metadata (locale TEXT DEFAULT \"en_US\")")
db.execute("INSERT INTO android_metadata VALUES (\"en_US\")")
db.execute("
CREATE TABLE #{##card_table_name} (
_id INTEGER PRIMARY KEY,
name TEXT UNIQUE
)")
cards.each do |card|
begin
db.execute("INSERT INTO #{#card_table_name} (_id, name) VALUES (?, ?)",
card.id, card.name)
rescue => e
puts "#{card.name} (#{card.id})"
puts e
end
end
When I go into the database, both the one made from the ruby script, and the one from using adb and examining the database on the emulator, I get this for the schema.
sqlite> .schema
CREATE TABLE Cards (
_id INTEGER PRIMARY KEY,
name TEXT UNIQUE
);
However, when I pull the data back out in my application, getString can't deal with the name, specifically, this block gets into the exception clause, and prints the name successfully within that block
Cursor cursor = myDataBase.query("Cards", new String[] {"_id", "name"}, null, null, null, null, null, "5");
while (cursor.moveToNext()) {
try {
cards.add(new Card(cursor.getInt(0), new String(cursor.getString(1))));
} catch (Exception e) {
byte[] blob = cursor.getBlob(1);
String translated = new String(blob);
Log.i(MagicApp.TAG, "DB retrival blew up on " + cursor.getInt(0) + ", " + blob + " : " + translated);
e.printStackTrace();
}
}
I can deal with that, but it seems like I shouldn't have to do that. Any one else encountered this, or know what I'm doing wrong?

SQLiteDatabase.insertOrThrow doesn't throw but not data is inserted

I'm trying to get familiar with Android and its database API.
I've created a class that inherits from SQLiteOpenHelper and this
is how I create the table in the database
#Override
public void onCreate(SQLiteDatabase db) {
try {
db.execSQL("CREATE TABLE " + FUELS_TABLE_NAME + " ("
+ "_ID INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "DATE_OF_FUELS DATE DEFAULT CURRENT_TIME,"
+ "SELLER_POSITION TEXT DEFAULT 'unknown',"
+ "AMOUNT REAL"
+ ");"
);
} catch (SQLException e) {
Log.e(DATABASE_NAME, e.toString());
}
}
The function used to add data to the DB is the following implemeneted within
the same class is
public void addNewFuel(float amount) {
// Create the content to insert into the database
ContentValues newEntry = new ContentValues();
newEntry.put("amount", amount);
// Get database handler
try {
db = getWritableDatabase();
} catch (SQLException e) {
Log.e(DATABASE_NAME, e.toString());
return;
}
// Begin transaction and insert data
long returnedValue;
db.beginTransaction();
try {
returnedValue = db.insertOrThrow(FUELS_TABLE_NAME, null, newEntry);
Log.v(DATABASE_NAME, "return value " + returnedValue);
} catch (SQLException e) {
Log.e(DATABASE_NAME, e.toString());
} finally {
db.endTransaction();
}
db.close();
}
but apparently no data is added. The returnValue is always 1. The method doesn't throw,
and when I pull out the DB with adb and look at it's content is totally empty.
I just can't understand what I'm missing.
Any suggestion would be appreciated.
Thanks,
S
McStretch's answer is incorrect. getWritableDatabase() does not create a transaction for your code, the quoted line from the docs is referring to transactions being used for the onCreate and onUpgrade methods meaning that you don't need to add transaction code in those methods. You still need add transaction code for any other method that requires transactions.
emitrax's code is not working correctly as db.setTransactionSuccessful() is not being called which means the transaction will be rollbacked by db.endTransaction().
See benritz's answer for the correct solution. This answer is incorrect, but I'm unfortunately not able to delete it since it's an accepted post.
/******* NOT CORRECT!!
Since you're inheriting from SQLiteOpenHelper, your call to getWritableDatabase() already starts a DB transaction. From the SQLiteOpenHelper API:
Transactions are used to make sure the
database is always in a sensible
state.
Thus you don't need to call db.beginTransaction() and db.endTransaction(). Those extraneous transaction calls are messing up your inserts. I plugged the same scenario into my project and found that the same index (6 in my case), was returned when using those transaction methods. When I remove the calls I get my desired results (multiple records inserted).
NOT CORRECT!! *******/

Categories

Resources