I've browsed some of the other questions about MySQL and Python on SO. There are a few things eluding me, because I'm pretty new to Python.
First, I'm trying to get a simple guestbook app to work. It takes posted variables and puts them into a MySQL database. Take a look:
con = MySQLdb.connect (host = "localhost",
user = "Chat",
passwd = "myPass",
db = "Chatserver")
cursor = con.cursor()
cursor.execute ("INSERT INTO guestbook (name,message) VALUES(%s,%s)",(name,greeting))
Ok, so some of the tutorials and answers on SO have many Quotation marks surrounding the SQL query, and I don't know why that is. I've tried it with 1 quote, I've tried it with 3 quotes, and it just never works. There are no exception callbacks and the code seems to run, but no records are ever entered into the database.
So my two questions are, how many quotation marks do I need when encapsulating the Queries, and why doesn't my script add anything to the database but not report any errors?
Ok, this answer Can't execute an INSERT statement in a Python script via MySQLdb helped me figure it out.
You have to add this at the end of your query.
cursor.execute(...)
con.commit() //this is what makes it actually do the execution?
Related
This question already has answers here:
How to use variables in SQL statement in Python?
(5 answers)
Closed 2 months ago.
def update_inv_quant():
new_quant = int(input("Enter the updated quantity in stock: "))
Hello! I'm wondering how to insert a user variable into an sql statement so that a record is updated to said variable. Also, it'd be really helpful if you could also help me figure out how to print records of the database into the actual python console. Thank you!
I tried doing soemthing like ("INSERT INTO Inv(ItemName) Value {user_iname)") but i'm not surprised it didnt work
It would have been more helpful if you specified an actual database.
First method (Bad)
The usual way (which is highly discouraged as Graybeard said in the comments) is using python's f-string. You can google what it is and how to use it more in-depth.
but basically, say you have two variables user_id = 1 and user_name = 'fish', f-string turns something like f"INSERT INTO mytable(id, name) values({user_id},'{user_name}')" into the string INSERT INTO mytable(id,name) values(1,'fish').
As we mentioned before, this causes something called SQL injection. There are many good youtube videos that demonstrate what that is and why it's dangerous.
Second method
The second method is dependent on what database you are using. For example, in Psycopg2 (Driver for PostgreSQL database), the cursor.execute method uses the following syntax to pass variables cur.execute('SELECT id FROM users WHERE cookie_id = %s',(cookieid,)), notice that the variables are passed in a tuple as a second argument.
All databases use similar methods, with minor differences. For example, I believe SQLite3 uses ? instead of psycopg2's %s. That's why I said that specifying the actual database would have been more helpful.
Fetching records
I am most familiar with PostgreSQL and psycopg2, so you will have to read the docs of your database of choice.
To fetch records, you send the query with cursor.execute() like we said before, and then call cursor.fetchone() which returns a single row, or cursor.fetchall() which returns all rows in an iterable that you can directly print.
Execute didn't update the database?
Statements executing from drivers are transactional, which is a whole topic by itself that I am sure will find people on the internet who can explain it better than I can. To keep things short, for the statement to physically change the database, you call connection.commit() after cursor.execute()
So finally to answer both of your questions, read the documentation of the database's driver and look for the execute method.
This is what I do (which is for sqlite3 and would be similar for other SQL type databases):
Assuming that you have connected to the database and the table exists (otherwise you need to create the table). For the purpose of the example, i have used a table called trades.
new_quant = 1000
# insert one record (row)
command = f"""INSERT INTO trades VALUES (
'some_ticker', {new_quant}, other_values, ...
) """
cur.execute(command)
con.commit()
print('trade inserted !!')
You can then wrap the above into your function accordingly.
I had no problem with SELECTing data in python from postgres database using cursor/execute. Just changed the sql to INSERT a row but nothing is inserted to DB. Can anyone let me know what should be modified? A little confused because everything is the same except for the sql statement.
<!-- language: python -->
#app.route("/addcontact")
def addcontact():
# this connection/cursor setting showed no problem so far
conn = pg.connect(conn_str)
cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
sql = f"INSERT INTO jna (sid, phone, email) VALUES ('123','123','123')"
cur.execute(sql)
return redirect("/contacts")
first look at your table setup and make sure your variables are named right in the right order, format and all that, if your not logging into the specific database on the sql server it won't know where the table is, you might need to send something like 'USE databasename' before you do your insert statement so your computer is in the right place in the server.
I might not be up to date with the language but is that 'f' supposed to be right before the quotes? if thats in ur code that'd probably throw an error unless it has a use im not aware of or its not relevant to the problem.
You have to commit your transaction by adding the line below after execute(sql)
conn.commit()
Ref: Using INSERT with a PostgreSQL Database using Python
I'm trying to enter data from python 3.4 into a MySQL database, with both of these entities being within pythonAnywhere. In other words, I'm writing a python 3.4 program in pythonAnywhere and need to connect to a MySQL db also within pythonAnywhere. I've checked other answers here and haven't quite figured it out. I've tried the ( -u -h -p) syntax mentioned by a few posts, but I'm not sure if that is just for gaining access from outside of pythonAnywhere.
Any help would be appreciated.
++++++++++++++++++++
Actually I figured it out (with kudos to Tony Darnell at the Scripting MySQL website, from whom I plagiarized most of this:
import MySQLdb
db=MySQLdb.connect(
host='Your_User_Name.mysql.pythonanywhere-services.com',
user='Your_User_Name',
passwd='Your_pythonAnywhere_password',
db='Your_User_Name$Your_Data_Base')
everything above starting with 'Your' refers to you personal account info with pythonanywhere
everything else gets listed exactly as shown. Watch that $ that follows your user name as part of the database name (db = etc.)
cursor = db.cursor ()
execute the SQL query using execute() method.
cursor.execute ("Enter any MySQL query here. use the quotes. no semi-colon")
fetch a single row from query using fetchone() method.
row = cursor.fetchone ()
print(row)
fetch all the rest of the query using fetchall() method
data = cursor.fetchall()
print(data)
close the cursor object
cursor.close ()
close the connection
db.close ()
I'm working on a project that requires me to programmatically create MySQL users from a django app. I can create the users just fine:
from django.db import connection, transaction
cursor = connection.cursor()
cursor.execute("CREATE USER %s#'%'", 'username')
cursor.execute("SET PASSWORD FOR %s#'%' = PASSWORD(%s)", ('username', 'pass'))
That works perfectly. The problem is when I try to grant permissions. The database name is also determined programmatically:
cursor.execute("GRANT SELECT ON %s.* TO %s#'%'", ('dbname', 'username'))
This results in a mysql error because when it does the string substitution, it places single quotes around the database name, which is syntactically incorrect:
DatabaseError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''dbname'.* to 'username'#'%'' at line 1")
How do I prevent the single quotes from being added around the %s for database name? I know that I could simply do the string substitution in Python and fix this, but that could potentially cause a SQL injection vulnerability.
Sometimes placeholders won't work (as you've found out), so you'll have to use string concatenation. Be careful - validate the string, make sure it's only composed of the characters you expect (don't just look for characters you don't expect), and you should be OK. Also get another developer to check your code, and comment it to make sure no-one else thinks you ought to be using placeholders.
I'm writing a quick web.py app and take data from web.input...
import web
urls = (
'/', 'something',
)
app = web.application(urls, globals())
db = web.database(dbn='postgres', db='database', user='username', password='password', host='127.0.0.1')
class something:
def GET(self):
i = web.input()
return db.select('foo.table', where="column=$variable", vars={'variable':i.input, })
if __name__ == "__main__": app.run()
Should I worry about passing i.input to db.select (or query etc.) as I do as part of vars? SQL injection possibilities etc. ?
Edit:
I have been playing around with this myself, trying to get something nasty happenning. Playing with quoting for example, http://localhost:8080/?id=13' or 'x' ='x results in nicely escaped sql being shown in Exceptions:
<sql: 'select * from foo.table where id = "13\' or \'x\'=\'x"'>
I've tried a few other common tests that the internet puts forward and think I'm quite happy web.py is dealing with the sanitisation... Would anyone else be able to comment?
http://webpy.org/cookbook/query says:
To prevent SQL injection attacks, db.query also accepts the "vars"
syntax as described in db.select:
results = db.query("SELECT * FROM users WHERE id=$id", vars={'id':10})
This will escape user input, if you're trusting them for the "id"
variable.
So I guess its as simple as that.
Of course I realise that I still need to validate user input if I'm going to be inserting it places...
The "nicely escaped sql" you see does not matter as it's never sent to the database engine.
In all cases, unless you manually insert the values into the SQL request string, you're safe against an SQL injection. This includes select/insert/update/delete methods as well as the $variable_name substitution style. In both cases the SQL request is not fully assembled as text, but properly converted into a SQL prepared statement and compiled by the DB engine as such. Only after that the parameters are actually substituted for statement execution. So, unless you build the SQL query string and/or parts of it by hand using the untrusted data, you're safe.
Unfortunately I'm unable to provide a link to any source better than the source code of the module as it was my only source of information.
Yes because some one can alter the variable especially if it comes from a url to say something like "selecte * from table where id = [ variable + DELETE TABLE[. This is an example of sql injection. This is especially critical if the user has any idea of what your back end data objects are named.
I'm not exactly certain how Python would handle parametrization of variables for a sql statement but I had to perform similar security fixes for cold fusion sites and ASP.net sites.