예제 #1
0
static void FreeInfos(ParamInfo* a, Py_ssize_t count)
{
    for (Py_ssize_t i = 0; i < count; i++)
    {
        if (a[i].allocated)
            pyodbc_free(a[i].ParameterValuePtr);
        Py_XDECREF(a[i].pParam);
    }
    pyodbc_free(a);
}
예제 #2
0
static PyObject* GetDataUser(Cursor* cur, Py_ssize_t iCol, int conv)
{
    // conv
    //   The index into the connection's user-defined conversions `conv_types`.

    bool isNull = false;
    byte* pbData = 0;
    Py_ssize_t cbData = 0;
    if (!ReadVarColumn(cur, iCol, SQL_C_BINARY, isNull, pbData, cbData))
        return 0;

    if (isNull)
    {
        I(pbData == 0 && cbData == 0);
        Py_RETURN_NONE;
    }

    PyObject* value = PyBytes_FromStringAndSize((char*)pbData, cbData);
    pyodbc_free(pbData);
    if (!value)
        return 0;

    PyObject* result = PyObject_CallFunction(cur->cnxn->conv_funcs[conv], "(O)", value);
    Py_DECREF(value);
    if (!result)
        return 0;

    return result;
}
예제 #3
0
static PyObject* GetText(Cursor* cur, Py_ssize_t iCol)
{
    // We are reading one of the SQL_WCHAR, SQL_WVARCHAR, etc., and will return
    // a string.
    //
    // If there is no configuration we would expect this to be UTF-16 encoded data.  (If no
    // byte-order-mark, we would expect it to be big-endian.)
    //
    // Now, just because the driver is telling us it is wide data doesn't mean it is true.
    // psqlodbc with UTF-8 will tell us it is wide data but you must ask for single-byte.
    // (Otherwise it is just UTF-8 with each character stored as 2 bytes.)  That's why we allow
    // the user to configure.

    ColumnInfo* pinfo = &cur->colinfos[iCol];
    const TextEnc& enc = IsWideType(pinfo->sql_type) ? cur->cnxn->sqlwchar_enc : cur->cnxn->sqlchar_enc;

    bool isNull = false;
    byte* pbData = 0;
    Py_ssize_t cbData = 0;
    if (!ReadVarColumn(cur, iCol, enc.ctype, isNull, pbData, cbData))
        return 0;

    if (isNull)
    {
        I(pbData == 0 && cbData == 0);
        Py_RETURN_NONE;
    }

    PyObject* result = TextBufferToObject(enc, pbData, cbData);

    pyodbc_free(pbData);

    return result;
}
예제 #4
0
static PyObject* GetBinary(Cursor* cur, Py_ssize_t iCol)
{
    // Reads SQL_BINARY.

    bool isNull = false;
    byte* pbData = 0;
    Py_ssize_t cbData = 0;
    if (!ReadVarColumn(cur, iCol, SQL_C_BINARY, isNull, pbData, cbData))
        return 0;

    if (isNull)
    {
        I(pbData == 0 && cbData == 0);
        Py_RETURN_NONE;
    }

    PyObject* obj;
#if PY_MAJOR_VERSION >= 3
    obj = PyBytes_FromStringAndSize((char*)pbData, cbData);
#else
    obj = PyByteArray_FromStringAndSize((char*)pbData, cbData);
#endif
    pyodbc_free(pbData);
    return obj;
}
예제 #5
0
void SQLWChar::Free()
{
    if (pch && owns_memory)
        pyodbc_free(pch);
    pch = 0;
    len = 0;
    owns_memory = false;
}
예제 #6
0
파일: row.cpp 프로젝트: Bobspadger/pyodbc
void FreeRowValues(Py_ssize_t cValues, PyObject** apValues)
{
    if (apValues)
    {
        for (Py_ssize_t i = 0; i < cValues; i++)
            Py_XDECREF(apValues[i]);
        pyodbc_free(apValues);
    }
}
예제 #7
0
파일: getdata.cpp 프로젝트: gthb/pyodbc
 ~DataBuffer()
 {
     if (!usingStack)
     {
         if (bufferOwner)
         {
             Py_DECREF(bufferOwner);
         }
         else
         {
             pyodbc_free(buffer);
         }
     }
 }
예제 #8
0
static byte* ReallocOrFreeBuffer(byte* pb, Py_ssize_t cbNeed)
{
    // Attempts to reallocate `pb` to size `cbNeed`.  If the realloc fails, the original memory
    // is freed, a memory exception is set, and 0 is returned.  Otherwise the new pointer is
    // returned.

    byte* pbNew = (byte*)realloc(pb, (size_t)cbNeed);
    if (pbNew == 0)
    {
        pyodbc_free(pb);
        PyErr_NoMemory();
        return 0;
    }
    return pbNew;
}
예제 #9
0
bool SQLWChar::Convert(PyObject* o)
{
    Free();

    if (!PyUnicode_Check(o))
    {
        PyErr_SetString(PyExc_TypeError, "Unicode required");
        return false;
    }

    Py_UNICODE* pU   = (Py_UNICODE*)PyUnicode_AS_UNICODE(o);
    Py_ssize_t  lenT = PyUnicode_GET_SIZE(o);

    if (SQLWCHAR_SIZE == Py_UNICODE_SIZE)
    {
        // The ideal case - SQLWCHAR and Py_UNICODE are the same, so we point into the Unicode object.

        pch         = (SQLWCHAR*)pU;
        len         = lenT;
        owns_memory = false;
        return true;
    }
    else
    {
        SQLWCHAR* pchT = (SQLWCHAR*)pyodbc_malloc(sizeof(SQLWCHAR) * (lenT + 1));
        if (pchT == 0)
        {
            PyErr_NoMemory();
            return false;
        }

        if (!sqlwchar_copy(pchT, pU, lenT))
        {
            pyodbc_free(pchT);
            return false;
        }
    
        pch = pchT;
        len = lenT;
        owns_memory = true;
        return true;
    }
}
예제 #10
0
파일: row.cpp 프로젝트: Bobspadger/pyodbc
static PyObject* new_check(PyObject* args)
{
    // We don't support a normal constructor, so only allow this for unpickling.  There should be a single arg that was
    // returned by Row_reduce.  Make sure the sizes match.  The desc and map should have one entry per column, which
    // should equal the number of remaining items.

    if (PyTuple_GET_SIZE(args) < 3)
        return 0;

    PyObject* desc = PyTuple_GET_ITEM(args, 0);
    PyObject* map  = PyTuple_GET_ITEM(args, 1);

    if (!PyTuple_CheckExact(desc) || !PyDict_CheckExact(map))
        return 0;

    Py_ssize_t cols = PyTuple_GET_SIZE(desc);

    if (PyDict_Size(map) != cols || PyTuple_GET_SIZE(args) - 2 != cols)
        return 0;

    PyObject** apValues = (PyObject**)pyodbc_malloc(sizeof(PyObject*) * cols);
    if (!apValues)
        return 0;

    for (int i = 0; i < cols; i++)
    {
        apValues[i] = PyTuple_GET_ITEM(args, i+2);
        Py_INCREF(apValues[i]);
    }

    // Row_Internal will incref desc and map.

    PyObject* self = (PyObject*)Row_InternalNew(desc, map, cols, apValues);
    if (!self)
        pyodbc_free(apValues);

    return self;
}
예제 #11
0
static bool ReadVarColumn(Cursor* cur, Py_ssize_t iCol, SQLSMALLINT ctype, bool& isNull, byte*& pbResult, Py_ssize_t& cbResult)
{
    // Called to read a variable-length column and return its data in a newly-allocated heap
    // buffer.
    //
    // Returns true if the read was successful and false if the read failed.  If the read
    // failed a Python exception will have been set.
    //
    // If a non-null and non-empty value was read, pbResult will be set to a buffer containing
    // the data and cbResult will be set to the byte length.  This length does *not* include a
    // null terminator.  In this case the data *must* be freed using pyodbc_free.
    //
    // If a null value was read, isNull is set to true and pbResult and cbResult will be set to
    // 0.
    //
    // If a zero-length value was read, isNull is set to false and pbResult and cbResult will
    // be set to 0.

    isNull   = false;
    pbResult = 0;
    cbResult = 0;

    const Py_ssize_t cbElement = (Py_ssize_t)(IsWideType(ctype) ? sizeof(ODBCCHAR) : 1);
    const Py_ssize_t cbNullTerminator = IsBinaryType(ctype) ? 0 : cbElement;

    // TODO: Make the initial allocation size configurable?
    Py_ssize_t cbAllocated = 4096;
    Py_ssize_t cbUsed = 0;
    byte* pb = (byte*)malloc((size_t)cbAllocated);
    if (!pb)
    {
        PyErr_NoMemory();
        return false;
    }

    SQLRETURN ret = SQL_SUCCESS_WITH_INFO;

    do
    {
        // Call SQLGetData in a loop as long as it keeps returning partial data (ret ==
        // SQL_SUCCESS_WITH_INFO).  Each time through, update the buffer pb, cbAllocated, and
        // cbUsed.

        Py_ssize_t cbAvailable = cbAllocated - cbUsed;
        SQLLEN cbData;

        Py_BEGIN_ALLOW_THREADS
        ret = SQLGetData(cur->hstmt, (SQLUSMALLINT)(iCol+1), ctype, &pb[cbUsed], (SQLLEN)cbAvailable, &cbData);
        Py_END_ALLOW_THREADS;

        TRACE("ReadVarColumn: SQLGetData avail=%d --> ret=%d cbData=%d\n", (int)cbAvailable, (int)ret, (int)cbData);

        if (!SQL_SUCCEEDED(ret) && ret != SQL_NO_DATA)
        {
            RaiseErrorFromHandle("SQLGetData", cur->cnxn->hdbc, cur->hstmt);
            return false;
        }

        if (ret == SQL_SUCCESS && cbData < 0)
        {
            // HACK: FreeTDS 0.91 on OS/X returns -4 for NULL data instead of SQL_NULL_DATA
            // (-1).  I've traced into the code and it appears to be the result of assigning -1
            // to a SQLLEN.  We are going to treat all negative values as NULL.
            ret = SQL_NULL_DATA;
            cbData = 0;
        }

        // SQLGetData behavior is incredibly quirky: It doesn't tell us the total, the total
        // we've read, or even the amount just read.  It returns the amount just read, plus any
        // remaining.  Unfortunately, the only way to pick them apart is to subtract out the
        // amount of buffer we supplied.

        if (ret == SQL_SUCCESS_WITH_INFO)
        {
            // This means we read some data, but there is more.  SQLGetData is very weird - it
            // sets cbRead to the number of bytes we read *plus* the amount remaining.

            Py_ssize_t cbRemaining = 0; // How many more bytes do we need to allocate, not including null?
            Py_ssize_t cbRead = 0; // How much did we just read, not including null?

            if (cbData == SQL_NO_TOTAL)
            {
                // This special value indicates there is more data but the driver can't tell us
                // how much more, so we'll just add whatever we want and try again.  It also
                // tells us, however, that the buffer is full, so the amount we read equals the
                // amount we offered.  Remember that if the type requires a null terminator, it
                // will be added *every* time, not just at the end, so we need to subtract it.

                cbRead = (cbAvailable - cbNullTerminator);
                cbRemaining = 1024 * 1024;
            }
            else if ((Py_ssize_t)cbData >= cbAvailable)
            {
                // We offered cbAvailable space, but there was cbData data.  The driver filled
                // the buffer with what it could.  Remember that if the type requires a null
                // terminator, the driver is going to append one on *every* read, so we need to
                // subtract them out.  At least we know the exact data amount now and we can
                // allocate a precise amount.

                cbRead = (cbAvailable - cbNullTerminator);
                cbRemaining = cbData - cbRead;
            }
            else
            {
                // I would not expect to get here - we apparently read all of the data but the
                // driver did not return SQL_SUCCESS?
                cbRead = (cbData - cbNullTerminator);
                cbRemaining = 0;
            }

            cbUsed += cbRead;

            if (cbRemaining > 0)
            {
                // This is a tiny bit complicated by the fact that the data is null terminated,
                // meaning we haven't actually used up the entire buffer (cbAllocated), only
                // cbUsed (which should be cbAllocated - cbNullTerminator).
                Py_ssize_t cbNeed = cbUsed + cbRemaining + cbNullTerminator;
                pb = ReallocOrFreeBuffer(pb, cbNeed);
                if (!pb)
                    return false;
                cbAllocated = cbNeed;
            }
        }
        else if (ret == SQL_SUCCESS)
        {
            // We read some data and this is the last batch (so we'll drop out of the
            // loop).
            //
            // If I'm reading the documentation correctly, SQLGetData is not going to
            // include the null terminator in cbRead.

            cbUsed += cbData;
        }
    }
    while (ret == SQL_SUCCESS_WITH_INFO);

    isNull = (ret == SQL_NULL_DATA);

    if (!isNull && cbUsed > 0)
    {
        pbResult = pb;
        cbResult = cbUsed;
    }
    else
    {
        pyodbc_free(pb);
    }

    return true;
}
예제 #12
0
static PyObject* GetDataDecimal(Cursor* cur, Py_ssize_t iCol)
{
    // The SQL_NUMERIC_STRUCT support is hopeless (SQL Server ignores scale on input parameters and output columns,
    // Oracle does something else weird, and many drivers don't support it at all), so we'll rely on the Decimal's
    // string parsing.  Unfortunately, the Decimal author does not pay attention to the locale, so we have to modify
    // the string ourselves.
    //
    // Oracle inserts group separators (commas in US, periods in some countries), so leave room for that too.
    //
    // Some databases support a 'money' type which also inserts currency symbols.  Since we don't want to keep track of
    // all these, we'll ignore all characters we don't recognize.  We will look for digits, negative sign (which I hope
    // is universal), and a decimal point ('.' or ',' usually).  We'll do everything as Unicode in case currencies,
    // etc. are too far out.

    const TextEnc& enc = cur->cnxn->sqlwchar_enc;
    // I'm going to request the data as Unicode in case there is a weird currency symbol.  If
    // this is a performance problems we may want a flag on this.

    bool isNull = false;
    byte* pbData = 0;
    Py_ssize_t cbData = 0;
    if (!ReadVarColumn(cur, iCol, enc.ctype, isNull, pbData, cbData))
        return 0;

    if (isNull)
    {
        I(pbData == 0 && cbData == 0);
        Py_RETURN_NONE;
    }

    Object result(TextBufferToObject(enc, pbData, cbData));

    pyodbc_free(pbData);

    if (!result)
        return 0;

    // Remove non-digits and convert the databases decimal to a '.' (required by decimal ctor).
    //
    // We are assuming that the decimal point and digits fit within the size of ODBCCHAR.

    // If Unicode, convert to UTF-8 and copy the digits and punctuation out.  Since these are
    // all ASCII characters, we can ignore any multiple-byte characters.  Fortunately, if a
    // character is multi-byte all bytes will have the high bit set.

    char* pch;
    Py_ssize_t cch;

#if PY_MAJOR_VERSION >= 3
    if (PyUnicode_Check(result))
    {
        pch = PyUnicode_AsUTF8AndSize(result, &cch);
    }
    else
    {
        int n = PyBytes_AsStringAndSize(result, &pch, &cch);
        if (n < 0)
            pch = 0;
    }
#else
    Object encoded;
    if (PyUnicode_Check(result))
    {
        encoded = PyUnicode_AsUTF8String(result);
        if (!encoded)
            return 0;
        result = encoded.Detach();
    }
    int n = PyString_AsStringAndSize(result, &pch, &cch);
    if (n < 0)
        pch = 0;
#endif

    if (!pch)
        return 0;

    // TODO: Why is this limited to 100?  Also, can we perform a check on the original and use
    // it as-is?
    char ascii[100];
    size_t asciilen = 0;

    const char* pchMax = pch + cch;
    while (pch < pchMax)
    {
        if ((*pch & 0x80) == 0)
        {
            if (*pch == chDecimal)
            {
                // Must force it to use '.' since the Decimal class doesn't pay attention to the locale.
                ascii[asciilen++] = '.';
            }
            else if ((*pch >= '0' && *pch <= '9') || *pch == '-')
            {
                ascii[asciilen++] = (char)(*pch);
            }
        }
        pch++;
    }

    ascii[asciilen] = 0;

    Object str(PyString_FromStringAndSize(ascii, (Py_ssize_t)asciilen));
    if (!str)
        return 0;
    PyObject* decimal_type = GetClassForThread("decimal", "Decimal");
    if (!decimal_type)
        return 0;
    PyObject* decimal = PyObject_CallFunction(decimal_type, "O", str.Get());
    Py_DECREF(decimal_type);
    return decimal;
}
예제 #13
0
파일: getdata.cpp 프로젝트: gthb/pyodbc
    PyObject* DetachValue()
    {
        // At this point, Trim should have been called by PostRead.

        if (bytesUsed == SQL_NULL_DATA || buffer == 0)
            Py_RETURN_NONE;

        if (usingStack)
        {
            if (dataType == SQL_C_CHAR)
                return PyBytes_FromStringAndSize(buffer, bytesUsed);

            if (dataType == SQL_C_BINARY)
            {
#if PY_VERSION_HEX >= 0x02060000
                return PyByteArray_FromStringAndSize(buffer, bytesUsed);
#else
                return PyBytes_FromStringAndSize(buffer, bytesUsed);
#endif
            }

            if (sizeof(SQLWCHAR) == Py_UNICODE_SIZE)
                return PyUnicode_FromUnicode((const Py_UNICODE*)buffer, bytesUsed / element_size);

            return PyUnicode_FromSQLWCHAR((const SQLWCHAR*)buffer, bytesUsed / element_size);
        }

        if (bufferOwner && PyUnicode_CheckExact(bufferOwner))
        {
            if (PyUnicode_Resize(&bufferOwner, bytesUsed / element_size) == -1)
                return 0;
            PyObject* tmp = bufferOwner;
            bufferOwner = 0;
            buffer      = 0;
            return tmp;
        }

        if (bufferOwner && PyBytes_CheckExact(bufferOwner))
        {
            if (_PyBytes_Resize(&bufferOwner, bytesUsed) == -1)
                return 0;
            PyObject* tmp = bufferOwner;
            bufferOwner = 0;
            buffer      = 0;
            return tmp;
        }

#if PY_VERSION_HEX >= 0x02060000
        if (bufferOwner && PyByteArray_CheckExact(bufferOwner))
        {
            if (PyByteArray_Resize(bufferOwner, bytesUsed) == -1)
                return 0;
            PyObject* tmp = bufferOwner;
            bufferOwner = 0;
            buffer      = 0;
            return tmp;
        }
#endif

        // We have allocated our own SQLWCHAR buffer and must now copy it to a Unicode object.
        I(bufferOwner == 0);
        PyObject* result = PyUnicode_FromSQLWCHAR((const SQLWCHAR*)buffer, bytesUsed / element_size);
        if (result == 0)
            return false;
        pyodbc_free(buffer);
        buffer = 0;
        return result;
    }