How to prevent PyMySQL from escaping identifier names? - python

I am utilizing PyMySQL with Python 2.7 and try to execute the following statement:
'INSERT INTO %s (%s, %s) VALUES (%s, %s) ON DUPLICATE KEY UPDATE %s = %s'
With the following parameters:
('artikel', 'REC_ID', 'odoo_created', u'48094', '2014-12-23 10:00:00', 'odoo_modified', '2014-12-23 10:00:00')
Always resulting in:
{ProgrammingError}(1064, u"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 ''artikel' ('REC_ID', 'odoo_created')\n
VALUES ('48094', '2014-12-' at line 1")
Which seems to me like PyMySQL is escaping all strings during formatting. How can I prevent that for database identifiers like table and column names? It corrupts the statement, since SELECTs from string literals (SELECT * FROM "table") are not possible in comparison to tables (SELECT * FROM table).

That's the point of DB API's substitution. It escapes values. You really shouldn't need to escape table/column names.
I'd use something like:
execute('''INSERT INTO {} ({}, {}) VALUES (%s, %s) ON DUPLICATE KEY UPDATE {} = %s'''
.format('artikel', 'REC_ID', 'odoo_created', 'odoo_modified'),
(u'48094', '2014-12-23 10:00:00', '2014-12-23 10:00:00')
)
Or, you know, just write the names directly.

Related

python pymssql error with query execution

This is the pymssql query I am working with
query = 'INSERT INTO [dbo].[helios_devops_data_curr] ("iipm.l3_it_org", "iipm.it_custodian","iipm.it_executive") VALUES ({}{}{})'.format("'Innovation and Technology'", "'bob tom'", "'bob tom'")
I'm using these values as an example, they are not the real values I'm trying to upload. However the errors are the same:
109, b'There are more columns in the INSERT statement than values specified in the VALUES clause. The number of values in the VALUES clause must match the number of columns specified in the INSERT statement.DB-Lib error message 20018, severity 15:\nGeneral SQL Server error: Check messages from the SQL Server\n')
I'm not sure why these error is occurring as there's clearly 3 columns and 3 values being inserted.
Any help on this would be appreciated
Your format placeholders might need commas between them:
query = 'INSERT INTO [dbo].[helios_devops_data_curr] ("iipm.l3_it_org", "iipm.it_custodian","iipm.it_executive") VALUES ({}, {}, {})'.format("'Innovation and Technology'", "'bob tom'", "'bob tom'")
Looking at the docs, it appears that pymssql might prefer you use C-style string-formatting symbols; maybe something like this:
query = "INSERT INTO dbo.helios_devops_data_curr(iipm.l3_it_org, iipm.it_custodian, iipm.it_executive) VALUES (%s, %s, %s)"
params = ("Innovation and Technology", "bob tom", "bob tom")
cursor.execute(query, params)
Here is another SO question with an example.

Using a variable for a table name with python sql cursor

I am using python sql cursor to dynamically access my database and I am in a situation where I want to use a variable in place of a table name. So far all of my attempts have resulted in syntax errors, although I (think?) I am doing things as expected? Unless a table name as a variable is different from a value as a variable:
here is what I currently have:
cursor.execute("INSERT INTO %s (word=%s,item_id=%s,word_tag=%s,unstemmed_word=%s, word_position=%s, TF=%s, normalized_term_frequency=%s, sentence=%s,anthology_id=%s) "%(table_name, stemmedWord,fle.split()[0], str(word[1]), uniqeWord, word_pos, TF, normalized_term_frequency, sentence, fle.split()[1].split(".")[0]))
and I have also tried this:
cursor.execute("INSERT INTO %s (word,item_id,word_tag,unstemmed_word, word_position, TF, normalized_term_frequency, sentence,anthology_id) values(%s, %s,%s, %s, %s, %s, %s, %s, %s)",(table_name, stemmedWord,fle.split()[0], str(word[1]), uniqeWord, word_pos, TF, normalized_term_frequency, sentence, fle.split()[1].split(".")[0]))
You cannot dynamically bind object names, only values. You'll have to resort to string manipulation for the table's name. E.g.:
sql = "INSERT INTO {} (word=%s,item_id=%s,word_tag=%s,unstemmed_word=%s, word_position=%s, TF=%s, normalized_term_frequency=%s, sentence=%s,anthology_id=%s)".format(table_name)
cursor.execute(sql % (stemmedWord,fle.split()[0], str(word[1]), uniqeWord, word_pos, TF, normalized_term_frequency, sentence, fle.split()[1].split(".")[0]))
If you are on python >= 3.6 this is probably better:
cursor.execute(f'INSERT INTO {table_name} (word="{stemmedWord}",item_id={fle.split()[0]},word_tag={str(word[1])},unstemmed_word="{oword_posrmuniqeWord}", word_position=word_pos, TF={TF}, normalized_term_frequency={normalized_term_frequency}, sentence="{sentence}",anthology_id={fle.split()[1].split(".")[0])}'
but I think your syntax errors are coming from two things:
you have provided a string to split fle on. (Correction this defaults to space - so is OK!)
you haven't quoted what seem to be obvious strings in you sql fields.

inputting var into an insert using python

I am using python 2.7 and postgresql 10.0.
For learning purposes I am attempting to get user raw_input and place into an insert execute, but no matter what I do, either it be %s or {} and using .format i am receiving errors.
all values are string except age (int)
specifically
with conn:
c.execute("INSERT INTO people(person_first, person_last, person_email,
person_age) VALUES ({}, {}, {}, {})".format(person_first, person_last,
person_email, person_age))
gives me non-string values (from the inputs)
and %s method gives me an error at the first '%' VALUES(%s, %s, %s, %s)
also have attempted VALUES (?, ?, ?, ?) and also unsuccessful similar to %s
The code, as pasted, looks wrong. You have with conn and c.execute. Assuming c is the cursor, and conn is the connection, the way to use them would look like this: with conn.cursor() as c:. The cursor is a context manager that will properly clean itself up when the with block exits.
Also, don't get in the habit of using .format() on your SQL. That will 1) be a vector for SQL injection vulnerabilities and 2) it will break if the input contains a single quote character.
So, combining those two points, your code should look like this:
with conn.cursor() as c:
c.execute("INSERT INTO people(person_first, person_last, person_email,
person_age) VALUES (%s, %s, %s, %s)", (person_first, person_last,
person_email, person_age,))
Note that the parameters are passed as a tuple directly to execute; the driver will parse the query, translate to appropriate SQL/parameter for the server, manage quoting, etc. If you are still seeing errors, post the traceback.
See also -
http://initd.org/psycopg/docs/usage.html#with-statement
http://initd.org/psycopg/docs/usage.html#the-problem-with-the-query-parameters
Hope this helps.

How to handle apostrophes in MySQL-Python?

A Python API is giving back u"'HOPPE'S No. 9'" as a value for a particular product attribute. I'm then looking to insert it into the DB, also using Python (python-mysqldb), with the following query:
INSERT INTO mytable (rating, Name) VALUES('5.0 (7)', 'HOPPE'S No. 9';
MySQL rejects this, and the suggested approach to handling a single quote in MySQL is to escape it first. This I need to do in Python, so I try:
In [5]: u"'HOPPE'S No. 9'".replace("'", "\'")
Out[5]: u"'HOPPE'S No. 9'"
When I incorporate this in my program, MySQL still rejects it. So I double-escape the apostrophe, and then an insert happens successfully. Thing is, it contains the escape character (so what gets written is 'HOPPE\'S No. 9').
If I need the second escape character, but when I add it gets left in, then how can I handle the escaping without having the escape character included in the string that gets inserted?
Edit: Based on theBjorn's suggestion, tried:
actualSQL = "INSERT INTO %s (%s) VALUES(%s);"
#cur.execute(queryString)
cur.execute(actualSQL,
(configData["table"], sqlFieldMappingString, sqlFieldValuesString))
but it looks like I'm back to where I was when I was trying to escape using the single escape with .replace():
Error 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 ''mytable' ('rating, Name, Image, mfg, price, URL') VALUES('\'5.0 (3)\', \'AR-1' at line 1
You should never construct sql that way. Use parameterized code instead:
cursor.execute(
"insert into mytable (rating, name) values (%s, %s);",
("5.0 (7)", "HOPPE'S No. 9")
)
your latest problem is due to the misconception that this is string interpolation, which it isn't (the use of %s is confusing), thus:
actualSQL = "INSERT INTO %s (%s) VALUES(%s);"
will be wrong. It is possible to construct your sql string, but probably easier to do so in two steps so we don't trip over sql parameter markers looking like string interpolation markers. Assuming you have the values in a tuple named field_values:
params = ["%s"] * len(field_values) # create a list with the correct number of parameter markers
sql = "insert into %s (%s) values (%s)" % ( # here we're using string interpolation, but not with the values
configData["table"],
sqlFieldMappingString,
', '.join(params)
)
if you print sql it should look like my example above. Now you can execute it with:
cursor.execute(sql, field_values)

Insert python list into Postgres database

I am having trouble in formatting the list for insertion using psycopg.
Here is a sample of code i am trying to do.
Basically I am just reading data from one table and trying to insert it into another table.
Code:
cur.execute("""select data from \"Table1\" where lat=-20.004189 and lon=-63.848004""")
rows = cur.fetchall()
print rows
cur.execute("""INSERT INTO \"%s\" (data) VALUES (ARRAY%s)""" % (args.tableName,rows)))
The result returned by first select query is like this:
[([6193, 3975, 4960, 5286, 3380, 970, 3328, 3173, 2897, 2457, 2443, 2674, 2172, 2740, 3738, 4907, 3691, 4234, 3651, 3215],)]
When I try to insert this into another table I get the following format error.
cur.execute(cur.mogrify("""INSERT INTO \"%s\" (data) VALUES (%s)""" % (args.tableName,rows)))
psycopg2.ProgrammingError: syntax error at or near "["
LINE 1: INSERT INTO "DUMMY1km" (data) VALUES ([([6193, 3975, 4960, 5...
I tried cur.mogrify, but it does not seem to help.
Please let me know if anyone has a work around for this issue.
Thanks
Adi
I don't think mogrify is needed here. Use executemany and pass rows as the second argument.
cur.executemany(
"""INSERT INTO "%s" (data) VALUES (%%s)""" % (args.tableName),rows)
Using parametrized arguments helps prevent SQL injection.
The table name can not be parametrized, so we do have to use string interpolation to place the table name in the SQL query. %%s gets escapes the percent sign and becomes %s after string interpolation.
By the way, (as a_horse_with_no_name has already pointed out) you can use the INSERT INTO ... SELECT form of INSERT to perform both SQL queries as one:
cur.execute(
"""INSERT INTO %s (data)
SELECT data FROM Table1
WHERE lat=-20.004189 AND lon=-63.848004""" % (args.tableName))
Per the question in the comments, if there are multiple fields, then the SQL becomes:
cur.executemany(
"""INSERT INTO {t} (lat,lon,data1,data2)
VALUES (%s,%s,%s,%s)""".format(t=args.tableName),rows)
(If you use the format method, then you don't have to escape all the other %ss.)

Categories

Resources