/* KInterbasDB Python Package - Implementation of Parameter Conversion Py->DB ** ** Version 3.1 ** ** The following contributors hold Copyright (C) over their respective ** portions of code (see license.txt for details): ** ** [Original Author (maintained through version 2.0-0.3.1):] ** 1998-2001 [alex] Alexander Kuznetsov ** [Maintainers (after version 2.0-0.3.1):] ** 2001-2002 [maz] Marek Isalski ** 2002-2004 [dsr] David Rushby ** [Contributors:] ** 2001 [eac] Evgeny A. Cherkashin ** 2001-2002 [janez] Janez Jere */ /* This source file is designed to be directly included in _kiconversion.c, ** without the involvement of a header file. */ /******************** FUNCTION PROTOTYPES:BEGIN ********************/ static int _try_to_accept_string_and_convert(PyObject *o, XSQLVAR *sqlvar); static int _PyObject2XSQLVAR_check_range_SQL_INTEGER( unsigned short dialect, short data_type, short data_subtype, short scale, PyObject *n, PyObject *min, PyObject *max ); static int _PyObject2XSQLVAR_check_range_SQL_CHARACTER(PyObject *o, int actualLength, int maxLength ); /******************** FUNCTION PROTOTYPES:END ********************/ /******************** CONVENIENCE DEFS:BEGIN ********************/ #define TRY_TO_ACCEPT_STRING_AND_CONVERT(o, sqlvar) \ if ( _try_to_accept_string_and_convert(o, sqlvar) == INPUT_OK ) { \ return INPUT_OK; \ } /* Else, do not immediately return or break. */ /* Don't allocate new memory if we're converting a database array element: */ #define ALLOC_IF_NOT_ARRAY_THEN_SET(buf_ptr, datatype, value) \ if (!is_array_element) { \ buf_ptr = (char *) kimem_main_malloc(sizeof(datatype)); \ if (buf_ptr == NULL) { goto fail; } \ } \ /* value may contain a Python API call; we must check for a Python error \ ** after evaluating value. */ \ { \ datatype temp = (datatype)(value); \ if (PyErr_Occurred()) { \ /* Error-handling code elsewhere will take care of freeing buf_ptr, for \ ** which we allocated space just above. */ \ goto fail; \ } \ *( (datatype *) buf_ptr ) = temp; \ } /******************** CONVENIENCE DEFS:END ********************/ #define conv_in_text_conventional(py_input, sqlvar, data_type) \ _conv_in_text( \ FALSE, /* This is not an array element. */ \ py_input, \ /* For non-array-element conversion: */ \ sqlvar, data_type, \ /* For array-element conversion; irrelevant here: */ \ NULL, -1, '\0' \ ) #define conv_in_text_array(data_slot, size_of_single_element, pad_char) \ _conv_in_text( \ TRUE, /* This is an array element. */ \ py_input, \ /* For non-array-element conversion: */ \ NULL, -1, \ /* For array-element conversion; irrelevant here: */ \ data_slot, size_of_single_element, pad_char \ ) /* The _conv_in_text function should not be called except via the ** conv_in_text_(conventional|array) macros defined above. */ static int _conv_in_text( /* Common: */ boolean is_array_element, PyObject *py_input, /* For non-array-element conversion: */ XSQLVAR *sqlvar, short data_type, /* For array-element conversion: */ char **data_slot, int defined_field_size, char array_value_pad_char ) { if ( !PyString_Check(py_input) ) { /* 2003.03.15: Finally implemented more informative error message. */ if (is_array_element || !PYTHON_2_2_OR_LATER) { /* Python < 2.2 will always choose this path. */ raise_exception( InterfaceError, "Type mismatch: input parameter must be a string." ); } else { #if PYTHON_2_2_OR_LATER PyObject *py_input_type = PyObject_Type(py_input); PyObject *py_input_type_str = PyObject_Str(py_input_type); /* sqlvar->aliasname is not null-terminated. */ PyObject *field_name = (sqlvar->aliasname_length == 0 ? PyString_FromString("[name not known at this stage of query execution]") : PyString_FromStringAndSize(sqlvar->aliasname, sqlvar->aliasname_length) ); PyObject *err_msg = PyString_FromFormat( "Type mismatch: Input parameter for field named %s must be a string," " rather than a %s.", PyString_AS_STRING(field_name), PyString_AS_STRING(py_input_type_str) ); Py_DECREF(py_input_type); Py_DECREF(py_input_type_str); Py_DECREF(field_name); /* Hmm... why not a PyExc_TypeError or a ProgrammingError? */ raise_exception( InterfaceError, PyString_AS_STRING(err_msg) ); Py_DECREF(err_msg); #endif /* PYTHON_2_2_OR_LATER */ } return INPUT_ERROR; } { int size_of_incoming_string = PyString_GET_SIZE(py_input); int max_allowed_length = (is_array_element ? defined_field_size : sqlvar->sqllen); /* Don't allow truncation; raise an exception if py_input is too long. */ if ( INPUT_ERROR == _PyObject2XSQLVAR_check_range_SQL_CHARACTER( py_input, size_of_incoming_string, max_allowed_length ) ) { return INPUT_ERROR; } if (!is_array_element) { /* This is not an array element; we're free to use sqlvar. */ assert (sqlvar != NULL); assert (data_slot == NULL); /* Coerce this sqlvar's type to SQL_TEXT (CHAR) so that we don't have to ** allocate a new buffer of size ** sizeof(short) + size_of_incoming_string ** just to have sizeof(short) extra bytes at the beginning to denote ** the length of the incoming value (as we normally would with a ** SQL_VARYING). */ if (data_type != SQL_TEXT) { data_type = SQL_TEXT; /* Reset the XSQLVAR's type code, retaining its original null flag. */ sqlvar->sqltype = SQL_TEXT | XSQLVAR_SQLTYPE_READ_NULL_FLAG(sqlvar); } sqlvar->sqllen = (short) size_of_incoming_string; /* !MUST! set the ** sqllen to prevent the database engine from bulldozing its way out ** to the field's defined length and corrupting the value in the ** database. ** The database engine assumes that an incoming CHAR buffer is sqllen ** bytes long (sqllen is initially set to the defined length of the ** CHAR field). The incoming buffer might not be long enough because ** we haven't allocated a full-sized buffer for the incoming value. ** Instead, we're using the pre-existing, null-terminated buffer ** inside the Python string object py_input). ** !Note that this XSQLVAR's original settings are later restored ** to prevent the database client library from concluding that the ** defined maximum length of this field is *really* ** size_of_incoming_string, or that this field is *really* a CHAR if ** sqltype originally indicated VARCHAR. ** In essence, this amounts to API abuse for the sake of a very ** significant optimization. */ sqlvar->sqldata = PyString_AS_STRING(py_input); } else { /* This is an array element. */ assert (sqlvar == NULL); assert (data_slot != NULL); /* Because we don't have an XSQLVAR structure to abuse, we must actually ** *copy* the incoming bytes into the array source buffer. */ memcpy(*data_slot, PyString_AS_STRING(py_input), size_of_incoming_string); memset( (*data_slot) + size_of_incoming_string, array_value_pad_char, defined_field_size - size_of_incoming_string ); } } /* end of namespace-block for size_of_incoming_string. */ return INPUT_OK; } /* _conv_in_text */ #define conv_in_internal_integer_types_conventional(py_input, sqlvar, \ dialect, data_type, data_subtype, scale \ ) \ _conv_in_internal_integer_types(FALSE, py_input, &sqlvar->sqldata, \ dialect, data_type, data_subtype, scale, \ sqlvar \ ) #define conv_in_internal_integer_types_array(py_input, data_slot, \ dialect, data_type, data_subtype, scale \ ) \ _conv_in_internal_integer_types(TRUE, py_input, data_slot, \ dialect, data_type, data_subtype, scale, \ NULL \ ) /* The _conv_in_internal_integer_types function should not be called except ** via the _conv_in_internal_integer_types_(conventional|array) macros defined ** above. */ static int _conv_in_internal_integer_types( boolean is_array_element, PyObject *py_input, char **data_slot, unsigned short dialect, short data_type, short data_subtype, short scale, XSQLVAR *sqlvar ) { PyObject *minN, *maxN; boolean isSQLShort = (data_type == SQL_SHORT); boolean isSQLLong = (data_type == SQL_LONG); boolean isPyInt = PyInt_Check(py_input); boolean isPyLong = PyLong_Check(py_input); if (is_array_element) { assert (sqlvar == NULL); } if ( !(isPyInt || isPyLong) ) { if (!is_array_element) { TRY_TO_ACCEPT_STRING_AND_CONVERT(py_input, sqlvar); } /* Raise a more informative error message. ** --But only on Python 2.2 or later. Of course, this could be done with ** C string operations rather than PyString_FromFormat on earlier Python ** versions, but why spend the extra effort in support of Luddites? */ #if PYTHON_2_2_OR_LATER { PyObject *py_input_type = PyObject_Type(py_input); PyObject *py_input_type_repr = PyObject_Repr(py_input_type); PyObject *py_input_repr = PyObject_Repr(py_input); PyObject *buffer = PyString_FromFormat( "Type mismatch while attempting to convert object of type %s" " to database-internal numeric type for storage%s." " The object in question is: %s", PyString_AsString(py_input_type_repr), (is_array_element ? " in array element" : ""), PyString_AsString(py_input_repr) ); raise_exception( InterfaceError, PyString_AsString(buffer) ); Py_DECREF(py_input_type); Py_DECREF(py_input_type_repr); Py_DECREF(buffer); } #else /* not PYTHON_2_2_OR_LATER */ raise_exception( InterfaceError, "Type mismatch while attempting to convert object to" " database-internal integer type for storage." ); #endif /* PYTHON_2_2_OR_LATER */ return INPUT_ERROR; } /* End of block that ensures that py_input is of an appropriate type. */ /* The next step is to ensure that the scaled value is not too large for ** storage in its internal format. If it is not too large, we will finally ** transfer the value from its Pythonic representation to the data_slot. */ if (isSQLShort) { minN = SHRT_MIN_As_PyObject; maxN = SHRT_MAX_As_PyObject; } else if (isSQLLong) { /* On non-Windows x86_64, a SQL_LONG is actually stored as an int, not a ** long. */ minN = INT_MIN_As_PyObject; maxN = INT_MAX_As_PyObject; #ifdef INTERBASE6_OR_LATER } else { /* data_type must be SQL_INT64 */ minN = LONG_LONG_MIN_As_PyObject; maxN = LONG_LONG_MAX_As_PyObject; #endif /* INTERBASE6_OR_LATER */ } if ( INPUT_ERROR == _PyObject2XSQLVAR_check_range_SQL_INTEGER( dialect, data_type, data_subtype, scale, py_input, minN, maxN ) ) { return INPUT_ERROR; } if (isSQLShort) { if (isPyInt) { ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, short, (short) PyInt_AS_LONG(py_input)); } else { /* Must be PyLong */ ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, short, (short) PyLong_AsLong(py_input)); } } else if (isSQLLong) { /* On non-Windows x86_64, a SQL_LONG is actually stored as an int, not a ** long. */ if (isPyInt) { ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, int, PyInt_AS_LONG(py_input)); } else { /* Must be PyLong */ ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, int, PyLong_AsLong(py_input)); } #ifdef INTERBASE6_OR_LATER } else { /* data_type must be SQL_INT64 */ if (isPyInt) { /* There is no PyInt_AsLongLong because a PyInt's value is stored ** internally as a C long. */ ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, LONG_LONG, PyInt_AS_LONG(py_input)); } else { /* Must be PyLong */ ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, LONG_LONG, PyLong_AsLongLong(py_input)); } #endif /* INTERBASE6_OR_LATER */ } return INPUT_OK; fail: assert (PyErr_Occurred()); return INPUT_ERROR; } /* _conv_in_internal_integer_types */ #define conv_in_float_conventional(py_input, sqlvar) \ _conv_in_float(FALSE, py_input, &(sqlvar->sqldata), sqlvar) #define conv_in_float_array(py_input, data_slot) \ _conv_in_float(TRUE, py_input, data_slot, NULL) /* The _conv_in_float function should not be called except via the ** conv_in_float_(conventional|array) macros defined above. */ static int _conv_in_float( boolean is_array_element, PyObject *py_input, char **data_slot, XSQLVAR *sqlvar ) { if (is_array_element) { assert (sqlvar == NULL); } if ( PyFloat_Check(py_input) ) { ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, float, PyFloat_AsDouble(py_input)); } else if ( PyInt_Check(py_input) ) { ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, float, PyInt_AsLong(py_input)); } else if ( PyLong_Check(py_input) ) { ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, float, PyLong_AsLong(py_input)); } else { if (!is_array_element) { TRY_TO_ACCEPT_STRING_AND_CONVERT(py_input, sqlvar); } /* YYY:raise more informative error msg: */ raise_exception( InterfaceError, "Type mismatch: " "PyFloat_Check/PyInt_Check/PyLong_Check and SQL_FLOAT" ); goto fail; } return INPUT_OK; fail: assert (PyErr_Occurred()); return INPUT_ERROR; } /* _conv_in_float */ #define conv_in_double_conventional(py_input, sqlvar) \ _conv_in_double(FALSE, py_input, &(sqlvar->sqldata), sqlvar) #define conv_in_double_array(py_input, data_slot) \ _conv_in_double(TRUE, py_input, data_slot, NULL) /* The _conv_in_double function should not be called except via the ** conv_in_double_(conventional|array) macros defined above. */ static int _conv_in_double( boolean is_array_element, PyObject *py_input, char **data_slot, XSQLVAR *sqlvar ) { if (is_array_element) { assert (sqlvar == NULL); } if ( PyFloat_Check(py_input) ) { ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, double, PyFloat_AsDouble(py_input)); } else if ( PyInt_Check(py_input) ) { ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, double, PyInt_AsLong(py_input)); } else if ( PyLong_Check(py_input) ) { ALLOC_IF_NOT_ARRAY_THEN_SET(*data_slot, double, PyLong_AsLong(py_input)); } else { if (!is_array_element) { TRY_TO_ACCEPT_STRING_AND_CONVERT(py_input, sqlvar); } raise_exception( InterfaceError, "Type mismatch: " "PyFloat_Check/PyLong_Check/PyInt_Check and SQL_D_FLOAT/SQL_DOUBLE" ); goto fail; } return INPUT_OK; fail: assert (PyErr_Occurred()); return INPUT_ERROR; } /* _conv_in_double */ /* Date/time types: */ static void raise_datetime_input_error(PyObject *py_input, const char *sql_type_name, const char *required_tuple_length ) { PyObject *py_input_type = PyObject_Type(py_input); PyObject *py_input_type_str = PyObject_Str(py_input_type); char *err_msg_buf = NULL; if (py_input_type_str == NULL) { PyErr_NoMemory(); goto RAISE_DATETIME_INPUT_ERROR_CLEANUP; }{ size_t py_input_type_str_len = PyString_GET_SIZE(py_input_type_str); const char *base_msg = "Type mismatch: For a %s field, you must supply a" " %s-sequence of integers, not a %s."; const size_t base_msg_len = strlen(base_msg); err_msg_buf = (char *) kimem_main_malloc( sizeof(char) * ( base_msg_len + strlen(sql_type_name) + strlen(required_tuple_length) + py_input_type_str_len + 1 )); if (err_msg_buf == NULL) { PyErr_NoMemory(); goto RAISE_DATETIME_INPUT_ERROR_CLEANUP; } sprintf(err_msg_buf, base_msg, sql_type_name, required_tuple_length, PyString_AS_STRING(py_input_type_str) ); raise_exception(InterfaceError, err_msg_buf); RAISE_DATETIME_INPUT_ERROR_CLEANUP: Py_XDECREF(py_input_type); Py_XDECREF(py_input_type_str); /* raise_exception makes a *copy* of the error message buffer that it ** receives, so it's our responsibility to free the buffer we ** allocated locally. */ if (err_msg_buf != NULL) { kimem_main_free(err_msg_buf); } } } /* raise_datetime_input_error */ #define _DATETIME_INPUT_EL(index, ERROR_LABEL) \ el = PySequence_Fast_GET_ITEM(py_input_as_tuple, index); /* borrowed ref */ \ if (!PyInt_Check(el)) { \ goto ERROR_LABEL; \ } #define conv_in_timestamp_conventional(py_input, sqlvar) \ _conv_in_timestamp(FALSE, py_input, &(sqlvar->sqldata), sqlvar) #define conv_in_timestamp_array(py_input, data_slot) \ _conv_in_timestamp(TRUE, py_input, data_slot, NULL) /* The _conv_in_timestamp function should not be called except via the ** conv_in_timestamp_(conventional|array) macros defined above. */ static int _conv_in_timestamp( boolean is_array_element, PyObject *py_input, char **data_slot, XSQLVAR *sqlvar ) { struct tm c_tm; if (is_array_element) { assert (sqlvar == NULL); } /* If py_input is a string, or is a non-sequence, then it's an invalid ** input value--unless the string happens to be a valid TIMESTAMP literal. */ if ( PyString_Check(py_input) || !PySequence_Check(py_input) ) { if (!is_array_element) { TRY_TO_ACCEPT_STRING_AND_CONVERT(py_input, sqlvar); } raise_datetime_input_error(py_input, "TIMESTAMP", "6"); return INPUT_ERROR; } else { int extraction_status = INPUT_ERROR; /* Guilty until proven innocent. */ PyObject *el = NULL; /* We already know that py_input is a sequence, so there's no need to pass ** an error message to PySequence_Fast. */ PyObject *py_input_as_tuple = PySequence_Fast(py_input, ""); if (py_input_as_tuple == NULL) { PyErr_NoMemory(); goto _CONV_IN_TIMESTAMP_EXTRACTION_ERROR; } if (PySequence_Fast_GET_SIZE(py_input_as_tuple) != 6) { raise_datetime_input_error(py_input, "TIMESTAMP", "6"); goto _CONV_IN_TIMESTAMP_EXTRACTION_ERROR; } #define _TIMESTAMP_INPUT_EL(index) \ _DATETIME_INPUT_EL(index, _CONV_IN_TIMESTAMP_EXTRACTION_ERROR) _TIMESTAMP_INPUT_EL(0); c_tm.tm_year = PyInt_AS_LONG(el) - 1900; _TIMESTAMP_INPUT_EL(1); c_tm.tm_mon = PyInt_AS_LONG(el) - 1; _TIMESTAMP_INPUT_EL(2); c_tm.tm_mday = PyInt_AS_LONG(el); _TIMESTAMP_INPUT_EL(3); c_tm.tm_hour = PyInt_AS_LONG(el); _TIMESTAMP_INPUT_EL(4); c_tm.tm_min = PyInt_AS_LONG(el); _TIMESTAMP_INPUT_EL(5); c_tm.tm_sec = PyInt_AS_LONG(el); extraction_status = INPUT_OK; goto __CONV_IN_TIMESTAMP_EXTRACTION_FINISHED; _CONV_IN_TIMESTAMP_EXTRACTION_ERROR: assert (extraction_status == INPUT_ERROR); __CONV_IN_TIMESTAMP_EXTRACTION_FINISHED: Py_XDECREF(py_input_as_tuple); if (extraction_status == INPUT_ERROR) { return extraction_status; } } if (!is_array_element) { *data_slot = (char *) kimem_main_malloc(sizeof(ISC_TIMESTAMP)); if (*data_slot == NULL) { return INPUT_ERROR; } } ENTER_DB isc_encode_timestamp( &c_tm, (ISC_TIMESTAMP *) *data_slot ); LEAVE_DB return INPUT_OK; } /* _conv_in_timestamp */ #ifdef INTERBASE6_OR_LATER #define conv_in_date_conventional(py_input, sqlvar) \ _conv_in_date(FALSE, py_input, &(sqlvar->sqldata), sqlvar) #define conv_in_date_array(py_input, data_slot) \ _conv_in_date(TRUE, py_input, data_slot, NULL) /* The _conv_in_date function should not be called except via the ** conv_in_date_(conventional|array) macros defined above. */ static int _conv_in_date( boolean is_array_element, PyObject *py_input, char **data_slot, XSQLVAR *sqlvar ) { struct tm c_tm; if (is_array_element) { assert (sqlvar == NULL); } /* If py_input is a string, or is a non-sequence, then it's an invalid ** input value--unless the string happens to be a valid DATE literal. */ if ( PyString_Check(py_input) || !PySequence_Check(py_input) ) { if (!is_array_element) { TRY_TO_ACCEPT_STRING_AND_CONVERT(py_input, sqlvar); } raise_datetime_input_error(py_input, "DATE", "3"); return INPUT_ERROR; } else { int extraction_status = INPUT_ERROR; /* Guilty until proven innocent. */ PyObject *el = NULL; /* We already know that py_input is a sequence, so there's no need to pass ** an error message to PySequence_Fast. */ PyObject *py_input_as_tuple = PySequence_Fast(py_input, ""); if (py_input_as_tuple == NULL) { PyErr_NoMemory(); goto _CONV_IN_DATE_EXTRACTION_ERROR; } if (PySequence_Fast_GET_SIZE(py_input_as_tuple) != 3) { raise_datetime_input_error(py_input, "DATE", "3"); goto _CONV_IN_DATE_EXTRACTION_ERROR; } #define _DATE_INPUT_EL(index) \ _DATETIME_INPUT_EL(index, _CONV_IN_DATE_EXTRACTION_ERROR) _DATE_INPUT_EL(0); c_tm.tm_year = PyInt_AS_LONG(el) - 1900; _DATE_INPUT_EL(1); c_tm.tm_mon = PyInt_AS_LONG(el) - 1; _DATE_INPUT_EL(2); c_tm.tm_mday = PyInt_AS_LONG(el); extraction_status = INPUT_OK; goto __CONV_IN_DATE_EXTRACTION_FINISHED; _CONV_IN_DATE_EXTRACTION_ERROR: assert (extraction_status == INPUT_ERROR); __CONV_IN_DATE_EXTRACTION_FINISHED: Py_XDECREF(py_input_as_tuple); if (extraction_status == INPUT_ERROR) { return extraction_status; } } if (!is_array_element) { *data_slot = (char *) kimem_main_malloc(sizeof(ISC_DATE)); if (*data_slot == NULL) { return INPUT_ERROR; } } ENTER_DB isc_encode_sql_date( &c_tm, (ISC_DATE *) *data_slot ); LEAVE_DB return INPUT_OK; } /* _conv_in_date */ #define conv_in_time_conventional(py_input, sqlvar) \ _conv_in_time(FALSE, py_input, &(sqlvar->sqldata), sqlvar) #define conv_in_time_array(py_input, data_slot) \ _conv_in_time(TRUE, py_input, data_slot, NULL) /* The _conv_in_time function should not be called except via the ** conv_in_time_(conventional|array) macros defined above. */ static int _conv_in_time( boolean is_array_element, PyObject *py_input, char **data_slot, XSQLVAR *sqlvar ) { struct tm c_tm; if (is_array_element) { assert (sqlvar == NULL); } /* If py_input is a string, or is a non-sequence, then it's an invalid ** input value--unless the string happens to be a valid TIME literal. */ if ( PyString_Check(py_input) || !PySequence_Check(py_input) ) { if (!is_array_element) { TRY_TO_ACCEPT_STRING_AND_CONVERT(py_input, sqlvar); } raise_datetime_input_error(py_input, "TIME", "3"); return INPUT_ERROR; } else { int extraction_status = INPUT_ERROR; /* Guilty until proven innocent. */ PyObject *el = NULL; /* We already know that py_input is a sequence, so there's no need to pass ** an error message to PySequence_Fast. */ PyObject *py_input_as_tuple = PySequence_Fast(py_input, ""); if (py_input_as_tuple == NULL) { PyErr_NoMemory(); goto _CONV_IN_TIME_EXTRACTION_ERROR; } if (PySequence_Fast_GET_SIZE(py_input_as_tuple) != 3) { raise_datetime_input_error(py_input, "DATE", "3"); goto _CONV_IN_TIME_EXTRACTION_ERROR; } #define _TIME_INPUT_EL(index) \ _DATETIME_INPUT_EL(index, _CONV_IN_TIME_EXTRACTION_ERROR) _TIME_INPUT_EL(0); c_tm.tm_hour = PyInt_AS_LONG(el); _TIME_INPUT_EL(1); c_tm.tm_min = PyInt_AS_LONG(el); _TIME_INPUT_EL(2); c_tm.tm_sec = PyInt_AS_LONG(el); extraction_status = INPUT_OK; goto __CONV_IN_TIME_EXTRACTION_FINISHED; _CONV_IN_TIME_EXTRACTION_ERROR: assert (extraction_status == INPUT_ERROR); __CONV_IN_TIME_EXTRACTION_FINISHED: Py_XDECREF(py_input_as_tuple); if (extraction_status == INPUT_ERROR) { return extraction_status; } } if (!is_array_element) { *data_slot = (char *) kimem_main_malloc(sizeof(ISC_TIME)); if (*data_slot == NULL) { return INPUT_ERROR; } } ENTER_DB isc_encode_sql_time( &c_tm, (ISC_TIME *) *data_slot ); LEAVE_DB return INPUT_OK; } /* _conv_in_time */ #endif /* INTERBASE6_OR_LATER */ static int conv_in_blob( CursorObject *cursor, XSQLVAR *sqlvar, PyObject *py_input ) { /* It would be cute to check for overflow here, but in reality it is not ** necessary. Interbase blobs have a theoretical maximum size of 34359738368 ** bytes (32GB), which far exceeds the theoretical limit of a Python buffer ** or string (INT_MAX, 2147483647 bytes on a typical 32-bit platform). ** The Python programmer simply could not create a single value large enough ** to overflow an Interbase blob (not even by implementing a custom sequence ** class that represents the composition of several buffers, since the ** Python C API function PySequence_Size returns an int). */ ISC_STATUS *status_vector = cursor->status_vector; isc_db_handle db_handle = cursor->connection->db_handle; isc_tr_handle trans_handle = CON_GET_TRANS_HANDLE(cursor->connection); /* 2003.10.15a:OK */ /* Next statement allocates space for the blob's id, not for the blob's ** contents (the contents are read in segment-at-a-time in the ** conv_in_blob_from_pystring function). */ /* 2003.07.22: bug fix: Should have allocated sizeof(ISC_QUAD) bytes, not ** sizeof(ISC_QUAD *), because isc_create_blob2 will be writing into ** sqlvar->sqldata a blob id, not a pointer to a blob id. */ sqlvar->sqldata = kimem_main_malloc( sizeof(ISC_QUAD) ); if ( PyString_Check(py_input) ) { /* conv_in_blob_from_pystring will raise an exception if necessary; we'll ** just pass its return value upward. */ return conv_in_blob_from_pystring ( py_input, (ISC_QUAD *) sqlvar->sqldata, status_vector, db_handle, trans_handle ); } else if ( PyBuffer_Check(py_input) ) { /* conv_in_blob_from_pybuffer will raise an exception if necessary; we'll ** just pass its return value upward. */ return conv_in_blob_from_pybuffer ( py_input, (ISC_QUAD *)(sqlvar->sqldata), status_vector, db_handle, trans_handle ); } else { raise_exception( InterfaceError, "Type mismatch: blob field requires string or buffer as input" ); return INPUT_ERROR; } return INPUT_OK; } /* conv_in_blob */ /******************** UTILITY FUNCTIONS:BEGIN ********************/ static int _try_to_accept_string_and_convert(PyObject *o, XSQLVAR *sqlvar) { if ( !PyString_Check(o) ) { return INPUT_ERROR; } /* Reset the XSQLVAR's type code, retaining its original null flag. */ sqlvar->sqltype = SQL_TEXT | XSQLVAR_SQLTYPE_READ_NULL_FLAG(sqlvar); sqlvar->sqllen = PyString_GET_SIZE(o); /* Refer to the existing buffer inside o; do not allocate new memory. */ sqlvar->sqldata = PyString_AS_STRING(o); return INPUT_OK; } /* _try_to_accept_string_and_convert */ static int _PyObject2XSQLVAR_check_range_SQL_CHARACTER( PyObject *s, int actualLength, int maxLength ) { if (actualLength > maxLength) { PyObject *messageFormat = PyString_FromString( "string overflow: value %d bytes long cannot fit in character" " field of maximum length %d (value is '%s')." ); PyObject *messageArgs = Py_BuildValue( "(iiO)", actualLength, maxLength, s ); PyObject *errorMessage = PyString_Format(messageFormat, messageArgs); raise_exception_with_numeric_error_code( ProgrammingError, -802, /* -802 is the IB error code for an overflow */ PyString_AsString(errorMessage) ); Py_DECREF(messageFormat); Py_DECREF(messageArgs); Py_DECREF(errorMessage); return INPUT_ERROR; } return INPUT_OK; } /* _PyObject2XSQLVAR_check_range_SQL_CHARACTER */ static int _PyObject2XSQLVAR_check_range_SQL_INTEGER( unsigned short dialect, short data_type, short data_subtype, short scale, PyObject *n, PyObject *min, PyObject *max ) { if ( PyObject_Compare(n, min) < 0 || PyObject_Compare(n, max) > 0 ) { const char *externalDataTypeName = get_external_data_type_name(dialect, data_type, data_subtype, scale ); const char *internalDataTypeName = get_internal_data_type_name(data_type); PyObject *messageFormat = PyString_FromString( "numeric overflow: value %d (%s scaled for %d decimal places) is of" " too great a magnitude to fit into its internal storage type %s," " which has range [%d, %d]." ); PyObject *messageArgs = Py_BuildValue("(OsisOO)", n, externalDataTypeName, abs(scale), internalDataTypeName, min, max ); PyObject *errorMessage = PyString_Format(messageFormat, messageArgs); raise_exception_with_numeric_error_code( ProgrammingError, -802, /* -802 is the IB error code for an overflow */ PyString_AsString(errorMessage) ); Py_DECREF(messageFormat); Py_DECREF(messageArgs); Py_DECREF(errorMessage); return INPUT_ERROR; } return INPUT_OK; } /* _PyObject2XSQLVAR_check_range_SQL_INTEGER */ /******************** UTILITY FUNCTIONS:END ********************/