Search code examples
pythontuplesparameterizationsqlite3-python

Tuple problem with parameterized SQLite query


I'm working on a telethon-based telegram chatbot that can query a customer db given a last name in the following format: /search thompson, but am having some trouble using the fill function to keep the queries safe.

I'm getting one of two errors - one is tuple index out of range when accessing query directly, and Incorrect number of bindings supplied. The current statement uses 1, and there are 8 supplied. when I use join (method 2 above). What am I doing incorrectly here?

UPDATE - this is the full error traceback followed by the code:

Traceback (most recent call last):
  File "/Users/.../.../.../.../script.py", line 155, in select
    test_message = create_message_select_query(res)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/.../.../.../.../script.py", line 115, in create_message_select_query
    lname = i[1]
            ~^^^
IndexError: tuple index out of range

And associated code:

# create message listing matches
def create_message_select_query(ans):
    text = ""
    for i in ans:
        id = i[0]
        lname = i[1]
        fname = i[2]
        creation_date = i[3]
        text += "<b>"+ str(id) +"</b> | " + "<b>"+ str(lname) +"</b> | " + "<b>"+ str(fname)+"</b> | " + "<b>"+ str(creation_date)+"</b>\n"
    message = "Information about customers:\n\n"+text
    return message

@client.on(events.NewMessage(pattern="(?i)/search"))

async def select(event):
    try:
        # Get the sender of the message
        sender = await event.get_sender()
        SENDER = sender.id
        
        # Get the text of the user AFTER the /search command
        list_of_words = event.message.text.split(" ")
        # accessing first item
        query = list_of_words[1]
             
        sql = "select (SELECT * from customers where lname = ?)"

        #args = ''.join((query))
        args = query
        
        cursor = conn.execute(sql, (args,))
        
        res = cursor.fetchall() # fetch all the results
        
        # If there is at least 1 row selected, print a message with matches
        # The message is created using the function defined above
        if(res):
            test_message = create_message_select_query(res) 
            await client.send_message(SENDER, test_message, parse_mode='html')
        # Otherwhise, print a default text
        else:
            text = "No matching customers found"
            await client.send_message(SENDER, text, parse_mode='html')

Solution

  • The second argument to execute() needs to be a sequence (usually a list or tuple) of one or more items.

    In your code you are passing a string as the second argument. Strings technically are sequences, but it counts each individual character as a separate item, which is why you get the incorrect number of bindings error.

    Pass the second argument as a list of one item:

    cursor = conn.execute(sql, [args])
    

    Or as a tuple of one item:

    cursor = conn.execute(sql, (args,))