Skip to content

Commit

Permalink
TVP Implementation and Testing (#488)
Browse files Browse the repository at this point in the history
* Merging updates. (#1)

Merging updates.

* fix for smalldatetime issue

* Fixed a bad merge

* Fix for inserting high unicode chars

* merge with main branch

* Fix for function sequence error

* reverted unnecessary file changes

* removed obsolete include

* Preliminary implementation of TVP

* Fix size for float

* Fix size for GUID

* Small TVP fixes and tests
  • Loading branch information
v-makouz authored and mkleehammer committed Dec 14, 2018
1 parent 978fc95 commit 1b1b287
Show file tree
Hide file tree
Showing 7 changed files with 483 additions and 35 deletions.
67 changes: 63 additions & 4 deletions src/cursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,11 +684,11 @@ static PyObject* execute(Cursor* cur, PyObject* pSql, PyObject* params, bool ski
if (ret == SQL_NEED_DATA)
{
szLastFunction = "SQLPutData";
if (PyBytes_Check(pInfo->pObject)
if (pInfo->pObject && (PyBytes_Check(pInfo->pObject)
#if PY_VERSION_HEX >= 0x02060000
|| PyByteArray_Check(pInfo->pObject)
#endif
)
))
{
char *(*pGetPtr)(PyObject*);
Py_ssize_t (*pGetLen)(PyObject*);
Expand All @@ -711,7 +711,7 @@ static PyObject* execute(Cursor* cur, PyObject* pSql, PyObject* params, bool ski

do
{
SQLLEN remaining = min(pInfo->maxlength, cb - offset);
SQLLEN remaining = pInfo->maxlength ? min(pInfo->maxlength, cb - offset) : cb;
TRACE("SQLPutData [%d] (%d) %.10s\n", offset, remaining, &p[offset]);
Py_BEGIN_ALLOW_THREADS
ret = SQLPutData(cur->hstmt, (SQLPOINTER)&p[offset], remaining);
Expand All @@ -723,7 +723,7 @@ static PyObject* execute(Cursor* cur, PyObject* pSql, PyObject* params, bool ski
while (offset < cb);
}
#if PY_MAJOR_VERSION < 3
else if (PyBuffer_Check(pInfo->pObject))
else if (pInfo->pObject && PyBuffer_Check(pInfo->pObject))
{
// Buffers can have multiple segments, so we might need multiple writes. Looping through buffers isn't
// difficult, but we've wrapped it up in an iterator object to keep this loop simple.
Expand All @@ -741,6 +741,65 @@ static PyObject* execute(Cursor* cur, PyObject* pSql, PyObject* params, bool ski
}
}
#endif
else if (pInfo->ParameterType == SQL_SS_TABLE)
{
// TVP
// Need to convert its columns into the bound row buffers
int hasTvpRows = 0;
if (pInfo->curTvpRow < PySequence_Length(pInfo->pObject))
{
PyObject *tvpRow = PySequence_GetItem(pInfo->pObject, pInfo->curTvpRow);
Py_XDECREF(tvpRow);
for (Py_ssize_t i = 0; i < PySequence_Size(tvpRow); i++)
{
struct ParamInfo newParam;
struct ParamInfo *prevParam = pInfo->nested + i;
PyObject *cell = PySequence_GetItem(tvpRow, i);
Py_XDECREF(cell);
memset(&newParam, 0, sizeof(newParam));
if (!GetParameterInfo(cur, i, cell, newParam, true))
{
// Error converting object
FreeParameterData(cur);
return NULL;
}
if (newParam.ValueType != prevParam->ValueType ||
newParam.ParameterType != prevParam->ParameterType)
{
FreeParameterData(cur);
return RaiseErrorV(0, ProgrammingError, "Type mismatch between TVP row values");
}
if (prevParam->allocated)
pyodbc_free(prevParam->ParameterValuePtr);
Py_XDECREF(prevParam->pObject);
newParam.BufferLength = newParam.StrLen_or_Ind;
newParam.StrLen_or_Ind = SQL_DATA_AT_EXEC;
Py_INCREF(cell);
newParam.pObject = cell;
*prevParam = newParam;
if(prevParam->ParameterValuePtr == &newParam.Data)
{
prevParam->ParameterValuePtr = &prevParam->Data;
}
}
pInfo->curTvpRow++;
hasTvpRows = 1;
}
Py_BEGIN_ALLOW_THREADS
ret = SQLPutData(cur->hstmt, hasTvpRows ? (SQLPOINTER)1 : 0, hasTvpRows);
Py_END_ALLOW_THREADS
if (!SQL_SUCCEEDED(ret))
return RaiseErrorFromHandle(cur->cnxn, "SQLPutData", cur->cnxn->hdbc, cur->hstmt);
}
else
{
// TVP column sent as DAE
Py_BEGIN_ALLOW_THREADS
ret = SQLPutData(cur->hstmt, pInfo->ParameterValuePtr, pInfo->BufferLength);
Py_END_ALLOW_THREADS
if (!SQL_SUCCEEDED(ret))
return RaiseErrorFromHandle(cur->cnxn, "SQLPutData", cur->cnxn->hdbc, cur->hstmt);
}
ret = SQL_NEED_DATA;
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/cursor.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ struct ParamInfo
// written to each SQLPutData call. (It is not clear if they are limited
// like SQLBindParameter or not.)

// For TVPs, the nested descriptors and current row.
struct ParamInfo *nested;
SQLLEN curTvpRow;

// Optional data. If used, ParameterValuePtr will point into this.
union
{
Expand Down
Loading

0 comments on commit 1b1b287

Please sign in to comment.