SQLite database not getting copied (No such a table exists error) - java

I think my database is not getting copied cause my database file in the assets folder is 32KB and the file that shows up in the device file explorer is 12KB. So I tried uploading database file from device file explorer then there was no errors. Please can somebody help me fix this?
This is the error I'm getting
This is my DatabaseHelper class
public class DatabaseAdapter {
DatabaseHelper helper;
SQLiteDatabase db;
List<Contacts> contactsList = new ArrayList<>();
List<Station> stationsList = new ArrayList<>();
List<Tip> tipsList = new ArrayList<>();
public DatabaseAdapter(Context context) {
helper = new DatabaseHelper(context);
db = helper.getWritableDatabase();
}
public List<Contacts> getAllContacts() {
String[] columns = {DatabaseHelper.KEY_NAME, DatabaseHelper.KEY_POSITION, DatabaseHelper.KEY_STATION, DatabaseHelper.KEY_PHONE_NUMBER, DatabaseHelper.KEY_EMAIL};
Cursor cursor = db.query(DatabaseHelper.TABLE_NAME1, columns, null, null, null, null, null, null);
while (cursor.moveToNext()) {
int index2 = cursor.getColumnIndex(DatabaseHelper.KEY_NAME);
String name = cursor.getString(index2);
int index3 = cursor.getColumnIndex(DatabaseHelper.KEY_POSITION);
String position = cursor.getString(index3);
int index4 = cursor.getColumnIndex(DatabaseHelper.KEY_STATION);
String station = cursor.getString(index4);
int index5 = cursor.getColumnIndex(DatabaseHelper.KEY_PHONE_NUMBER);
String phone_number = cursor.getString(index5);
int index6 = cursor.getColumnIndex(DatabaseHelper.KEY_EMAIL);
String email = cursor.getString(index6);
Contacts contact = new Contacts(name, position, station, phone_number, email);
contactsList.add(contact);
}
return contactsList;
}
public List<Station> getAllStations() {
String[] columns = {DatabaseHelper.KEY_S_NAME, DatabaseHelper.KEY_S_ADDRESS, DatabaseHelper.KEY_S_PHONE_NUMBER, DatabaseHelper.KEY_S_TOTAL_FIGHTERS, DatabaseHelper.KEY_S_TOTAL_VEHICLES, DatabaseHelper.KEY_S_LAT, DatabaseHelper.KEY_S_LON};
Cursor cursor = db.query(DatabaseHelper.TABLE_NAME2, columns, null, null, null, null, null, null);
while (cursor.moveToNext()) {
int index1 = cursor.getColumnIndex(DatabaseHelper.KEY_S_NAME);
String name = cursor.getString(index1);
int index2 = cursor.getColumnIndex(DatabaseHelper.KEY_S_ADDRESS);
String address = cursor.getString(index2);
int index3 = cursor.getColumnIndex(DatabaseHelper.KEY_S_PHONE_NUMBER);
String phone_number = cursor.getString(index3);
int index4 = cursor.getColumnIndex(DatabaseHelper.KEY_S_TOTAL_FIGHTERS);
int total_f = cursor.getInt(index4);
int index5 = cursor.getColumnIndex(DatabaseHelper.KEY_S_TOTAL_VEHICLES);
int total_v = cursor.getInt(index5);
int index6 = cursor.getColumnIndex(DatabaseHelper.KEY_S_LAT);
String lat = cursor.getString(index6);
int index7 = cursor.getColumnIndex(DatabaseHelper.KEY_S_LON);
String lon = cursor.getString(index7);
Station station = new Station(name, address, phone_number, total_f, total_v, lat, lon);
stationsList.add(station);
}
return stationsList;
}
public List<Tip> getAllTips() {
String[] columns = {DatabaseHelper.KEY_TIP_TOPIC, DatabaseHelper.KEY_TIP_SUB_TOPIC};
Cursor cursor = db.query(DatabaseHelper.TABLE_NAME3, columns, null, null, null, null, null, null);
while (cursor.moveToNext()) {
int index2 = cursor.getColumnIndex(DatabaseHelper.KEY_TIP_TOPIC);
String topic = cursor.getString(index2);
int index3 = cursor.getColumnIndex(DatabaseHelper.KEY_TIP_SUB_TOPIC);
String sub_topic = cursor.getString(index3);
Tip tip = new Tip(topic, sub_topic);
tipsList.add(tip);
}
return tipsList;
}
private static class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "Firefighters.db";
private static final String TABLE_NAME1 = "contact_list";
private static final String TABLE_NAME2 = "station_list";
private static final String TABLE_NAME3 = "tips";
private static final int DATABASE_VERSION = 2;
private static final String KEY_NAME = "name";
private static final String KEY_POSITION = "position";
private static final String KEY_STATION = "station";
private static final String KEY_PHONE_NUMBER = "phone_number";
private static final String KEY_EMAIL = "email";
private static final String KEY_S_NAME = "name";
private static final String KEY_S_ADDRESS = "address";
private static final String KEY_S_PHONE_NUMBER = "phone_number";
private static final String KEY_S_TOTAL_FIGHTERS = "total_fighters";
private static final String KEY_S_TOTAL_VEHICLES = "total_vehicles";
private static final String KEY_S_LAT = "lat";
private static final String KEY_S_LON = "long";
private static final String KEY_TIP_TOPIC = "tip_topic";
private static final String KEY_TIP_SUB_TOPIC = "tip_sub_topic";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
db.disableWriteAheadLogging();
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
}
This is my database copy class
public class PreCreateDB {
public static void copyDB(Context context){
try{
String destPath = "/data/data/"+ context.getPackageName()
+ "/databases";
File f = new File(destPath);
if(!f.exists()){
f.mkdir();
rawCopy(context.getAssets().open("Firefighters.db"), new FileOutputStream(destPath + "/Firefighters.db"));
}
} catch (IOException e){
e.printStackTrace();
}
}
public static void rawCopy(InputStream inputStream, OutputStream outputStream) throws IOException{
byte[] buffer = new byte[1024];
int length;
while((length = inputStream.read(buffer)) > 0){
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
}
}
And this is how I call them
PreCreateDB.copyDB(mContext);
databaseAdapter = new DatabaseAdapter(mContext);
stationsList = databaseAdapter.getAllStations();
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(mContext);
recyclerView.setLayoutManager(layoutManager);
stationsAdapter = new StationsAdapter(mContext, stationsList, recyclerView);
recyclerView.setAdapter(stationsAdapter);
-- Solution that worked for me --
I tried everything and none of them seem to work so then I tried this SQLiteAssetHelper library and it worked! All I did was extend Database helper with SQLiteAssetHelper. This is my Database helper now.
private static class DatabaseHelper extends SQLiteAssetHelper {
private static final String DATABASE_NAME = "Firefighters.db";
private static final String TABLE_NAME1 = "contact_list";
private static final String TABLE_NAME2 = "station_list";
private static final String TABLE_NAME3 = "tips";
private static final int DATABASE_VERSION = 2;
private static final String KEY_NAME = "name";
private static final String KEY_POSITION = "position";
private static final String KEY_STATION = "station";
private static final String KEY_PHONE_NUMBER = "phone_number";
private static final String KEY_EMAIL = "email";
private static final String KEY_S_NAME = "name";
private static final String KEY_S_ADDRESS = "address";
private static final String KEY_S_PHONE_NUMBER = "phone_number";
private static final String KEY_S_TOTAL_FIGHTERS = "total_fighters";
private static final String KEY_S_TOTAL_VEHICLES = "total_vehicles";
private static final String KEY_S_LAT = "lat";
private static final String KEY_S_LON = "long";
private static final String KEY_TIP_TOPIC = "tip_topic";
private static final String KEY_TIP_SUB_TOPIC = "tip_sub_topic";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}

Correction
Your issue is that you have other databases/files (thanks to google stuff). So the database folder already exists and therefore it won't copy the file but instead it will open a new database with just the android_metadata table.
Try using :-
public static void copyDB(Context context){
String destPath = context.getDatabasePath("FireFighters.db").getAbsolutePath();
File f = new File(destPath);
if(!f.exists()){
if(!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
try {
rawCopy(context.getAssets().open("Firefighters.db"), new FileOutputStream(destPath + "/Firefighters.db"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
So this checks to see if the database file (Firefighters.db) itself exists. If not then it will:-
create the database directory if it doesn't exists
irrespective of the databases directory existing then copy the Firefighters.db.
If Firefighters.db file exists then the file is not copied.
Previous Answer (probably not applicable)
I would suspect that what has been copied is not what you expect it to be. The 12KB along with message (table not found) indicates 2 things. A valid database exists and that it likely has a few components. i.e. (tables,views,indexes,triggers) (each would take up at least 4KB (1 page))
First thing to try is uninstalling the App and rerunning to eliminate an existing attempt leaving a valid but empty component wise (tables etc) database.
It that doesn't resolve the issue then I would suggest adding the following
DatabaseUtils.dumpCursor(databaseAdapter.db.rawQuery("SELECT * FROM sqlite_master",null));
before the line stationsList = databaseAdapter.getAllStations();
This will extract a list of all the components (tables, views triggers, indexes) in the database e.g. something like :-
2022-01-23 13:01:13.611 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#45ef147
2022-01-23 13:01:13.611 I/System.out: 0 {
2022-01-23 13:01:13.612 I/System.out: type=table
2022-01-23 13:01:13.612 I/System.out: name=android_metadata
2022-01-23 13:01:13.612 I/System.out: tbl_name=android_metadata
2022-01-23 13:01:13.612 I/System.out: rootpage=3
2022-01-23 13:01:13.612 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
2022-01-23 13:01:13.612 I/System.out: }
2022-01-23 13:01:13.612 I/System.out: <<<<<
i.e. the above has only the android_metadata table which the SQLiteOpenHelper creates.
Note the above was created using your helper without PreCreateDB,copyDB being called. And low and behold device Explorer shows:-
As such it doesn't look like the PreCreateDB.copyDB is copying the file OR if it is that perhaps it's corrupted in which case SQLiteOpenHelper will prsent you a brand spanking new but empty database bar the android_metadata table.
Additional
Doing a quick test of your code but with a database that contains other tables (for my convenience rather than create one after studying your code) and using outStream().flush.
Then using :-
PreCreateDB.copyDB(this);
databaseAdapter = new DatabaseAdapter(this);
DatabaseUtils.dumpCursor(databaseAdapter.db.rawQuery("SELECT * FROM sqlite_master",null));
results in :-
2022-01-23 13:25:25.439 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#dda8d74
2022-01-23 13:25:25.440 I/System.out: 0 {
2022-01-23 13:25:25.440 I/System.out: type=table
2022-01-23 13:25:25.440 I/System.out: name=kmmAccounts
2022-01-23 13:25:25.440 I/System.out: tbl_name=kmmAccounts
2022-01-23 13:25:25.440 I/System.out: rootpage=2
2022-01-23 13:25:25.441 I/System.out: sql=CREATE TABLE kmmAccounts (id varchar(32) NOT NULL, institutionId varchar(32), parentId varchar(32), lastReconciled timestamp, lastModified timestamp, openingDate date, accountNumber mediumtext, accountType varchar(16) NOT NULL, accountTypeString mediumtext, isStockAccount char(1), accountName mediumtext, description mediumtext, currencyId varchar(32), balance mediumtext, balanceFormatted mediumtext, transactionCount bigint unsigned, PRIMARY KEY (id))
2022-01-23 13:25:25.441 I/System.out: }
2022-01-23 13:25:25.441 I/System.out: 1 {
2022-01-23 13:25:25.441 I/System.out: type=index
2022-01-23 13:25:25.441 I/System.out: name=sqlite_autoindex_kmmAccounts_1
2022-01-23 13:25:25.441 I/System.out: tbl_name=kmmAccounts
2022-01-23 13:25:25.441 I/System.out: rootpage=3
2022-01-23 13:25:25.441 I/System.out: sql=null
2022-01-23 13:25:25.441 I/System.out: }
2022-01-23 13:25:25.441 I/System.out: 2 {
2022-01-23 13:25:25.441 I/System.out: type=table
2022-01-23 13:25:25.441 I/System.out: name=kmmAccountsPayeeIdentifier
2022-01-23 13:25:25.441 I/System.out: tbl_name=kmmAccountsPayeeIdentifier
2022-01-23 13:25:25.442 I/System.out: rootpage=4
2022-01-23 13:25:25.442 I/System.out: sql=CREATE TABLE kmmAccountsPayeeIdentifier (accountId varchar(32) NOT NULL, userorder smallint unsigned NOT NULL, identifierId varchar(32) NOT NULL, PRIMARY KEY (accountId, userorder))
2022-01-23 13:25:25.442 I/System.out: }
....
Device explorer shows :-
So your code, with the flush added, works. So it's either excluding the flush or the asset file that is at fault and I would guess that the asset file is either not the correct file name, empty component wise or is corrupt.
Corrupt File
If it is corrupt the log should show as such e.g. (an image copied into asset as Firfighters.db) :-
2022-01-23 13:37:07.973 E/SQLiteLog: (26) file is not a database
2022-01-23 13:37:07.974 E/DefaultDatabaseErrorHandler: Corruption reported by sqlite on database: /data/user/0/a.a.so70599236javasqlitenorows/databases/Firefighters.db
2022-01-23 13:37:07.974 E/DefaultDatabaseErrorHandler: deleting the database file: /data/user/0/a.a.so70599236javasqlitenorows/databases/Firefighters.db
2022-01-23 13:37:08.013 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#dda8d74
2022-01-23 13:37:08.014 I/System.out: 0 {
2022-01-23 13:37:08.014 I/System.out: type=table
2022-01-23 13:37:08.014 I/System.out: name=android_metadata
2022-01-23 13:37:08.014 I/System.out: tbl_name=android_metadata
2022-01-23 13:37:08.014 I/System.out: rootpage=3
2022-01-23 13:37:08.014 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
2022-01-23 13:37:08.014 I/System.out: }
2022-01-23 13:37:08.014 I/System.out: <<<<<
Incorrect Named Asset File
renaming the asset to anything other than Firefighters.db (e.g. NotFirefighters.db) results in the log including:-
2022-01-23 13:43:18.204 W/System.err: java.io.FileNotFoundException: Firefighters.db
2022-01-23 13:43:18.204 W/System.err: at android.content.res.AssetManager.nativeOpenAsset(Native Method)
2022-01-23 13:43:18.204 W/System.err: at android.content.res.AssetManager.open(AssetManager.java:744)
2022-01-23 13:43:18.204 W/System.err: at android.content.res.AssetManager.open(AssetManager.java:721)
2022-01-23 13:43:18.204 W/System.err: at a.a.so70599236javasqlitenorows.PreCreateDB.copyDB(PreCreateDB.java:20)
2022-01-23 13:43:18.204 W/System.err: at a.a.so70599236javasqlitenorows.MainActivity.onCreate(MainActivity.java:27)
2022-01-23 13:43:18.204 W/System.err: at android.app.Activity.performCreate(Activity.java:7136)
2022-01-23 13:43:18.204 W/System.err: at android.app.Activity.performCreate(Activity.java:7127)
2022-01-23 13:43:18.205 W/System.err: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
2022-01-23 13:43:18.205 W/System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
2022-01-23 13:43:18.205 W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
2022-01-23 13:43:18.205 W/System.err: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
2022-01-23 13:43:18.205 W/System.err: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
2022-01-23 13:43:18.205 W/System.err: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
2022-01-23 13:43:18.205 W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
2022-01-23 13:43:18.205 W/System.err: at android.os.Handler.dispatchMessage(Handler.java:106)
2022-01-23 13:43:18.205 W/System.err: at android.os.Looper.loop(Looper.java:193)
2022-01-23 13:43:18.205 W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6669)
2022-01-23 13:43:18.205 W/System.err: at java.lang.reflect.Method.invoke(Native Method)
2022-01-23 13:43:18.205 W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
2022-01-23 13:43:18.206 W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2022-01-23 13:43:18.233 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#dda8d74
2022-01-23 13:43:18.234 I/System.out: 0 {
2022-01-23 13:43:18.234 I/System.out: type=table
2022-01-23 13:43:18.234 I/System.out: name=android_metadata
2022-01-23 13:43:18.234 I/System.out: tbl_name=android_metadata
2022-01-23 13:43:18.234 I/System.out: rootpage=3
2022-01-23 13:43:18.234 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
2022-01-23 13:43:18.234 I/System.out: }
2022-01-23 13:43:18.234 I/System.out: <<<<<
So by adding the sqlite extract and cursor dump, running after uninstalling the App and viewing the log should establish the cause.

Related

Android Studio SQLite database asset into Recyclerview but only showing specific data

I'm new to Android Studio having only worked with it for two months and been coding with Java for a year.
Currently I'm working on a pet adoption application where the goal is to have the user answer four questions about the kind of pet they want and based on the checkboxes the application will show a list of pets that match the user's wants.
I thought I could use SQLite as the database to add the pets in and then when the user checks the checkbox and submits the application can review the database and send the pet's name, age, and gender in a Recyclerview.
I'm finding out it is not as easy as I thought and can use some outside suggestions as I only have two more weeks to work on it. Here is what I have so far:
Main Activity
DataBaseHelper
import android.content.Context;
import com.readystatesoftware.sqliteasset.SQLiteAssetHelper;
public class DBHelper extends SQLiteAssetHelper {
public static final String DBNAME = "PetAdoption.db";
public static final int DBVERSION = 1;
public DBHelper(Context context) {
super(context,DBNAME,null,DBVERSION);
}
}
DatabaseAccess
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DatabaseAccess {
private SQLiteOpenHelper openHelper;
private SQLiteDatabase database;
private static DatabaseAccess instance;
/**
* Private constructor to avoid object creation from outside classes.
*
* #param context
*/
private DatabaseAccess(Context context) {
this.openHelper = new DBHelper(context);
}
/**
* Return a singleton instance of DatabaseAccess.
*
* #param context the Context
* #return the instance of DatabaseAccess
*/
public static DatabaseAccess getInstance(Context context) {
if (instance == null) {
instance = new DatabaseAccess(context);
}
return instance;
}
/**
* Open the database connection.
*/
public void openDatabase() {
this.database = openHelper.getWritableDatabase();
}
public SQLiteDatabase getWritableDatabase() {
return openHelper.getWritableDatabase();
}
public SQLiteDatabase getReadableDataBase() {
return openHelper.getReadableDatabase();
}
/**
* Close the database connection.
*/
public void closeDatabase() {
if (database != null) {
this.database.close();
}
}
}
Main Activity
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private Context context;
private String query;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DatabaseAccess databaseAccess = DatabaseAccess.getInstance(context);
databaseAccess.openDatabase();
Cursor cursor = databaseAccess.getWritableDatabase().rawQuery(query, null);
}
}
I know I still need a model for the Recylerview and specific code to pull the pets that match the checkboxes, but I'm not sure I'm even going in the right direction. Any suggestions would be very helpful.
Any suggestions would be very helpful.
Perhaps consider the following.
First rather than have an asset (pre-packaged database) the demo creates the database and loads some data (for convenience).
As the schama isn't available this has been made up (this answer is about the principle as opposed to the actual data which is not available).
The table is called pet it has 5 columns:-
_id (the android standard for the id column that uniquely identifies a row)
type for the type of pet (dog, cat ....)
breed e.g. alsatian
lifestage newborn, old ....
cost
Some data is loaded (in the onCreate method, Note instead of SQLiteAssetHelper the stock SQliteOpenHelper has been used as there is no asset to load)
So purely for convenience DBHelper is :-
public class DBHelper extends SQLiteOpenHelper /* changed for simulation of asset */ {
public static final String DBNAME = "PetAdoption.db";
public static final int DBVERSION = 1;
private static String[] testdata1 = new String[]{"Dog","Alsatian","old","100"};
private static String[] testdata2 = new String[]{"Dog","Golden Retriever","newborn","200"};
private static String[] testdata3 = new String[]{"Cat","Siamese","young","150"};
private static String[] testdata4 = new String[]{"Cat","Burmese","mature","110"};
private static String[] testdata5 = new String[]{"Cat","Persian","old","75"};
private static String[] testdata6 = new String[]{"Dog","Corgi","mature","300"};
public DBHelper(Context context) {
super(context,DBNAME,null,DBVERSION);
}
/* ADDED to simulate getting data from asset */
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("CREATE TABLE IF NOT EXISTS pet (" +
BaseColumns._ID + " INTEGER PRIMARY KEY" +
"," + "type TEXT" +
"," + "breed TEXT" +
"," + "lifestage TEXT" +
"," + "cost REAL" +
")"
);
insertTestData(sqLiteDatabase,testdata1);
insertTestData(sqLiteDatabase,testdata2);
insertTestData(sqLiteDatabase,testdata3);
insertTestData(sqLiteDatabase,testdata4);
insertTestData(sqLiteDatabase,testdata5);
insertTestData(sqLiteDatabase,testdata6);
}
private void insertTestData(SQLiteDatabase db, String[] data) {
if (data.length != 4) return;
ContentValues cv = new ContentValues();
cv.put("type",data[0]);
cv.put("breed",data[1]);
cv.put("lifestage",data[2]);
cv.put("cost",data[3]);
db.insert("pet",null,cv);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
The resultant pet table will then be:-
To give an idea of what could be done to select data with some flexibility MainActivity has been changed to be:-
public class MainActivity extends AppCompatActivity {
//private Context context;
//private String query;
private String typeSelection = "dog";
private String breedSelection = "alsatian";
private String lifeStageSelection = "young";
private String lowerCostRangeSelection = "0.0";
private String upperCostRangeSelection = "150";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
DatabaseAccess databaseAccess = DatabaseAccess.getInstance(context);
databaseAccess.openDatabase();
Cursor cursor = databaseAccess.getWritableDatabase().rawQuery(query, null);
*/
DatabaseUtils.dumpCursor(
getSelection(typeSelection,breedSelection,lifeStageSelection,lowerCostRangeSelection,upperCostRangeSelection)
);
DatabaseUtils.dumpCursor(
getSelection("Dog",null,null,null,null)
);
DatabaseUtils.dumpCursor(
getSelection("Cat",null,null,null,null)
);
DatabaseUtils.dumpCursor(
getSelection(null,null,null,null,null)
);
}
private Cursor getSelection(String type, String breed, String lifeStage, String lowerCost, String upperCost ) {
String[] args = null;
ArrayList<String> argsArrayList = new ArrayList<>();
StringBuilder whereClause = new StringBuilder();
if (type != null && type.length() > 0) {
if (whereClause.length() < 1) whereClause.append(" ");
else whereClause.append(" AND ");
whereClause.append(" type=?");
argsArrayList.add(type);
}
if (breed != null && breed.length() > 0) {
if (whereClause.length() < 1) whereClause.append(" ");
else whereClause.append(" AND ");
whereClause.append(" breed=?");
argsArrayList.add(breed);
}
if (lifeStage != null && type.length() > 0) {
if (whereClause.length() < 1) whereClause.append(" ");
else whereClause.append(" AND ");
whereClause.append(" lifestage=?");
argsArrayList.add(lifeStage);
}
if (lowerCost != null && upperCost != null && lowerCost.length() > 0 && upperCost.length() > 0) {
if (whereClause.length() < 1) whereClause.append(" ");
else whereClause.append(" AND ");
whereClause.append(" cost BETWEEN ? AND ?");
argsArrayList.add(lowerCost);
argsArrayList.add(upperCost);
}
if (whereClause.length() > 1) {
args = new String[argsArrayList.size()];
int i = 0;
for (String s: argsArrayList) {
args[i++] = s;
}
}
return DatabaseAccess.getInstance(this).getWritableDatabase().query("pet",null,whereClause.toString(),args,null,null,null);
}
}
the getSelection method being the main addition i.e. the code that allows selection according to, in this case, 5 values:-
the type
the breed
the lifestage
the lower cost and and the upper cost (i.e. a range selection)
the SQLiteDatabase conveneince query method has been used, this is recommended over rawQuery.
The method is designed to be flexible and allow selection by none are all values. None would select every row.
Note that lower and upper cost must both be provided as they are a range.
The code within the onCreate method simply calls the getSelection method to reflect various selections.
The first of the 4, will retrieve nothing as no row would match all the given criteria.
The second will select rows where type is Dog (3 rows).
The third will select rows where the type is Cat (the other 3 rows).
The fourth returns all rows (as nulls are passed which equates to no selections criteria).
Note the method hasn't undergone comprehensive testing and is meant as a pointer.
DatabaseUtils is a class that as it's name suggests has some useful utilities, like, as demonstrated dumping a Cursor.
The Result as output to the log being:-
2022-10-16 22:56:51.850 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#9c8df94
2022-10-16 22:56:51.850 I/System.out: <<<<<
2022-10-16 22:56:51.851 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#f1e7a3d
2022-10-16 22:56:51.852 I/System.out: 0 {
2022-10-16 22:56:51.852 I/System.out: _id=1
2022-10-16 22:56:51.852 I/System.out: type=Dog
2022-10-16 22:56:51.852 I/System.out: breed=Alsatian
2022-10-16 22:56:51.853 I/System.out: lifestage=old
2022-10-16 22:56:51.853 I/System.out: cost=100
2022-10-16 22:56:51.853 I/System.out: }
2022-10-16 22:56:51.853 I/System.out: 1 {
2022-10-16 22:56:51.853 I/System.out: _id=2
2022-10-16 22:56:51.853 I/System.out: type=Dog
2022-10-16 22:56:51.853 I/System.out: breed=Golden Retriever
2022-10-16 22:56:51.853 I/System.out: lifestage=newborn
2022-10-16 22:56:51.853 I/System.out: cost=200
2022-10-16 22:56:51.854 I/System.out: }
2022-10-16 22:56:51.854 I/System.out: 2 {
2022-10-16 22:56:51.854 I/System.out: _id=6
2022-10-16 22:56:51.854 I/System.out: type=Dog
2022-10-16 22:56:51.854 I/System.out: breed=Corgi
2022-10-16 22:56:51.854 I/System.out: lifestage=mature
2022-10-16 22:56:51.854 I/System.out: cost=300
2022-10-16 22:56:51.854 I/System.out: }
2022-10-16 22:56:51.854 I/System.out: <<<<<
2022-10-16 22:56:51.854 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#166d232
2022-10-16 22:56:51.855 I/System.out: 0 {
2022-10-16 22:56:51.855 I/System.out: _id=3
2022-10-16 22:56:51.856 I/System.out: type=Cat
2022-10-16 22:56:51.856 I/System.out: breed=Siamese
2022-10-16 22:56:51.856 I/System.out: lifestage=young
2022-10-16 22:56:51.856 I/System.out: cost=150
2022-10-16 22:56:51.856 I/System.out: }
2022-10-16 22:56:51.856 I/System.out: 1 {
2022-10-16 22:56:51.856 I/System.out: _id=4
2022-10-16 22:56:51.856 I/System.out: type=Cat
2022-10-16 22:56:51.856 I/System.out: breed=Burmese
2022-10-16 22:56:51.856 I/System.out: lifestage=mature
2022-10-16 22:56:51.856 I/System.out: cost=110
2022-10-16 22:56:51.856 I/System.out: }
2022-10-16 22:56:51.856 I/System.out: 2 {
2022-10-16 22:56:51.856 I/System.out: _id=5
2022-10-16 22:56:51.856 I/System.out: type=Cat
2022-10-16 22:56:51.856 I/System.out: breed=Persian
2022-10-16 22:56:51.856 I/System.out: lifestage=old
2022-10-16 22:56:51.856 I/System.out: cost=75
2022-10-16 22:56:51.856 I/System.out: }
2022-10-16 22:56:51.856 I/System.out: <<<<<
2022-10-16 22:56:51.857 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#17eeb83
2022-10-16 22:56:51.857 I/System.out: 0 {
2022-10-16 22:56:51.857 I/System.out: _id=1
2022-10-16 22:56:51.857 I/System.out: type=Dog
2022-10-16 22:56:51.857 I/System.out: breed=Alsatian
2022-10-16 22:56:51.857 I/System.out: lifestage=old
2022-10-16 22:56:51.858 I/System.out: cost=100
2022-10-16 22:56:51.858 I/System.out: }
2022-10-16 22:56:51.858 I/System.out: 1 {
2022-10-16 22:56:51.858 I/System.out: _id=2
2022-10-16 22:56:51.858 I/System.out: type=Dog
2022-10-16 22:56:51.858 I/System.out: breed=Golden Retriever
2022-10-16 22:56:51.858 I/System.out: lifestage=newborn
2022-10-16 22:56:51.858 I/System.out: cost=200
2022-10-16 22:56:51.858 I/System.out: }
2022-10-16 22:56:51.858 I/System.out: 2 {
2022-10-16 22:56:51.858 I/System.out: _id=3
2022-10-16 22:56:51.858 I/System.out: type=Cat
2022-10-16 22:56:51.858 I/System.out: breed=Siamese
2022-10-16 22:56:51.858 I/System.out: lifestage=young
2022-10-16 22:56:51.858 I/System.out: cost=150
2022-10-16 22:56:51.858 I/System.out: }
2022-10-16 22:56:51.858 I/System.out: 3 {
2022-10-16 22:56:51.858 I/System.out: _id=4
2022-10-16 22:56:51.858 I/System.out: type=Cat
2022-10-16 22:56:51.858 I/System.out: breed=Burmese
2022-10-16 22:56:51.858 I/System.out: lifestage=mature
2022-10-16 22:56:51.859 I/System.out: cost=110
2022-10-16 22:56:51.859 I/System.out: }
2022-10-16 22:56:51.859 I/System.out: 4 {
2022-10-16 22:56:51.859 I/System.out: _id=5
2022-10-16 22:56:51.859 I/System.out: type=Cat
2022-10-16 22:56:51.859 I/System.out: breed=Persian
2022-10-16 22:56:51.859 I/System.out: lifestage=old
2022-10-16 22:56:51.859 I/System.out: cost=75
2022-10-16 22:56:51.859 I/System.out: }
2022-10-16 22:56:51.859 I/System.out: 5 {
2022-10-16 22:56:51.859 I/System.out: _id=6
2022-10-16 22:56:51.859 I/System.out: type=Dog
2022-10-16 22:56:51.859 I/System.out: breed=Corgi
2022-10-16 22:56:51.859 I/System.out: lifestage=mature
2022-10-16 22:56:51.859 I/System.out: cost=300
2022-10-16 22:56:51.859 I/System.out: }
2022-10-16 22:56:51.859 I/System.out: <<<<<

Failed to read row 0, column -1 from a CursorWindow which has 1 rows, 9 columns

I'm trying to load data from my table in sqlite Database to my ExpandableListView inside my activity. I followed the answer from this question Android ExpandableListView and SQLite Database.
My parent list will show MVP_INDUSTRY_TYPE Column depends on date Selected,
My child list will show MVP_BRCH_CODE_NAME and MVP_BRCH_ADDRESS.
DatabaseHelper. java
package com.example.spmapp;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class DataBaseHelper extends SQLiteOpenHelper {
public static final String MVP_TBL = "MVP_tbl";
public static final String MVP_BRCH_CODE_NAME = "MVP_BRCH_CODE_NAME";
public static final String MVP_ID = "MVP_ID";
public static final String MVP_BRCH_ADDRESS = "MVP_BRCH_ADDRESS";
public static final String MVP_AREA = "AREA";
public static final String MVP_AREA_CODE = "AREA_CODE";
public static final String MVP_INDUSTRY_TYPE = "MVP_INDUSTRY_TYPE";
public static final String token = "TOKEN";
public static final String MVP_DATE = "SCHEDULED_DATE";
public static final String MVP_CLASS_ID = "MVP_CLASS_ID";
public DataBaseHelper(#Nullable Context context) {
super(context, "taggedList.db", null, 1);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String createMVPVirtualTableStatement = "CREATE VIRTUAL TABLE IF NOT EXISTS " + MVP_TBL + " USING FTS3(" + MVP_BRCH_CODE_NAME + ", " + MVP_ID + " , " + MVP_BRCH_ADDRESS + ", " + MVP_AREA + ", " + MVP_AREA_CODE + ", " + MVP_INDUSTRY_TYPE + ", " + token + ", " + MVP_DATE + ", " + MVP_CLASS_ID + ")";
sqLiteDatabase.execSQL(createMVPVirtualTableStatement);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
onCreate(sqLiteDatabase);
}
public Cursor getSelectedParentMVPDate(String txtMVPDate){
SQLiteDatabase db = this.getWritableDatabase();
String query = "Select * from "+MVP_TBL+" WHERE " +MVP_DATE+ " LIKE '%"+txtMVPDate+"%' LIMIT 50";
return db.rawQuery(query, null);
}
public Cursor getSelectedChildMVPDate(String MVPIndustry){
SQLiteDatabase db = this.getWritableDatabase();
String query = "Select * from "+MVP_TBL+" WHERE " +MVP_INDUSTRY_TYPE+ " LIKE '%"+MVPIndustry+"%' LIMIT 50";
return db.rawQuery(query, null);
}
}
MasterVisitPlan.java
public class MasterVisitPlan extends AppCompatActivity implements AdapterView.OnItemSelectedListener,CalendarAdapter.OnItemListener {
private boolean isBackPressedOnce = false;
public static String email;
public static String VisitDate;
public static String ItemBrnchCodeName;
public static String mrCode;
public static String ClassID;
private static String token;
private static String bearerToken;
public static int counterVisit;
private RecyclerView calendarRecyclerView;
private LocalDate selectedDate;
private TextView monthYearText;
TextView empName, empPos, date;
GoogleSignInClient mGoogleSignInClient;
DrawerLayout drawerLayout;
ImageView gps, empPhoto;
ConstraintLayout calendar;
DataBaseHelper dataBaseHelper;
private Cursor mGroupsCursor; // cursor for list of groups (list top nodes)
private int mGroupIdColumnIndex;
private MyExpandableListAdapter mAdapter;
SimpleCursorAdapter sca;
Cursor csr;
SearchView searchView;
ListView Searchlstview;
#Override
protected void onCreate(Bundle savedIntanceState) {
super.onCreate(savedIntanceState);
setContentView(R.layout.activity_master_visit_plan);
initWidgets();
selectedDate = LocalDate.now();
setMonthView();
setOrRefreshListView();
getCurrentDate();
dataBaseHelper = new DataBaseHelper(MasterVisitPlan.this);
fillMVPdata();
}
private void fillMVPdata(){
mGroupsCursor = dataBaseHelper.getSelectedParentMVPDate(date.getText().toString());
startManagingCursor(mGroupsCursor);
mGroupsCursor.moveToFirst();
ExpandableListView Selectedlstview = (ExpandableListView) findViewById(R.id.MVPListitem);
mAdapter = new MyExpandableListAdapter(mGroupsCursor, this,
R.layout.mvp_list_parent,
R.layout.mvp_list_child,
new String[] {DataBaseHelper.MVP_INDUSTRY_TYPE},
new int[] {R.id.txtMVPParent},
new String[] {DataBaseHelper.MVP_BRCH_CODE_NAME, DataBaseHelper.MVP_BRCH_ADDRESS},
new int[] {R.id.txtviewBrnchCodeName, R.id.txtviewBrchAddr});
Selectedlstview.setAdapter(mAdapter);
}
public class MyExpandableListAdapter extends SimpleCursorTreeAdapter {
public MyExpandableListAdapter(Cursor cursor, Context context,int groupLayout, int childLayout, String[] groupFrom,
int[] groupTo, String[] childrenFrom, int[] childrenTo) {
super(context, cursor, groupLayout, groupFrom, groupTo,
childLayout, childrenFrom, childrenTo);
}
#Override
protected Cursor getChildrenCursor(Cursor cursor) {
#SuppressLint("Range") Cursor childCursor = dataBaseHelper.getSelectedChildMVPDate(cursor.getString(cursor.getColumnIndex("MVP_INDUSTRY_TYPE")));
startManagingCursor(childCursor);
childCursor.moveToFirst();
return childCursor;
}
}
}
Column -1 indicates that the column is not in the Cursor when using the getColumnIndex method.
As the only occurrence of the method, in the provided code, is in the getSelectedChildMVPDate method in the DatabaseHelper class, then that must be where the issue is taking place.
Replicating the essentials of your code with an additional method in DataBaseHelper class :-
public void insertMVPTBLRow(String branchCodeName, long id, String address, String area, String areacode, String industryType, String tkn, String date, String classId) {
ContentValues cv = new ContentValues();
cv.put(MVP_BRCH_CODE_NAME,branchCodeName);
cv.put(MVP_ID,id);
cv.put(MVP_BRCH_ADDRESS,address);
cv.put(MVP_AREA,area);
cv.put(MVP_AREA_CODE,areacode);
cv.put(MVP_INDUSTRY_TYPE,industryType);
cv.put(token,tkn);
cv.put(MVP_DATE,date);
cv.put(MVP_CLASS_ID,classId);
this.getWritableDatabase().insert(MVP_TBL,null,cv);
}
and then using the following code in an activity:-
dataBaseHelper = new DataBaseHelper(this);
dataBaseHelper.getWritableDatabase().delete(DataBaseHelper.MVP_TBL,null,null);
dataBaseHelper.insertMVPTBLRow("B1",100,"StreetX","Area1","A001","I001","tkn001",String.valueOf(System.currentTimeMillis()),"CLASS1");
dataBaseHelper.insertMVPTBLRow("B1",101,"StreetX","Area1","A001","I001","tkn002",String.valueOf(System.currentTimeMillis()),"CLASS1");
mGroupsCursor = dataBaseHelper.getSelectedParentMVPDate("");
startManagingCursor(mGroupsCursor);
mGroupsCursor.moveToFirst();
Cursor cursor = mGroupsCursor;
#SuppressLint("Range") Cursor childCursor = dataBaseHelper.getSelectedChildMVPDate(cursor.getString(cursor.getColumnIndex("MVP_INDUSTRY_TYPE")));
startManagingCursor(childCursor);
childCursor.moveToFirst();
DatabaseUtils.dumpCursor(mGroupsCursor);
DatabaseUtils.dumpCursor(childCursor);
Note empty string passed so all rows are extracted.
Results in a successful run with the Log including:-
2022-06-15 10:55:26.892 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#2caa87e
2022-06-15 10:55:26.893 I/System.out: 0 {
2022-06-15 10:55:26.893 I/System.out: MVP_BRCH_CODE_NAME=B1
2022-06-15 10:55:26.893 I/System.out: MVP_ID=100
2022-06-15 10:55:26.893 I/System.out: MVP_BRCH_ADDRESS=StreetX
2022-06-15 10:55:26.893 I/System.out: AREA=Area1
2022-06-15 10:55:26.893 I/System.out: AREA_CODE=A001
2022-06-15 10:55:26.893 I/System.out: MVP_INDUSTRY_TYPE=I001
2022-06-15 10:55:26.893 I/System.out: TOKEN=tkn001
2022-06-15 10:55:26.893 I/System.out: SCHEDULED_DATE=1655254526888
2022-06-15 10:55:26.893 I/System.out: MVP_CLASS_ID=CLASS1
2022-06-15 10:55:26.893 I/System.out: }
2022-06-15 10:55:26.893 I/System.out: 1 {
2022-06-15 10:55:26.893 I/System.out: MVP_BRCH_CODE_NAME=B1
2022-06-15 10:55:26.893 I/System.out: MVP_ID=101
2022-06-15 10:55:26.893 I/System.out: MVP_BRCH_ADDRESS=StreetX
2022-06-15 10:55:26.894 I/System.out: AREA=Area1
2022-06-15 10:55:26.894 I/System.out: AREA_CODE=A001
2022-06-15 10:55:26.894 I/System.out: MVP_INDUSTRY_TYPE=I001
2022-06-15 10:55:26.894 I/System.out: TOKEN=tkn002
2022-06-15 10:55:26.895 I/System.out: SCHEDULED_DATE=1655254526889
2022-06-15 10:55:26.895 I/System.out: MVP_CLASS_ID=CLASS1
2022-06-15 10:55:26.895 I/System.out: }
2022-06-15 10:55:26.895 I/System.out: <<<<<
2022-06-15 10:55:26.895 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#f1451df
2022-06-15 10:55:26.895 I/System.out: 0 {
2022-06-15 10:55:26.895 I/System.out: MVP_BRCH_CODE_NAME=B1
2022-06-15 10:55:26.895 I/System.out: MVP_ID=100
2022-06-15 10:55:26.895 I/System.out: MVP_BRCH_ADDRESS=StreetX
2022-06-15 10:55:26.895 I/System.out: AREA=Area1
2022-06-15 10:55:26.895 I/System.out: AREA_CODE=A001
2022-06-15 10:55:26.895 I/System.out: MVP_INDUSTRY_TYPE=I001
2022-06-15 10:55:26.895 I/System.out: TOKEN=tkn001
2022-06-15 10:55:26.896 I/System.out: SCHEDULED_DATE=1655254526888
2022-06-15 10:55:26.896 I/System.out: MVP_CLASS_ID=CLASS1
2022-06-15 10:55:26.896 I/System.out: }
2022-06-15 10:55:26.896 I/System.out: 1 {
2022-06-15 10:55:26.896 I/System.out: MVP_BRCH_CODE_NAME=B1
2022-06-15 10:55:26.896 I/System.out: MVP_ID=101
2022-06-15 10:55:26.896 I/System.out: MVP_BRCH_ADDRESS=StreetX
2022-06-15 10:55:26.896 I/System.out: AREA=Area1
2022-06-15 10:55:26.896 I/System.out: AREA_CODE=A001
2022-06-15 10:55:26.896 I/System.out: MVP_INDUSTRY_TYPE=I001
2022-06-15 10:55:26.896 I/System.out: TOKEN=tkn002
2022-06-15 10:55:26.896 I/System.out: SCHEDULED_DATE=1655254526889
2022-06-15 10:55:26.896 I/System.out: MVP_CLASS_ID=CLASS1
2022-06-15 10:55:26.896 I/System.out: }
2022-06-15 10:55:26.897 I/System.out: <<<<<
Now considering the message Failed to read row 0, column -1 from a CursorWindow which has 1 rows, 9 columns
Then
The Cursor is positioned at row 0 (not at row -1 which is before the first row)
Of the 9 columns the specified column has not been found.
From the dump of both cursors there are 9 columns.
getColumnIndex has a bug in that it is case sensitive
However, as the above works, this is not an issue with your code although I would strongly suggest changing your code to use cursor.getColumnIndex(/*"MVP_INDUSTRY_TYPE" <<<<< CHANGED*/ DataBaseHelper.MVP_INDUSTRY_TYPE) (obviously the comment could be omitted)
As such the issue is either:-
Elsewhere in your code, or
That the columns name coded/used in the onCreate method have been changed BUT that they have not been applied.
The onCreate method runs once and only once when the database is created.
The onCreate method will never automatically run again unless the database is deleted.
Uninstalling the App will delete the database BUT will lose any existing data.
If you need to retain existing data, then you need to rebuild the table with the correct column name, noting that virtual tables has restrictions. You would probably need to utilise the onOpen method and within the method:-
create the new table BUT with a different name
populate the newly created table with the data from the orginal table
drop the original table
rename the newly created table with the original/required name
However, as onOpen runs whenever the database is opened you would want to limit this to only do the above when required (i.e. when there is a naming discrepancy). The following onOPen method could be the basis
:-
#Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
Log.d("ONOPEN","ON OPEN INVOKED");
Cursor checkit = db.query(MVP_TBL,null,null,null,null,null,null,"1");
boolean needToProceed = false;
for (String s: new String[]{MVP_AREA,MVP_AREA_CODE,MVP_DATE,MVP_ID,MVP_BRCH_ADDRESS,MVP_BRCH_CODE_NAME,MVP_CLASS_ID,MVP_INDUSTRY_TYPE,token}) {
boolean found = false;
for (String cc: checkit.getColumnNames()) {
if (cc.equals(s)) {
Log.d("ONOPEN","Column " + cc + " matched " + s);
found = true;
break;
}
}
if (!found) {
Log.d("ONOPEN","!!!!COLUMN " + s + " NOT MATCHED.!!!!" );
needToProceed = true;
break;
}
}
if (!needToProceed) return;
Log.d("ONOPEN","PROCEEDING WITH RECREATION OF " + MVP_TBL +" TABLE.");
String renamed = "ORIGINAL_" + MVP_TBL;
db.execSQL("ALTER TABLE " + MVP_TBL + " RENAME TO " + renamed + ";");
onCreate(db);
db.execSQL("INSERT INTO " + renamed + " SELECT * FROM " + MVP_TBL);
db.execSQL("DROP TABLE IF EXISTS " + MVP_TBL);
db.execSQL("ALTER TABLE " + renamed + " RENAME TO " + MVP_TBL);
}
The Logging should be removed if distributing the App.

Fail to create 2 table in Android Studio using SQLite

I have created 2 table, but the others is still not found. The table won't created but i have create in database helper using execSQL
2019-12-28 23:42:18.971 30262-30262/com.example.ppdb E/SQLiteLog: (1) no such table: peserta
2019-12-28 23:42:18.972 30262-30262/com.example.ppdb E/SQLiteDatabase: Error inserting tgl_lahir= agama= jk= tmp_lahir= alamat= nama=Anto
android.database.sqlite.SQLiteException: no such table: peserta (code 1): , while compiling: INSERT INTO peserta(tgl_lahir,agama,jk,tmp_lahir,alamat,nama) VALUES (?,?,?,?,?,?)
This is my DatabaseHelper using TABLE_PESERTA = 'peserta'
public class DatabasePesertaHelper extends SQLiteOpenHelper implements Database {
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = DatabaseContents.DATABASE.toString();
public DatabasePesertaHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE peserta" + "("
+ "_id INTEGER PRIMARY KEY,"
+ "nama TEXT(100),"
+ "jenis_kelamin TEXT(1),"
+ "tempat_lahir TEXT(20),"
+ "tgl_lahir TEXT(12),"
+ "alamat TEXT(30),"
+ "agama TEXT(30),"
+ "id_ortu INTEGER,"
+ "FOREIGN KEY (id_ortu) REFERENCES " + DatabaseContents.TABLE_USERS + "(_id)"
+ ");");
Log.d("CREATE DATABASE", "Create " + DatabaseContents.TABLE_PESERTA +" Successfully.");
}
// Upgrading database
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + DatabaseContents.TABLE_PESERTA);
// Create tables again
onCreate(db);
}
Anyone can help me pls?
Thank you!
Explanation
It would appear that you are trying to use multiple Database Helpers, one per table for the same database. Only one Helper, the first, encountered for the lifetime of the database, will call the onCreate method and therefore the likely issue that you are encountering.
The typical fix would be to use a single Database Helper (it is not a table helper).
Assume that you have a database helper for the Users table that is :-
public class DatabaseUserHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = DatabaseContents.DATABASE.toString();
public DatabaseUserHelper(Context context) {
super(context, DATABASE_NAME, null,DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.d("CREATEUSER","Creating User Table");
db.execSQL("CREATE TABLE " + DatabaseContents.TABLE_USERS +
"(" +
"_id INTEGER PRIMARY KEY," +
" username text" +
")");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
and you have the DatabasePesertaHelper as you have included in the question, then using :-
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DatabaseUserHelper userHelper = new DatabaseUserHelper(this);
logTables(userHelper.getWritableDatabase());
DatabasePesertaHelper pesertaHelper = new DatabasePesertaHelper(this);
logTables(pesertaHelper.getWritableDatabase());
}
private void logTables(SQLiteDatabase db) {
Cursor c = db.query("sqlite_master",null,null,null,null,null,null);
DatabaseUtils.dumpCursor(c);
c.close();
}
}
And the App is run, from new, then the log contains :-
12-29 09:34:28.582 2511-2511/? D/CREATEUSER: Creating User Table
12-29 09:34:28.587 2511-2511/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#1351978
12-29 09:34:28.587 2511-2511/? I/System.out: 0 {
12-29 09:34:28.587 2511-2511/? I/System.out: type=table
12-29 09:34:28.587 2511-2511/? I/System.out: name=android_metadata
12-29 09:34:28.587 2511-2511/? I/System.out: tbl_name=android_metadata
12-29 09:34:28.587 2511-2511/? I/System.out: rootpage=3
12-29 09:34:28.587 2511-2511/? I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
12-29 09:34:28.587 2511-2511/? I/System.out: }
12-29 09:34:28.587 2511-2511/? I/System.out: 1 {
12-29 09:34:28.587 2511-2511/? I/System.out: type=table
12-29 09:34:28.588 2511-2511/? I/System.out: name=users
12-29 09:34:28.588 2511-2511/? I/System.out: tbl_name=users
12-29 09:34:28.588 2511-2511/? I/System.out: rootpage=4
12-29 09:34:28.588 2511-2511/? I/System.out: sql=CREATE TABLE users(_id INTEGER PRIMARY KEY, username text)
12-29 09:34:28.588 2511-2511/? I/System.out: }
12-29 09:34:28.588 2511-2511/? I/System.out: <<<<<
12-29 09:34:28.590 2511-2511/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#fdb49b7
12-29 09:34:28.590 2511-2511/? I/System.out: 0 {
12-29 09:34:28.590 2511-2511/? I/System.out: type=table
12-29 09:34:28.590 2511-2511/? I/System.out: name=android_metadata
12-29 09:34:28.590 2511-2511/? I/System.out: tbl_name=android_metadata
12-29 09:34:28.590 2511-2511/? I/System.out: rootpage=3
12-29 09:34:28.590 2511-2511/? I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
12-29 09:34:28.590 2511-2511/? I/System.out: }
12-29 09:34:28.590 2511-2511/? I/System.out: 1 {
12-29 09:34:28.590 2511-2511/? I/System.out: type=table
12-29 09:34:28.590 2511-2511/? I/System.out: name=users
12-29 09:34:28.590 2511-2511/? I/System.out: tbl_name=users
12-29 09:34:28.590 2511-2511/? I/System.out: rootpage=4
12-29 09:34:28.590 2511-2511/? I/System.out: sql=CREATE TABLE users(_id INTEGER PRIMARY KEY, username text)
12-29 09:34:28.590 2511-2511/? I/System.out: }
12-29 09:34:28.590 2511-2511/? I/System.out: <<<<<
i.e. The User table has been created, although the DatabasePesertaHelper has not issues, the Peserta table is not created (if order of instantiating the usersHelper and pesertaHelper were swapped and pesertaHelper was the first then only the Peserta table would be created and then ONLY if the database did not exist).
Suggested Fix
The typical fix would be to combine both tables into the one helper and to then uninstall the App and to rerun.
Note that this will delete all existing data, this typically acceptable when developing an App.
As such the DatabaseUserHelper as shown above could become :-
public class DatabaseUserHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = DatabaseContents.DATABASE.toString();
public DatabaseUserHelper(Context context) {
super(context, DATABASE_NAME, null,DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.d("CREATEUSER","Creating User Table");
db.execSQL("CREATE TABLE " + DatabaseContents.TABLE_USERS +
"(" +
"_id INTEGER PRIMARY KEY," +
" username text" +
")");
Log.d("CREATEPESERTA","Creating Perserta Table");
db.execSQL("CREATE TABLE peserta" + "("
+ "_id INTEGER PRIMARY KEY,"
+ "nama TEXT(100),"
+ "jenis_kelamin TEXT(1),"
+ "tempat_lahir TEXT(20),"
+ "tgl_lahir TEXT(12),"
+ "alamat TEXT(30),"
+ "agama TEXT(30),"
+ "id_ortu INTEGER,"
+ "FOREIGN KEY (id_ortu) REFERENCES " + DatabaseContents.TABLE_USERS + "(_id)"
+ ");");
Log.d("CREATE DATABASE", "Create " + DatabaseContents.TABLE_PESERTA + " Successfully.");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
After deleteting the App's Data (or uninstalling the App) and rerunning the activity code above results in :-
12-29 10:01:37.265 D/CREATEUSER: Creating User Table
12-29 10:01:37.265 D/CREATEPESERTA: Creating Perserta Table
12-29 10:01:37.265 D/CREATE DATABASE: Create peserta Successfully.
12-29 10:01:37.270 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#1351978
12-29 10:01:37.270 I/System.out: 0 {
12-29 10:01:37.270 I/System.out: type=table
12-29 10:01:37.270 I/System.out: name=android_metadata
12-29 10:01:37.270 I/System.out: tbl_name=android_metadata
12-29 10:01:37.270 I/System.out: rootpage=3
12-29 10:01:37.270 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
12-29 10:01:37.270 I/System.out: }
12-29 10:01:37.270 I/System.out: 1 {
12-29 10:01:37.270 I/System.out: type=table
12-29 10:01:37.270 I/System.out: name=users
12-29 10:01:37.270 I/System.out: tbl_name=users
12-29 10:01:37.270 I/System.out: rootpage=4
12-29 10:01:37.270 I/System.out: sql=CREATE TABLE users(_id INTEGER PRIMARY KEY, username text)
12-29 10:01:37.270 I/System.out: }
12-29 10:01:37.270 I/System.out: 2 {
12-29 10:01:37.270 I/System.out: type=table
12-29 10:01:37.270 I/System.out: name=peserta
12-29 10:01:37.270 I/System.out: tbl_name=peserta
12-29 10:01:37.270 I/System.out: rootpage=5
12-29 10:01:37.270 I/System.out: sql=CREATE TABLE peserta(_id INTEGER PRIMARY KEY,nama TEXT(100),jenis_kelamin TEXT(1),tempat_lahir TEXT(20),tgl_lahir TEXT(12),alamat TEXT(30),agama TEXT(30),id_ortu INTEGER,FOREIGN KEY (id_ortu) REFERENCES users(_id))
12-29 10:01:37.270 I/System.out: }
12-29 10:01:37.270 I/System.out: <<<<<
12-29 10:01:37.273 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#fdb49b7
12-29 10:01:37.273 I/System.out: 0 {
12-29 10:01:37.273 I/System.out: type=table
12-29 10:01:37.273 I/System.out: name=android_metadata
12-29 10:01:37.273 I/System.out: tbl_name=android_metadata
12-29 10:01:37.273 I/System.out: rootpage=3
12-29 10:01:37.273 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
12-29 10:01:37.273 I/System.out: }
12-29 10:01:37.273 I/System.out: 1 {
12-29 10:01:37.273 I/System.out: type=table
12-29 10:01:37.273 I/System.out: name=users
12-29 10:01:37.273 I/System.out: tbl_name=users
12-29 10:01:37.273 I/System.out: rootpage=4
12-29 10:01:37.273 I/System.out: sql=CREATE TABLE users(_id INTEGER PRIMARY KEY, username text)
12-29 10:01:37.273 I/System.out: }
12-29 10:01:37.273 I/System.out: 2 {
12-29 10:01:37.274 I/System.out: type=table
12-29 10:01:37.274 I/System.out: name=peserta
12-29 10:01:37.274 I/System.out: tbl_name=peserta
12-29 10:01:37.274 I/System.out: rootpage=5
12-29 10:01:37.274 I/System.out: sql=CREATE TABLE peserta(_id INTEGER PRIMARY KEY,nama TEXT(100),jenis_kelamin TEXT(1),tempat_lahir TEXT(20),tgl_lahir TEXT(12),alamat TEXT(30),agama TEXT(30),id_ortu INTEGER,FOREIGN KEY (id_ortu) REFERENCES users(_id))
12-29 10:01:37.274 I/System.out: }
12-29 10:01:37.274 I/System.out: <<<<<
Note that there is no need for DatabasePesertahelper as DatabaseUserHelper provides access to both tables.

How to use triggers to create table dynamically

I like to create a table dynamically when a user registers to create account, So I have tried it with triggers, I don't know weather I can create table using triggers dynamically. I am absolutely new to android. It shows syntax error.
I have generated a database for entering in my data, when multiple accounts logged in I like to create table separately for every user i.e seperate table which contains data alone not the username and password.So I have created a method "trigger_table" in which I have created trigger and I have called it in "register" method and I have called register method in the button b1 where b1 is the register button. When I click on this button a table should be automatically created
public class sql{
public Boolean register(String username, String Password) {
SQLiteDatabase s = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("username", username);
values.put("Password", Password);
long row = s.insert("log", null, values);
trigger_table(username);//trigger method is called
if (row == -1)
return false;
else
return true;
}
}
public Boolean trigger_table(String t) {
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("CREATE TRIGGER aft_insert AFTER INSERT ON log AS BEGIN
CREATE TABLE"+t+"(username text ,Date date ,description text ,Amount
int)");
return true;// I have created method trigger table
}
b1.setOnClickListener((v) -> {
String s1 = t1.getText().toString();
String s2 = t2.getText().toString();
String s3 = t3.getText().toString();
try {
sql s = new sql(this);//this is class name which
Boolean bo ;
if(s2.equals(s3))
{
bo= s.register(s1,s2);//called register method
if(bo == true) {
b.setMessage("Account created")
.setPositiveButton("Ok",null);
AlertDialog al = b.create();
al.show();
}
}
else{
b.setMessage("Account does not created")
.setPositiveButton("Ok",null);
AlertDialog al = b.create();
al.show();
}
}
catch(Exception e) {
b.setMessage(e.toString())
.setPositiveButton("Ok", null);
AlertDialog al = b.create();
al.show();
t1.setText("");
t2.setText("");
}
});
In short you cannot use CREATE TABLE within a TRIGGER.
TRIGGERS are limited to performing UPDATE, INSERT, DELETE and SELECT operations within the BEGIN END section/clause (i.e. the actions that can be taken/done).
SQL As Understood By SQLite - CREATE TRIGGER
Additional re comment :-
The main idea is when a user gives username and password on register
form it gets stored on a table called "log" and when a data i.e
username is inserted, a new table must be created for that user.Is
there is any possible ways of doing it?
This couldn't be done directly using SQL, there are numerous ways it could be done programatically. However, it very much goes against typical/recommend use as by having numerous tables with the same schema has many disadvantages when a single column relating to the current user would suffice for a single table for other data.
Each table has a least a 4k overhead just for the pages specific to that table. There are a greater number of tables in the schema (the sqlite_master table) thus increased processing requirements when accessing any identifier (name) as some examples.
Example
The following is a simple example of how you could do the above :-
The Database Helper (DBHelper.java)
:-
public class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "myuserdb";
public static final int DBVERSION = 1;
public static final String TBL_LOG = "log";
public static final String COL_LOG_ID = BaseColumns._ID;
public static final String COL_LOG_USERNAME = "user_name";
public static final String COL_LOG_PASSWORD = "password";
public static final String COL_USER_ID = BaseColumns._ID;
public static final String COL_USER_DATA = "user_data";
SQLiteDatabase mDB;
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
mDB = this.getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
String crt_log_table = "CREATE TABLE IF NOT EXISTS " + TBL_LOG + "(" +
COL_LOG_ID + " INTEGER PRIMARY KEY, " +
COL_LOG_USERNAME + " TEXT UNIQUE, " +
COL_LOG_PASSWORD + " TEXT" +
")";
db.execSQL(crt_log_table);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public long addLog(String user, String password) {
ContentValues cv = new ContentValues();
cv.put(COL_LOG_USERNAME,user);
cv.put(COL_LOG_PASSWORD,password);
long userid = mDB.insert(TBL_LOG,null,cv);
if (userid > 0) {
createUserSpecificTable(user);
}
return userid;
}
public boolean login(String user, String password) {
boolean rv = false;
String whereclause = COL_LOG_USERNAME + "=? AND " + COL_LOG_PASSWORD + "=?";
String[] whereargs = new String[]{user,password};
Cursor csr = mDB.query(TBL_LOG,null,whereclause,whereargs,null,null,null);
if (csr.getCount() > 0) {
rv = true;
}
csr.close();
return rv;
}
private void createUserSpecificTable(String user) {
String crt_userSpecific_table = "CREATE TABLE IF NOT EXISTS " + user + "(" +
COL_USER_ID + " INTEGER PRIARY KEY," +
COL_USER_DATA + " TEXT " +
")";
mDB.execSQL(crt_userSpecific_table);
}
public void addUserData(String user, String data) {
ContentValues cv = new ContentValues();
cv.put(COL_USER_DATA,data);
// User specific
mDB.insert(user,null,cv);
}
public Cursor getUserData(String user) {
return mDB.query(user,null,null,null,null,null,null);
}
}
method addLog registers a new user and build the user specific table.
method login allows a user to login returning true if the login was successful, else false.
method adduserData adds some user specific data based upon the user passed.
method getUserData returns the user specific data for a user as a Cursor.
Note the above requires that a username adheres to unenclosed (identifier) table naming rules.
Testing Activity
:-
The following creates a number of logins, mocks some user sessions, writing the user's data to the log and finally then writes the schema (contents of sqlite_master to the log, to show that the user specific tables have been created ) :-
public class MainActivity extends AppCompatActivity {
DBHelper mDBHlpr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDBHlpr = new DBHelper(this);
mDBHlpr.addLog("Fred","1234");
mDBHlpr.addLog("Sue","5678");
mDBHlpr.addLog("Mary","1111");
mDBHlpr.addLog("Tom","0000");
doMockUserSession("MRNOBODY","HACKIT");
doMockUserSession("Fred","1234");
doMockUserSession("Sue","666");
doMockUserSession("Sue","5678");
doMockUserSession("Mary","1111");
doMockUserSession("Tom","0000");
//Get all Items from the schema and write to the log
DatabaseUtils.dumpCursor(mDBHlpr.getWritableDatabase().query("sqlite_master",null,null,null,null,null,null));
}
private void doMockUserSession(String user, String password) {
if (mDBHlpr.login(user,password)) {
mDBHlpr.addUserData(user,"MY DATA " + String.valueOf(System.currentTimeMillis()));
Cursor csr = mDBHlpr.getUserData(user);
DatabaseUtils.dumpCursor(csr);
csr.close();
} else {
Log.d("LOGINFAIL","Login failed for user " + user);
}
}
}
Resultant output
The above (after a few runs) results in :-
2019-02-13 10:07:06.170 D/LOGINFAIL: Login failed for user MRNOBODY
2019-02-13 10:07:06.173 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#5690395
2019-02-13 10:07:06.175 I/System.out: 0 {
2019-02-13 10:07:06.175 I/System.out: _id=null
2019-02-13 10:07:06.175 I/System.out: user_data=MY DATA 1550011948580
2019-02-13 10:07:06.175 I/System.out: }
2019-02-13 10:07:06.175 I/System.out: 1 {
2019-02-13 10:07:06.176 I/System.out: _id=null
2019-02-13 10:07:06.176 I/System.out: user_data=MY DATA 1550012073536
2019-02-13 10:07:06.176 I/System.out: }
2019-02-13 10:07:06.176 I/System.out: 2 {
2019-02-13 10:07:06.176 I/System.out: _id=null
2019-02-13 10:07:06.176 I/System.out: user_data=MY DATA 1550012826172
2019-02-13 10:07:06.176 I/System.out: }
2019-02-13 10:07:06.176 I/System.out: <<<<<
2019-02-13 10:07:06.178 D/LOGINFAIL: Login failed for user Sue
2019-02-13 10:07:06.179 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#70c1caa
2019-02-13 10:07:06.179 I/System.out: 0 {
2019-02-13 10:07:06.179 I/System.out: _id=null
2019-02-13 10:07:06.179 I/System.out: user_data=MY DATA 1550011948588
2019-02-13 10:07:06.179 I/System.out: }
2019-02-13 10:07:06.179 I/System.out: 1 {
2019-02-13 10:07:06.179 I/System.out: _id=null
2019-02-13 10:07:06.180 I/System.out: user_data=MY DATA 1550012073545
2019-02-13 10:07:06.180 I/System.out: }
2019-02-13 10:07:06.180 I/System.out: 2 {
2019-02-13 10:07:06.180 I/System.out: _id=null
2019-02-13 10:07:06.180 I/System.out: user_data=MY DATA 1550012826178
2019-02-13 10:07:06.181 I/System.out: }
2019-02-13 10:07:06.181 I/System.out: <<<<<
2019-02-13 10:07:06.182 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#660309b
2019-02-13 10:07:06.182 I/System.out: 0 {
2019-02-13 10:07:06.182 I/System.out: _id=null
2019-02-13 10:07:06.182 I/System.out: user_data=MY DATA 1550011948594
2019-02-13 10:07:06.182 I/System.out: }
2019-02-13 10:07:06.182 I/System.out: 1 {
2019-02-13 10:07:06.183 I/System.out: _id=null
2019-02-13 10:07:06.183 I/System.out: user_data=MY DATA 1550012073547
2019-02-13 10:07:06.183 I/System.out: }
2019-02-13 10:07:06.183 I/System.out: 2 {
2019-02-13 10:07:06.183 I/System.out: _id=null
2019-02-13 10:07:06.183 I/System.out: user_data=MY DATA 1550012826181
2019-02-13 10:07:06.183 I/System.out: }
2019-02-13 10:07:06.183 I/System.out: <<<<<
2019-02-13 10:07:06.186 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#8a61c38
2019-02-13 10:07:06.186 I/System.out: 0 {
2019-02-13 10:07:06.186 I/System.out: _id=null
2019-02-13 10:07:06.186 I/System.out: user_data=MY DATA 1550011948596
2019-02-13 10:07:06.186 I/System.out: }
2019-02-13 10:07:06.186 I/System.out: 1 {
2019-02-13 10:07:06.186 I/System.out: _id=null
2019-02-13 10:07:06.186 I/System.out: user_data=MY DATA 1550012073550
2019-02-13 10:07:06.186 I/System.out: }
2019-02-13 10:07:06.187 I/System.out: 2 {
2019-02-13 10:07:06.187 I/System.out: _id=null
2019-02-13 10:07:06.187 I/System.out: user_data=MY DATA 1550012826185
2019-02-13 10:07:06.187 I/System.out: }
2019-02-13 10:07:06.187 I/System.out: <<<<<
2019-02-13 10:07:06.187 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#6a34411
2019-02-13 10:07:06.187 I/System.out: 0 {
2019-02-13 10:07:06.187 I/System.out: type=table
2019-02-13 10:07:06.187 I/System.out: name=android_metadata
2019-02-13 10:07:06.188 I/System.out: tbl_name=android_metadata
2019-02-13 10:07:06.188 I/System.out: rootpage=3
2019-02-13 10:07:06.188 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
2019-02-13 10:07:06.188 I/System.out: }
2019-02-13 10:07:06.188 I/System.out: 1 {
2019-02-13 10:07:06.188 I/System.out: type=table
2019-02-13 10:07:06.188 I/System.out: name=log
2019-02-13 10:07:06.188 I/System.out: tbl_name=log
2019-02-13 10:07:06.188 I/System.out: rootpage=4
2019-02-13 10:07:06.188 I/System.out: sql=CREATE TABLE log(_id INTEGER PRIMARY KEY, user_name TEXT UNIQUE, password TEXT)
2019-02-13 10:07:06.188 I/System.out: }
2019-02-13 10:07:06.188 I/System.out: 2 {
2019-02-13 10:07:06.188 I/System.out: type=index
2019-02-13 10:07:06.188 I/System.out: name=sqlite_autoindex_log_1
2019-02-13 10:07:06.188 I/System.out: tbl_name=log
2019-02-13 10:07:06.188 I/System.out: rootpage=5
2019-02-13 10:07:06.188 I/System.out: sql=null
2019-02-13 10:07:06.188 I/System.out: }
2019-02-13 10:07:06.189 I/System.out: 3 {
2019-02-13 10:07:06.189 I/System.out: type=table
2019-02-13 10:07:06.189 I/System.out: name=Fred
2019-02-13 10:07:06.189 I/System.out: tbl_name=Fred
2019-02-13 10:07:06.189 I/System.out: rootpage=6
2019-02-13 10:07:06.189 I/System.out: sql=CREATE TABLE Fred(_id INTEGER PRIARY KEY,user_data TEXT )
2019-02-13 10:07:06.189 I/System.out: }
2019-02-13 10:07:06.189 I/System.out: 4 {
2019-02-13 10:07:06.189 I/System.out: type=table
2019-02-13 10:07:06.189 I/System.out: name=Sue
2019-02-13 10:07:06.189 I/System.out: tbl_name=Sue
2019-02-13 10:07:06.189 I/System.out: rootpage=7
2019-02-13 10:07:06.189 I/System.out: sql=CREATE TABLE Sue(_id INTEGER PRIARY KEY,user_data TEXT )
2019-02-13 10:07:06.189 I/System.out: }
2019-02-13 10:07:06.189 I/System.out: 5 {
2019-02-13 10:07:06.189 I/System.out: type=table
2019-02-13 10:07:06.189 I/System.out: name=Mary
2019-02-13 10:07:06.189 I/System.out: tbl_name=Mary
2019-02-13 10:07:06.189 I/System.out: rootpage=8
2019-02-13 10:07:06.189 I/System.out: sql=CREATE TABLE Mary(_id INTEGER PRIARY KEY,user_data TEXT )
2019-02-13 10:07:06.189 I/System.out: }
2019-02-13 10:07:06.189 I/System.out: 6 {
2019-02-13 10:07:06.189 I/System.out: type=table
2019-02-13 10:07:06.190 I/System.out: name=Tom
2019-02-13 10:07:06.190 I/System.out: tbl_name=Tom
2019-02-13 10:07:06.190 I/System.out: rootpage=9
2019-02-13 10:07:06.190 I/System.out: sql=CREATE TABLE Tom(_id INTEGER PRIARY KEY,user_data TEXT )
2019-02-13 10:07:06.190 I/System.out: }
2019-02-13 10:07:06.190 I/System.out: <<<<<

Database Helper class?

I am having trouble getting my database to effectively store information. I am using Android Studio and I am trying to create a sqlite db on the fly and insert information into it.
I am not able to insert information into my table ( I am returning a -1), however, I am not sure if the problem is the insert statement or the table/db creation.
Here is the code. Any help would be appreciated.. I have been banging my head on this for a while now.
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "DatabaseHelper";
SQLiteDatabase database;
private static final String Database_Name = "CISP_340.db";
private static final String Table_Name = "ANIMALS";
private static final String col1 = "_ID";
private static final String col2 = "ANIMAL_TYPE_CD";
private static final String col3 = "COUNT_NO";
private static final String col4 = "SEENON_DTM";
private static final String col5 = "COMMENTS_TXT";
public DatabaseHelper(Context context){
super(context, Table_Name, null, 1);
database = getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE " + Table_Name + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, "+
col2 + " INTEGER DEFAULT 0, " +
col3 +" INTEGER, " +
col4 + " TEXT, " +
col5 + " TEXT)";
db.execSQL(createTable);
}
#Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
db.execSQL("DROP IF TABLE EXISTS " + Table_Name);
onCreate(db);
}
public boolean addData(Animal animal){
ContentValues contentValues = new ContentValues();
contentValues.put(col5, animal.getComments());
Log.d(TAG, "addData: Adding " + animal.toString() + " to " + Table_Name);
long result = database.insert(Table_Name, null, contentValues);
if (result == -1) {
return false;
}else{
return true;
}
}
public Cursor getData(){
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT * FROM " + Table_Name;
Cursor data = db.rawQuery(query, null);
return data;
}
}
Here is my animal Class:
public class Animal {
Animal(){
//Blank
}
Animal(int animalType, int count, String seenOn, String comments){
this.animalType = animalType;
this.count = count;
this.seenOn = seenOn;
this.comments = comments;
}
private int animalType;
private int count;
private String seenOn;
private String comments;
public int getAnimalType() {
return animalType;
}
public void setAnimalType(int type){
this.animalType = type;
}
public int getCount() {
return count;
}
public void setCount(int count){
this.count = count;
}
public String getSeenOn() {
return seenOn;
}
public void setSeenOn(String seenOn){
this.seenOn = seenOn;
}
public String getComments() {
return comments;
}
public void setComments(String comments){
this.comments = comments;
}
#Override
public String toString(){
return "Animal type: " + animalType + ", Animal count: " + count + ", Animal was seen on: " + seenOn + ", Comments about encounter: " + comments;
}
}
Here is my MainActivity:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
DatabaseHelper dataBaseHelper;
private Button btnAdd, btnView;
private EditText editText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.editText);
btnAdd = (Button) findViewById(R.id.btnAdd);
btnView = (Button) findViewById(R.id.btnView);
dataBaseHelper = new DatabaseHelper(this);
Animal myAnimal = new Animal(1, 0, "Yes", "Raining");
Animal myAnimal2 = new Animal(1, 0, "No", "");
addAnimal(myAnimal);
addAnimal(myAnimal2);
btnAdd.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
Animal animal = new Animal();
animal.setComments(editText.getText().toString());
if (editText.length() != 0){
addAnimal(animal);
editText.setText("");
}else{
returnMessage("You must put something into this field");
}
}
});
btnView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
Intent intent = new Intent(MainActivity.this, ListDataActivity.class);
startActivity(intent);
}
});
}
public void addAnimal( Animal animal ){
boolean insertData = dataBaseHelper.addData(animal);
if (insertData){
returnMessage("Success");
}else{
returnMessage("Fail");
}
}
private void returnMessage(String message){
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
Output in LogCat when attempting to insert in the constructor:
12-02 17:20:23.624 4100-4100/edu.davenport.cisp340.animaltracker E/SQLiteDatabase: Error inserting COUNT_NO=0 ANIMAL_TYPE_CD=1 SEENON_DTM=Yes COMMENTS_TXT=Raining
android.database.sqlite.SQLiteException: table ANIMALS has no column named SEENON_DTM (code 1): , while compiling: INSERT INTO ANIMALS(COUNT_NO,ANIMAL_TYPE_CD,SEENON_DTM,COMMENTS_TXT) VALUES (?,?,?,?)
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:500)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1472)
at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1343)
at edu.davenport.cisp340.animaltracker.DatabaseHelper.addData(DatabaseHelper.java:59)
at edu.davenport.cisp340.animaltracker.MainActivity.addAnimal(MainActivity.java:65)
at edu.davenport.cisp340.animaltracker.MainActivity.onCreate(MainActivity.java:32)
at android.app.Activity.performCreate(Activity.java:6980)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6540)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Edit
Now that you added the log. The issue is that column SEENON_DTM doesn't exist.
As per :-
table ANIMALS has no column named SEENON_DTM
You have probably added the column since running the App. Just amending the SQL used by the onCreate method isn't enough to change the structure of the database. That is onCreate is only run once when the database is created, the database is then saved to a file and hence how it stays around. Subequent instantation of the DatabaseHelper, find the file and doesn't call onCreate.
The fix, if losing any data (no useful data would likely exist) isn't an issue is to do one of the following;
delete the App's data (from settings), or
uninstall the App, or
increase the database version i.e. change super(context, Table_Name, null, 1); to super(context, Table_Name, null, 2); (1 to 2)
(this will result in the onUpgrade method running which should drop the table (see note below about using DROP TABLE IF EXISTS and not DROP IF TABLE EXISTS))
and then rerun the App.
I believe that you code is not an issue (the only issue in the code is with DROP IF TABLE EXISTS, it should be DROP TABLE IF EXISTS ).
Your code works as expected (see below), so the issue is either how you are checking the data or that the Animal class is the cause.
Below is code that uses you DatabaseHelper code and invokes it from an Activity (the Animal class may be different to yours).
I'd suggest trying the code below, suitably adjusted for your DatabaseHelper class (i.e. change AnimalDBhelper to DatabaseHelper) and then checking the log. The output should be as below (perhaps with more rows if you have added rows and the database hasn't been deleted).
Testing
Using a copy of your code (renaming the class to AnimalDBhelper to suit my testing environment) and then using the following code in an activity (the invoking code) :-
public class MainActivity extends AppCompatActivity {
AnimalDBhelper mADBHlpr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
// Create two animals
mADBHlpr = new AnimalDBhelper(this);
Animal myanimal1 = new Animal(1,0,"Yes","Raining");
Animal myanimal2 = new Animal(1,0,"No","");
mADBHlpr.addData(myanimal1); // Add the first animal
Cursor csr = mADBHlpr.getData(); get the data
DatabaseUtils.dumpCursor(csr); dump the data (write it to the log)
mADBHlpr.addData(myanimal2); // Add the 2nd
csr = mADBHlpr.getData();
DatabaseUtils.dumpCursor(csr);
csr.close(); // Done with the cursor so close
}
}
Result :-
12-02 19:37:54.040 1172-1172/? D/DatabaseHelper: addData: Adding ?.Animal#534af570 to ANIMALS
12-02 19:37:54.044 1172-1172/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#534a5df8
12-02 19:37:54.044 1172-1172/? I/System.out: 0 {
12-02 19:37:54.044 1172-1172/? I/System.out: ID=1
12-02 19:37:54.044 1172-1172/? I/System.out: ANIMAL_TYPE_CD=0
12-02 19:37:54.044 1172-1172/? I/System.out: COUNT_NO=null
12-02 19:37:54.044 1172-1172/? I/System.out: SEENON_DTM=null
12-02 19:37:54.044 1172-1172/? I/System.out: COMMENTS_TXT=Raining
12-02 19:37:54.044 1172-1172/? I/System.out: }
12-02 19:37:54.044 1172-1172/? I/System.out: <<<<<
12-02 19:37:54.044 1172-1172/? D/DatabaseHelper: addData: Adding ?.Animal#534af5c4 to ANIMALS
12-02 19:37:54.048 1172-1172/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#534ab7d4
12-02 19:37:54.048 1172-1172/? I/System.out: 0 {
12-02 19:37:54.048 1172-1172/? I/System.out: ID=1
12-02 19:37:54.048 1172-1172/? I/System.out: ANIMAL_TYPE_CD=0
12-02 19:37:54.048 1172-1172/? I/System.out: COUNT_NO=null
12-02 19:37:54.048 1172-1172/? I/System.out: SEENON_DTM=null
12-02 19:37:54.048 1172-1172/? I/System.out: COMMENTS_TXT=Raining
12-02 19:37:54.048 1172-1172/? I/System.out: }
12-02 19:37:54.048 1172-1172/? I/System.out: 1 {
12-02 19:37:54.048 1172-1172/? I/System.out: ID=2
12-02 19:37:54.048 1172-1172/? I/System.out: ANIMAL_TYPE_CD=0
12-02 19:37:54.048 1172-1172/? I/System.out: COUNT_NO=null
12-02 19:37:54.048 1172-1172/? I/System.out: SEENON_DTM=null
12-02 19:37:54.048 1172-1172/? I/System.out: COMMENTS_TXT=
12-02 19:37:54.048 1172-1172/? I/System.out: }
12-02 19:37:54.048 1172-1172/? I/System.out: <<<<<
You haven't really described what's going wrong (are you querying the Cursor and not finding the data you expect?), but you need to close the cursor somewhere (see this answer), and you don't need to get the database in getComment() since you already have it. Here's a version that ought to work in your example class.
public String getComment(){
String query = "SELECT * FROM " + Table_Name;
String comments = "";
Cursor data = database.rawQuery(query, null);
if( data.moveToFirst() ) { // iterate all the rows of the table
do {
String val = data.getString(4); // pull out column 5
// String val = data.getString(data.getColumnIndex(col5)); // or this way if you prefer
comments += val; // do something with the data - e.g. rebuild Animal object
} while (data.moveToNext());
}
data.close();
return comments;
}

Categories