Why doesn't my function with variables update data? - python

def overwriteFlat(top, curTable, rawEntrylist, columns):
rawEntrylist = rawEntrylist
entryList = list()
for value in rawEntrylist:
entryList.append(value.get())
conn = sqlite3.connect('data.db')
c = conn.cursor()
for i in range(len(columns)):
if entryList[i] != '':
c.execute("""UPDATE """+curTable+""" SET """+columns[i]+""" = :"""+columns[i]+""" WHERE """+columns[0]+""" = """ + str(entryList[0]), {columns[i]: entryList[i]})
print(curTable,columns[i],entryList[i])
conn.commit()
c.close()
conn.close()
closeWin(top)
Output:
Flat ID 23
Flat Street Test
Flat Street_Number 100
I put in "Test" and "100" so that works. I provide a window for input, the input gets put into here and everything provided gets overwritten in provided ID. Because of print() I see it goes into the right table, it also selects the right column and doesn't throw any exception. But it doesn't update database.
Database not locked.
Variables all valid and work.
No exception is thrown.
Vulnerable to injection, soon as it works I'll change it.

Thanks to #JohnGordon i found the solution
But just so if someone wants to use Variables in Sqlite i will explain how as this is hardly explained anywhere on the Internet (at least at my Beginner-Programmer-Level)
Usually Sql commands work like this and are pretty static:
"UPDATE Your_Table SET Your_Column = :Your_Column WHERE IndexColumn = Your_Index), {Your_Column: Your_Value}"
But by using +Variable+ you can use Variables in there
so its the same thing but with whatever Variable you want:
"UPDATE "+curTable+" SET "+columns[i]+" = :"+columns[i]+" WHERE "+columns[i]+" = " + str(entryList[0]), {columns[i]: entryList[i]}
You can now have the Variables "curTable", "columns", "entryList" set to whatever you want and dont need a static line for everything
The same works with INSERT and the other things too
Edit: (its now 3 hours later, 1 AM and i got the safer way)
NOW THAT YOU GOT THAT READ THIS
you will be vulnerable to SQL Injection, and you need to still change that code to this:
query = " UPDATE "+curTable+" SET "+columns[i]+" = ? WHERE "+columns[0]+" = ?"
c.execute(query, (entryList[i], entryList[0], ))
this makes it safer, but as i am not a pro yet maybe someone can confirm
Edit: Removed triple-quotes as they are only needed in multiple-sentence sql stuff thanks for the hint #Tim Roberts

Related

SQLite3 Formatting Issue with Parameters - Updating an existing value by adding another value

I am currently in the process of learning how to use the sqlite3 module inside Python. I'm trying to write code that will update a value from a column in sqlite by adding a new value to an existing value, but I'm running into formatting issues that I don't know how to fix...
I know that the basic syntax for doing this (as far as I'm aware) is the following:
sql_statement = "UPDATE table
SET column_name = column_name + new_value
WHERE condition;"
The issue I'm running into is that I'm trying to insert the column name using dictionary parameters from python. This is where the problem is occuring in my code:
muscle = 'Lats'
num_sets = 5
week_num = 40
sql_statement = f"UPDATE WeeklyMuscleSets
SET {muscle} = (:muscle) + (:num_sets)
WHERE WeekID = (:week_num);"
parameters = {'muscle':muscle,'num_sets':num_sets,'week_num':week_num}
c.execute(sql_statement,parameters)
The code runs just fine, but instead of adding to the existing value in the table it is replacing it. I did some testing, and when I manually enter the value for the "muscle" variable, it updates just fine.
muscle = 'Lats'
num_sets = 5
week_num = 40
sql_statement = f"UPDATE WeeklyMuscleSets
SET {muscle} = Lats + (:num_sets)
WHERE WeekID = (:week_num);"
parameters = {'num_sets':num_sets,'week_num':week_num}
c.execute(sql_statement,parameters)
It also worked when I used f-string formatting for the muscle variable, however I know that is bad practice and leaves the code vulnerable to injection attacks.
For some reason when I use the parameters it doesn't add the new value to the existing one and instead replaces it, and I'm at a loss as to why. Any help with this is greatly appreciated!
This is parameterized query. Then the query and values are sent to the DBMS engin separately and the DBMS use the values in the parsed query. Then the parsed query stored and used again so the performance improved and SQL injection can not be happened.
If you want to add num_sets to the current value of muscle you must use muscle + :num_sets :
num_sets = 5
week_num = 40
sql_statement = f"UPDATE WeeklyMuscleSets
SET muscle = muscle + :num_sets
WHERE WeekID = :week_num;"
parameters = {'num_sets':num_sets,'week_num':week_num}
c.execute(sql_statement,parameters)
Are you sure your code runs fine? According to this post and this one, it isn't possible to use named placeholders for table names or column names. You are trying to use a named placeholder for a column so I would expect an exception to be raised.
Two ways around the problem spring to mind:
Use string {formatting}. As you point out, this has the downside of allowing SQL injection attacks. However, it is possible to sanitise data from the user. If security is that much of a concern, you should probably be using some kind of ORM instead of raw SQL.
Re-structure your table so that it looks more like:
create WeeklyMuscleSets (
muscle varchar,
number_of_sets number,
week number
)
and your query to look more like this:
update WeeklyMuscleSets
set number_of_sets = number_of_sets + :extra_sets
where muscle = :muscle

SQL Server variables not working

I have a script with the following:
UPDATE table
SET column to update = ?
WHERE condition = ?", "text to insert", "text to test condition"
For some reason SQL is not executing or even reading this line. When I misspell any of the reserved words or column names I do not get an error.
HOWEVER, when I have
UPDATE table
SET column to update = "text to insert"
WHERE Name = "text to test condition"
SQL behaves as expected.
The problem is the second method,which works, is not adequate for my needs. Am I missing something?
Thanks
Since this is tagged with pyodbc, I'm assuming you're trying to do run a query with parameters. Your code should probably read something like this:
pyodbc.execute(
"""
UPDATE table
SET column_to_update = ?
WHERE other_column = ?
""",
"text to put in column_to_update",
"text to test condition in other_column",
)
Please note that parameters marked with a ? must be tied to a data typed object such as a column, so they can be bound. See:
https://github.com/mkleehammer/pyodbc/wiki/Getting-started#parameters
Good luck!
I'm going to assume that you are trying to run a SQL query from some client code by passing in variables with the query, though I'm not sure of this or what language you might be using - please clarify and add tags so we can help.
SQL Server does not use ? for parameter placeholders like in other DBMS queries (say, SQLite which uses ? in the way you are trying to use them). Instead, you need to either let an ORM tool declare variables for you, and use those, or explicitly declare your own parameters and pass them in. You haven't told us the development environment you're using or what method of SQL connection and ORM (if any) you're using, but here's a quick example using the very excellent Dapper ORM in C# from here, given an open connection conn:
string val = "my value";
conn.Execute("insert MyTable (val) values(#val)", new {val});
// or: conn.Execute("insert MyTable (val) values(#val)", new {val = val});"
conn.Execute("update MyTable set val = #val where Id = #id", new {val, id = 1});
In the background, Dapper handles the mapping and creation of variables, such that the actual SQL script received by SQL Server is something closer to this:
-- first query:
declare #val nvarchar(max) = 'my value';
insert MyTable (val) values(#val);
-- second query:
declare #val nvarchar(max) = 'my value', #id int = 1;
update MyTable set val = #val where Id = #id
On the other hand, if you are just going to execute a raw query directly with a SqlConnection, try something like this (equivalent to the first query above):
// Assumes an open connection conn
string val = "my value";
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "insert MyTable (val) values(#val)";
cmd.Parameters.AddWithValue("#val", val); // This creates the #val declaration for you when the query is executed
cmd.ExecuteNonQuery();
}
Whatever you do, parameterize your parameters, and beware of SQL injection!
Hope that helps. If you'd like a clearer example, please give us some code to show how you're passing the query to the SQL Connection for execution.

Python Mysql get variable value after select completes

So I am trying to do an IF statement after the select is done in python. Hard to explain, better to provide an example of it:
customer = cursor.execute("SELECT * FROM customer")
try:
customer['name']="john"
(do something here)
except:
customer['name']!="john"
(do something else here)
I hope this makes sense and sorry if this is not enough information. Trying to think of how to explain this. I don't want it to do a WHERE statement in the select because I don't want it to NOT SELECT certain information just because their 'name' is not "john"
First of all, you are not telling us which library you are using for working with MySQL. I assume its MySQLdb.
After executing SQL query with cursor.execute you have to call fetchall or fetchone. In later case you will be able to do customer['name'].
Example:
results = cursor.execute("SELECT * FROM customers")
customer = cursor.fetchone()
You shouldn't be using try/except since there is not an obvious case when any exception is thrown or is expected.

Python Sqlite3 Database table isn't being updated

I'm creating a change-password page for a website, which requests the new password and the current password. The old password is hashed and salted using the scrypt library then compared to the password stored in the sqlite3 database, and if these are a match, the new password is hashed and the database is updated. However I am having difficulty executing the update command, as it throws a sqlite3.OperationalError: unrecognised token: "\" error. The execute statement currently has the following code:
c.execute("UPDATE users SET password = \'{0}\' WHERE memberID = \'{1}\'".format(newPas, memID))
Initially we believed this error to have been caused by the use of ' in the string formatting due to the presence of ' within the new password itself, so this was run again as:
c.execute("UPDATE users SET password = \"{0}\" WHERE memberID = \"{1}\"".format(newPas, memID))
This successfully runs, but doesn't actually change anything in the database. We also attempted to create a query string and then execute the string.
query = "UPDATE users SET password = {0} WHERE memberID = {1}".format(newPas, memID)
c.execute(query)
This caused a sqlite3.OperationalError: near "'\xa1\x91\x9f\x88\xfb\x81\x12\xd4\xc2\xf9\xce\x91y\xf0/\xe1*#\x8aj\xc7\x1d\xd3\x91\x14\xcb\xa4\xabaP[\x02\x1d\x1b\xabr\xc7\xe4\xee\x19\x80c\x8e|\xc0S\xaaX\xc6\x04\xab\x08\x9b\x8e\xd7zB\xc6\x84[\xfb\xbc\x8d\xfc'": syntax error. I believe that this is caused by the presence of ' and " characters within the password, but I am unsure how to get around this issue as these are added by the hashing process and thus removing them would change the password.
The password I would like to add is:
b'\xa1\x91\x9f\x88\xfb\x81\x12\xd4\xc2\xf9\xce\x91y\xf0/\xe1*#\x8aj\xc7\x1d\xd3\x91\x14\xcb\xa4\xabaP[\x02\x1d\x1b\xabr\xc7\xe4\xee\x19\x80c\x8e|\xc0S\xaaX\xc6\x04\xab\x08\x9b\x8e\xd7zB\xc6\x84[\xfb\xbc\x8d\xfc'
I was wondering if anyone could share some insights into why it isn't liking the "\" character or why it isn't updating the database, and point me in the right direction to making it work. If you need more information or code snippets or just want to yell at me, please don't hesitate to! Thank you in advance :)
A couple of things with your code:
You should not use format to build your queries like this. This leaves you liable to SQL injection and, whilst you might sanitise your inputs in this case, it's a bad habit that will bite you.
All changes need to be committed to the database to actually take effect. This is why your second query did not throw an error but equally did not make any changes to the database.
The correct formatting of this query would be:
conn = sqlite3.connect('my_db.db')
c = conn.cursor()
query = "UPDATE users SET password = ? WHERE memberID = ?"
c.execute(query, (newPas, memID))
conn.commit() # To finalise the alteration
As a side note, the cursor expects a tuple in this case, so a common stumbling block comes when passing single values:
query = "UPDATE users SET password = ? WHERE memberID = 'abc'"
c.execute(query, (newPas)) # Throws "incorrect number of bindings" error
# Use this instead i.e. pass single value as a tuple
c.execute(query, (newPas,))
You could use format to create variable field names in a query, since placeholders are not allowed in this case:
fields = ['a', 'b', 'c']
query = "UPDATE users SET {} = ?".format(random.choice(fields))
in addition to using it to help you build big queries where it would be tedious to manually type all the placeholders, and difficult to ensure that you had the correct number if your code changed:
my_list = ['a', 'b',...., n]
placeholders = ', '.join(['?' for item in my_list])
query = "INSERT .... VALUES = ({})".format(placeholders)
You should use parametrized queries something like this:
c.execute("""UPDATE users SET password = ? WHERE memberID = ?;""", (newPas, memID))
It will allow to avoid nasty things like SQL-injections.

how to assign an sql value to this python variable

ok i got this as simple as i can, everythings working and i need one last thing before I'm done with this issue
i am using sqlite3 module in python
i also have very limited sql expierance
the problem-
i need to take the only value out of an sql table; the tablename is saves and the row id is 0 the name of the row is lvl. i need to then assign this as the value of the python variable lvl. Then on closure of the program i need to update the sql table with the current value of the python variable lvl (it will take the place of the data i just retrieved--there will also be numerous operations in between).
My code for assigning the value of the python Variable
conn = sql.connect('databaserm/database')
curs = conn.cursor()
curs.execute('SELECT 0 FROM saves')
lvl = curs.fetchone()
conn.commit
conn.close()
after running this i get the output
None
and my code for adding data to the database on closure
elif choice == q:
if choice == q:
cn = sqlite3.connect('/databaserm/database')
curs = cn.cursor()
curs.execute('INSERT INTO saves (lvl) VALUES (?)', lvl)
cn.commit
cn.close()
loop1 = 0
loop = 10000
print "Goodbye!"
sys.exit(0)
after running this with a preloaded database and the previous code ommited i get a connection error
i would be overjoyed at any help i'm offered and hope to work out a solution to this soon
SELECT 0 FROM saves is not sensible (or valid) SQL, you probably want to do something like SELECT * FROM saves WHERE lvl = 0
I suggest reading some sql tutorial

Categories

Resources