Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSqlQuery prepared statment using QString as a bind value

QSqlQuery prepared statment using QString as a bind value

Scheduled Pinned Locked Moved Unsolved General and Desktop
5 Posts 3 Posters 169 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    sairun
    wrote on last edited by
    #1

    I'm trying to prepare and exec the following SQL statement to check the existence of some IDs in a SQLite3 database

    QString idList = "(289455),(241326),(212694),(212676),...";
    
    QSqlQuery q( db );
            q.prepare( "WITH cte( id ) AS (VALUES :val) "
                                " SELECT id FROM cte LEFT JOIN records t" 
                                " ON t.rid = cte.id WHERE t.rid IS NULL");
            q.bindValue( ":val", idList  );
    

    The idList may have 1 up to 500 ids, each within parenthesis, to be used in a Common Table Expression (CTE). Apparently this construct doesn't work. idList is passed as a QVariant and somewhow it doesn't get replaced as a regular string in the query. The result is always a "Parameter count mismatch" error!

    The solution is to build the query as a QString by concatenating the parts and executing it. But I wonder why the prepared query doesn't work in this case. I've used this type of construct to bind string values elsewhere, such as passwords or user names. Is there a size limit for the values passed to a prepared query?

    JonBJ Christian EhrlicherC 2 Replies Last reply
    0
    • S sairun

      I'm trying to prepare and exec the following SQL statement to check the existence of some IDs in a SQLite3 database

      QString idList = "(289455),(241326),(212694),(212676),...";
      
      QSqlQuery q( db );
              q.prepare( "WITH cte( id ) AS (VALUES :val) "
                                  " SELECT id FROM cte LEFT JOIN records t" 
                                  " ON t.rid = cte.id WHERE t.rid IS NULL");
              q.bindValue( ":val", idList  );
      

      The idList may have 1 up to 500 ids, each within parenthesis, to be used in a Common Table Expression (CTE). Apparently this construct doesn't work. idList is passed as a QVariant and somewhow it doesn't get replaced as a regular string in the query. The result is always a "Parameter count mismatch" error!

      The solution is to build the query as a QString by concatenating the parts and executing it. But I wonder why the prepared query doesn't work in this case. I've used this type of construct to bind string values elsewhere, such as passwords or user names. Is there a size limit for the values passed to a prepared query?

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @sairun
      For bound variables you can only use what the driver actually accepts. This does not mean you can use them "anywhere", e.g. as though it was a "textual substitution". I don't know what SQLite actually accepts for its VALUES syntax, but I very much doubt it allows any single variable in (VALUES :val). It is likely to want each item/element passed in separately. You might try with idList being a QStringList rather than a single QString, but again I doubt it will accept that either.

      As a similar example, if you wanted to generate a clause like

      WHERE something IN ( val1, val2, val3, ...)
      

      I know that you cannot do that via IN ( :vals ) for the same reason.

      Either generate the whole thing with as many separate variables as items and as many separate binds or generate a complete literal string as should be passed to SQLite for the statement without variables/bindings.

      1 Reply Last reply
      1
      • S Offline
        S Offline
        sairun
        wrote on last edited by
        #3

        Thanks, I suspect that trying to pass the idList as a literal string it gets quoted autommatically which does not work for the CTE. I think I'm not even going to try the QStringList variant. I'll just build a query string by concatenation and use it.

        JonBJ 1 Reply Last reply
        0
        • S sairun

          Thanks, I suspect that trying to pass the idList as a literal string it gets quoted autommatically which does not work for the CTE. I think I'm not even going to try the QStringList variant. I'll just build a query string by concatenation and use it.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @sairun
          Indeed. When building a string of a complete SQL statement without variable bindings it is your responsibility to verify any user input involved for potential SQL injection. If your ids are all stored as integers you should be OK.

          1 Reply Last reply
          1
          • S sairun

            I'm trying to prepare and exec the following SQL statement to check the existence of some IDs in a SQLite3 database

            QString idList = "(289455),(241326),(212694),(212676),...";
            
            QSqlQuery q( db );
                    q.prepare( "WITH cte( id ) AS (VALUES :val) "
                                        " SELECT id FROM cte LEFT JOIN records t" 
                                        " ON t.rid = cte.id WHERE t.rid IS NULL");
                    q.bindValue( ":val", idList  );
            

            The idList may have 1 up to 500 ids, each within parenthesis, to be used in a Common Table Expression (CTE). Apparently this construct doesn't work. idList is passed as a QVariant and somewhow it doesn't get replaced as a regular string in the query. The result is always a "Parameter count mismatch" error!

            The solution is to build the query as a QString by concatenating the parts and executing it. But I wonder why the prepared query doesn't work in this case. I've used this type of construct to bind string values elsewhere, such as passwords or user names. Is there a size limit for the values passed to a prepared query?

            Christian EhrlicherC Offline
            Christian EhrlicherC Offline
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #5

            @sairun said in QSqlQuery prepared statment using QString as a bind value:

            somewhow it doesn't get replaced as a regular string in the query.

            This would completely contradict the prepared query idiom... https://en.wikipedia.org/wiki/Prepared_statement

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved