Repository: ansible-collections/community.general

Issue:
odbc : [HY010] [unixODBC][Driver Manager]Function sequence error (0) (SQLFetch)
##### SUMMARY
Unable to connect to Microsoft SQL Server in order to perform a query. SQL trace shows the authentication succeeding , and data being returned. However, the module fails to parse the results.

##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
odbc

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes -->
```
ansible 2.10.1
  ansible python module location = /usr/local/lib/python3.6/site-packages/ansible
  python version = 3.6.8 (default, Dec  5 2019, 15:45:45) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
```

##### CONFIGURATION
```
Default
```

##### OS / ENVIRONMENT

Red Hat Enterprise Linux release 8.2 (Ootpa)

##### STEPS TO REPRODUCE
```yaml
    - name: Test select from SQL
      community.general.odbc:
        dsn: "DRIVER={ODBC Driver 17 for SQL Server};Server=server01;Database=main;Trusted_Connection=Yes;"
        query: "select x=1"
```

##### EXPECTED RESULTS
Query is returned.


##### ACTUAL RESULTS
<!--- Describe what actually happened. If possible run with extra verbosity (-vvvv) -->
fatal: [localhost]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "dsn": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "params": null,
            "query": "select x=1"
        }
    },
    "msg": "Exception while reading rows: ('HY010', '[HY010] [unixODBC][Driver Manager]Function sequence error (0) (SQLFetch)')"
}



Discussion:
Files identified in the description:
* [`plugins/modules/database/misc/odbc.py`](https://github.com/ansible-collections/community.general/blob/master/plugins/modules/database/misc/odbc.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @john-westcott-iv
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

cnxn = pyodbc.connect("DRIVER={ODBC Driver 17 for SQL Server};Server=server01;Database=main;Trusted_Connection=Yes;")
cursor = cnxn.cursor()
cursor.execute("select x=1;") 
    <pyodbc.Cursor object at 0x7f230ac3beb8>
row = cursor.fetchone() 
while row: 
...     print(row[0])
...     row = cursor.fetchone()
... 
`1`



Above shows the same python3.6 using pyodbc to query the sql server with the same DSN
The code currently uses the fetchall instead of fetchone. Could you try executing this and let me know if it gives you an exception?
```
cnxn = pyodbc.connect("DRIVER={ODBC Driver 17 for SQL Server};Server=server01;Database=main;Trusted_Connection=Yes;")
cursor = cnxn.cursor()
cursor.execute("select x=1;")
cursor.commit()
for row in cursor.fetchall():
    print(row[0])
```
In fact, if I comment line 120 `#cursor.commit()` the whole thing runs fine.
Same error directly in python when cursor.commit is used.

`pyodbc.Error: ('HY010', '[HY010] [unixODBC][Driver Manager]Function sequence error (0) (SQLFetch)')`

Removing cursor.commit() causes it to work.
https://stackoverflow.com/questions/25769043/function-sequence-error-in-pyodbc
@joshinryz I made a PR to add a commit parameter to the module. With this new version if you do `commit: False` the module will not do the commit after the execute. This should allow more flexibility and provide a way to solve your problem. Thanks for the report.

Resolving patch:
diff --git a/plugins/modules/database/misc/odbc.py b/plugins/modules/database/misc/odbc.py
--- a/plugins/modules/database/misc/odbc.py
+++ b/plugins/modules/database/misc/odbc.py
@@ -31,7 +31,14 @@
         - Parameters to pass to the SQL query.
       type: list
       elements: str
-
+    commit:
+      description:
+        - Perform a commit after the execution of the SQL query.
+        - Some databases allow a commit after a select whereas others raise an exception.
+        - Default is C(true) to support legacy module behavior.
+      type: bool
+      default: yes
+      version_added: 1.3.0
 requirements:
   - "python >= 2.6"
   - "pyodbc"
@@ -49,6 +56,7 @@
     query: "Select * from table_a where column1 = ?"
     params:
       - "value1"
+    commit: false
   changed_when: no
 '''
 
@@ -86,12 +94,14 @@ def main():
             dsn=dict(type='str', required=True, no_log=True),
             query=dict(type='str', required=True),
             params=dict(type='list', elements='str'),
+            commit=dict(type='bool', default=True),
         ),
     )
 
     dsn = module.params.get('dsn')
     query = module.params.get('query')
     params = module.params.get('params')
+    commit = module.params.get('commit')
 
     if not HAS_PYODBC:
         module.fail_json(msg=missing_required_lib('pyodbc'))
@@ -117,7 +127,8 @@ def main():
             cursor.execute(query, params)
         else:
             cursor.execute(query)
-        cursor.commit()
+        if commit:
+            cursor.commit()
         try:
             # Get the rows out into an 2d array
             for row in cursor.fetchall():


Test patch: