0

I'm working on a put request for a proof-of-concept at work. This project is my first time working with SQL since I got frustrated with it 10 years ago, so bear with me.

I want to update the POTS lines information for a particular store, so I'm having a request sent with data I'll parse and send an UPDATE query. I'm finding success when doing 1 individual entry at a time, but when adding multiple variables it gives me an error stating no column found by name: <name> where <name> is equal to the value I sent in the very next entry.

So take this statement:

cur.execute('UPDATE Pots SET Pots_ForwardOnFail={1}, Pots_FirePrimary={2}, Pots_FireSecondary={3}, Pots_BurglarPrimary={4}, Pots_DNR={5}, Pots_Passenger={6}, Pots_Freight={7} WHERE StoreNumber={0};'.format(args["Store"], args["HuntLine"], args["FirePrimary"], args["FireSecondary"], args["Burglar"], args["DNR"], args["PassengerElevator"], args["FreightElevator"]))

This sample post:

curl --request POST \
  --url http://127.0.0.1:9099/pots/42 \
  --form Store=42 \
  --form HuntLine=OnTheHunt \
  --form FirePrimary=FireHot \
  --form FireSecondary=FireNotSoHot \
  --form Burglar=Hamburglar \
  --form DNR=DNWut \
  --form PassengerElevator=GoingUp \
  --form FreightElevator=GoingDown

This would update the database column Pots_ForwardOnFail for store 42 with the value OnTheHunt, however I would be prompted with an error:

sqlite3.OperationalError: no such column: OnTheHunt

I've tried methods to no avail, and this just tells me that my syntax for handling multiple variables is not correct when working with UPDATE.

Flimzy
  • 60,850
  • 13
  • 104
  • 147
CodeSpent
  • 1,254
  • 3
  • 15
  • 34
  • I'm voting to close this question as off-topic because the issue wasn't programming related. The issue was in my testing. The database was accepting integers and I gave it strings of keyboard mashing while testing. – CodeSpent Nov 28 '18 at 03:29

2 Answers2

1

In this update query, string parameters are not enclosed in quotes. So, to DB these look like column names.

To validate , you can print the query before sending it to DB.

qry='UPDATE Pots SET Pots_ForwardOnFail={1}, Pots_FirePrimary={2}, Pots_FireSecondary={3}, Pots_BurglarPrimary={4}, Pots_DNR={5}, Pots_Passenger={6}, Pots_Freight={7} WHERE StoreNumber={0};'.format(args["Store"], args["HuntLine"], args["FirePrimary"], args["FireSecondary"], args["Burglar"], args["DNR"], args["PassengerElevator"], args["FreightElevator"])
print(qry)
cur.execute(qry)

This post has an example of how query should look like to DB. Escape single quote character for use in an SQLite query

Example of enclosing strings in query :

qry="UPDATE Pots SET Pots_ForwardOnFail='{1}', Pots_FirePrimary='{2}', WHERE StoreNumber={0};".format(args["Store"], args["HuntLine"])
Shamit Verma
  • 3,829
  • 21
  • 22
  • Actually it turned out to just be my way of testing.. I was sending strings to columns that accept integers. I would be curious to find out why it defaults to assuming its a column name if the type doesn't match. Nonetheless this is a very productive answer because validating queries like that is something I should definitely be doing. – CodeSpent Nov 28 '18 at 03:34
  • 1
    To DB; this query is sent : UPDATE Pots SET HuntLine=OnTheHunt (Query translates to "set value of column HuntLine to be same as value of Column OnTheHunt"). Query should have been UPDATE Pots SET HuntLine='OnTheHunt' – Shamit Verma Nov 28 '18 at 03:37
  • Ohhh, that makes perfect sense considering I was sending as strings. Interesting. So really the query IS wrong, however, since the columns only accept integers it didn't matter in this case. Looking at your query, though, I see no difference to mine? – CodeSpent Nov 28 '18 at 03:38
  • 1
    What is the type of HuntLine column ? Is it integer ? – Shamit Verma Nov 28 '18 at 03:41
  • Yes, but for the sake of learning my mistake here, lets pretend all columns accept a string. From there what is the most minimal way to "wrap" my arguments in single quotes? – CodeSpent Nov 28 '18 at 03:41
  • Shamit didn't try to fix your query, he added the line underneath to print it as an example of how you can debug. The error message from the db was pretty clear though – Caius Jard Nov 28 '18 at 03:45
  • 1
    If all columns are of string type, then query should work if you add quotes. UPDATE Pots SET HuntLine='OnTheHunt' – Shamit Verma Nov 28 '18 at 03:45
  • @ShamitVerma right but I'm not manually typing these strings, they're coming from a post request. How can these arguments be evaluated to be wrapped in delimiters without me manipulating them? – CodeSpent Nov 28 '18 at 03:46
  • 1
    Added example in answer. Basically enclose parameters like {1} in quotes if parameter is of type string. – Shamit Verma Nov 28 '18 at 03:50
  • I don't know why I was under the impression it'd read {0} as a string in those conditions.. well done to all of you and thanks! – CodeSpent Nov 28 '18 at 03:58
1

Simple syntax error caused by a lack of delimiters around your test data, by the looks of it

UPDATE table SET HuntLine=OnTheHunt

Will try and set the value of column HuntLine equal to the value of column OnTheHunt. Your table doesn't have a column called OnTheHunt so query fails

UPDATE table SET HuntLine='OnTheHunt'

Will try and set the value of column HuntLine to the constant string 'OnTheHunt'

Ints would work, as they don't require a delimiter:

UPDATE table SET HuntLine=42

Most other data types tend to be passed into sql queries using strings

UPDATE table SET HuntDate='2018-01-01'

If huntdate is a date type then this string will usually be parsed and represented internally as a date. Some db require an additional keyword to trigger the parsing, like

UPDATE table SET HuntDate=DATE '2018-01-01'

Last tip, unrelated. Please have a good read through http://bobby-tables.com and absorb that advice, and then going forward never write python like this again. It's a massive security risk and I flat out wouldn't hire a developer that wrote code like this in an interview process test; I suspect many employers are the same

I'm hesitant to fix your query so it runs, because I wouldn't want to risk legitimising the way it's done, when it should be parameterised instead but..

Had you used double quotes for your string and single quotes around every curly bracket set where the column is a string:

qry="UPDATE Pots SET Pots_ForwardOnFail='{1}', Pots_FirePrimary='{2}'...

Then it would have worked out but it is still a massive security hole. Always parameterise your queries/never concatenate values supplied by the user into your query string.. in c# and sqlserver (what I know off by heart) parameterised queries look like this:

command.QueryText = "update pots set huntline=@hl, forwardonfail=@fof, fireprimary=@fp...";
command.Parameters.AddWithValue("@hl", request.Form["huntline"]);
command.Parameters.AddWithValue("@fp", request.Form["firepri"]);
command.Parameters.AddWithValue("@fof", request.Form["fwdonfail"]);

Not a million miles from what you have already but immune to users putting sql into the text boxes and wrecking your db/exposing its contents. Python and sqlite should have something similar

Caius Jard
  • 47,616
  • 4
  • 34
  • 62
  • None of my SQL gets used. I build it up only enough to test logic on my front end. It'll be left to people experienced to handle that. This is also a throwaway SQLite database, so no harm to do. In my use case, how would you change the query? – CodeSpent Nov 28 '18 at 03:43
  • 1
    Still a good idea to learn the practice - string concat for sql is a terrible habit that the whole world needs to kick :) added an edit, but do have a go at making this your first practice of parameterizing. I've never used SQLite+php but in most languages the process is no more complex or arduous than what you've gone through to realise this work so far. I'll add another note to that effect – Caius Jard Nov 28 '18 at 03:54
  • This is Python but yeah I hear ya! If I *had* to incorporate good practices I would absolutely take the time, but with my focus just being the data getting from the front end to the server and knowing all my code will later be deleted, I tend to just rush through it haha. – CodeSpent Nov 28 '18 at 03:57
  • 1
    Yeah "there's nothing as permanent as temporary" - another reason to use parameters is even for innocent data; as soon as Patrick O'Brien comes along and types his last name into your form, the query fails with a syntax error if it's just concatenated in straight. Then you get to linking "I'll just replace all the apostrophes..". Parameters all the way, ftw! – Caius Jard Nov 28 '18 at 04:05