How to fix 'database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0'? - cursor

I am setting up a database with Android SQLite for my weight_activity with a dialog. In that Activity I save the current weight and I want to request the saved value for the current weight when starting the activity to display it.
The Error I get is:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.thisfit/com.example.thisfit.Weight_Activity}: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
Caused by: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
at android.database.AbstractCursor.checkPosition(AbstractCursor.java:460)
This is the code that requests the current weight in my activity class
public void getCurrentWeightAsFloat() {
textView_currentWeight.setText(String.valueOf(weight_dbHandler.getCurrentWeight()));
} //public void getCurrentWeightAsFloat()
This is the whole database code. I post this because I don't know, if the problem could be in another section of the code and not just the method getCurrentWeight():
public class Weight_Database extends SQLiteOpenHelper {
//region Attributes
private static final String TAG = "weight_database";
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "weight_database.db";
private static final String TABLE_NAME = "weight_table";
private static final String COL1 = "ID";
private static final String COL2 = "Weight";
private static final String COL3 = "Date";
//endregion
//region Constructors
public Weight_Database(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
// SQLiteDatabase db = this.getWritableDatabase();
}
//endregion
//region Methods
#Override
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE " + TABLE_NAME
+ " (ID INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COL2 + " FLOAT, "
+ COL3 + " DATE )";
db.execSQL(createTable);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
public boolean addNewCurrentWeightAsFloat(float newCurrentWeightAsFloat){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COL2, newCurrentWeightAsFloat);
Log.d(TAG, "addWeight: Adding " + newCurrentWeightAsFloat + " to " + TABLE_NAME);
long result = db.insert(TABLE_NAME, null, contentValues);
//if date as inserted incorrectly it will return -1
if (result == -1){
return false;
} else {
return true;
}
} //public boolean addNewCurrentWeightAsFloat(String newCurrentWeightAsFloat)
public float getCurrentWeight(){
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT Weight FROM " + TABLE_NAME + " ORDER BY ID DESC LIMIT 1";
Cursor data = db.rawQuery(query, null);
data.moveToFirst();
float currentWeightAsFloat = data.getFloat(data.getColumnIndex("content"));
return currentWeightAsFloat;
} //public float getCurrentWeight()
//Returns the whole table as a raw query
public Cursor getData(){
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT * FROM " + TABLE_NAME;
Cursor data = db.rawQuery(query, null);
return data;
} //public Cursor getData()
//endregion
} //class Weight_Database
I expect to get the latest weight entered by selecting the ID DESCending with a Limit of 1.
I want to get this float of my current weight and display it in a textView afterwards.
Have a nice day and thanks in advance :)

Your table has no data.
You should check the return values of data.moveToFirst() and only try to call getFloat() on the cursor in case it returned true.

Related

Null pointer exception when inserting data into Android SQLite Database

I'm just starting an Android Studio project and Ive created a small player database and I have been trying to add player details into the database. However each time the program crashes with a null pointer exception. A quick debgug suggests the problem is with the call to the OnClickListener in the OnCreate method. What changes need to be made to the code? Thanks
public class DatabaseHelper {
// Declare instance of DBHelper class, context and SQLiteDatabase
private DBHelper ourDbHelper;
private final Context ourContext;
private SQLiteDatabase myDb;
// Initialise the database and table names and version
private static final String DATABASE_NAME = "Club";
private static final String PLAYER_TABLE_NAME = "Players";
//Initialise the PLAYER_TABLE_NAME field names
private static final String PLAYER_ID = "player_id";
private static final String PLAYER_SURNAME = "player_surname";
private static final String PLAYER_FORENAME = "player_forename";
private static final String PLAYER_AGE = "player_age";
private static final String PLAYER_DOB = "player_dob";
private static class DBHelper extends SQLiteOpenHelper {
// This constructor takes the context, db name and db version as
parameters
// and applies them to the DBHelper class
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// This constructor takes context as parameter and assigns it to
variable
#Override
public void onCreate(SQLiteDatabase db) {
//Executes the following queries to create the Player Table
db.execSQL("CREATE TABLE " + PLAYER_TABLE_NAME + " (" + PLAYER_ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ PLAYER_FORENAME + "TEXT NOT NULL, " + PLAYER_SURNAME +
"TEXT NOT NULL, " +
PLAYER_AGE + " INTEGER NOT NULL, " + PLAYER_DOB + "DATE
NOT NULL );");
}//OnCreate
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int
newVersion) {
// if table is upgraded or already exists
db.execSQL("DROP TABLE IF EXISTS " + PLAYER_TABLE_NAME);
onCreate(db);
}//OnUpgrade
}//DBHelperClass
// Constructor takes a context as a parameter and assigns it to
ourContext
public DatabaseHelper (Context c){
ourContext = c;
}//constructor
// Open writable database and allow to be modified
public DatabaseHelper open() throws SQLException {
ourDbHelper = new DBHelper(ourContext);
myDb = ourDbHelper.getWritableDatabase();
return this;
}//open
//method to close the db to modification
public void close() {
ourDbHelper.close();
}//close
// method to create an entry to the Player table with player attributes as parameters
public long createEntry (String forename, String surname, String age, String dob){
//contentValues will hold the information to be added to the database
ContentValues contentValues = new ContentValues();
//Using put method, insert the parameters into the fields in the table
contentValues.put(PLAYER_FORENAME, forename);
contentValues.put(PLAYER_SURNAME, surname);
contentValues.put(PLAYER_AGE,age);
contentValues.put(PLAYER_DOB, String.valueOf(dob));
//insert the values into the player table
//assign to variable result to check if data added correctly
return myDb.insert(PLAYER_TABLE_NAME,null,contentValues);
}//createEntry
Here is the AddPlayer activity class
public class AddPlayer extends Activity implements View.OnClickListener {
//declare variables
Button confirmAdd;
EditText editSurname, editForename, editAge, editDOB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_player_activity);
//Initialise variables
editForename = (EditText) findViewById(R.id.editPlayerForename);
editSurname = (EditText) findViewById(R.id.editPlayerSurname);
editAge = (EditText) findViewById(R.id.editPlayerAge);
editDOB = (EditText) findViewById(R.id.editPlayerDOB);
confirmAdd = (Button) findViewById(R.id.addPlayerBtn);
//set onclicklisteners
confirmAdd.setOnClickListener(this);
}
#Override
public void onClick(View v) {
String forename = editForename.getText().toString();
String surname = editSurname.getText().toString();
String age = editAge.getText().toString();
String dob = editDOB.getText().toString();
DatabaseHelper myDb = new DatabaseHelper(AddPlayer.this);
myDb.open();
myDb.createEntry(forename, surname, age, dob);
Toast.makeText(AddPlayer.this, "Data Inserted", Toast.LENGTH_LONG).show();
}
Change this
DatabaseHelper myDb = new DatabaseHelper(AddPlayer.this);
myDb.open()
To
DatabaseHelper myDb = new DatabaseHelper(this.getContext());
myDb.open();

Multiple database db2 and sql server with single query

The db2 database is called panth01
the sqlserver database is called proof
As you can see in the code, I made a single query, to extract language in db2 and language in sqlserver.
The problem that in Db2 the column is called LANGUAGE
In sqlserver the column is called LINGUA
In db2 the LANGUAGE column has two words "en"
in SqlServer the LINGUA column has three corners "eng"
I made the query:
//DB2
private static final String DB_DRIVER_DB2 = "com.ibm.db2.jcc.DB2Driver";
private static final String DB_CONNECTION_DB2 = "jdbc:db2://10.12.230.83:50000/PANTH01";
private static final String DB_USER_DB2 = "finance";
private static final String DB_PASSWORD_DB2 = "finance";
//SQLSERVER
private static final String DB_DRIVER_SQLSERVER = "net.sourceforge.jtds.jdbc.Driver";
private static final String DB_CONNECTION_SQLSERVER = "jdbc:jtds:sqlserver://10.65.21.15:1433;DatabaseName=PROVA";
private static final String DB_USER_SQLSERVER = "sa";
private static final String DB_PASSWORD_SQLSERVER = "sa";
public void selectTHERACLASS_HDR_THERACLASS_HDR_NLS() throws Exception {
//DB2_inizio
Connection dbConnection = null;
Statement statement = null;
//DB2_fine
//SqlServer_inzio
Connection dbConnectionSqlServer = null;
Statement statementSqlServer = null;
//SqlServer_fine
//Query SqlServer and db2
String query = "select PANTH01.THERA.CLASS_HDR.LANGUAGE, PROVA.DIZIOPT.LINGUA from PANTH01.THERA.CLASS_HDR JOIN PROVA.DIZIOPT.LINGUA ON PANTH01.THERA.CLASS_HDR.LANGUAGE = PROVA.DIZIOPT.LINGUA";
try {
//DB2_inizio
dbConnection = getConnectionDb2();
statement = dbConnection.createStatement();
//DB2_fine
//sqlserver_inizio
dbConnectionSqlServer = getConnectionSqlServer();
statementSqlServer = dbConnectionSqlServer.createStatement();
ResultSet rSqlServer = statementSqlServer.executeQuery(query);
//sqlserver_inizio_fine
while (rSqlServer.next()) {
String language = rSqlServer.getString("LANGUAGE");
String lingua = rSqlServer.getString("LINGUA");
System.out.println("LANGUAGE: " + language);
System.out.println("LINGUA: " + lingua);
}
} catch (SQLException e) {
System.out.println(e.getMessage());
} finally {
if (statement != null && statementSqlServer != null) {
statement.close();
statementSqlServer.close();
}
if (dbConnection != null && dbConnectionSqlServer != null) {
dbConnection.close();
dbConnectionSqlServer.close();
}
}
}
Output
Invalid object name 'PANTH01.THERA.CLASS_HDR'

android.database.sqlite.SQLiteException: no such column: user_id (code 1 SQLITE_ERROR):

being an Android Studio beginner i tend to get lots and lots of tiny errors i cannot find out, please let me know what I am doing wrong because I've tried all the other answers somehow and it doesn't get better :)
public class DatabaseHelper extends SQLiteOpenHelper{
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "UserManager.db";
private static final String TABLE_USER = "user";
private static final String COLUMN_USER_ID= "user_id";
private static final String COLUMN_USER_NAME= "user_name";
private static final String COLUMN_USER_EMAIL= "user_email";
private static final String COLUMN_USER_PASSWORD= "user_password";
private String CREATE_USER_TABLE = "CREATE TABLE " + TABLE_USER + "(" +
COLUMN_USER_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COLUMN_USER_NAME + " TEXT," + COLUMN_USER_EMAIL + " TEXT," +
COLUMN_USER_PASSWORD + " TEXT" + ")";
private String DROP_USER_TABLE = " DROP TABLE IF EXISTS " + TABLE_USER;
public DatabaseHelper(Context context){
super(context, DATABASE_NAME,null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db){
db.execSQL(CREATE_USER_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
db.execSQL(DROP_USER_TABLE);
onCreate(db);
}
public void addUser(User user){
SQLiteDatabase db= this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_USER_NAME, user.getName());
values.put(COLUMN_USER_EMAIL, user.getEmail());
values.put(COLUMN_USER_PASSWORD, user.getPassword());
db.insert(TABLE_USER,null, values);
db.close();
}
public boolean checkUser(String password, String email){
String[] columns = {
COLUMN_USER_ID
};
SQLiteDatabase db= this.getWritableDatabase();
String selection = COLUMN_USER_EMAIL + " = ? " + "AND "+ COLUMN_USER_PASSWORD+" =? ";
String[] selectionArgs = { email,password };
Cursor cursor = db.query(TABLE_USER,
columns,
selection,
selectionArgs,
null,
null,
null);
int cursorCount = cursor.getCount();
cursor.close();
db.close();
if(cursorCount > 0){
return true;
}
return false;
}
}
I know the logcat let me know this:
07-11 22:08:29.072 9071-9071/com.example.lavinia.sqllogin E/AndroidRuntime:
FATAL EXCEPTION: main
Process: com.example.lavinia.sqllogin, PID: 9071
android.database.sqlite.SQLiteException: no such column: user_id (code 1
SQLITE_ERROR): , while compiling: SELECT user_id FROM user WHERE user_email =
?AND user_password =?
And I can't find the wrong usage of user_id, I think I used it fine and the app will stop working after I Login myself. (the app has login and registration activities- and the registration works ok, but pressing the Login button in the Login.activity will make the app crash)
Thank you very much for you support :) If needed, I will provide with further code.
This issue is probably due to i tend to get lots and lots of tiny errors in conjunction with a common misconception regarding the onCreate method.
The onCreate method automatically runs only once when the database is and has actually been created. It does not run every time the App is run.
As such any changes (corrections included) to the structure (tables and columns) will not be applied if they are coded/actioned within the onCreate method.
When developing the easiest fix is to do one of the following 3:-
delete the App's data (deletes the database so onCreate will be called).
uninstall the App (deletes the database so onCreate will be called).
if the onUpgrade method will drop the table(s) and then call onCreate , to increase the database version number as passed as the 4th parameter to the SQLIteOpenHelper sub-class (aka the DatabaseHelper class).
After doing one of the above, rerun the App.
NOTE any existing data will be lost.
If data has to be retained then a fix is more complicated but would be based upon using ALTER TABLE statements.

How can I implement this T-SQL in my stored procedure?

I'm new to SQL Server and want to implement this scenario. My stored procedure gets 8 input parameters from a C# web application, and checks all input has into the table. For that purpose I wrote this simple stored procedure:
CREATE PROCEDURE CheckValid
#p_bank varchar,
#p_pay_date varchar,
#p_bill_id varchar,
#p_payment_id varchar,
#p_ref_code varchar,
#p_branch varchar,
#p_channel_type varchar,
#p_send_date varchar
AS
BEGIN
SELECT
[p_bank], [p_pay_date], [p_bill_id], [p_payment_id],
[p_ref_code], [p_branch], [p_channel_type], [p_send_date]
FROM
[SAMPLE].[dbo].[MixedTable]
WHERE
[p_bank] = #p_bank
AND [p_pay_date] = #p_pay_date
AND [p_bill_id] = #p_bill_id
AND [p_payment_id] = #p_payment_id
AND [p_ref_code] = #p_ref_code
AND [p_branch] = #p_branch
AND [p_channel_type] = #p_channel_type
AND [p_send_date] = #p_send_date
END
But want to return to c# application this scenario, for example c# sends all field but when stored procedure select run for this purpose can not find data, for example p_bill_id not correct into the table for more explain in select query into where clause in the [p_bill_id]=#p_bill_id not trust and now want to return sp this :
p_bill_id,not found
and other example c# all variable correct but two field [p_channel_type] and [p_payment_id] not correct into where clause but other 6 field correct now SP return this:
[p_channel_type],not found
[p_payment_id],not found
Summary of question:
When data for passed parameter value is not found, I want it to return that corresponding column.
For example:
[p_channel_type],not found
[p_payment_id],not found
Note, varchar means varchar(1) so you should specify length for each argument explicitly like varchar(100)
CREATE PROCEDURE CheckValid
#p_bank varchar(<length>),
#p_pay_date varchar(<length>),
#p_bill_id varchar(<length>),
#p_payment_id varchar(<length>),
#p_ref_code varchar(<length>),
#p_branch varchar(<length>),
#p_channel_type varchar(<length>),
#p_send_date varchar(<length>)
AS
BEGIN
if not exists(select 1 from dbo.BankTable where p_bank = #p_bank)
begin
raiserror('Bank %s not found', 16, 1, #p_bank)
return
end
if not exists(select 1 from dbo.BillTable where p_bill_id = #p_bill_id)
begin
raiserror('Bill %s not found', 16, 1, #p_bill_id)
return
end
...
SELECT [p_bank],[p_pay_date],[p_bill_id],[p_payment_id],[p_ref_code],[p_branch],[p_channel_type],[p_send_date]
FROM [SAMPLE].[dbo].[MixedTable]
where [p_bank]=#p_bank and [p_pay_date]=#p_pay_date
and [p_bill_id]=#p_bill_id and [p_payment_id]=#p_payment_id
and [p_ref_code]=#p_ref_code and [p_branch]=#p_branch
and [p_channel_type]=#p_channel_type and [p_send_date]=#p_send_date
END
GO
Instead of creating stored procedure for this move "validation" logic to your c# application.
Database is just IO device and I think keeping "business logic" in IO device not a good approach.
// Class which represent your eight parameters
public class Data
{
public string Bank { get; set; }
public string PayDate { get; set; }
public string BillId { get; set; }
public string PaymentId { get; set; }
public string RefCode { get; set; }
public string Branch { get; set; }
public string ChannelType { get; set; }
public string SendDate { get; set; }
}
public class Validation
{
private Data _data;
public Validation(Data data)
{
_data = data;
}
public IEnumerable<string> Validate()
{
var columns = new KeyValuePair<string, string>[]
{
new KeyValuePair("p_bank", _data.Bank),
new KeyValuePair("p_pay_date", _data.PayDate),
new KeyValuePair("p_bill_id", _data.BillId),
new KeyValuePair("p_payment_id", _data.PaymentId),
new KeyValuePair("p_ref_code], _data.RefCode),
new KeyValuePair("p_branch", _data.Branch),
new KeyValuePair("p_channel_type", _data.ChannelType),
new KeyValuePair("p_send_date", _data.SendDate)
};
return columns.Where(pair => IsValueExists(pair.Key, pair.Value) == false);
}
private bool IsValueExists(string columnName, string value)
{
var query =
$"SELECT [{columnName}]
FROM [SAMPLE].[dbo].[MixedTable]
WHERE [{columnName}] = #value";
var parameter = new SqlParameter
{
ParameterName = "#value",
SqlDbType = SqlDbType.VarChar,
Value = _data.Bank
};
using (var connection = new SqlConnection(yourConnectionString))
using (var command = new SqlCommand(query, connection))
{
command.Parameters.Add(parameter);
connection.Open();
var value = command.ExecuteScalar();
return value != null; // null returned if no rows exists
}
}
}
Then you can use this method somewhere
var data = new Data { Bank = "BankName", RefCode = "SomeRefcode" } // put all values
var validation = new Validation(data);
var invalidValues = validation.Validate();
foreach(var invalidValue in invalidValues)
{
// Print or save column names where value is invalid
}

Prevent SQL injection when building query

I know usually how to prevent it using preparedStatements, but now I have such a method for bulding queries. For example in Java:
private String buildQuery(String where) {
String query = "SELECT id, name FROM someTable";
if(where.length() > 0) {
query = query + " WHERE " + where;
}
return query;
}
'where' string is like this 'variable = value'. How can i prevent it here? I thought of passing variable and value separately, creating prepared statement using them and then returning that prepared statement as string somehow, but I'm not sure.
This is not specific to any one DB API.
TL;DR: Don't pass "SQL fragments" around.
Rather than passing complete clauses fro a select statement, or (sub-)expressions to add into a select clause, pass the components keeping the user data separate from the identifiers.
In this case do not pass name = value, pass them separately. Then validate name is a valid column for the table, and generate a parameter for the value part.
Thus, pseudo-code (my Java is rusty):
function BuildCommand(string column, object value) {
if !IsValidColumn("theTable", column)) throw InvalidOperation(...)
string sql = "Select column from theTable where " + column + " = #p0";
SqlCommand cmd = new SqlCommand(sql);
cmd.Parameters.Add("#p0", value);
return cmd;
}
You can use a map to pass your values and build a preparedStatement. Check the code below it should be something similar to that logic
public static PreparedStatement buildQuery(String where,Map<Integer, String> cond)
throws SQLException {
PreparedStatement stat = null;
String query = "SELECT id, name FROM someTable " + where;
try {
stat = con.prepareStatement(query);
for (Map.Entry<Integer, String> e : cond.entrySet()) {
stat.setString(e.getKey(), e.getValue());
}
} catch (SQLException e ) {
// Handle ex
} finally {
}
return stat;
}
public static void main(String[] a) throws SQLException {
Map<Integer,String> cond =new HashMap<Integer, String>();
cond.put(1,"val22");
cond.put(2,"val2");
buildQuery("col1 = ? and col2= ?", cond);
}
My suggestion is that if you have an array of where clauses in the parameter and rewrite the function as :
private String buildQuery(String[] where) {
String query = "SELECT id, name FROM someTable";
query = query + " WHERE "
for(int i = 0; i < where.length; i++) {
if(i > 0){
query = query + " AND "
}
query = query + w + " = ?";
}
return query;
}

Resources