mirror of
https://github.com/mariadb-corporation/mariadb-connector-python.git
synced 2025-08-04 08:04:45 +00:00
Follow up for CONPY-299
- Added byteswap function for vector (bigendian) - Use buffer protocol instead of calling array's methods
This commit is contained in:
@ -24,6 +24,53 @@
|
|||||||
#define IS_DECIMAL_TYPE(type) \
|
#define IS_DECIMAL_TYPE(type) \
|
||||||
((type) == MYSQL_TYPE_NEWDECIMAL || (type) == MYSQL_TYPE_DOUBLE || (type) == MYSQL_TYPE_FLOAT)
|
((type) == MYSQL_TYPE_NEWDECIMAL || (type) == MYSQL_TYPE_DOUBLE || (type) == MYSQL_TYPE_FLOAT)
|
||||||
|
|
||||||
|
static char *ma_byteswap(char *buf, size_t itemsize, size_t len)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
Py_ssize_t i;
|
||||||
|
|
||||||
|
switch (itemsize) {
|
||||||
|
case 1:
|
||||||
|
return buf;
|
||||||
|
case 2:
|
||||||
|
for (p = buf, i = len; --i >= 0; p += itemsize) {
|
||||||
|
char p0 = p[0];
|
||||||
|
p[0] = p[1];
|
||||||
|
p[1] = p0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
for (p = buf, i = len; --i >= 0; p += itemsize) {
|
||||||
|
char p0 = p[0];
|
||||||
|
char p1 = p[1];
|
||||||
|
p[0] = p[3];
|
||||||
|
p[1] = p[2];
|
||||||
|
p[2] = p1;
|
||||||
|
p[3] = p0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
for (p = buf, i = len; --i >= 0; p += itemsize) {
|
||||||
|
char p0 = p[0];
|
||||||
|
char p1 = p[1];
|
||||||
|
char p2 = p[2];
|
||||||
|
char p3 = p[3];
|
||||||
|
p[0] = p[7];
|
||||||
|
p[1] = p[6];
|
||||||
|
p[2] = p[5];
|
||||||
|
p[3] = p[4];
|
||||||
|
p[4] = p3;
|
||||||
|
p[5] = p2;
|
||||||
|
p[6] = p1;
|
||||||
|
p[7] = p0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
long MrdbIndicator_AsLong(PyObject *column)
|
long MrdbIndicator_AsLong(PyObject *column)
|
||||||
{
|
{
|
||||||
PyObject *pyLong= PyObject_GetAttrString(column, "indicator");
|
PyObject *pyLong= PyObject_GetAttrString(column, "indicator");
|
||||||
@ -299,7 +346,7 @@ static uint8_t check_time(MYSQL_TIME *tm)
|
|||||||
|
|
||||||
Year must be < 10000, month < 12, day < 32
|
Year must be < 10000, month < 12, day < 32
|
||||||
|
|
||||||
Years with 2 digits, are converted to values 1970-2069 according to
|
Years with 2 digits, are converted to values 1970-2069 according to
|
||||||
usual rules:
|
usual rules:
|
||||||
|
|
||||||
00-69 is converted to 2000-2069.
|
00-69 is converted to 2000-2069.
|
||||||
@ -382,7 +429,7 @@ int Py_str_to_TIME(const char *str, size_t length, MYSQL_TIME *tm)
|
|||||||
{
|
{
|
||||||
if (parse_time(p, end - p, &p, tm))
|
if (parse_time(p, end - p, &p, tm))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
tm->year = tm->month = tm->day = 0;
|
tm->year = tm->month = tm->day = 0;
|
||||||
tm->time_type = MYSQL_TIMESTAMP_TIME;
|
tm->time_type = MYSQL_TIMESTAMP_TIME;
|
||||||
return 0;
|
return 0;
|
||||||
@ -419,7 +466,7 @@ error:
|
|||||||
static PyObject *Mrdb_GetTimeDelta(MYSQL_TIME *tm)
|
static PyObject *Mrdb_GetTimeDelta(MYSQL_TIME *tm)
|
||||||
{
|
{
|
||||||
int days, hour, minute, second, second_part;
|
int days, hour, minute, second, second_part;
|
||||||
|
|
||||||
hour= (tm->neg) ? -1 * tm->hour : tm->hour;
|
hour= (tm->neg) ? -1 * tm->hour : tm->hour;
|
||||||
minute= (tm->neg) ? -1 * tm->minute : tm->minute;
|
minute= (tm->neg) ? -1 * tm->minute : tm->minute;
|
||||||
second= (tm->neg) ? -1 * tm->second : tm->second;
|
second= (tm->neg) ? -1 * tm->second : tm->second;
|
||||||
@ -428,7 +475,7 @@ static PyObject *Mrdb_GetTimeDelta(MYSQL_TIME *tm)
|
|||||||
days= hour / 24;
|
days= hour / 24;
|
||||||
hour= hour % 24;
|
hour= hour % 24;
|
||||||
second= hour * 3600 + minute * 60 + second;
|
second= hour * 3600 + minute * 60 + second;
|
||||||
|
|
||||||
return PyDelta_FromDSU(days, second, second_part);
|
return PyDelta_FromDSU(days, second, second_part);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,7 +499,7 @@ static PyObject *ma_convert_value(MrdbCursor *self,
|
|||||||
}
|
}
|
||||||
return new_value;
|
return new_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
field_fetch_fromtext(MrdbCursor *self, char *data, unsigned int column)
|
field_fetch_fromtext(MrdbCursor *self, char *data, unsigned int column)
|
||||||
{
|
{
|
||||||
@ -492,8 +539,8 @@ field_fetch_fromtext(MrdbCursor *self, char *data, unsigned int column)
|
|||||||
self->values[column]= PyLong_FromString(p, NULL, 0);
|
self->values[column]= PyLong_FromString(p, NULL, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MYSQL_TYPE_FLOAT:
|
case MYSQL_TYPE_FLOAT:
|
||||||
case MYSQL_TYPE_DOUBLE:
|
case MYSQL_TYPE_DOUBLE:
|
||||||
{
|
{
|
||||||
double d= atof(data);
|
double d= atof(data);
|
||||||
self->values[column]= PyFloat_FromDouble(d);
|
self->values[column]= PyFloat_FromDouble(d);
|
||||||
@ -525,7 +572,7 @@ field_fetch_fromtext(MrdbCursor *self, char *data, unsigned int column)
|
|||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
self->values[column]= Py_None;
|
self->values[column]= Py_None;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
if (check_date(tm.year, tm.month, tm.day) &&
|
if (check_date(tm.year, tm.month, tm.day) &&
|
||||||
check_time(&tm))
|
check_time(&tm))
|
||||||
@ -551,13 +598,13 @@ field_fetch_fromtext(MrdbCursor *self, char *data, unsigned int column)
|
|||||||
}
|
}
|
||||||
if (self->fields[column].charsetnr== CHARSET_BINARY)
|
if (self->fields[column].charsetnr== CHARSET_BINARY)
|
||||||
{
|
{
|
||||||
self->values[column]=
|
self->values[column]=
|
||||||
PyBytes_FromStringAndSize((const char *)data,
|
PyBytes_FromStringAndSize((const char *)data,
|
||||||
(Py_ssize_t)length[column]);
|
(Py_ssize_t)length[column]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self->values[column]=
|
self->values[column]=
|
||||||
PyUnicode_FromStringAndSize((const char *)data,
|
PyUnicode_FromStringAndSize((const char *)data,
|
||||||
(Py_ssize_t)length[column]);
|
(Py_ssize_t)length[column]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -612,11 +659,11 @@ field_fetch_fromtext(MrdbCursor *self, char *data, unsigned int column)
|
|||||||
if ((val= ma_convert_value(self, type, self->values[column])))
|
if ((val= ma_convert_value(self, type, self->values[column])))
|
||||||
self->values[column]= val;
|
self->values[column]= val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* field_fetch_callback
|
/* field_fetch_callback
|
||||||
This function was previously registered with mysql_stmt_attr_set and
|
This function was previously registered with mysql_stmt_attr_set and
|
||||||
STMT_ATTR_FIELD_FETCH_CALLBACK parameter. Instead of filling a bind
|
STMT_ATTR_FIELD_FETCH_CALLBACK parameter. Instead of filling a bind
|
||||||
buffer MariaDB Connector/C sends raw data in row for the specified column.
|
buffer MariaDB Connector/C sends raw data in row for the specified column.
|
||||||
In case of a NULL value row ptr will be NULL.
|
In case of a NULL value row ptr will be NULL.
|
||||||
|
|
||||||
@ -659,7 +706,7 @@ field_fetch_callback(void *data, unsigned int column, unsigned char **row)
|
|||||||
*row+= 2;
|
*row+= 2;
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_INT24:
|
case MYSQL_TYPE_INT24:
|
||||||
self->values[column]=
|
self->values[column]=
|
||||||
(self->fields[column].flags & UNSIGNED_FLAG) ?
|
(self->fields[column].flags & UNSIGNED_FLAG) ?
|
||||||
PyLong_FromUnsignedLong((unsigned long)uint3korr(*row)) :
|
PyLong_FromUnsignedLong((unsigned long)uint3korr(*row)) :
|
||||||
PyLong_FromLong((long)sint3korr(*row));
|
PyLong_FromLong((long)sint3korr(*row));
|
||||||
@ -722,7 +769,7 @@ field_fetch_callback(void *data, unsigned int column, unsigned char **row)
|
|||||||
}
|
}
|
||||||
if (len == 11)
|
if (len == 11)
|
||||||
second_part= uint4korr(*row + 7);
|
second_part= uint4korr(*row + 7);
|
||||||
self->values[column]= PyDateTime_FromDateAndTime(year, month,
|
self->values[column]= PyDateTime_FromDateAndTime(year, month,
|
||||||
day, hour, minute, second, second_part);
|
day, hour, minute, second, second_part);
|
||||||
*row+= len;
|
*row+= len;
|
||||||
break;
|
break;
|
||||||
@ -782,13 +829,13 @@ field_fetch_callback(void *data, unsigned int column, unsigned char **row)
|
|||||||
self->fields[column].max_length= length;
|
self->fields[column].max_length= length;
|
||||||
if (self->fields[column].charsetnr== CHARSET_BINARY)
|
if (self->fields[column].charsetnr== CHARSET_BINARY)
|
||||||
{
|
{
|
||||||
self->values[column]=
|
self->values[column]=
|
||||||
PyBytes_FromStringAndSize((const char *)*row,
|
PyBytes_FromStringAndSize((const char *)*row,
|
||||||
(Py_ssize_t)length);
|
(Py_ssize_t)length);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self->values[column]=
|
self->values[column]=
|
||||||
PyUnicode_FromStringAndSize((const char *)*row,
|
PyUnicode_FromStringAndSize((const char *)*row,
|
||||||
(Py_ssize_t)length);
|
(Py_ssize_t)length);
|
||||||
}
|
}
|
||||||
*row+= length;
|
*row+= length;
|
||||||
@ -831,7 +878,7 @@ field_fetch_callback(void *data, unsigned int column, unsigned char **row)
|
|||||||
if (length > self->fields[column].max_length)
|
if (length > self->fields[column].max_length)
|
||||||
self->fields[column].max_length= length;
|
self->fields[column].max_length= length;
|
||||||
} else {
|
} else {
|
||||||
self->values[column]=
|
self->values[column]=
|
||||||
PyUnicode_FromStringAndSize((const char *)*row,
|
PyUnicode_FromStringAndSize((const char *)*row,
|
||||||
(Py_ssize_t)length);
|
(Py_ssize_t)length);
|
||||||
utf8len= (unsigned long)PyUnicode_GET_LENGTH(self->values[column]);
|
utf8len= (unsigned long)PyUnicode_GET_LENGTH(self->values[column]);
|
||||||
@ -886,13 +933,13 @@ end:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
mariadb_get_column_info
|
mariadb_get_column_info
|
||||||
This function analyzes the Python object and calculates the corresponding
|
This function analyzes the Python object and calculates the corresponding
|
||||||
MYSQL_TYPE, unsigned flag or NULL values and stores the information in
|
MYSQL_TYPE, unsigned flag or NULL values and stores the information in
|
||||||
MrdbParamInfo pointer.
|
MrdbParamInfo pointer.
|
||||||
*/
|
*/
|
||||||
static uint8_t
|
static uint8_t
|
||||||
mariadb_get_column_info(PyObject *obj, MrdbParamInfo *paraminfo)
|
mariadb_get_column_info(PyObject *obj, MrdbParamInfo *paraminfo)
|
||||||
{
|
{
|
||||||
if (obj == NULL)
|
if (obj == NULL)
|
||||||
@ -943,8 +990,11 @@ mariadb_get_column_info(PyObject *obj, MrdbParamInfo *paraminfo)
|
|||||||
paraminfo->type= MYSQL_TYPE_LONG_BLOB;
|
paraminfo->type= MYSQL_TYPE_LONG_BLOB;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else if (Py_TYPE(obj)->tp_str) {
|
||||||
/* If Object has string representation, we will use string representation */
|
/* If Object has string representation, we will use string representation */
|
||||||
|
paraminfo->type= MYSQL_TYPE_VAR_STRING;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
/* no corresponding object, return error */
|
/* no corresponding object, return error */
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
@ -965,7 +1015,7 @@ PyObject *ListOrTuple_GetItem(PyObject *obj, Py_ssize_t index)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
mariadb_get_parameter()
|
mariadb_get_parameter()
|
||||||
@brief Returns a bulk parameter which was passed to
|
@brief Returns a bulk parameter which was passed to
|
||||||
@ -979,7 +1029,7 @@ PyObject *ListOrTuple_GetItem(PyObject *obj, Py_ssize_t index)
|
|||||||
|
|
||||||
@return 0 on success, 1 on error
|
@return 0 on success, 1 on error
|
||||||
*/
|
*/
|
||||||
static uint8_t
|
static uint8_t
|
||||||
mariadb_get_parameter(MrdbCursor *self,
|
mariadb_get_parameter(MrdbCursor *self,
|
||||||
uint8_t is_bulk,
|
uint8_t is_bulk,
|
||||||
uint32_t row_nr,
|
uint32_t row_nr,
|
||||||
@ -1060,7 +1110,7 @@ mariadb_get_parameter(MrdbCursor *self,
|
|||||||
{
|
{
|
||||||
param->indicator= STMT_INDICATOR_NULL;
|
param->indicator= STMT_INDICATOR_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
param->value= column;
|
param->value= column;
|
||||||
param->indicator= STMT_INDICATOR_NONE;
|
param->indicator= STMT_INDICATOR_NONE;
|
||||||
@ -1070,7 +1120,7 @@ end:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
mariadb_get_parameter_info
|
mariadb_get_parameter_info
|
||||||
mariadb_get_parameter_info fills the MYSQL_BIND structure
|
mariadb_get_parameter_info fills the MYSQL_BIND structure
|
||||||
with correct field_types for the Python objects.
|
with correct field_types for the Python objects.
|
||||||
@ -1079,7 +1129,7 @@ end:
|
|||||||
the field type (e.g. by checking maxbit size for a PyLong).
|
the field type (e.g. by checking maxbit size for a PyLong).
|
||||||
If the types in this column differ we will return an error.
|
If the types in this column differ we will return an error.
|
||||||
*/
|
*/
|
||||||
static uint8_t
|
static uint8_t
|
||||||
mariadb_get_parameter_info(MrdbCursor *self,
|
mariadb_get_parameter_info(MrdbCursor *self,
|
||||||
MYSQL_BIND *param,
|
MYSQL_BIND *param,
|
||||||
uint32_t column_nr)
|
uint32_t column_nr)
|
||||||
@ -1090,10 +1140,10 @@ mariadb_get_parameter_info(MrdbCursor *self,
|
|||||||
|
|
||||||
param->is_unsigned= 0;
|
param->is_unsigned= 0;
|
||||||
paramvalue.indicator= 0;
|
paramvalue.indicator= 0;
|
||||||
|
uint8_t rc;
|
||||||
|
|
||||||
if (!self->array_size)
|
if (!self->array_size)
|
||||||
{
|
{
|
||||||
uint8_t rc;
|
|
||||||
memset(&pinfo, 0, sizeof(MrdbParamInfo));
|
memset(&pinfo, 0, sizeof(MrdbParamInfo));
|
||||||
if (mariadb_get_parameter(self, 0, 0, column_nr, ¶mvalue))
|
if (mariadb_get_parameter(self, 0, 0, column_nr, ¶mvalue))
|
||||||
return 1;
|
return 1;
|
||||||
@ -1103,15 +1153,14 @@ mariadb_get_parameter_info(MrdbCursor *self,
|
|||||||
{
|
{
|
||||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
||||||
"Can't retrieve column information for parameter %d",
|
"Can't retrieve column information for parameter %d",
|
||||||
column_nr);
|
column_nr + 1);
|
||||||
}
|
}
|
||||||
if (rc == 2)
|
if (rc == 2)
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(NULL, Mariadb_NotSupportedError, 0,
|
mariadb_throw_exception(NULL, Mariadb_NotSupportedError, 0,
|
||||||
"Data type '%s' in column %d not supported in MariaDB Connector/Python",
|
"Data type '%s' in column %d not supported in MariaDB Connector/Python",
|
||||||
Py_TYPE(paramvalue.value)->tp_name, column_nr);
|
Py_TYPE(paramvalue.value)->tp_name, column_nr + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
param->buffer_type= pinfo.type;
|
param->buffer_type= pinfo.type;
|
||||||
@ -1122,11 +1171,20 @@ mariadb_get_parameter_info(MrdbCursor *self,
|
|||||||
if (mariadb_get_parameter(self, 1, i, column_nr, ¶mvalue))
|
if (mariadb_get_parameter(self, 1, i, column_nr, ¶mvalue))
|
||||||
return 1;
|
return 1;
|
||||||
memset(&pinfo, 0, sizeof(MrdbParamInfo));
|
memset(&pinfo, 0, sizeof(MrdbParamInfo));
|
||||||
if (mariadb_get_column_info(paramvalue.value, &pinfo) && !paramvalue.indicator)
|
if ((rc= mariadb_get_column_info(paramvalue.value, &pinfo) && !paramvalue.indicator))
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 1,
|
if (rc == 1)
|
||||||
"Invalid parameter type at row %d, column %d",
|
{
|
||||||
i+1, column_nr + 1);
|
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
||||||
|
"Can't retrieve column information for parameter %d at row %d.",
|
||||||
|
column_nr + 1, i + 1);
|
||||||
|
}
|
||||||
|
if (rc == 2)
|
||||||
|
{
|
||||||
|
mariadb_throw_exception(NULL, Mariadb_NotSupportedError, 0,
|
||||||
|
"Data type '%s' in column %d at row %d not supported in MariaDB Connector/Python",
|
||||||
|
Py_TYPE(paramvalue.value)->tp_name, column_nr + 1, i+1);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1213,7 +1271,7 @@ static Py_ssize_t ListOrTuple_Size(PyObject *obj)
|
|||||||
This function validates the specified bulk parameters and
|
This function validates the specified bulk parameters and
|
||||||
translates the field types to MYSQL_TYPE_*.
|
translates the field types to MYSQL_TYPE_*.
|
||||||
*/
|
*/
|
||||||
uint8_t
|
uint8_t
|
||||||
mariadb_check_bulk_parameters(MrdbCursor *self,
|
mariadb_check_bulk_parameters(MrdbCursor *self,
|
||||||
PyObject *data)
|
PyObject *data)
|
||||||
{
|
{
|
||||||
@ -1222,14 +1280,14 @@ mariadb_check_bulk_parameters(MrdbCursor *self,
|
|||||||
if (!CHECK_TYPE((data), &PyList_Type) &&
|
if (!CHECK_TYPE((data), &PyList_Type) &&
|
||||||
!CHECK_TYPE(data, &PyTuple_Type))
|
!CHECK_TYPE(data, &PyTuple_Type))
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(self->stmt, Mariadb_InterfaceError, 1,
|
mariadb_throw_exception(self->stmt, Mariadb_InterfaceError, 1,
|
||||||
"Data must be passed as sequence (Tuple or List)");
|
"Data must be passed as sequence (Tuple or List)");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(self->array_size= (uint32_t)ListOrTuple_Size(data)))
|
if (!(self->array_size= (uint32_t)ListOrTuple_Size(data)))
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(self->stmt, Mariadb_InterfaceError, 1,
|
mariadb_throw_exception(self->stmt, Mariadb_InterfaceError, 1,
|
||||||
"Empty parameter list. At least one row must be specified");
|
"Empty parameter list. At least one row must be specified");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1256,10 +1314,10 @@ mariadb_check_bulk_parameters(MrdbCursor *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!self->parseinfo.paramcount ||
|
if (!self->parseinfo.paramcount ||
|
||||||
(self->parseinfo.paramstyle != PYFORMAT &&
|
(self->parseinfo.paramstyle != PYFORMAT &&
|
||||||
self->parseinfo.paramcount != ListOrTuple_Size(obj)))
|
self->parseinfo.paramcount != ListOrTuple_Size(obj)))
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(self->stmt, Mariadb_ProgrammingError, 1,
|
mariadb_throw_exception(self->stmt, Mariadb_ProgrammingError, 1,
|
||||||
"Invalid number of parameters in row %d", i+1);
|
"Invalid number of parameters in row %d", i+1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1275,7 +1333,7 @@ mariadb_check_bulk_parameters(MrdbCursor *self,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(self->value= PyMem_RawCalloc(self->parseinfo.paramcount,
|
if (!(self->value= PyMem_RawCalloc(self->parseinfo.paramcount,
|
||||||
sizeof(MrdbParamValue))))
|
sizeof(MrdbParamValue))))
|
||||||
{
|
{
|
||||||
mariadb_throw_exception(NULL, Mariadb_InterfaceError, 0,
|
mariadb_throw_exception(NULL, Mariadb_InterfaceError, 0,
|
||||||
@ -1341,7 +1399,7 @@ error:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
mariadb_param_to_bind()
|
mariadb_param_to_bind()
|
||||||
|
|
||||||
@brief Set the current value for the specified bind buffer
|
@brief Set the current value for the specified bind buffer
|
||||||
@ -1352,7 +1410,7 @@ error:
|
|||||||
|
|
||||||
@return 0 on success, otherwise error
|
@return 0 on success, otherwise error
|
||||||
*/
|
*/
|
||||||
static uint8_t
|
static uint8_t
|
||||||
mariadb_param_to_bind(MrdbCursor *self,
|
mariadb_param_to_bind(MrdbCursor *self,
|
||||||
MYSQL_BIND *bind,
|
MYSQL_BIND *bind,
|
||||||
MrdbParamValue *value)
|
MrdbParamValue *value)
|
||||||
@ -1428,27 +1486,41 @@ mariadb_param_to_bind(MrdbCursor *self,
|
|||||||
*(double *)value->num= (double)PyFloat_AsDouble(value->value);
|
*(double *)value->num= (double)PyFloat_AsDouble(value->value);
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_LONG_BLOB:
|
case MYSQL_TYPE_LONG_BLOB:
|
||||||
|
if (value->free_me)
|
||||||
|
{
|
||||||
|
MARIADB_FREE_MEM(value->buffer);
|
||||||
|
value->free_me= 0;
|
||||||
|
}
|
||||||
if (!strcmp(Py_TYPE(value->value)->tp_name, "array.array") ||
|
if (!strcmp(Py_TYPE(value->value)->tp_name, "array.array") ||
|
||||||
!strcmp(Py_TYPE(value->value)->tp_name, "array"))
|
!strcmp(Py_TYPE(value->value)->tp_name, "array"))
|
||||||
{
|
{
|
||||||
Py_ssize_t size= PySequence_Length(value->value);
|
|
||||||
PyObject *byte_array= NULL;
|
PyObject *byte_array= NULL;
|
||||||
|
Py_buffer v;
|
||||||
|
|
||||||
bind->buffer= NULL;
|
bind->buffer= NULL;
|
||||||
|
if (PyObject_GetBuffer(value->value, &v, PyBUF_CONTIG_RO) < 0)
|
||||||
if (!size)
|
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if (!PyObject_HasAttrString(value->value, "tobytes"))
|
if (!v.len)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if (!(byte_array= PyObject_CallMethod(value->value, "tobytes", NULL)))
|
bind->buffer_length= (unsigned long)v.len;
|
||||||
goto end;
|
#if PY_BIG_ENDIAN == 0
|
||||||
|
bind->buffer= (void *)v.buf;
|
||||||
|
#else
|
||||||
|
bind->buffer= value->buffer= PyMem_RawCalloc(1, v.len);
|
||||||
|
if (!bind->buffer)
|
||||||
|
{
|
||||||
|
mariadb_throw_exception(NULL, Mariadb_InterfaceError, 0,
|
||||||
|
"Not enough memory (tried to allocated %lld bytes)", v.len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
value->free_me= 1;
|
||||||
|
memcpy(bind->buffer, v.buf, v.len);
|
||||||
|
|
||||||
bind->buffer= (void *)PyBytes_AS_STRING(byte_array);
|
bind->buffer= ma_byteswap((char *)bind->buffer, v.itemsize, v.len);
|
||||||
bind->buffer_length= (unsigned long)PyBytes_GET_SIZE(byte_array);
|
#endif
|
||||||
|
PyBuffer_Release(&v);
|
||||||
Py_DECREF(byte_array);
|
|
||||||
} else {
|
} else {
|
||||||
bind->buffer_length= (unsigned long)PyBytes_GET_SIZE(value->value);
|
bind->buffer_length= (unsigned long)PyBytes_GET_SIZE(value->value);
|
||||||
bind->buffer= (void *) PyBytes_AS_STRING(value->value);
|
bind->buffer= (void *) PyBytes_AS_STRING(value->value);
|
||||||
@ -1464,37 +1536,43 @@ mariadb_param_to_bind(MrdbCursor *self,
|
|||||||
mariadb_pydate_to_tm(bind->buffer_type, value->value, &value->tm);
|
mariadb_pydate_to_tm(bind->buffer_type, value->value, &value->tm);
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_NEWDECIMAL:
|
case MYSQL_TYPE_NEWDECIMAL:
|
||||||
{
|
|
||||||
Py_ssize_t len;
|
|
||||||
PyObject *obj= NULL;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
if (value->free_me)
|
|
||||||
MARIADB_FREE_MEM(value->buffer);
|
|
||||||
if (!strcmp(Py_TYPE(value->value)->tp_name, "decimal.Decimal") ||
|
|
||||||
!strcmp(Py_TYPE(value->value)->tp_name, "Decimal"))
|
|
||||||
{
|
|
||||||
obj= PyObject_Str(value->value);
|
|
||||||
p= (void *)PyUnicode_AsUTF8AndSize(obj, &len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
obj= PyObject_Str(value->value);
|
|
||||||
p= (void *)PyUnicode_AsUTF8AndSize(obj, &len);
|
|
||||||
}
|
|
||||||
bind->buffer= value->buffer= PyMem_RawCalloc(1, len);
|
|
||||||
memcpy(value->buffer, p, len);
|
|
||||||
value->free_me= 1;
|
|
||||||
bind->buffer_length= (unsigned long)len;
|
|
||||||
Py_DECREF(obj);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MYSQL_TYPE_VAR_STRING:
|
case MYSQL_TYPE_VAR_STRING:
|
||||||
{
|
{
|
||||||
Py_ssize_t len;
|
Py_ssize_t len;
|
||||||
|
|
||||||
bind->buffer= (void *)PyUnicode_AsUTF8AndSize(value->value, &len);
|
if (value->free_me)
|
||||||
bind->buffer_length= (unsigned long)len;
|
{
|
||||||
|
MARIADB_FREE_MEM(value->buffer);
|
||||||
|
value->free_me= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CHECK_TYPE(value->value, &PyUnicode_Type)) {
|
||||||
|
bind->buffer= (void *)PyUnicode_AsUTF8AndSize(value->value, &len);
|
||||||
|
bind->buffer_length= (unsigned long)len;
|
||||||
|
} else {
|
||||||
|
PyObject *obj= PyObject_Str(value->value);
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (!obj) {
|
||||||
|
mariadb_throw_exception(self->stmt, Mariadb_ProgrammingError, 0,
|
||||||
|
"Python type %s has no string representation",
|
||||||
|
Py_TYPE(value->value)->tp_name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p= (void *)PyUnicode_AsUTF8AndSize(obj, &len);
|
||||||
|
if (!(bind->buffer= value->buffer= PyMem_RawCalloc(1, len)))
|
||||||
|
{
|
||||||
|
mariadb_throw_exception(NULL, Mariadb_InterfaceError, 0,
|
||||||
|
"Not enough memory (tried to allocated %lld bytes)", len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
value->free_me= 1;
|
||||||
|
memcpy(bind->buffer, p, len);
|
||||||
|
bind->buffer_length= (unsigned long)len;
|
||||||
|
Py_DECREF(obj);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MYSQL_TYPE_NULL:
|
case MYSQL_TYPE_NULL:
|
||||||
@ -1506,7 +1584,7 @@ end:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
mariadb_param_update()
|
mariadb_param_update()
|
||||||
@brief Callback function which updates the bind structure's buffer and
|
@brief Callback function which updates the bind structure's buffer and
|
||||||
length with data from the specified row number. This callback function
|
length with data from the specified row number. This callback function
|
||||||
@ -1529,7 +1607,7 @@ mariadb_param_update(void *data, MYSQL_BIND *bind, uint32_t row_nr)
|
|||||||
|
|
||||||
for (i=0; i < self->parseinfo.paramcount; i++)
|
for (i=0; i < self->parseinfo.paramcount; i++)
|
||||||
{
|
{
|
||||||
if (mariadb_get_parameter(self, (self->array_size > 0),
|
if (mariadb_get_parameter(self, (self->array_size > 0),
|
||||||
row_nr, i, &self->value[i]))
|
row_nr, i, &self->value[i]))
|
||||||
{
|
{
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -94,7 +94,7 @@ class TestCursor(unittest.TestCase):
|
|||||||
cursor.execute("INSERT INTO t_vector VALUES (?,?)", (1, data))
|
cursor.execute("INSERT INTO t_vector VALUES (?,?)", (1, data))
|
||||||
cursor.execute("SELECT id, v, Vec_ToText(v) FROM t_vector")
|
cursor.execute("SELECT id, v, Vec_ToText(v) FROM t_vector")
|
||||||
row= cursor.fetchone()
|
row= cursor.fetchone()
|
||||||
|
self.connection.commit()
|
||||||
check_data= [row[1], array.array('f', eval(row[2]))]
|
check_data= [row[1], array.array('f', eval(row[2]))]
|
||||||
|
|
||||||
cursor.execute("DROP TABLE t_vector")
|
cursor.execute("DROP TABLE t_vector")
|
||||||
@ -613,6 +613,27 @@ class TestCursor(unittest.TestCase):
|
|||||||
self.assertEqual(row[0], 2)
|
self.assertEqual(row[0], 2)
|
||||||
del cursor
|
del cursor
|
||||||
|
|
||||||
|
def test_conpy298(self):
|
||||||
|
import uuid, ipaddress
|
||||||
|
|
||||||
|
cursor= self.connection.cursor()
|
||||||
|
cursor.execute("DROP TABLE IF EXISTS t1")
|
||||||
|
cursor.execute("CREATE TABLE t1 (a inet6, b inet4, c uuid)")
|
||||||
|
|
||||||
|
values= (ipaddress.ip_address('::'), ipaddress.ip_address('192.168.0.1'),
|
||||||
|
uuid.uuid4())
|
||||||
|
|
||||||
|
cursor.execute("INSERT INTO t1 VALUES (?, ?, ?)", values)
|
||||||
|
cursor.execute("SELECT a,b,c FROM t1")
|
||||||
|
row= cursor.fetchone()
|
||||||
|
|
||||||
|
self.assertEqual(row[0], values[0].__str__())
|
||||||
|
self.assertEqual(row[1], values[1].__str__())
|
||||||
|
self.assertEqual(row[2], values[2].__str__())
|
||||||
|
|
||||||
|
cursor.execute("DROP TABLE t1")
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
def test_conpy34(self):
|
def test_conpy34(self):
|
||||||
cursor = self.connection.cursor()
|
cursor = self.connection.cursor()
|
||||||
cursor.execute("CREATE TEMPORARY TABLE t1 (a varchar(20),"
|
cursor.execute("CREATE TEMPORARY TABLE t1 (a varchar(20),"
|
||||||
|
Reference in New Issue
Block a user