diff --git a/src/connection.cpp b/src/connection.cpp index d459bf4d..86a5e4d6 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -976,6 +976,9 @@ static int Connection_settimeout(PyObject* self, PyObject* value, void* closure) return -1; } + // this same value is used for the cursor timeout + cnxn->timeout = timeout; + SQLRETURN ret; Py_BEGIN_ALLOW_THREADS ret = SQLSetConnectAttr(cnxn->hdbc, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER)(uintptr_t)timeout, SQL_IS_UINTEGER); @@ -986,8 +989,6 @@ static int Connection_settimeout(PyObject* self, PyObject* value, void* closure) return -1; } - cnxn->timeout = timeout; - return 0; } diff --git a/src/cursor.cpp b/src/cursor.cpp index f0520f6c..ff071eda 100644 --- a/src/cursor.cpp +++ b/src/cursor.cpp @@ -1129,6 +1129,40 @@ static PyObject* Cursor_executemany(PyObject* self, PyObject* args) Py_RETURN_NONE; } +static char set_attr_doc[] = + "set_attr(attr_id, value) -> None\n\n" + "Calls SQLSetStmtAttr with the given values.\n\n" + "attr_id\n" + " The attribute id (integer) to set. These are ODBC or driver constants.\n\n" + "value\n" + " An integer value.\n\n" + "At this time, only integer values are supported and are always passed as SQLUINTEGER."; + +static PyObject* Cursor_set_attr(PyObject* self, PyObject* args) +{ + if (!Cursor_Check(self)) + { + PyErr_SetString(ProgrammingError, "Invalid cursor object."); + return 0; + } + + int id; + int value; + if (!PyArg_ParseTuple(args, "ii", &id, &value)) + return 0; + + Cursor* cursor = (Cursor *)self; + + SQLRETURN ret; + Py_BEGIN_ALLOW_THREADS + ret = SQLSetStmtAttr(cursor->hstmt, id, (SQLPOINTER)(intptr_t)value, SQL_IS_INTEGER); + Py_END_ALLOW_THREADS + + if (!SQL_SUCCEEDED(ret)) + return RaiseErrorFromHandle(cursor->cnxn, "SQLSetStmtAttr", cursor->cnxn->hdbc, cursor->hstmt); + Py_RETURN_NONE; +} + static PyObject* Cursor_setinputsizes(PyObject* self, PyObject* sizes) { if (!Cursor_Check(self)) @@ -1136,7 +1170,7 @@ static PyObject* Cursor_setinputsizes(PyObject* self, PyObject* sizes) PyErr_SetString(ProgrammingError, "Invalid cursor object."); return 0; } - + Cursor *cur = (Cursor*)self; if (Py_None == sizes) { @@ -2410,7 +2444,8 @@ static PyMethodDef Cursor_methods[] = { "skip", (PyCFunction)Cursor_skip, METH_VARARGS, skip_doc }, { "commit", (PyCFunction)Cursor_commit, METH_NOARGS, commit_doc }, { "rollback", (PyCFunction)Cursor_rollback, METH_NOARGS, rollback_doc }, - {"cancel", (PyCFunction)Cursor_cancel, METH_NOARGS, cancel_doc}, + { "cancel", (PyCFunction)Cursor_cancel, METH_NOARGS, cancel_doc }, + { "set_attr", Cursor_set_attr, METH_VARARGS, set_attr_doc }, {"__enter__", Cursor_enter, METH_NOARGS, enter_doc }, {"__exit__", Cursor_exit, METH_VARARGS, exit_doc }, {0, 0, 0, 0} @@ -2527,7 +2562,7 @@ Cursor_New(Connection* cnxn) if (cnxn->timeout) { Py_BEGIN_ALLOW_THREADS - ret = SQLSetStmtAttr(cur->hstmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)(uintptr_t)cnxn->timeout, 0); + ret = SQLSetStmtAttr(cur->hstmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)(uintptr_t)cnxn->timeout, SQL_IS_UINTEGER); Py_END_ALLOW_THREADS if (!SQL_SUCCEEDED(ret)) diff --git a/src/pyodbcmodule.cpp b/src/pyodbcmodule.cpp index 6c4d77aa..bfb8cfd0 100644 --- a/src/pyodbcmodule.cpp +++ b/src/pyodbcmodule.cpp @@ -311,7 +311,7 @@ static bool AllocateEnv() } } Py_DECREF(odbcversion); - + if (!SQL_SUCCEEDED(SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, defaultVersion, sizeof(int)))) { PyErr_SetString(PyExc_RuntimeError, "Unable to set SQL_ATTR_ODBC_VERSION attribute."); @@ -1064,6 +1064,9 @@ static const ConstantDef aConstants[] = { MAKECONST(SQL_PACKET_SIZE), MAKECONST(SQL_ATTR_ANSI_APP), + // Cursor Attributes + MAKECONST(SQL_ATTR_QUERY_TIMEOUT), + // SQL_CONVERT_X MAKECONST(SQL_CONVERT_FUNCTIONS), MAKECONST(SQL_CONVERT_BIGINT), @@ -1107,6 +1110,10 @@ static const ConstantDef aConstants[] = { MAKECONST(SQL_OJ_NOT_ORDERED), MAKECONST(SQL_OJ_INNER), MAKECONST(SQL_OJ_ALL_COMPARISON_OPS), + + // Misc + MAKECONST(SQL_IS_UINTEGER), + MAKECONST(SQL_IS_UINTEGER), };