Android - SQLiteStatement (multiple insert) execute fails with API Level 14 - android

I use the following code to insert new lines efficiently in a DB :
#Override
public void insertImpacts(HolderExpense expense, int[] shares, int[] amounts, HolderUser[] users) {
try {
mDb.beginTransaction(); // the insertion of the impacts of one expense are considered to be ONE block
String sql = "INSERT INTO "+DATABASE_TABLE_IMPACTS+" "+
"("+IMPACT_USERROWID+", "+IMPACT_EXPENSEROWID+", "+IMPACT_TTROWID+", "+IMPACT_NUMBEROFPARTS+", "+IMPACT_FIXEDAMOUNT+") VALUES (?, ?, ?, ?, ?)";
SQLiteStatement stmt = mDb.compileStatement(sql);
stmt.bindLong(2, expense.rowId);
stmt.bindLong(3, expense.tt.rowId);
int i = 0;
while (i < shares.length) {
if (users[i] != null) {
Log.v(TAG, "user " +i+": users[i].rowId:"+users[i].rowId+" expense.rowId:"+expense.rowId+" expense.tt.rowId:"+expense.tt.rowId+" shares[i]:"+shares[i]+" amounts[i]:"+amounts[i]+" ");
stmt.bindLong(1, users[i].rowId);
stmt.bindString(4, shares[i]+"");
stmt.bindString(5, amounts[i]+"");
stmt.execute();
}
i++;
}
stmt.close();
mDb.setTransactionSuccessful();
}
catch (Exception e) { e.printStackTrace(); throw new RuntimeException("insertImpacts() failed"); }
finally { mDb.endTransaction(); }
}
It works until android 4.x where I get that error:
02-26 14:27:46.179: W/System.err(937): android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed
02-26 14:27:46.179: W/System.err(937): at android.database.sqlite.SQLiteStatement.native_execute(Native Method)
02-26 14:27:46.219: W/System.err(937): at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:92)
02-26 14:27:46.219: W/System.err(937): at android.database.sqlite.SQLiteStatement.execute(SQLiteStatement.java:70)
Seems it crashes at stmt.execute() when inserting the second line into the table.
Any clue ?
-- EDITION --
The schema of the table is the following:
private static final String DATABASE_CREATE_TABLE_IMPACTS =
"create table " + DATABASE_TABLE_IMPACTS + " ("
+ IMPACT_ROWID + " integer primary key autoincrement, "
+ IMPACT_USERROWID + " integer not null, "
+ IMPACT_EXPENSEROWID + " integer not null, "
+ IMPACT_TTROWID + " integer not null, "
+ IMPACT_NUMBEROFPARTS + " integer not null, "
+ IMPACT_FIXEDAMOUNT + " integer not null, "
+ "constraint i_cstr1 unique ("+IMPACT_USERROWID+", "+IMPACT_EXPENSEROWID+")); ";
This code works like a charm on Android 2.2 (but fails on Android 4.0).
Print of the two first lines I insert (it crashes when trying to insert the second):
02-26 14:27:46.069: E/DatabaseAdapter.java(937): user 0: users[i].rowId:7 expense.rowId:2 expense.tt.rowId:2 shares[i]:1 amounts[i]:-1
02-26 14:27:46.069: E/DatabaseAdapter.java(937): user 1: users[i].rowId:5 expense.rowId:2 expense.tt.rowId:2 shares[i]:1 amounts[i]:-1

Found. The different version of android do not behave the same way. On Android 4.x, all the 'bindXXX' lines must be placed in the 'while' loop. Even if it is repetitive.
while (i < shares.length) {
if (users[i] != null) {
stmt.bindLong(1, users[i].rowId);
stmt.bindLong(2, expense.rowId);
stmt.bindLong(3, expense.tt.rowId);
stmt.bindString(4, String.valueOf(shares[i]));
stmt.bindString(5, String.valueOf(amounts[i]));
stmt.execute();
}
i++;
}

This is perfect Gilbou! I also made your data binding solution for my task: csv file importing to SQLite database. There was about 25.000 rows in the csv file, and importing it and insert to SQLite takes for me about 5 seconds (before it took 5 minutes without data binding!!)
Thank you so so much!
I also share mine, maybe it can helps for somebody, too (Android 4.0):
public boolean updateFromCsv() {
boolean ok = true;
String line = "";
BufferedReader br = null;
try {
FileInputStream fis = new FileInputStream(Environment
.getExternalStorageDirectory().getAbsolutePath()
+ "/Servantes/Be/leltariv_export.csv");
br = new BufferedReader(new InputStreamReader(fis));
} catch (FileNotFoundException e) {
ok = false;
e.printStackTrace();
}
try {
database.beginTransaction();
String sql = "INSERT INTO "+LeltarTable.TABLE_LELTAR_NEV+" "+
"("+LeltarTable.COLUMN_ID+", "+LeltarTable.COLUMN_LSZ+", "+LeltarTable.COLUMN_MEGN+", "+LeltarTable.COLUMN_HELY+", "+LeltarTable.COLUMN_DARAB+") VALUES (?, ?, ?, ?, 0)";
SQLiteStatement stmt = database.compileStatement(sql);
while ((line = br.readLine()) != null) {
String[] colums = line.split(";");
stmt.bindAllArgsAsStrings(colums);
stmt.execute();
}
stmt.close();
database.setTransactionSuccessful();
}catch (Exception e) {
e.printStackTrace();
ok = false;
}
finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
ok = false;
}
database.endTransaction();
}
return ok;
}

Related

Android - SQLiteException while deleting record

Currently We have one application in which we are receiving many crash reports while deleting record from database .
Here is method in which app is crashing.
public int deleteGroupMap(String nickName) {
SQLiteDatabase database = this.getWritableDatabase();
try {
return database.delete(TABLE_NAME_GROUP_MAP, COLUMN_GMAP_NICK_NAME + " = '" + nickName + "'", null);
} catch (Exception e) {
e.printStackTrace();
} finally {
database.close();
}
return 0;
}
but we am getting following exception:
android.database.sqlite.SQLiteException: near "adz": syntax error
(code 1): , while compiling: DELETE FROM groups_map WHERE
gmap_nick_name = ''adz.'
Any help will be appreciated.
Look at delete signature:
int delete (String table, String whereClause, String[] whereArgs)
Third argument is where args:
You may include ?s in the where clause, which will be replaced by the
values from whereArgs. The values will be bound as Strings.
It's automatically escaped, so there is no need to put quotes (', ") manually.
Use where args instead of strings concating:
database.delete(TABLE_NAME_GROUP_MAP, COLUMN_GMAP_NICK_NAME + " = ?", new String[] { nickName });
Try Like This
public int deleteGroupMap(String nickName) {
SQLiteDatabase database = this.getWritableDatabase();
try {
database .execSQL("DELETE FROM "+ TABLE_NAME_GROUP_MAP + " WHERE " + COLUMN_GMAP_NICK_NAME + " = "+nickName+"");
database .close();
} catch (Exception e) {
e.printStackTrace();
} finally {
database.close();
}
return 0;
}
Try this
return database.delete(TABLE_NAME_GROUP_MAP, COLUMN_GMAP_NICK_NAME + "= ?" , new String[]{Long.toString(nickName)});
You should also use parameter markers because appending values directly is error prone when the source contains special characters.
try following because it will also prevent SQL injections to your app
database.delete(TABLE_NAME_GROUP_MAP, COLUMN_GMAP_NICK_NAME + "=?", new String[]{String.valueOf(nickName));

Connect to MSSQL with USB in android

private void fillCustomerInformationFields() throws SQLException {
Connection conn = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet;
Intent intent = getIntent();
String IDValue = intent.getStringExtra("id");
String query = "SELECT SiparisID, M.MusteriAdi + ' ' + M.MusteriSoyadi AS MusteriAdi, U.UrunAdi," +
" CASE WHEN OdemeTuru=0 THEN ? WHEN OdemeTuru=1 THEN ? WHEN OdemeTuru=2 THEN ? END AS OdemeTuru, TeslimTarihi,"+
"M.musteriAdresi, SiparisDurumu, Aciklama FROM Siparisler S INNER JOIN Musteriler M ON M.MusteriID=S.MusteriID INNER JOIN Urunler U ON U.UrunID=S.urunID"+
"WHERE S.SiparisID='"+IDValue+"'";
try {
conn = getDBConnection();
preparedStatement = conn.prepareStatement(query);
preparedStatement.setString(1,"Peşin");
preparedStatement.setString(2,"Taksitli");
preparedStatement.setString(3,"Kapıda");
resultSet = preparedStatement.executeQuery();
while(resultSet.next())
{
edtSiparisID.setText(resultSet.getString("SiparisID"));
edtUrunAdi.setText(resultSet.getString("UrunAdi"));
edtMusteriAdi.setText(resultSet.getString("MusteriAdi"));
edtOdemeTuru.setText(resultSet.getString("OdemeTuru"));
edtTeslimTarihi.setText(resultSet.getString("TeslimTarihi"));
edtSiparisAdresi.setText(resultSet.getString("musteriAdresi"));
edtAciklama.setText(resultSet.getString("Aciklama"));
}
}catch (SQLException e){
e.printStackTrace();
}finally {
if(preparedStatement != null){
preparedStatement.close();
}
if(conn != null){
conn.close();
}
}
}
Hello everyone. İ'm making a project and i connect to mssql from android app via usb. I wrote to code for read data from mssql but i'm getting error. how can i fix the error? Thanks for the help
The exception displayed in LogCat is:
com.example.uur.stock W/System.err﹕ java.sql.SQLException: Incorrect syntax near 'S'.
Check your query
String query = "SELECT SiparisID, M.MusteriAdi + ' ' + M.MusteriSoyadi AS MusteriAdi, U.UrunAdi," +
" CASE WHEN OdemeTuru=0 THEN ? WHEN OdemeTuru=1 THEN ? WHEN OdemeTuru=2 THEN ? END AS OdemeTuru, TeslimTarihi,"+
"M.musteriAdresi, SiparisDurumu, Aciklama FROM Siparisler S INNER JOIN Musteriler M ON M.MusteriID=S.MusteriID INNER JOIN Urunler U ON U.UrunID=S.urunID"+
"WHERE S.SiparisID='"+IDValue+"'";
this is causing the exception:
FROM Siparisler S JOIN Musteriler M
must change to
FROM Siparisler as S JOIN Musteriler as M
More info:
SQLite - ALIAS Syntax

Multiple Where clause in Android SQL statement

I am having some problem with the SQL statement for Android. Basically I have two where clause, bookID and userID and the SQL statement that I am having now:
public boolean updateLoan(String bookID, String userID, String currentDate) {
try {
ContentValues cv = new ContentValues();
cv.put("loanDate", currentDate);
mDb.update("loanBook", cv,
" bookID= '" + bookID + "'", null);
return true;
} catch (Exception ex) {
Log.e(TAG, ex.toString());
return false;
}
}
So I wonder how could I put two where clause in this method as currently I only can where clause by bookID. Do I simply put an "&" and continue the SQL statement?
Thanks in advance.
Do I simply put an "&" and continue the SQL statement?
Yes, use AND instead of &

SQLiteDatabaseLockedException: database is locked retrycount exceeded

I am doing Stock management application and it required frequent access to database to view and edit data. While repeating this process many times ,database get locked.
Getting 2 error :
"A SQLiteConnection object for database was leaked! Please fix your application to end transactions in progress properly and to close the database when it is no longer needed."
"SQLiteDatabaseLockedException: database is locked (code 5): retrycount exceeded"
After get this error it take long time to complete database insert operation.
How can I fix this issue.
public synchronized boolean insert(BeanOrderHeader orderHdrItem) throws Exception {
boolean status=false;
try {
//Create Sqlite object to insert order details
db = getSQLiteDatabase();
//Before insert delete records if already exists
deleteOrderData(db,orderHdrItem);
db.beginTransactionNonExclusive();
// db.beginTransaction();
getPaymentPreparedStatement(db,orderHdrItem);
status= true;
db.setTransactionSuccessful();
db.endTransaction();
if(orderHdrItem.isNewOrder())
mCounterProvider.updateOrderBillNumber();
} catch (Exception e) {
e.printStackTrace();
status= false;
throw new Exception("Failed to save the order. Please check the log for details");
}finally{
db.setTransactionSuccessful();
db.endTransaction();
}
return status;
}
protected SQLiteDatabase getSQLiteDatabase() {
if(myDataBase==null)
open();
if(!myDataBase.isOpen())
open();
return myDataBase;
}
public SQLiteStatement getPaymentPreparedStatement(SQLiteDatabase db,BeanOrderHeader
orderHeader) throws Exception{
ArrayList<BeanOrderPayment> orderPaymentlList=orderHeader.getOrderPaymentItems();
SQLiteStatement prep;
String insert_sql="insert into "+"order_payments "+" (" +
"order_id, "+
"payment_mode, "+
"paid_amount, "+
"card_name, "+
"card_type, "+
"card_no, "+
"name_on_card, "+
"card_expiry_month, "+
"card_expiry_year, "+
"card_approval_code, "+
"card_account_type, "+
"company_id, "+
"voucher_id, "+
"voucher_value, "+
"voucher_count, "+
"cashier_id, "+
"payment_date, " +
"payment_time "+
",id " +
",discount_id" +
",discount_code" +
",discount_name" +
",discount_description" +
",discount_price" +
",discount_is_percentage" +
",discount_is_overridable" +
",discount_amount" +
",is_repayment" +
",is_voucher_balance_returned" +
",partial_balance" +
") "+
" values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
prep=db.compileStatement(insert_sql);
int counter=0;
if(mPosOrderUtil==null)
mPosOrderUtil=new PosOrderUtil(getContext());
for (BeanOrderPayment payItem: orderPaymentlList){
prep.bindString(1, payItem.getOrderId());
prep.bindLong(2, payItem.getPaymentMode().getValue());
prep.bindDouble(3, payItem.getPaidAmount());
prep.bindString(4, payItem.getCardName());
prep.bindString(5, payItem.getCardType());
prep.bindString(6, payItem.getCardNo());
prep.bindString(7, payItem.getNameOnCard());
prep.bindLong(8, payItem.getCardExpiryMonth());
prep.bindLong(9, payItem.getCardExpiryYear());
prep.bindString(10, payItem.getCardApprovalCode());
prep.bindString(11, payItem.getAccount());
prep.bindLong(12, payItem.getCompanyId());
prep.bindLong(13, payItem.getVoucherId());
prep.bindDouble(14, payItem.getVoucherValue());
prep.bindLong(15, payItem.getVoucherCount());
prep.bindLong(16, payItem.getCashierID());
prep.bindString(17, payItem.getPaymentDate());
prep.bindString(18, payItem.getPaymentTime());
prep.bindString(19, mPosOrderUtil.appendToId(orderHeader.getOrderId(), counter++)); //Id generated from order id
BeanDiscount disc=payItem.getDiscount();
if(disc!=null){
prep.bindLong(20, disc.getId());
prep.bindString(21, disc.getCode());
prep.bindString(22, disc.getName());
prep.bindString(23, disc.getDescription());
prep.bindDouble(24, disc.getPrice());
prep.bindLong(25, getIntFromBoolean(disc.isPercentage()));
prep.bindLong(26, getIntFromBoolean(disc.isOverridable()));
prep.bindDouble(27, payItem.getPaidAmount());
}
prep.bindLong(28, getIntFromBoolean(payItem.isRepayment()));
prep.bindLong(29, getIntFromBoolean(payItem.isVoucherBalanceReturned()));
prep.bindDouble(30, payItem.getPartialBalance());
prep.executeInsert();
prep.clearBindings();
}
return prep;
}
You need to close your SQLiteHelper class instance after db operations
dbHelper.close()
At last I resolve issue by keeping a single object of SQLiteDatabase instance. If database structure is complex, use single object to access data from all table so we can manage sq-lite database easily.
After db operations close database object to resolve database leak
mDatabase.close()
The other reason for this SQLiteDatabaseLockedException is starting a transaction and not closing it in finally block and later trying to do something with the DB.
Bad:
SQLiteDatabase db = this.getReadableDatabase();
db.beginTransaction();
//DO some db writing
db.setTransactionSuccessful();
db.endTransaction();
Good:
SQLiteDatabase db = this.getReadableDatabase();
db.beginTransaction();
try {
//DO some db writing
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

Error on using REPLACE character manipulation function on query SQLite Android

it gives me an error when I am using this key but when I use LENGTH, it works fine. I hope it is allowed on android sqlite coz it's the best way for this:
I am just trying to remove the spaces after words that will be selected from Database.
public ArrayList<String> getCorrectList() {
// TODO Auto-generated method stub
Cursor c = db.rawQuery("SELECT REPLACE(Level_1, ' ', '') FROM " + TABLE, null);
ArrayList<String> resultsList = new ArrayList<String>();
try {
if (c != null) {
if (c.moveToFirst()) {
do {
String levelData = c.getString(c
.getColumnIndex("Level_1"));
resultsList.add("" + c.getColumnIndex("Level_1"));
} while (c.moveToNext());
}
}
} catch (SQLiteException e) {
Log.e("Database", "Cannot get List (" + e + ")");
}
Log.d("array", "List: " + resultsList);
Collections.shuffle(resultsList);
return resultsList;
}
This works fine in SQLite3 shell:
e$ sqlite3
SQLite version 3.7.14.1 2012-10-04 19:37:12
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table t(a,b,c);
sqlite> select replace(a,' ', '') from t;
REPLACE is both a function and a command in SQLite3. Perhaps db.rawQuery is parsing the query and getting confused by REPLACE. Try this:
db.rawQuery("select rtrim(replace(Level_1, ' ', '')) FROM " + TABLE, null);

Categories

Resources