public void deleteData(String name,int itemID){
SQLiteDatabase db=getWritableDatabase();
String query="DELETE FROM "+ TABLE_NAME + " WHERE "+ "'"+ COL1 +"'"+ " = "+ itemID + " AND "+ "'" + COL2 + "'" +" ="+ " '"+ name + "'";
db.execSQL(query);
db.execSQL(query);
}
The following are wrong or could be considered as wrong.
There should be no need to call the exact same query twice.
It is considered better to use the Android SDK's convenience methods when they suit (instead of using the execSQL method the delete method is more appropriate).
There is the potential for SQLinjection attacks when parameters are used directly in strings that are executed directly as SQL (note resolving 2 and using the appropriate parameters resolves this issue).
There is, unless the columns are named with invalid names, no need to enclose column names in single quotes or alternative characters (invalid names can make life difficult so if used they would be considered wrong by many).
If the delete (the first one), is not working or if the delete appears to not return an appropriate result after using pragma count_changes that could be due to the row not existing (did the row get inserted?) or that the 2nd query which would delete nothing is hiding the result of the first query.
pragma count_changes is deprecated in later version of SQLite so should no longer be used (albeit that Android's SQlite version is typically some way behind).
As a fix to all bar the id not existing you could use the following :-
public int deleteData(String name,int itemID){
SQLiteDatabase db=getWritableDatabase();
String whereclause = COL1 + "=? AND " + COL2 + "=?";
String[] whereargs = new String[]{String.valueOf(int),name};
return db.delete(TABLE_NAME,whereclause,whereargs);
}
Note that the methods signature results in an int being returned, this will be the number of rows deleted.
Related
In android studio, I want to take a value from an edit text and put it in database, when I enter another value from the edit text it will add that to the first one. like if i put 50, then i put 25, in the database it will contain 75
i am using this code to update the values in the database
public boolean addvalue(long rowId, String newAmt) {
String where = "KEY_ROWID" + "=" + rowid;
SQLiteDatabase db = myDBHelper.getWritableDatabase();
ContentValues newValues = new ContentValues();
newValues.put(KEY_PROG, newAmt);
return db.update(DATABASE_TABLE, newValues, where, null) !=0;
}
when i try to run, the update does apply and it simply replaces the former with the latter, i am still new to android studio and sqlite please help
ContentValues objects handle only plain values.
To be able to do computations, you have to use execSQL() instead:
db.execSQL("UPDATE "+DATABASE_TABLE+
" SET "+KEY_PROG+"="+KEY_PROG+"+?"+
" WHERE "+KEY_ROWID+"=?",
new Object[]{ newAmt, rowId });
execSQL() does not return anything, so if you really need the number of updated rows, you have to use a separate query:
return DatabaseUtils.longForQuery(db, "SELECT changes()", null) > 0;
The code I have a problem with:
NpgsqlCommand if_ex = new NpgsqlCommand("SELECT count(id_unit) FROM unit WHERE name=" + "'" + tmp + "'", conn);
int ex = (int)if_ex.ExecuteScalar();
Throws an exception:
Specified cast is not valid.
I am trying to get the row count of columns that have the same name (the string that I pass)
i know I should use parameters, but at this point I am only testing a few things so I figured might as well just do it like this for now.
This problem happens because the return type of a query like: select count(*) is an long and not an int. If you change your code to long ex = (long)if_ex.ExecuteScalar(); you will get what you want. I hope it helps.
Read this:
https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
On the dynamic sql part it has various such as this:
So, if you had an existing Dynamic query being generated in your code that was going to Oracle that looked like this:
String query = "SELECT user_id FROM user_data WHERE user_name = '" + req.getParameter("userID")
+ "' and user_password = '" + req.getParameter("pwd") +"'";
try {
Statement statement = connection.createStatement( … );
ResultSet results = statement.executeQuery( query );
}
You would rewrite the first line to look like this:
Codec ORACLE_CODEC = new OracleCodec();
String query = "SELECT user_id FROM user_data WHERE user_name = '" +
ESAPI.encoder().encodeForSQL( ORACLE_CODEC, req.getParameter("userID")) + "' and user_password = '"
+ ESAPI.encoder().encodeForSQL( ORACLE_CODEC, req.getParameter("pwd")) +"'";
And it would now be safe from SQL injection, regardless of the input supplied.
But the later is says:
Oracle 10g escaping
An alternative for Oracle 10g and later is to place { and } around the string to escape the entire string. However, you have to be careful that there isn't a } character already in the string. You must search for these and if there is one, then you must replace it with }}. Otherwise that character will end the escaping early, and may introduce a vulnerability.
I did not see an example, but does this mean I can use braces instead of the Codec ORACLE_CODEC....etc.? Does anyone have an example? Thanks.
No, this is not an injection prevention technique. The only way to be 100% sure that you're not vulnerable to injection is to use prepared statements and bind parameters for all user input that needs to be inserted into the query. Anything less than that, and you're pretty much just rolling the dice.
In SQLite I can run the following query to get a list of columns in a table:
PRAGMA table_info(myTable)
This gives me the columns but no information about what the primary keys may be. Additionally, I can run the following two queries for finding indexes and foreign keys:
PRAGMA index_list(myTable)
PRAGMA foreign_key_list(myTable)
But I cannot seem to figure out how to view the primary keys. Does anyone know how I can go about doing this?
Note: I also know that I can do:
select * from sqlite_master where type = 'table' and name ='myTable';
And it will give the the create table statement which shows the primary keys. But I am looking for a way to do this without parsing the create statement.
The table_info DOES give you a column named pk (last one) indicating if it is a primary key (if so the index of it in the key) or not (zero).
To clarify, from the documentation:
The "pk" column in the result set is zero for columns that are not
part of the primary key, and is the index of the column in the primary
key for columns that are part of the primary key.
Hopefully this helps someone:
After some research and pain the command that worked for me to find the primary key column name was:
SELECT l.name FROM pragma_table_info("Table_Name") as l WHERE l.pk = 1;
For the ones trying to retrieve a pk name in android, and while using the ROOM library.
#Oogway101's answer was throwing an error: "no such column [your_table_name] ... etc.. etc...
my way of query submition was:
String pkSearch = "SELECT l.name FROM pragma_table_info(" + tableName + ") as l WHERE l.pk = 1;";
database.query(new SimpleSQLiteQuery(pkSearch)
I tried using the (") quotations and still error.
String pkSearch = "SELECT l.name FROM pragma_table_info(\"" + tableName + "\") as l WHERE l.pk = 1;";
So my solution was this:
String pragmaInfo = "PRAGMA table_info(" + tableName + ");";
Cursor c = database.query(new SimpleSQLiteQuery(pragmaInfo));
String id = null;
c.moveToFirst();
do {
if (c.getInt(5) == 1) {
id = c.getString(1);
}
} while (c.moveToNext() && id == null);
Log.println(Log.ASSERT, TAG, "AbstractDao: pk is: " + id);
The explanation is that:
A) PRAGMA table_info returns a cursor with various indices, the response is atleast of length 6... didnt check more...
B) index 1 has the column name.
C) index 5 has the "pk" value, either 0 if it is not a primary key, or 1 if its a pk.
You can define more than one pk so this will not bring an accurate result if your table has more than one (IMHO more than one is bad design and balloons the complexity of the database beyond human comprehension).
So how will this fit into the #Dao? (you may ask...)
When making the Dao "abstract" you have access to a default constructor which has the database in it:
from the docummentation:
An abstract #Dao class can optionally have a constructor that takes a Database as its only parameter.
this is the constructor that will grant you access to the query.
There is a catch though...
You may use the Dao during a database creation with the .addCallback() method:
instance = Room.databaseBuilder(context.getApplicationContext(),
AppDatabase2.class, "database")
.addCallback(
//You may use the Daos here.
)
.build();
If you run a query in the constructor of the Dao, the database will enter a feedback loop of infinite instantiation.
This means that the query MUST be used LAZILY (just at the moment the user needs something), and because the value will never change, it can be stored. and never re-queried.
I'm using Mac OS X v10.4.11 with the standard Java (1.5.0_19) and sqlite3 (3.1.3) that came it. (Yeah, a little old... but see comment below.)
I have a sqlite3 database with a table with a few hundred thousand rows, with "name" and "stored" text columns. Name is one of six (so far) short strings; stored is a 19-character standard date-time string. Each column has a stand-alone index. There are only six unique name values. The following query:
select distinct name from myTable where stored >= date("now");
lists the relevant names instantly when I perform it through the Mac OS X "sqlite3" application. But it takes over 2 seconds to find each name (total of about 15 seconds) when I do the same thing in the usual way in my application:
String q = "SELECT DISTINCT name FROM myTable " +
"WHERE stored >= DATE('now');" ;
try {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(q);
while (rs.next()) {
final String s = rs.getString("symbol");
System.err.println("Got " + s);
}
rs.close();
}
I've tried this with both sqlitejdbc-v054 and sqlitejdbc-v055 . No perceptible difference.
Is this a known deficiency? If not, anyone have any suggestions how to attack it ?